diff options
author | xrs <xrs@mail36.net> | 2017-03-12 15:34:30 +0100 |
---|---|---|
committer | xrs <xrs@mail36.net> | 2017-03-12 15:34:30 +0100 |
commit | 02babcf349e9b80f4ff12893b4f8a78601c0e91c (patch) | |
tree | b8ed076a358afe2affb09971a066749e14d52064 | |
parent | 7cd462b984eddaf5872de7d1f75389fb6c5a5146 (diff) | |
parent | 7d473d08bcc4929c58b85ace2b16f781d721ad13 (diff) | |
download | gnunet-02babcf349e9b80f4ff12893b4f8a78601c0e91c.tar.gz gnunet-02babcf349e9b80f4ff12893b4f8a78601c0e91c.zip |
Merge branch 'master' of ssh://gnunet.org/gnunet
63 files changed, 7516 insertions, 26962 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index 4f3e964e3..cc23ef1f6 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c | |||
@@ -812,6 +812,7 @@ start_process (struct ServiceList *sl, | |||
812 | "%s %s", | 812 | "%s %s", |
813 | fin_options, | 813 | fin_options, |
814 | optpos); | 814 | optpos); |
815 | GNUNET_free (fin_options); | ||
815 | GNUNET_free (optpos); | 816 | GNUNET_free (optpos); |
816 | } | 817 | } |
817 | else | 818 | else |
diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am index b52079b2e..1fe912305 100644 --- a/src/cadet/Makefile.am +++ b/src/cadet/Makefile.am | |||
@@ -23,7 +23,6 @@ AM_CLFAGS = -g | |||
23 | 23 | ||
24 | libexec_PROGRAMS = \ | 24 | libexec_PROGRAMS = \ |
25 | gnunet-service-cadet \ | 25 | gnunet-service-cadet \ |
26 | gnunet-service-cadet-new \ | ||
27 | $(EXP_LIBEXEC) | 26 | $(EXP_LIBEXEC) |
28 | 27 | ||
29 | bin_PROGRAMS = \ | 28 | bin_PROGRAMS = \ |
@@ -61,88 +60,40 @@ gnunet_cadet_LDADD = \ | |||
61 | libgnunetcadetnew.la \ | 60 | libgnunetcadetnew.la \ |
62 | $(top_builddir)/src/util/libgnunetutil.la | 61 | $(top_builddir)/src/util/libgnunetutil.la |
63 | 62 | ||
64 | gnunet_service_cadet_new_SOURCES = \ | ||
65 | gnunet-service-cadet-new.c gnunet-service-cadet-new.h \ | ||
66 | gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \ | ||
67 | gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \ | ||
68 | gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \ | ||
69 | gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \ | ||
70 | gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \ | ||
71 | gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \ | ||
72 | gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \ | ||
73 | gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h | ||
74 | gnunet_service_cadet_new_LDADD = \ | ||
75 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
76 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
77 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
78 | $(top_builddir)/src/dht/libgnunetdht.la \ | ||
79 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
80 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
81 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | ||
82 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
83 | $(top_builddir)/src/block/libgnunetblock.la | ||
84 | |||
85 | gnunet_service_cadet_SOURCES = \ | 63 | gnunet_service_cadet_SOURCES = \ |
86 | gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \ | 64 | gnunet-service-cadet.c gnunet-service-cadet.h \ |
87 | gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \ | ||
88 | gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ | 65 | gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ |
89 | gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ | 66 | gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \ |
90 | gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ | 67 | gnunet-service-cadet_core.c gnunet-service-cadet_core.h \ |
91 | gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ | 68 | gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ |
92 | gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ | 69 | gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ |
93 | cadet_path.c cadet_path.h \ | 70 | gnunet-service-cadet_tunnels.c gnunet-service-cadet_tunnels.h \ |
94 | cadet_common.c \ | 71 | gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \ |
95 | gnunet-service-cadet.c | 72 | gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h |
96 | gnunet_service_cadet_CFLAGS = $(AM_CFLAGS) | ||
97 | gnunet_service_cadet_LDADD = \ | 73 | gnunet_service_cadet_LDADD = \ |
98 | $(top_builddir)/src/util/libgnunetutil.la \ | 74 | $(top_builddir)/src/util/libgnunetutil.la \ |
99 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
100 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
101 | $(top_builddir)/src/ats/libgnunetats.la \ | 75 | $(top_builddir)/src/ats/libgnunetats.la \ |
76 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
102 | $(top_builddir)/src/dht/libgnunetdht.la \ | 77 | $(top_builddir)/src/dht/libgnunetdht.la \ |
103 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 78 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
79 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
104 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | 80 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ |
105 | $(top_builddir)/src/hello/libgnunethello.la \ | 81 | $(top_builddir)/src/hello/libgnunethello.la \ |
106 | $(top_builddir)/src/block/libgnunetblock.la | 82 | $(top_builddir)/src/block/libgnunetblock.la |
107 | if LINUX | 83 | if LINUX |
108 | gnunet_service_cadet_LDFLAGS = -lrt | 84 | gnunet_service_cadet_new_LDFLAGS = -lrt |
109 | endif | 85 | endif |
110 | 86 | ||
111 | 87 | ||
112 | if HAVE_TESTING | 88 | if HAVE_TESTING |
113 | noinst_LTLIBRARIES = libgnunetcadettest.la libgnunetcadettestnew.la $(noinst_LIB_EXP) | 89 | noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP) |
114 | noinst_PROGRAMS = gnunet-cadet-profiler | 90 | # noinst_PROGRAMS = gnunet-cadet-profiler |
115 | endif | 91 | endif |
116 | 92 | ||
117 | libgnunetcadettest_la_SOURCES = \ | ||
118 | cadet_test_lib.c cadet_test_lib.h | ||
119 | libgnunetcadettest_la_LIBADD = \ | ||
120 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
121 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
122 | libgnunetcadet.la | ||
123 | |||
124 | if HAVE_TESTING | 93 | if HAVE_TESTING |
125 | check_PROGRAMS = \ | 94 | check_PROGRAMS = \ |
126 | test_cadet_local_mq \ | 95 | test_cadet_local_mq \ |
127 | test_cadet_2_forward_new \ | 96 | test_cadet_2_forward \ |
128 | test_cadet_2_forward_new \ | ||
129 | test_cadet_2_signal_new \ | ||
130 | test_cadet_2_keepalive_new \ | ||
131 | test_cadet_2_speed_new \ | ||
132 | test_cadet_2_speed_ack_new \ | ||
133 | test_cadet_2_speed_backwards_new \ | ||
134 | test_cadet_2_speed_reliable_new \ | ||
135 | test_cadet_2_speed_reliable_backwards_new \ | ||
136 | test_cadet_5_forward_new \ | ||
137 | test_cadet_5_signal_new \ | ||
138 | test_cadet_5_keepalive_new \ | ||
139 | test_cadet_5_speed_new \ | ||
140 | test_cadet_5_speed_ack_new \ | ||
141 | test_cadet_5_speed_reliable_new \ | ||
142 | test_cadet_5_speed_reliable_backwards_new \ | ||
143 | test_cadet_5_speed_backwards_new \ | ||
144 | test_cadet_single \ | ||
145 | test_cadet_local \ | ||
146 | test_cadet_2_forward \ | 97 | test_cadet_2_forward \ |
147 | test_cadet_2_signal \ | 98 | test_cadet_2_signal \ |
148 | test_cadet_2_keepalive \ | 99 | test_cadet_2_keepalive \ |
@@ -161,32 +112,10 @@ check_PROGRAMS = \ | |||
161 | test_cadet_5_speed_backwards | 112 | test_cadet_5_speed_backwards |
162 | endif | 113 | endif |
163 | 114 | ||
164 | ld_cadet_test_lib = \ | ||
165 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
166 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
167 | libgnunetcadettest.la \ | ||
168 | libgnunetcadet.la \ | ||
169 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
170 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
171 | |||
172 | dep_cadet_test_lib = \ | ||
173 | libgnunetcadet.la \ | ||
174 | libgnunetcadettest.la \ | ||
175 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
176 | |||
177 | |||
178 | gnunet_cadet_profiler_SOURCES = \ | ||
179 | gnunet-cadet-profiler.c | ||
180 | gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib) | ||
181 | 115 | ||
182 | 116 | #gnunet_cadet_profiler_SOURCES = \ | |
183 | test_cadet_single_SOURCES = \ | 117 | # gnunet-cadet-profiler.c |
184 | test_cadet_single.c | 118 | #gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib) |
185 | test_cadet_single_LDADD = $(ld_cadet_test_lib) | ||
186 | |||
187 | test_cadet_local_SOURCES = \ | ||
188 | test_cadet_local.c | ||
189 | test_cadet_local_LDADD = $(ld_cadet_test_lib) | ||
190 | 119 | ||
191 | 120 | ||
192 | test_cadet_local_mq_SOURCES = \ | 121 | test_cadet_local_mq_SOURCES = \ |
@@ -196,6 +125,26 @@ test_cadet_local_mq_LDADD = \ | |||
196 | $(top_builddir)/src/testing/libgnunettesting.la \ | 125 | $(top_builddir)/src/testing/libgnunettesting.la \ |
197 | $(top_builddir)/src/util/libgnunetutil.la | 126 | $(top_builddir)/src/util/libgnunetutil.la |
198 | 127 | ||
128 | |||
129 | libgnunetcadettest_la_SOURCES = \ | ||
130 | cadet_test_lib.c cadet_test_lib.h | ||
131 | libgnunetcadettest_la_LIBADD = \ | ||
132 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
133 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
134 | libgnunetcadetnew.la | ||
135 | |||
136 | ld_cadet_test_lib = \ | ||
137 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
138 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
139 | libgnunetcadetnew.la \ | ||
140 | libgnunetcadettest.la \ | ||
141 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
142 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
143 | dep_cadet_test_lib = \ | ||
144 | libgnunetcadetnew.la \ | ||
145 | libgnunetcadettest.la \ | ||
146 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
147 | |||
199 | test_cadet_2_forward_SOURCES = \ | 148 | test_cadet_2_forward_SOURCES = \ |
200 | test_cadet.c | 149 | test_cadet.c |
201 | test_cadet_2_forward_LDADD = $(ld_cadet_test_lib) | 150 | test_cadet_2_forward_LDADD = $(ld_cadet_test_lib) |
@@ -228,7 +177,6 @@ test_cadet_2_speed_reliable_backwards_SOURCES = \ | |||
228 | test_cadet.c | 177 | test_cadet.c |
229 | test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) | 178 | test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) |
230 | 179 | ||
231 | |||
232 | test_cadet_5_forward_SOURCES = \ | 180 | test_cadet_5_forward_SOURCES = \ |
233 | test_cadet.c | 181 | test_cadet.c |
234 | test_cadet_5_forward_LDADD = $(ld_cadet_test_lib) | 182 | test_cadet_5_forward_LDADD = $(ld_cadet_test_lib) |
@@ -262,92 +210,6 @@ test_cadet_5_speed_reliable_backwards_SOURCES = \ | |||
262 | test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) | 210 | test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) |
263 | 211 | ||
264 | 212 | ||
265 | # NEW TESTS | ||
266 | libgnunetcadettestnew_la_SOURCES = \ | ||
267 | cadet_test_lib_new.c cadet_test_lib_new.h | ||
268 | libgnunetcadettestnew_la_LIBADD = \ | ||
269 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
270 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
271 | libgnunetcadetnew.la | ||
272 | |||
273 | ld_cadet_test_lib_new = \ | ||
274 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
275 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
276 | libgnunetcadetnew.la \ | ||
277 | libgnunetcadettestnew.la \ | ||
278 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
279 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
280 | dep_cadet_test_lib_new = \ | ||
281 | libgnunetcadetnew.la \ | ||
282 | libgnunetcadettestnew.la \ | ||
283 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
284 | |||
285 | test_cadet_2_forward_new_SOURCES = \ | ||
286 | test_cadet_new.c | ||
287 | test_cadet_2_forward_new_LDADD = $(ld_cadet_test_lib_new) | ||
288 | |||
289 | test_cadet_2_signal_new_SOURCES = \ | ||
290 | test_cadet_new.c | ||
291 | test_cadet_2_signal_new_LDADD = $(ld_cadet_test_lib_new) | ||
292 | |||
293 | test_cadet_2_keepalive_new_SOURCES = \ | ||
294 | test_cadet_new.c | ||
295 | test_cadet_2_keepalive_new_LDADD = $(ld_cadet_test_lib_new) | ||
296 | |||
297 | test_cadet_2_speed_new_SOURCES = \ | ||
298 | test_cadet_new.c | ||
299 | test_cadet_2_speed_new_LDADD = $(ld_cadet_test_lib_new) | ||
300 | |||
301 | test_cadet_2_speed_ack_new_SOURCES = \ | ||
302 | test_cadet_new.c | ||
303 | test_cadet_2_speed_ack_new_LDADD = $(ld_cadet_test_lib_new) | ||
304 | |||
305 | test_cadet_2_speed_backwards_new_SOURCES = \ | ||
306 | test_cadet_new.c | ||
307 | test_cadet_2_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new) | ||
308 | |||
309 | test_cadet_2_speed_reliable_new_SOURCES = \ | ||
310 | test_cadet_new.c | ||
311 | test_cadet_2_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new) | ||
312 | |||
313 | test_cadet_2_speed_reliable_backwards_new_SOURCES = \ | ||
314 | test_cadet_new.c | ||
315 | test_cadet_2_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new) | ||
316 | |||
317 | |||
318 | test_cadet_5_forward_new_SOURCES = \ | ||
319 | test_cadet_new.c | ||
320 | test_cadet_5_forward_new_LDADD = $(ld_cadet_test_lib_new) | ||
321 | |||
322 | test_cadet_5_signal_new_SOURCES = \ | ||
323 | test_cadet_new.c | ||
324 | test_cadet_5_signal_new_LDADD = $(ld_cadet_test_lib_new) | ||
325 | |||
326 | test_cadet_5_keepalive_new_SOURCES = \ | ||
327 | test_cadet_new.c | ||
328 | test_cadet_5_keepalive_new_LDADD = $(ld_cadet_test_lib_new) | ||
329 | |||
330 | test_cadet_5_speed_new_SOURCES = \ | ||
331 | test_cadet_new.c | ||
332 | test_cadet_5_speed_new_LDADD = $(ld_cadet_test_lib_new) | ||
333 | |||
334 | test_cadet_5_speed_ack_new_SOURCES = \ | ||
335 | test_cadet_new.c | ||
336 | test_cadet_5_speed_ack_new_LDADD = $(ld_cadet_test_lib_new) | ||
337 | |||
338 | test_cadet_5_speed_backwards_new_SOURCES = \ | ||
339 | test_cadet_new.c | ||
340 | test_cadet_5_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new) | ||
341 | |||
342 | test_cadet_5_speed_reliable_new_SOURCES = \ | ||
343 | test_cadet_new.c | ||
344 | test_cadet_5_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new) | ||
345 | |||
346 | test_cadet_5_speed_reliable_backwards_new_SOURCES = \ | ||
347 | test_cadet_new.c | ||
348 | test_cadet_5_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new) | ||
349 | |||
350 | |||
351 | if ENABLE_TEST_RUN | 213 | if ENABLE_TEST_RUN |
352 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | 214 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; |
353 | TESTS = \ | 215 | TESTS = \ |
diff --git a/src/cadet/cadet.conf.in b/src/cadet/cadet.conf.in index 86ba2e535..d50e168f0 100644 --- a/src/cadet/cadet.conf.in +++ b/src/cadet/cadet.conf.in | |||
@@ -3,7 +3,7 @@ FORCESTART = YES | |||
3 | AUTOSTART = @AUTOSTART@ | 3 | AUTOSTART = @AUTOSTART@ |
4 | @JAVAPORT@PORT = 2096 | 4 | @JAVAPORT@PORT = 2096 |
5 | HOSTNAME = localhost | 5 | HOSTNAME = localhost |
6 | BINARY = gnunet-service-cadet-new | 6 | BINARY = gnunet-service-cadet |
7 | # PREFIX = valgrind --leak-check=yes | 7 | # PREFIX = valgrind --leak-check=yes |
8 | ACCEPT_FROM = 127.0.0.1; | 8 | ACCEPT_FROM = 127.0.0.1; |
9 | ACCEPT_FROM6 = ::1; | 9 | ACCEPT_FROM6 = ::1; |
diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h index 451d1f354..99f9f2653 100644 --- a/src/cadet/cadet.h +++ b/src/cadet/cadet.h | |||
@@ -59,7 +59,7 @@ extern "C" | |||
59 | #include "gnunet_core_service.h" | 59 | #include "gnunet_core_service.h" |
60 | #include "gnunet_cadet_service.h" | 60 | #include "gnunet_cadet_service.h" |
61 | #include "gnunet_protocols.h" | 61 | #include "gnunet_protocols.h" |
62 | #include <gnunet_cadet_service.h> | 62 | #include "gnunet_cadet_service.h" |
63 | 63 | ||
64 | /******************************************************************************/ | 64 | /******************************************************************************/ |
65 | /************************** CONSTANTS ******************************/ | 65 | /************************** CONSTANTS ******************************/ |
diff --git a/src/cadet/cadet_path.c b/src/cadet/cadet_path.c deleted file mode 100644 index 79a498805..000000000 --- a/src/cadet/cadet_path.c +++ /dev/null | |||
@@ -1,363 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001 - 2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/cadet_path.c | ||
23 | * @brief Path handling functions | ||
24 | * @author Bartlomiej Polot | ||
25 | */ | ||
26 | |||
27 | #include "cadet.h" | ||
28 | #include "cadet_path.h" | ||
29 | #include "gnunet-service-cadet_peer.h" | ||
30 | |||
31 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-pth",__VA_ARGS__) | ||
32 | |||
33 | |||
34 | /** | ||
35 | * @brief Destroy a path after some time has past. | ||
36 | * Removes the path from the peer (must not be used for direct paths). | ||
37 | * | ||
38 | * @param cls Closure (path to destroy). | ||
39 | */ | ||
40 | static void | ||
41 | path_destroy_delayed (void *cls) | ||
42 | { | ||
43 | struct CadetPeerPath *path = cls; | ||
44 | struct CadetPeer *peer; | ||
45 | |||
46 | path->path_delete = NULL; | ||
47 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
48 | "Destroy delayed %p (%u)\n", | ||
49 | path, | ||
50 | path->length); | ||
51 | GNUNET_assert (2 < path->length); | ||
52 | peer = GCP_get_short (path->peers[path->length - 1], | ||
53 | GNUNET_NO); | ||
54 | GNUNET_assert (NULL != peer); | ||
55 | GCP_remove_path (peer, path); | ||
56 | } | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Create a new path | ||
61 | * | ||
62 | * @param length How many hops will the path have. | ||
63 | * @return A newly allocated path with a peer array of the specified length. | ||
64 | */ | ||
65 | struct CadetPeerPath * | ||
66 | path_new (unsigned int length) | ||
67 | { | ||
68 | struct CadetPeerPath *p; | ||
69 | |||
70 | p = GNUNET_new (struct CadetPeerPath); | ||
71 | if (length > 0) | ||
72 | { | ||
73 | p->length = length; | ||
74 | p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); | ||
75 | } | ||
76 | LOG (GNUNET_ERROR_TYPE_DEBUG, "New path %p (%u)\n", p, p->length); | ||
77 | return p; | ||
78 | } | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Invert the path | ||
83 | * | ||
84 | * @param path the path to invert | ||
85 | */ | ||
86 | void | ||
87 | path_invert (struct CadetPeerPath *path) | ||
88 | { | ||
89 | GNUNET_PEER_Id aux; | ||
90 | unsigned int i; | ||
91 | |||
92 | for (i = 0; i < path->length / 2; i++) | ||
93 | { | ||
94 | aux = path->peers[i]; | ||
95 | path->peers[i] = path->peers[path->length - i - 1]; | ||
96 | path->peers[path->length - i - 1] = aux; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Duplicate a path, incrementing short peer's rc. | ||
103 | * | ||
104 | * @param path The path to duplicate. | ||
105 | */ | ||
106 | struct CadetPeerPath * | ||
107 | path_duplicate (const struct CadetPeerPath *path) | ||
108 | { | ||
109 | struct CadetPeerPath *aux; | ||
110 | unsigned int i; | ||
111 | |||
112 | aux = path_new (path->length); | ||
113 | GNUNET_memcpy (aux->peers, | ||
114 | path->peers, | ||
115 | path->length * sizeof (GNUNET_PEER_Id)); | ||
116 | for (i = 0; i < aux->length; i++) | ||
117 | GNUNET_PEER_change_rc (aux->peers[i], 1); | ||
118 | return aux; | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Get the length of a path. | ||
124 | * | ||
125 | * @param path The path to measure, with the local peer at any point of it. | ||
126 | * | ||
127 | * @return Number of hops to reach destination. | ||
128 | * UINT_MAX in case the peer is not in the path. | ||
129 | */ | ||
130 | unsigned int | ||
131 | path_get_length (struct CadetPeerPath *path) | ||
132 | { | ||
133 | if (NULL == path) | ||
134 | return UINT_MAX; | ||
135 | return path->length; | ||
136 | } | ||
137 | |||
138 | |||
139 | |||
140 | /** | ||
141 | * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. | ||
142 | * | ||
143 | * Never invalidates a two-hop (direct) path, only a core handler can do that. | ||
144 | * | ||
145 | * Rationale: DHT_get sometimes returns bad cached results, for instance, | ||
146 | * on a locally cached result where the PUT followed a path that is no longer | ||
147 | * current. The path must remain "known and marked as invalid" for a while. | ||
148 | * | ||
149 | * @param p Path to invalidate. | ||
150 | */ | ||
151 | void | ||
152 | path_invalidate (struct CadetPeerPath *p) | ||
153 | { | ||
154 | if (NULL != p->path_delete) | ||
155 | return; | ||
156 | |||
157 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
158 | "Invalidating path %p (%u)\n", | ||
159 | p, | ||
160 | p->length); | ||
161 | p->path_delete | ||
162 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
163 | &path_destroy_delayed, p); | ||
164 | } | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Builds a path from a PeerIdentity array. | ||
169 | * | ||
170 | * @param peers PeerIdentity array. | ||
171 | * @param size Size of the @c peers array. | ||
172 | * @param myid ID of local peer, to find @c own_pos. | ||
173 | * @param own_pos Output parameter: own position in the path. | ||
174 | * | ||
175 | * @return Fixed and shortened path. | ||
176 | */ | ||
177 | struct CadetPeerPath * | ||
178 | path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers, | ||
179 | unsigned int size, | ||
180 | GNUNET_PEER_Id myid, | ||
181 | unsigned int *own_pos) | ||
182 | { | ||
183 | struct CadetPeerPath *path; | ||
184 | GNUNET_PEER_Id shortid; | ||
185 | unsigned int i; | ||
186 | unsigned int j; | ||
187 | unsigned int offset; | ||
188 | |||
189 | /* Create path */ | ||
190 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); | ||
191 | path = path_new (size); | ||
192 | *own_pos = 0; | ||
193 | offset = 0; | ||
194 | for (i = 0; i < size; i++) | ||
195 | { | ||
196 | LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n", | ||
197 | i, GNUNET_i2s (&peers[i])); | ||
198 | shortid = GNUNET_PEER_intern (&peers[i]); | ||
199 | |||
200 | /* Check for loops / duplicates */ | ||
201 | for (j = 0; j < i - offset; j++) | ||
202 | { | ||
203 | if (path->peers[j] == shortid) | ||
204 | { | ||
205 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j); | ||
206 | offset = i - j; | ||
207 | LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset); | ||
208 | GNUNET_PEER_change_rc (shortid, -1); | ||
209 | } | ||
210 | } | ||
211 | LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset); | ||
212 | path->peers[i - offset] = shortid; | ||
213 | if (path->peers[i - offset] == myid) | ||
214 | *own_pos = i - offset; | ||
215 | } | ||
216 | path->length -= offset; | ||
217 | |||
218 | if (path->peers[*own_pos] != myid) | ||
219 | { | ||
220 | /* create path: self not found in path through self */ | ||
221 | GNUNET_break_op (0); | ||
222 | path_destroy (path); | ||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | return path; | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Test if two paths are equivalent (equal or revese of each other). | ||
232 | * | ||
233 | * @param p1 First path | ||
234 | * @param p2 Second path | ||
235 | * | ||
236 | * @return #GNUNET_YES if both paths are equivalent | ||
237 | * #GNUNET_NO otherwise | ||
238 | */ | ||
239 | int | ||
240 | path_equivalent (const struct CadetPeerPath *p1, | ||
241 | const struct CadetPeerPath *p2) | ||
242 | { | ||
243 | unsigned int i; | ||
244 | unsigned int l; | ||
245 | unsigned int half; | ||
246 | |||
247 | if (NULL == p1 || NULL == p2) | ||
248 | return GNUNET_NO; | ||
249 | |||
250 | if (p1->length != p2->length) | ||
251 | return GNUNET_NO; | ||
252 | |||
253 | l = p1->length; | ||
254 | if (0 == memcmp (p1->peers, p2->peers, sizeof (p1->peers[0]) * l)) | ||
255 | return GNUNET_YES; | ||
256 | |||
257 | half = l / 2; | ||
258 | l = l - 1; | ||
259 | for (i = 0; i <= half; i++) | ||
260 | if (p1->peers[i] != p2->peers[l - i]) | ||
261 | return GNUNET_NO; | ||
262 | |||
263 | return GNUNET_YES; | ||
264 | } | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Test if a path is valid (or at least not known to be invalid). | ||
269 | * | ||
270 | * @param path Path to test. | ||
271 | * | ||
272 | * @return #GNUNET_YES If the path is valid or unknown, | ||
273 | * #GNUNET_NO If the path is known to be invalid. | ||
274 | */ | ||
275 | int | ||
276 | path_is_valid (const struct CadetPeerPath *path) | ||
277 | { | ||
278 | return (NULL == path->path_delete); | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Destroy the path and free any allocated resources linked to it | ||
284 | * | ||
285 | * @param p the path to destroy | ||
286 | * | ||
287 | * @return #GNUNET_OK on success | ||
288 | */ | ||
289 | int | ||
290 | path_destroy (struct CadetPeerPath *p) | ||
291 | { | ||
292 | if (NULL == p) | ||
293 | return GNUNET_OK; | ||
294 | |||
295 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
296 | "destroying path %p (%u)\n", | ||
297 | p, | ||
298 | p->length); | ||
299 | GNUNET_PEER_decrement_rcs (p->peers, p->length); | ||
300 | GNUNET_free_non_null (p->peers); | ||
301 | if (NULL != p->path_delete) | ||
302 | GNUNET_SCHEDULER_cancel (p->path_delete); | ||
303 | GNUNET_free (p); | ||
304 | return GNUNET_OK; | ||
305 | } | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Compare two paths. | ||
310 | * | ||
311 | * @param p1 First path. | ||
312 | * @param p2 Second path. | ||
313 | * | ||
314 | * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1. | ||
315 | * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2. | ||
316 | * 0 if they are identical. | ||
317 | */ | ||
318 | int | ||
319 | path_cmp (const struct CadetPeerPath *p1, | ||
320 | const struct CadetPeerPath *p2) | ||
321 | { | ||
322 | if (p1->length > p2->length) | ||
323 | return 1; | ||
324 | |||
325 | if (p1->length < p2->length) | ||
326 | return -1; | ||
327 | |||
328 | return memcmp (p1->peers, | ||
329 | p2->peers, | ||
330 | sizeof (GNUNET_PEER_Id) * p1->length); | ||
331 | } | ||
332 | |||
333 | |||
334 | char * | ||
335 | path_2s (struct CadetPeerPath *p) | ||
336 | { | ||
337 | char *s; | ||
338 | char *old; | ||
339 | unsigned int i; | ||
340 | |||
341 | old = GNUNET_strdup (""); | ||
342 | for (i = 0; i < p->length; i++) | ||
343 | { | ||
344 | GNUNET_asprintf (&s, "%s %s", | ||
345 | old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); | ||
346 | GNUNET_free_non_null (old); | ||
347 | old = s; | ||
348 | } | ||
349 | return old; | ||
350 | } | ||
351 | |||
352 | |||
353 | void | ||
354 | path_debug (struct CadetPeerPath *p) | ||
355 | { | ||
356 | unsigned int i; | ||
357 | |||
358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n"); | ||
359 | for (i = 0; i < p->length; i++) | ||
360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", | ||
361 | GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); | ||
362 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n"); | ||
363 | } | ||
diff --git a/src/cadet/cadet_path.h b/src/cadet/cadet_path.h deleted file mode 100644 index bb68eec42..000000000 --- a/src/cadet/cadet_path.h +++ /dev/null | |||
@@ -1,226 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001 - 2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/cadet_path.h | ||
23 | * @brief Path handling functions | ||
24 | * @author Bartlomiej Polot | ||
25 | */ | ||
26 | |||
27 | #ifndef CADET_PATH_H_ | ||
28 | #define CADET_PATH_H_ | ||
29 | |||
30 | #ifdef __cplusplus | ||
31 | extern "C" | ||
32 | { | ||
33 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
34 | } | ||
35 | #endif | ||
36 | #endif | ||
37 | |||
38 | |||
39 | /******************************************************************************/ | ||
40 | /************************ DATA STRUCTURES ****************************/ | ||
41 | /******************************************************************************/ | ||
42 | |||
43 | /** | ||
44 | * Information regarding a possible path to reach a single peer | ||
45 | */ | ||
46 | struct CadetPeerPath | ||
47 | { | ||
48 | |||
49 | /** | ||
50 | * Linked list | ||
51 | */ | ||
52 | struct CadetPeerPath *next; | ||
53 | struct CadetPeerPath *prev; | ||
54 | |||
55 | /** | ||
56 | * List of all the peers that form the path from origin to target. | ||
57 | */ | ||
58 | GNUNET_PEER_Id *peers; | ||
59 | |||
60 | /** | ||
61 | * Number of peers (hops) in the path | ||
62 | */ | ||
63 | unsigned int length; | ||
64 | |||
65 | /** | ||
66 | * User defined data store. | ||
67 | */ | ||
68 | struct CadetConnection *c; | ||
69 | |||
70 | /** | ||
71 | * Path's score, how reliable is the path. | ||
72 | */ | ||
73 | // int score; | ||
74 | |||
75 | /** | ||
76 | * Task to delete the path. | ||
77 | * We tried it, it didn't work, don't try again in a while. | ||
78 | */ | ||
79 | struct GNUNET_SCHEDULER_Task * path_delete; | ||
80 | |||
81 | }; | ||
82 | |||
83 | /******************************************************************************/ | ||
84 | /************************* FUNCTIONS *****************************/ | ||
85 | /******************************************************************************/ | ||
86 | |||
87 | /** | ||
88 | * Create a new path. | ||
89 | * | ||
90 | * @param length How many hops will the path have. | ||
91 | * | ||
92 | * @return A newly allocated path with a peer array of the specified length. | ||
93 | */ | ||
94 | struct CadetPeerPath * | ||
95 | path_new (unsigned int length); | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Invert the path. | ||
100 | * | ||
101 | * @param path The path to invert. | ||
102 | */ | ||
103 | void | ||
104 | path_invert (struct CadetPeerPath *path); | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Duplicate a path, incrementing short peer's rc. | ||
109 | * | ||
110 | * @param path The path to duplicate. | ||
111 | */ | ||
112 | struct CadetPeerPath * | ||
113 | path_duplicate (const struct CadetPeerPath *path); | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Get the length of a path. | ||
118 | * | ||
119 | * @param path The path to measure, with the local peer at any point of it. | ||
120 | * | ||
121 | * @return Number of hops to reach destination. | ||
122 | * UINT_MAX in case the peer is not in the path. | ||
123 | */ | ||
124 | unsigned int | ||
125 | path_get_length (struct CadetPeerPath *path); | ||
126 | |||
127 | /** | ||
128 | * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. | ||
129 | * | ||
130 | * DHT_get sometimes returns bad cached results, for instance, on a locally | ||
131 | * cached result where the PUT followed a path that is no longer current. | ||
132 | * | ||
133 | * @param p Path to invalidate. | ||
134 | */ | ||
135 | void | ||
136 | path_invalidate (struct CadetPeerPath *p); | ||
137 | |||
138 | /** | ||
139 | * Test if two paths are equivalent (equal or revese of each other). | ||
140 | * | ||
141 | * @param p1 First path | ||
142 | * @param p2 Second path | ||
143 | * | ||
144 | * @return GNUNET_YES if both paths are equivalent | ||
145 | * GNUNET_NO otherwise | ||
146 | */ | ||
147 | int | ||
148 | path_equivalent (const struct CadetPeerPath *p1, | ||
149 | const struct CadetPeerPath *p2); | ||
150 | |||
151 | /** | ||
152 | * Test if a path is valid (or at least not known to be invalid). | ||
153 | * | ||
154 | * @param path Path to test. | ||
155 | * | ||
156 | * @return #GNUNET_YES If the path is valid or unknown, | ||
157 | * #GNUNET_NO If the path is known to be invalid. | ||
158 | */ | ||
159 | int | ||
160 | path_is_valid (const struct CadetPeerPath *path); | ||
161 | |||
162 | /** | ||
163 | * Destroy the path and free any allocated resources linked to it | ||
164 | * | ||
165 | * @param p the path to destroy | ||
166 | * | ||
167 | * @return GNUNET_OK on success | ||
168 | */ | ||
169 | int | ||
170 | path_destroy (struct CadetPeerPath *p); | ||
171 | |||
172 | /** | ||
173 | * Compare two paths. | ||
174 | * | ||
175 | * @param p1 First path. | ||
176 | * @param p2 Second path. | ||
177 | * | ||
178 | * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1. | ||
179 | * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2. | ||
180 | * 0 if they are identical. | ||
181 | */ | ||
182 | int | ||
183 | path_cmp (const struct CadetPeerPath *p1, const struct CadetPeerPath *p2); | ||
184 | |||
185 | /** | ||
186 | * Builds a path from a PeerIdentity array. | ||
187 | * | ||
188 | * @param peers PeerIdentity array. | ||
189 | * @param size Size of the @c peers array. | ||
190 | * @param myid ID of local peer, to find @c own_pos. | ||
191 | * @param own_pos Output parameter: own position in the path. | ||
192 | * | ||
193 | * @return Fixed and shortened path. | ||
194 | */ | ||
195 | struct CadetPeerPath * | ||
196 | path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers, | ||
197 | unsigned int size, | ||
198 | GNUNET_PEER_Id myid, | ||
199 | unsigned int *own_pos); | ||
200 | |||
201 | /** | ||
202 | * Path -> allocated one line string. Caller must free. | ||
203 | * | ||
204 | * @param p Path. | ||
205 | */ | ||
206 | char * | ||
207 | path_2s (struct CadetPeerPath *p); | ||
208 | |||
209 | /** | ||
210 | * Print info about the path for debug. | ||
211 | * | ||
212 | * @param p Path to debug. | ||
213 | */ | ||
214 | void | ||
215 | path_debug (struct CadetPeerPath *p); | ||
216 | |||
217 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
218 | { | ||
219 | #endif | ||
220 | #ifdef __cplusplus | ||
221 | } | ||
222 | #endif | ||
223 | |||
224 | |||
225 | /* ifndef CADET_PATH_H */ | ||
226 | #endif | ||
diff --git a/src/cadet/cadet_protocol.h b/src/cadet/cadet_protocol.h index d2426addb..560c186cd 100644 --- a/src/cadet/cadet_protocol.h +++ b/src/cadet/cadet_protocol.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2001 - 2011 GNUnet e.V. | 3 | Copyright (C) 2007 - 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,8 +19,10 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @author Bartlomiej Polot | ||
23 | * @file cadet/cadet_protocol.h | 22 | * @file cadet/cadet_protocol.h |
23 | * @brief P2P messages used by CADET | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
24 | */ | 26 | */ |
25 | 27 | ||
26 | #ifndef CADET_PROTOCOL_H_ | 28 | #ifndef CADET_PROTOCOL_H_ |
@@ -298,17 +300,10 @@ struct GNUNET_CADET_TunnelEncryptedMessage | |||
298 | */ | 300 | */ |
299 | struct GNUNET_MessageHeader header; | 301 | struct GNUNET_MessageHeader header; |
300 | 302 | ||
301 | #if NEW_CADET | ||
302 | /** | 303 | /** |
303 | * Reserved, for alignment. | 304 | * Reserved, for alignment. |
304 | */ | 305 | */ |
305 | uint32_t reserved GNUNET_PACKED; | 306 | uint32_t reserved GNUNET_PACKED; |
306 | #else | ||
307 | /** | ||
308 | * Maximum packet ID authorized. | ||
309 | */ | ||
310 | struct CadetEncryptedMessageIdentifier cemi; | ||
311 | #endif | ||
312 | 307 | ||
313 | /** | 308 | /** |
314 | * ID of the connection. | 309 | * ID of the connection. |
@@ -322,89 +317,18 @@ struct GNUNET_CADET_TunnelEncryptedMessage | |||
322 | */ | 317 | */ |
323 | struct GNUNET_ShortHashCode hmac; | 318 | struct GNUNET_ShortHashCode hmac; |
324 | 319 | ||
325 | #if NEW_CADET | ||
326 | /** | 320 | /** |
327 | * Axolotl-header that specifies which keys to use in which ratchet | 321 | * Axolotl-header that specifies which keys to use in which ratchet |
328 | * to decrypt the body that follows. | 322 | * to decrypt the body that follows. |
329 | */ | 323 | */ |
330 | struct GNUNET_CADET_AxHeader ax_header; | 324 | struct GNUNET_CADET_AxHeader ax_header; |
331 | #else | ||
332 | /** | ||
333 | * Number of messages sent with the current ratchet key. | ||
334 | */ | ||
335 | uint32_t Ns GNUNET_PACKED; | ||
336 | |||
337 | /** | ||
338 | * Number of messages sent with the previous ratchet key. | ||
339 | */ | ||
340 | uint32_t PNs GNUNET_PACKED; | ||
341 | 325 | ||
342 | /** | 326 | /** |
343 | * Current ratchet key. | ||
344 | */ | ||
345 | struct GNUNET_CRYPTO_EcdhePublicKey DHRs; | ||
346 | #endif | ||
347 | /** | ||
348 | * Encrypted content follows. | 327 | * Encrypted content follows. |
349 | */ | 328 | */ |
350 | }; | 329 | }; |
351 | 330 | ||
352 | 331 | ||
353 | #ifndef NEW_CADET | ||
354 | |||
355 | /** | ||
356 | * Message to query a peer about its Flow Control status regarding a tunnel. | ||
357 | * | ||
358 | * It is NOT yet clear if we need this. | ||
359 | */ | ||
360 | struct GNUNET_CADET_ConnectionHopByHopPollMessage | ||
361 | { | ||
362 | /** | ||
363 | * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL | ||
364 | */ | ||
365 | struct GNUNET_MessageHeader header; | ||
366 | |||
367 | /** | ||
368 | * Last packet sent. | ||
369 | */ | ||
370 | struct CadetEncryptedMessageIdentifier cemi; | ||
371 | |||
372 | /** | ||
373 | * ID of the connection. | ||
374 | */ | ||
375 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
376 | |||
377 | }; | ||
378 | |||
379 | |||
380 | /** | ||
381 | * Message to acknowledge cadet encrypted traffic, used for | ||
382 | * flow-control on a hop-by-hop basis on the connection-level. Note | ||
383 | * that we do use the @e cemi from the tunnel layer as the connection | ||
384 | * layer's header is included/shared with the tunnel layer messages, | ||
385 | * and we only do flow control for the payload. | ||
386 | */ | ||
387 | struct GNUNET_CADET_ConnectionEncryptedAckMessage | ||
388 | { | ||
389 | /** | ||
390 | * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK | ||
391 | */ | ||
392 | struct GNUNET_MessageHeader header; | ||
393 | |||
394 | /** | ||
395 | * Maximum packet ID authorized. | ||
396 | */ | ||
397 | struct CadetEncryptedMessageIdentifier cemi_max; | ||
398 | |||
399 | /** | ||
400 | * ID of the connection. | ||
401 | */ | ||
402 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
403 | }; | ||
404 | |||
405 | #endif | ||
406 | |||
407 | |||
408 | /******************************************************************************/ | 332 | /******************************************************************************/ |
409 | /******************************* CHANNEL ***********************************/ | 333 | /******************************* CHANNEL ***********************************/ |
410 | /******************************************************************************/ | 334 | /******************************************************************************/ |
@@ -450,83 +374,19 @@ struct GNUNET_CADET_ChannelManageMessage | |||
450 | */ | 374 | */ |
451 | struct GNUNET_MessageHeader header; | 375 | struct GNUNET_MessageHeader header; |
452 | 376 | ||
453 | #ifdef NEW_CADET | ||
454 | /** | 377 | /** |
455 | * For alignment. | 378 | * For alignment. |
456 | */ | 379 | */ |
457 | uint32_t reserved GNUNET_PACKED; | 380 | uint32_t reserved GNUNET_PACKED; |
458 | #endif | ||
459 | |||
460 | /** | ||
461 | * ID of the channel | ||
462 | */ | ||
463 | struct GNUNET_CADET_ChannelTunnelNumber ctn; | ||
464 | }; | ||
465 | |||
466 | |||
467 | #ifndef NEW_CADET | ||
468 | |||
469 | /** | ||
470 | * Message for cadet data traffic. | ||
471 | */ | ||
472 | struct GNUNET_CADET_ChannelAppDataMessage | ||
473 | { | ||
474 | /** | ||
475 | * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST, | ||
476 | * #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN | ||
477 | */ | ||
478 | struct GNUNET_MessageHeader header; | ||
479 | |||
480 | /** | ||
481 | * Unique ID of the payload message | ||
482 | */ | ||
483 | /* NEW: struct ChannelMessageIdentifier */ | ||
484 | uint32_t mid GNUNET_PACKED; | ||
485 | 381 | ||
486 | /** | 382 | /** |
487 | * ID of the channel | 383 | * ID of the channel |
488 | */ | 384 | */ |
489 | struct GNUNET_CADET_ChannelTunnelNumber ctn; | 385 | struct GNUNET_CADET_ChannelTunnelNumber ctn; |
490 | |||
491 | /** | ||
492 | * Payload follows | ||
493 | */ | ||
494 | }; | 386 | }; |
495 | 387 | ||
496 | 388 | ||
497 | /** | 389 | /** |
498 | * Message to acknowledge end-to-end data. | ||
499 | */ | ||
500 | struct GNUNET_CADET_ChannelDataAckMessage | ||
501 | { | ||
502 | /** | ||
503 | * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK | ||
504 | */ | ||
505 | struct GNUNET_MessageHeader header; | ||
506 | |||
507 | /** | ||
508 | * ID of the channel | ||
509 | */ | ||
510 | struct GNUNET_CADET_ChannelTunnelNumber ctn; | ||
511 | |||
512 | /** | ||
513 | * Bitfield of already-received messages past @e mid. | ||
514 | * pid + 1 @ LSB | ||
515 | * pid + 64 @ MSB | ||
516 | */ | ||
517 | uint64_t futures GNUNET_PACKED; | ||
518 | |||
519 | /** | ||
520 | * Last message ID received. | ||
521 | */ | ||
522 | /* NEW: struct ChannelMessageIdentifier */ | ||
523 | uint32_t mid GNUNET_PACKED; | ||
524 | }; | ||
525 | |||
526 | #else | ||
527 | |||
528 | |||
529 | /** | ||
530 | * Number used to uniquely identify messages in a CADET Channel. | 390 | * Number used to uniquely identify messages in a CADET Channel. |
531 | */ | 391 | */ |
532 | struct ChannelMessageIdentifier | 392 | struct ChannelMessageIdentifier |
@@ -595,8 +455,6 @@ struct GNUNET_CADET_ChannelDataAckMessage | |||
595 | }; | 455 | }; |
596 | 456 | ||
597 | 457 | ||
598 | #endif | ||
599 | |||
600 | GNUNET_NETWORK_STRUCT_END | 458 | GNUNET_NETWORK_STRUCT_END |
601 | 459 | ||
602 | #if 0 /* keep Emacsens' auto-indent happy */ | 460 | #if 0 /* keep Emacsens' auto-indent happy */ |
diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c index 9a70dad49..c3a1540f4 100644 --- a/src/cadet/cadet_test_lib.c +++ b/src/cadet/cadet_test_lib.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2012 GNUnet e.V. | 3 | Copyright (C) 2012, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -24,9 +24,10 @@ | |||
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | #include "cadet_test_lib.h" | 27 | #include "cadet_test_lib_new.h" |
28 | #include "gnunet_cadet_service.h" | 28 | #include "gnunet_cadet_service.h" |
29 | 29 | ||
30 | |||
30 | /** | 31 | /** |
31 | * Test context for a CADET Test. | 32 | * Test context for a CADET Test. |
32 | */ | 33 | */ |
@@ -40,7 +41,7 @@ struct GNUNET_CADET_TEST_Context | |||
40 | /** | 41 | /** |
41 | * Array of handles to the CADET for each peer. | 42 | * Array of handles to the CADET for each peer. |
42 | */ | 43 | */ |
43 | struct GNUNET_CADET_Handle **cadetes; | 44 | struct GNUNET_CADET_Handle **cadets; |
44 | 45 | ||
45 | /** | 46 | /** |
46 | * Operation associated with the connection to the CADET. | 47 | * Operation associated with the connection to the CADET. |
@@ -48,6 +49,11 @@ struct GNUNET_CADET_TEST_Context | |||
48 | struct GNUNET_TESTBED_Operation **ops; | 49 | struct GNUNET_TESTBED_Operation **ops; |
49 | 50 | ||
50 | /** | 51 | /** |
52 | * Number of peers running, size of the arrays above. | ||
53 | */ | ||
54 | unsigned int num_peers; | ||
55 | |||
56 | /** | ||
51 | * Main function of the test to run once all CADETs are available. | 57 | * Main function of the test to run once all CADETs are available. |
52 | */ | 58 | */ |
53 | GNUNET_CADET_TEST_AppMain app_main; | 59 | GNUNET_CADET_TEST_AppMain app_main; |
@@ -58,30 +64,35 @@ struct GNUNET_CADET_TEST_Context | |||
58 | void *app_main_cls; | 64 | void *app_main_cls; |
59 | 65 | ||
60 | /** | 66 | /** |
61 | * Number of peers running, size of the arrays above. | 67 | * Handler for incoming tunnels. |
62 | */ | 68 | */ |
63 | unsigned int num_peers; | 69 | GNUNET_CADET_ConnectEventHandler connects; |
64 | 70 | ||
65 | /** | 71 | /** |
66 | * Handler for incoming tunnels. | 72 | * Function called when the transmit window size changes. |
67 | */ | 73 | */ |
68 | GNUNET_CADET_InboundChannelNotificationHandler *new_channel; | 74 | GNUNET_CADET_WindowSizeEventHandler window_changes; |
69 | 75 | ||
70 | /** | 76 | /** |
71 | * Cleaner for destroyed incoming tunnels. | 77 | * Cleaner for destroyed incoming tunnels. |
72 | */ | 78 | */ |
73 | GNUNET_CADET_ChannelEndHandler *cleaner; | 79 | GNUNET_CADET_DisconnectEventHandler disconnects; |
74 | 80 | ||
75 | /** | 81 | /** |
76 | * Message handlers. | 82 | * Message handlers. |
77 | */ | 83 | */ |
78 | struct GNUNET_CADET_MessageHandler* handlers; | 84 | struct GNUNET_MQ_MessageHandler *handlers; |
79 | 85 | ||
80 | /** | 86 | /** |
81 | * Application ports. | 87 | * Application ports. |
82 | */ | 88 | */ |
83 | const struct GNUNET_HashCode **ports; | 89 | const struct GNUNET_HashCode **ports; |
84 | 90 | ||
91 | /** | ||
92 | * Number of ports in #ports. | ||
93 | */ | ||
94 | unsigned int port_count; | ||
95 | |||
85 | }; | 96 | }; |
86 | 97 | ||
87 | 98 | ||
@@ -94,6 +105,11 @@ struct GNUNET_CADET_TEST_AdapterContext | |||
94 | * Peer number for the particular peer. | 105 | * Peer number for the particular peer. |
95 | */ | 106 | */ |
96 | unsigned int peer; | 107 | unsigned int peer; |
108 | |||
109 | /** | ||
110 | * Port handlers for open ports. | ||
111 | */ | ||
112 | struct GNUNET_CADET_Port **ports; | ||
97 | 113 | ||
98 | /** | 114 | /** |
99 | * General context. | 115 | * General context. |
@@ -114,26 +130,28 @@ struct GNUNET_CADET_TEST_AdapterContext | |||
114 | */ | 130 | */ |
115 | static void * | 131 | static void * |
116 | cadet_connect_adapter (void *cls, | 132 | cadet_connect_adapter (void *cls, |
117 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 133 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
118 | { | 134 | { |
119 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; | 135 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; |
120 | struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; | 136 | struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; |
121 | struct GNUNET_CADET_Handle *h; | 137 | struct GNUNET_CADET_Handle *h; |
138 | unsigned int i; | ||
122 | 139 | ||
123 | h = GNUNET_CADET_connect (cfg, | 140 | h = GNUNET_CADET_connecT (cfg); |
124 | (void *) (long) actx->peer, | ||
125 | ctx->cleaner, | ||
126 | ctx->handlers); | ||
127 | if (NULL == ctx->ports) | 141 | if (NULL == ctx->ports) |
128 | return h; | 142 | return h; |
129 | 143 | ||
130 | for (int i = 0; NULL != ctx->ports[i]; i++) | 144 | actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *); |
145 | for (i = 0; i < ctx->port_count; i++) | ||
131 | { | 146 | { |
132 | (void ) GNUNET_CADET_open_port (h, ctx->ports[i], | 147 | actx->ports[i] = GNUNET_CADET_open_porT (h, |
133 | ctx->new_channel, | 148 | ctx->ports[i], |
134 | (void *) (long) actx->peer); | 149 | ctx->connects, |
150 | (void *) (long) actx->peer, | ||
151 | ctx->window_changes, | ||
152 | ctx->disconnects, | ||
153 | ctx->handlers); | ||
135 | } | 154 | } |
136 | |||
137 | return h; | 155 | return h; |
138 | } | 156 | } |
139 | 157 | ||
@@ -152,6 +170,15 @@ cadet_disconnect_adapter (void *cls, | |||
152 | struct GNUNET_CADET_Handle *cadet = op_result; | 170 | struct GNUNET_CADET_Handle *cadet = op_result; |
153 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; | 171 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; |
154 | 172 | ||
173 | if (NULL != actx->ports) | ||
174 | { | ||
175 | for (int i = 0; i < actx->ctx->port_count; i++) | ||
176 | { | ||
177 | GNUNET_CADET_close_port (actx->ports[i]); | ||
178 | actx->ports[i] = NULL; | ||
179 | } | ||
180 | GNUNET_free (actx->ports); | ||
181 | } | ||
155 | GNUNET_free (actx); | 182 | GNUNET_free (actx); |
156 | GNUNET_CADET_disconnect (cadet); | 183 | GNUNET_CADET_disconnect (cadet); |
157 | } | 184 | } |
@@ -186,18 +213,18 @@ cadet_connect_cb (void *cls, | |||
186 | for (i = 0; i < ctx->num_peers; i++) | 213 | for (i = 0; i < ctx->num_peers; i++) |
187 | if (op == ctx->ops[i]) | 214 | if (op == ctx->ops[i]) |
188 | { | 215 | { |
189 | ctx->cadetes[i] = ca_result; | 216 | ctx->cadets[i] = ca_result; |
190 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); | 217 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); |
191 | } | 218 | } |
192 | for (i = 0; i < ctx->num_peers; i++) | 219 | for (i = 0; i < ctx->num_peers; i++) |
193 | if (NULL == ctx->cadetes[i]) | 220 | if (NULL == ctx->cadets[i]) |
194 | return; /* still some CADET connections missing */ | 221 | return; /* still some CADET connections missing */ |
195 | /* all CADET connections ready! */ | 222 | /* all CADET connections ready! */ |
196 | ctx->app_main (ctx->app_main_cls, | 223 | ctx->app_main (ctx->app_main_cls, |
197 | ctx, | 224 | ctx, |
198 | ctx->num_peers, | 225 | ctx->num_peers, |
199 | ctx->peers, | 226 | ctx->peers, |
200 | ctx->cadetes); | 227 | ctx->cadets); |
201 | } | 228 | } |
202 | 229 | ||
203 | 230 | ||
@@ -213,7 +240,7 @@ GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx) | |||
213 | ctx->ops[i] = NULL; | 240 | ctx->ops[i] = NULL; |
214 | } | 241 | } |
215 | GNUNET_free (ctx->ops); | 242 | GNUNET_free (ctx->ops); |
216 | GNUNET_free (ctx->cadetes); | 243 | GNUNET_free (ctx->cadets); |
217 | GNUNET_free (ctx); | 244 | GNUNET_free (ctx); |
218 | GNUNET_SCHEDULER_shutdown (); | 245 | GNUNET_SCHEDULER_shutdown (); |
219 | } | 246 | } |
@@ -243,12 +270,23 @@ cadet_test_run (void *cls, | |||
243 | struct GNUNET_CADET_TEST_Context *ctx = cls; | 270 | struct GNUNET_CADET_TEST_Context *ctx = cls; |
244 | unsigned int i; | 271 | unsigned int i; |
245 | 272 | ||
273 | if (0 != links_failed) | ||
274 | { | ||
275 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n", | ||
276 | links_failed); | ||
277 | exit (2); | ||
278 | } | ||
279 | |||
246 | if (num_peers != ctx->num_peers) | 280 | if (num_peers != ctx->num_peers) |
247 | { | 281 | { |
248 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", | 282 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", |
249 | num_peers, ctx->num_peers); | 283 | num_peers, ctx->num_peers); |
250 | exit (1); | 284 | exit (1); |
251 | } | 285 | } |
286 | |||
287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
288 | "Testbed up, %u peers and %u links\n", | ||
289 | num_peers, links_succeeded); | ||
252 | ctx->peers = peers; | 290 | ctx->peers = peers; |
253 | for (i = 0; i < num_peers; i++) | 291 | for (i = 0; i < num_peers; i++) |
254 | { | 292 | { |
@@ -270,31 +308,52 @@ cadet_test_run (void *cls, | |||
270 | } | 308 | } |
271 | 309 | ||
272 | 310 | ||
311 | /** | ||
312 | * Run a test using the given name, configuration file and number of peers. | ||
313 | * All cadet callbacks will receive the peer number (long) as the closure. | ||
314 | * | ||
315 | * @param testname Name of the test (for logging). | ||
316 | * @param cfgfile Name of the configuration file. | ||
317 | * @param num_peers Number of peers to start. | ||
318 | * @param tmain Main function to run once the testbed is ready. | ||
319 | * @param tmain_cls Closure for @a tmain. | ||
320 | * @param connects Handler for incoming channels. | ||
321 | * @param window_changes Handler for the window size change notification. | ||
322 | * @param disconnects Cleaner for destroyed incoming channels. | ||
323 | * @param handlers Message handlers. | ||
324 | * @param ports Ports the peers offer, NULL-terminated. | ||
325 | */ | ||
273 | void | 326 | void |
274 | GNUNET_CADET_TEST_run (const char *testname, | 327 | GNUNET_CADET_TEST_ruN (const char *testname, |
275 | const char *cfgname, | 328 | const char *cfgfile, |
276 | unsigned int num_peers, | 329 | unsigned int num_peers, |
277 | GNUNET_CADET_TEST_AppMain tmain, | 330 | GNUNET_CADET_TEST_AppMain tmain, |
278 | void *tmain_cls, | 331 | void *tmain_cls, |
279 | GNUNET_CADET_InboundChannelNotificationHandler new_channel, | 332 | GNUNET_CADET_ConnectEventHandler connects, |
280 | GNUNET_CADET_ChannelEndHandler cleaner, | 333 | GNUNET_CADET_WindowSizeEventHandler window_changes, |
281 | struct GNUNET_CADET_MessageHandler* handlers, | 334 | GNUNET_CADET_DisconnectEventHandler disconnects, |
282 | const struct GNUNET_HashCode **ports) | 335 | struct GNUNET_MQ_MessageHandler *handlers, |
336 | const struct GNUNET_HashCode **ports) | ||
283 | { | 337 | { |
284 | struct GNUNET_CADET_TEST_Context *ctx; | 338 | struct GNUNET_CADET_TEST_Context *ctx; |
285 | 339 | ||
286 | ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); | 340 | ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); |
287 | ctx->num_peers = num_peers; | 341 | ctx->num_peers = num_peers; |
288 | ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *)); | 342 | ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *); |
289 | ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle *)); | 343 | ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *); |
290 | ctx->app_main = tmain; | 344 | ctx->app_main = tmain; |
291 | ctx->app_main_cls = tmain_cls; | 345 | ctx->app_main_cls = tmain_cls; |
292 | ctx->new_channel = new_channel; | 346 | ctx->connects = connects; |
293 | ctx->cleaner = cleaner; | 347 | ctx->window_changes = window_changes; |
294 | ctx->handlers = handlers; | 348 | ctx->disconnects = disconnects; |
349 | ctx->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
295 | ctx->ports = ports; | 350 | ctx->ports = ports; |
351 | ctx->port_count = 0; | ||
352 | while (NULL != ctx->ports[ctx->port_count]) | ||
353 | ctx->port_count++; | ||
354 | |||
296 | GNUNET_TESTBED_test_run (testname, | 355 | GNUNET_TESTBED_test_run (testname, |
297 | cfgname, | 356 | cfgfile, |
298 | num_peers, | 357 | num_peers, |
299 | 0LL, NULL, NULL, | 358 | 0LL, NULL, NULL, |
300 | &cadet_test_run, ctx); | 359 | &cadet_test_run, ctx); |
diff --git a/src/cadet/cadet_test_lib.h b/src/cadet/cadet_test_lib.h index 464977d42..4b3a6b18d 100644 --- a/src/cadet/cadet_test_lib.h +++ b/src/cadet/cadet_test_lib.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2012 GNUnet e.V. | 3 | Copyright (C) 2012,2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -49,41 +49,41 @@ struct GNUNET_CADET_TEST_Context; | |||
49 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. | 49 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. |
50 | * @param num_peers Number of peers that are running. | 50 | * @param num_peers Number of peers that are running. |
51 | * @param peers Array of peers. | 51 | * @param peers Array of peers. |
52 | * @param cadetes Handle to each of the CADETs of the peers. | 52 | * @param cadets Handle to each of the CADETs of the peers. |
53 | */ | 53 | */ |
54 | typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, | 54 | typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, |
55 | struct GNUNET_CADET_TEST_Context *ctx, | 55 | struct GNUNET_CADET_TEST_Context *ctx, |
56 | unsigned int num_peers, | 56 | unsigned int num_peers, |
57 | struct GNUNET_TESTBED_Peer **peers, | 57 | struct GNUNET_TESTBED_Peer **peers, |
58 | struct GNUNET_CADET_Handle **cadetes); | 58 | struct GNUNET_CADET_Handle **cadets); |
59 | 59 | ||
60 | 60 | ||
61 | /** | 61 | /** |
62 | * Run a test using the given name, configuration file and number of | 62 | * Run a test using the given name, configuration file and number of peers. |
63 | * peers. | 63 | * All cadet callbacks will receive the peer number (long) as the closure. |
64 | * All cadet callbacks will receive the peer number as the closure. | ||
65 | * | 64 | * |
66 | * @param testname Name of the test (for logging). | 65 | * @param testname Name of the test (for logging). |
67 | * @param cfgname Name of the configuration file. | 66 | * @param cfgfile Name of the configuration file. |
68 | * @param num_peers Number of peers to start. | 67 | * @param num_peers Number of peers to start. |
69 | * @param tmain Main function to run once the testbed is ready. | 68 | * @param tmain Main function to run once the testbed is ready. |
70 | * @param tmain_cls Closure for 'tmain'. | 69 | * @param tmain_cls Closure for @a tmain. |
71 | * @param new_channel Handler for incoming tunnels. | 70 | * @param connects Handler for incoming channels. |
72 | * @param cleaner Cleaner for destroyed incoming tunnels. | 71 | * @param window_changes Handler for the window size change notification. |
72 | * @param disconnects Cleaner for destroyed incoming channels. | ||
73 | * @param handlers Message handlers. | 73 | * @param handlers Message handlers. |
74 | * @param ports Ports the peers offer, NULL-terminated. | 74 | * @param ports Ports the peers offer, NULL-terminated. |
75 | */ | 75 | */ |
76 | void | 76 | void |
77 | GNUNET_CADET_TEST_run (const char *testname, | 77 | GNUNET_CADET_TEST_ruN (const char *testname, |
78 | const char *cfgname, | 78 | const char *cfgfile, |
79 | unsigned int num_peers, | 79 | unsigned int num_peers, |
80 | GNUNET_CADET_TEST_AppMain tmain, | 80 | GNUNET_CADET_TEST_AppMain tmain, |
81 | void *tmain_cls, | 81 | void *tmain_cls, |
82 | GNUNET_CADET_InboundChannelNotificationHandler new_channel, | 82 | GNUNET_CADET_ConnectEventHandler connects, |
83 | GNUNET_CADET_ChannelEndHandler cleaner, | 83 | GNUNET_CADET_WindowSizeEventHandler window_changes, |
84 | struct GNUNET_CADET_MessageHandler* handlers, | 84 | GNUNET_CADET_DisconnectEventHandler disconnects, |
85 | const struct GNUNET_HashCode **ports); | 85 | struct GNUNET_MQ_MessageHandler *handlers, |
86 | 86 | const struct GNUNET_HashCode **ports); | |
87 | 87 | ||
88 | /** | 88 | /** |
89 | * Clean up the testbed. | 89 | * Clean up the testbed. |
diff --git a/src/cadet/cadet_test_lib_new.c b/src/cadet/cadet_test_lib_new.c deleted file mode 100644 index c3a1540f4..000000000 --- a/src/cadet/cadet_test_lib_new.c +++ /dev/null | |||
@@ -1,362 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/cadet_test_lib.c | ||
22 | * @author Bartlomiej Polot | ||
23 | * @brief library for writing CADET tests | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "cadet_test_lib_new.h" | ||
28 | #include "gnunet_cadet_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Test context for a CADET Test. | ||
33 | */ | ||
34 | struct GNUNET_CADET_TEST_Context | ||
35 | { | ||
36 | /** | ||
37 | * Array of running peers. | ||
38 | */ | ||
39 | struct GNUNET_TESTBED_Peer **peers; | ||
40 | |||
41 | /** | ||
42 | * Array of handles to the CADET for each peer. | ||
43 | */ | ||
44 | struct GNUNET_CADET_Handle **cadets; | ||
45 | |||
46 | /** | ||
47 | * Operation associated with the connection to the CADET. | ||
48 | */ | ||
49 | struct GNUNET_TESTBED_Operation **ops; | ||
50 | |||
51 | /** | ||
52 | * Number of peers running, size of the arrays above. | ||
53 | */ | ||
54 | unsigned int num_peers; | ||
55 | |||
56 | /** | ||
57 | * Main function of the test to run once all CADETs are available. | ||
58 | */ | ||
59 | GNUNET_CADET_TEST_AppMain app_main; | ||
60 | |||
61 | /** | ||
62 | * Closure for 'app_main'. | ||
63 | */ | ||
64 | void *app_main_cls; | ||
65 | |||
66 | /** | ||
67 | * Handler for incoming tunnels. | ||
68 | */ | ||
69 | GNUNET_CADET_ConnectEventHandler connects; | ||
70 | |||
71 | /** | ||
72 | * Function called when the transmit window size changes. | ||
73 | */ | ||
74 | GNUNET_CADET_WindowSizeEventHandler window_changes; | ||
75 | |||
76 | /** | ||
77 | * Cleaner for destroyed incoming tunnels. | ||
78 | */ | ||
79 | GNUNET_CADET_DisconnectEventHandler disconnects; | ||
80 | |||
81 | /** | ||
82 | * Message handlers. | ||
83 | */ | ||
84 | struct GNUNET_MQ_MessageHandler *handlers; | ||
85 | |||
86 | /** | ||
87 | * Application ports. | ||
88 | */ | ||
89 | const struct GNUNET_HashCode **ports; | ||
90 | |||
91 | /** | ||
92 | * Number of ports in #ports. | ||
93 | */ | ||
94 | unsigned int port_count; | ||
95 | |||
96 | }; | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Context for a cadet adapter callback. | ||
101 | */ | ||
102 | struct GNUNET_CADET_TEST_AdapterContext | ||
103 | { | ||
104 | /** | ||
105 | * Peer number for the particular peer. | ||
106 | */ | ||
107 | unsigned int peer; | ||
108 | |||
109 | /** | ||
110 | * Port handlers for open ports. | ||
111 | */ | ||
112 | struct GNUNET_CADET_Port **ports; | ||
113 | |||
114 | /** | ||
115 | * General context. | ||
116 | */ | ||
117 | struct GNUNET_CADET_TEST_Context *ctx; | ||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Adapter function called to establish a connection to | ||
123 | * the CADET service. | ||
124 | * | ||
125 | * @param cls closure | ||
126 | * @param cfg configuration of the peer to connect to; will be available until | ||
127 | * GNUNET_TESTBED_operation_done() is called on the operation returned | ||
128 | * from GNUNET_TESTBED_service_connect() | ||
129 | * @return service handle to return in 'op_result', NULL on error | ||
130 | */ | ||
131 | static void * | ||
132 | cadet_connect_adapter (void *cls, | ||
133 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
134 | { | ||
135 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; | ||
136 | struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; | ||
137 | struct GNUNET_CADET_Handle *h; | ||
138 | unsigned int i; | ||
139 | |||
140 | h = GNUNET_CADET_connecT (cfg); | ||
141 | if (NULL == ctx->ports) | ||
142 | return h; | ||
143 | |||
144 | actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *); | ||
145 | for (i = 0; i < ctx->port_count; i++) | ||
146 | { | ||
147 | actx->ports[i] = GNUNET_CADET_open_porT (h, | ||
148 | ctx->ports[i], | ||
149 | ctx->connects, | ||
150 | (void *) (long) actx->peer, | ||
151 | ctx->window_changes, | ||
152 | ctx->disconnects, | ||
153 | ctx->handlers); | ||
154 | } | ||
155 | return h; | ||
156 | } | ||
157 | |||
158 | |||
159 | /** | ||
160 | * Adapter function called to destroy a connection to | ||
161 | * the CADET service. | ||
162 | * | ||
163 | * @param cls closure | ||
164 | * @param op_result service handle returned from the connect adapter | ||
165 | */ | ||
166 | static void | ||
167 | cadet_disconnect_adapter (void *cls, | ||
168 | void *op_result) | ||
169 | { | ||
170 | struct GNUNET_CADET_Handle *cadet = op_result; | ||
171 | struct GNUNET_CADET_TEST_AdapterContext *actx = cls; | ||
172 | |||
173 | if (NULL != actx->ports) | ||
174 | { | ||
175 | for (int i = 0; i < actx->ctx->port_count; i++) | ||
176 | { | ||
177 | GNUNET_CADET_close_port (actx->ports[i]); | ||
178 | actx->ports[i] = NULL; | ||
179 | } | ||
180 | GNUNET_free (actx->ports); | ||
181 | } | ||
182 | GNUNET_free (actx); | ||
183 | GNUNET_CADET_disconnect (cadet); | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Callback to be called when a service connect operation is completed. | ||
189 | * | ||
190 | * @param cls The callback closure from functions generating an operation. | ||
191 | * @param op The operation that has been finished. | ||
192 | * @param ca_result The service handle returned from | ||
193 | * GNUNET_TESTBED_ConnectAdapter() (cadet handle). | ||
194 | * @param emsg Error message in case the operation has failed. | ||
195 | * NULL if operation has executed successfully. | ||
196 | */ | ||
197 | static void | ||
198 | cadet_connect_cb (void *cls, | ||
199 | struct GNUNET_TESTBED_Operation *op, | ||
200 | void *ca_result, | ||
201 | const char *emsg) | ||
202 | { | ||
203 | struct GNUNET_CADET_TEST_Context *ctx = cls; | ||
204 | unsigned int i; | ||
205 | |||
206 | if (NULL != emsg) | ||
207 | { | ||
208 | fprintf (stderr, "Failed to connect to CADET service: %s\n", | ||
209 | emsg); | ||
210 | GNUNET_SCHEDULER_shutdown (); | ||
211 | return; | ||
212 | } | ||
213 | for (i = 0; i < ctx->num_peers; i++) | ||
214 | if (op == ctx->ops[i]) | ||
215 | { | ||
216 | ctx->cadets[i] = ca_result; | ||
217 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); | ||
218 | } | ||
219 | for (i = 0; i < ctx->num_peers; i++) | ||
220 | if (NULL == ctx->cadets[i]) | ||
221 | return; /* still some CADET connections missing */ | ||
222 | /* all CADET connections ready! */ | ||
223 | ctx->app_main (ctx->app_main_cls, | ||
224 | ctx, | ||
225 | ctx->num_peers, | ||
226 | ctx->peers, | ||
227 | ctx->cadets); | ||
228 | } | ||
229 | |||
230 | |||
231 | void | ||
232 | GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx) | ||
233 | { | ||
234 | unsigned int i; | ||
235 | |||
236 | for (i = 0; i < ctx->num_peers; i++) | ||
237 | { | ||
238 | GNUNET_assert (NULL != ctx->ops[i]); | ||
239 | GNUNET_TESTBED_operation_done (ctx->ops[i]); | ||
240 | ctx->ops[i] = NULL; | ||
241 | } | ||
242 | GNUNET_free (ctx->ops); | ||
243 | GNUNET_free (ctx->cadets); | ||
244 | GNUNET_free (ctx); | ||
245 | GNUNET_SCHEDULER_shutdown (); | ||
246 | } | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Callback run when the testbed is ready (peers running and connected to | ||
251 | * each other) | ||
252 | * | ||
253 | * @param cls Closure (context). | ||
254 | * @param h the run handle | ||
255 | * @param num_peers Number of peers that are running. | ||
256 | * @param peers Handles to each one of the @c num_peers peers. | ||
257 | * @param links_succeeded the number of overlay link connection attempts that | ||
258 | * succeeded | ||
259 | * @param links_failed the number of overlay link connection attempts that | ||
260 | * failed | ||
261 | */ | ||
262 | static void | ||
263 | cadet_test_run (void *cls, | ||
264 | struct GNUNET_TESTBED_RunHandle *h, | ||
265 | unsigned int num_peers, | ||
266 | struct GNUNET_TESTBED_Peer **peers, | ||
267 | unsigned int links_succeeded, | ||
268 | unsigned int links_failed) | ||
269 | { | ||
270 | struct GNUNET_CADET_TEST_Context *ctx = cls; | ||
271 | unsigned int i; | ||
272 | |||
273 | if (0 != links_failed) | ||
274 | { | ||
275 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n", | ||
276 | links_failed); | ||
277 | exit (2); | ||
278 | } | ||
279 | |||
280 | if (num_peers != ctx->num_peers) | ||
281 | { | ||
282 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", | ||
283 | num_peers, ctx->num_peers); | ||
284 | exit (1); | ||
285 | } | ||
286 | |||
287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
288 | "Testbed up, %u peers and %u links\n", | ||
289 | num_peers, links_succeeded); | ||
290 | ctx->peers = peers; | ||
291 | for (i = 0; i < num_peers; i++) | ||
292 | { | ||
293 | struct GNUNET_CADET_TEST_AdapterContext *newctx; | ||
294 | newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext); | ||
295 | newctx->peer = i; | ||
296 | newctx->ctx = ctx; | ||
297 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i); | ||
298 | ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx, | ||
299 | peers[i], | ||
300 | "cadet", | ||
301 | &cadet_connect_cb, | ||
302 | ctx, | ||
303 | &cadet_connect_adapter, | ||
304 | &cadet_disconnect_adapter, | ||
305 | newctx); | ||
306 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Run a test using the given name, configuration file and number of peers. | ||
313 | * All cadet callbacks will receive the peer number (long) as the closure. | ||
314 | * | ||
315 | * @param testname Name of the test (for logging). | ||
316 | * @param cfgfile Name of the configuration file. | ||
317 | * @param num_peers Number of peers to start. | ||
318 | * @param tmain Main function to run once the testbed is ready. | ||
319 | * @param tmain_cls Closure for @a tmain. | ||
320 | * @param connects Handler for incoming channels. | ||
321 | * @param window_changes Handler for the window size change notification. | ||
322 | * @param disconnects Cleaner for destroyed incoming channels. | ||
323 | * @param handlers Message handlers. | ||
324 | * @param ports Ports the peers offer, NULL-terminated. | ||
325 | */ | ||
326 | void | ||
327 | GNUNET_CADET_TEST_ruN (const char *testname, | ||
328 | const char *cfgfile, | ||
329 | unsigned int num_peers, | ||
330 | GNUNET_CADET_TEST_AppMain tmain, | ||
331 | void *tmain_cls, | ||
332 | GNUNET_CADET_ConnectEventHandler connects, | ||
333 | GNUNET_CADET_WindowSizeEventHandler window_changes, | ||
334 | GNUNET_CADET_DisconnectEventHandler disconnects, | ||
335 | struct GNUNET_MQ_MessageHandler *handlers, | ||
336 | const struct GNUNET_HashCode **ports) | ||
337 | { | ||
338 | struct GNUNET_CADET_TEST_Context *ctx; | ||
339 | |||
340 | ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); | ||
341 | ctx->num_peers = num_peers; | ||
342 | ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *); | ||
343 | ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *); | ||
344 | ctx->app_main = tmain; | ||
345 | ctx->app_main_cls = tmain_cls; | ||
346 | ctx->connects = connects; | ||
347 | ctx->window_changes = window_changes; | ||
348 | ctx->disconnects = disconnects; | ||
349 | ctx->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
350 | ctx->ports = ports; | ||
351 | ctx->port_count = 0; | ||
352 | while (NULL != ctx->ports[ctx->port_count]) | ||
353 | ctx->port_count++; | ||
354 | |||
355 | GNUNET_TESTBED_test_run (testname, | ||
356 | cfgfile, | ||
357 | num_peers, | ||
358 | 0LL, NULL, NULL, | ||
359 | &cadet_test_run, ctx); | ||
360 | } | ||
361 | |||
362 | /* end of cadet_test_lib.c */ | ||
diff --git a/src/cadet/cadet_test_lib_new.h b/src/cadet/cadet_test_lib_new.h deleted file mode 100644 index 4b3a6b18d..000000000 --- a/src/cadet/cadet_test_lib_new.h +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012,2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/cadet_test_lib.h | ||
22 | * @author Bartlomiej Polot | ||
23 | * @brief library for writing CADET tests | ||
24 | */ | ||
25 | #ifndef CADET_TEST_LIB_H | ||
26 | #define CADET_TEST_LIB_H | ||
27 | |||
28 | #ifdef __cplusplus | ||
29 | extern "C" | ||
30 | { | ||
31 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
32 | } | ||
33 | #endif | ||
34 | #endif | ||
35 | |||
36 | #include "gnunet_testbed_service.h" | ||
37 | #include "gnunet_cadet_service.h" | ||
38 | |||
39 | /** | ||
40 | * Test context for a CADET Test. | ||
41 | */ | ||
42 | struct GNUNET_CADET_TEST_Context; | ||
43 | |||
44 | |||
45 | /** | ||
46 | * Main function of a CADET test. | ||
47 | * | ||
48 | * @param cls Closure. | ||
49 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. | ||
50 | * @param num_peers Number of peers that are running. | ||
51 | * @param peers Array of peers. | ||
52 | * @param cadets Handle to each of the CADETs of the peers. | ||
53 | */ | ||
54 | typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, | ||
55 | struct GNUNET_CADET_TEST_Context *ctx, | ||
56 | unsigned int num_peers, | ||
57 | struct GNUNET_TESTBED_Peer **peers, | ||
58 | struct GNUNET_CADET_Handle **cadets); | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Run a test using the given name, configuration file and number of peers. | ||
63 | * All cadet callbacks will receive the peer number (long) as the closure. | ||
64 | * | ||
65 | * @param testname Name of the test (for logging). | ||
66 | * @param cfgfile Name of the configuration file. | ||
67 | * @param num_peers Number of peers to start. | ||
68 | * @param tmain Main function to run once the testbed is ready. | ||
69 | * @param tmain_cls Closure for @a tmain. | ||
70 | * @param connects Handler for incoming channels. | ||
71 | * @param window_changes Handler for the window size change notification. | ||
72 | * @param disconnects Cleaner for destroyed incoming channels. | ||
73 | * @param handlers Message handlers. | ||
74 | * @param ports Ports the peers offer, NULL-terminated. | ||
75 | */ | ||
76 | void | ||
77 | GNUNET_CADET_TEST_ruN (const char *testname, | ||
78 | const char *cfgfile, | ||
79 | unsigned int num_peers, | ||
80 | GNUNET_CADET_TEST_AppMain tmain, | ||
81 | void *tmain_cls, | ||
82 | GNUNET_CADET_ConnectEventHandler connects, | ||
83 | GNUNET_CADET_WindowSizeEventHandler window_changes, | ||
84 | GNUNET_CADET_DisconnectEventHandler disconnects, | ||
85 | struct GNUNET_MQ_MessageHandler *handlers, | ||
86 | const struct GNUNET_HashCode **ports); | ||
87 | |||
88 | /** | ||
89 | * Clean up the testbed. | ||
90 | * | ||
91 | * @param ctx handle for the testbed | ||
92 | */ | ||
93 | void | ||
94 | GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx); | ||
95 | |||
96 | |||
97 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
98 | { | ||
99 | #endif | ||
100 | #ifdef __cplusplus | ||
101 | } | ||
102 | #endif | ||
103 | |||
104 | |||
105 | /* ifndef CADET_TEST_LIB_H */ | ||
106 | #endif | ||
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c deleted file mode 100644 index 93f53de4c..000000000 --- a/src/cadet/gnunet-service-cadet-new.c +++ /dev/null | |||
@@ -1,1496 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2013, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet-new.c | ||
23 | * @brief GNUnet CADET service with encryption | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * Dictionary: | ||
28 | * - peer: other cadet instance. If there is direct connection it's a neighbor. | ||
29 | * - path: series of directly connected peer from one peer to another. | ||
30 | * - connection: path which is being used in a tunnel. | ||
31 | * - tunnel: encrypted connection to a peer, neighbor or not. | ||
32 | * - channel: logical link between two clients, on the same or different peers. | ||
33 | * have properties like reliability. | ||
34 | */ | ||
35 | |||
36 | #include "platform.h" | ||
37 | #include "gnunet_util_lib.h" | ||
38 | #include "cadet.h" | ||
39 | #include "gnunet_statistics_service.h" | ||
40 | #include "gnunet-service-cadet-new.h" | ||
41 | #include "gnunet-service-cadet-new_channel.h" | ||
42 | #include "gnunet-service-cadet-new_connection.h" | ||
43 | #include "gnunet-service-cadet-new_core.h" | ||
44 | #include "gnunet-service-cadet-new_dht.h" | ||
45 | #include "gnunet-service-cadet-new_hello.h" | ||
46 | #include "gnunet-service-cadet-new_tunnels.h" | ||
47 | #include "gnunet-service-cadet-new_peer.h" | ||
48 | #include "gnunet-service-cadet-new_paths.h" | ||
49 | |||
50 | #define LOG(level, ...) GNUNET_log (level,__VA_ARGS__) | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Struct containing information about a client of the service | ||
55 | */ | ||
56 | struct CadetClient | ||
57 | { | ||
58 | /** | ||
59 | * Linked list next | ||
60 | */ | ||
61 | struct CadetClient *next; | ||
62 | |||
63 | /** | ||
64 | * Linked list prev | ||
65 | */ | ||
66 | struct CadetClient *prev; | ||
67 | |||
68 | /** | ||
69 | * Tunnels that belong to this client, indexed by local id, | ||
70 | * value is a `struct CadetChannel`. | ||
71 | */ | ||
72 | struct GNUNET_CONTAINER_MultiHashMap32 *channels; | ||
73 | |||
74 | /** | ||
75 | * Handle to communicate with the client | ||
76 | */ | ||
77 | struct GNUNET_MQ_Handle *mq; | ||
78 | |||
79 | /** | ||
80 | * Client handle. | ||
81 | */ | ||
82 | struct GNUNET_SERVICE_Client *client; | ||
83 | |||
84 | /** | ||
85 | * Ports that this client has declared interest in. | ||
86 | * Indexed by port, contains *Client. | ||
87 | */ | ||
88 | struct GNUNET_CONTAINER_MultiHashMap *ports; | ||
89 | |||
90 | /** | ||
91 | * Channel ID to use for the next incoming channel for this client. | ||
92 | * Wraps around (in theory). | ||
93 | */ | ||
94 | struct GNUNET_CADET_ClientChannelNumber next_ccn; | ||
95 | |||
96 | /** | ||
97 | * ID of the client, mainly for debug messages. Purely internal to this file. | ||
98 | */ | ||
99 | unsigned int id; | ||
100 | }; | ||
101 | |||
102 | /******************************************************************************/ | ||
103 | /*********************** GLOBAL VARIABLES ****************************/ | ||
104 | /******************************************************************************/ | ||
105 | |||
106 | /****************************** Global variables ******************************/ | ||
107 | |||
108 | /** | ||
109 | * Handle to our configuration. | ||
110 | */ | ||
111 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
112 | |||
113 | /** | ||
114 | * Handle to the statistics service. | ||
115 | */ | ||
116 | struct GNUNET_STATISTICS_Handle *stats; | ||
117 | |||
118 | /** | ||
119 | * Handle to communicate with ATS. | ||
120 | */ | ||
121 | struct GNUNET_ATS_ConnectivityHandle *ats_ch; | ||
122 | |||
123 | /** | ||
124 | * Local peer own ID. | ||
125 | */ | ||
126 | struct GNUNET_PeerIdentity my_full_id; | ||
127 | |||
128 | /** | ||
129 | * Own private key. | ||
130 | */ | ||
131 | struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; | ||
132 | |||
133 | /** | ||
134 | * Signal that shutdown is happening: prevent recovery measures. | ||
135 | */ | ||
136 | int shutting_down; | ||
137 | |||
138 | /** | ||
139 | * DLL with all the clients, head. | ||
140 | */ | ||
141 | static struct CadetClient *clients_head; | ||
142 | |||
143 | /** | ||
144 | * DLL with all the clients, tail. | ||
145 | */ | ||
146 | static struct CadetClient *clients_tail; | ||
147 | |||
148 | /** | ||
149 | * Next ID to assign to a client. | ||
150 | */ | ||
151 | static unsigned int next_client_id; | ||
152 | |||
153 | /** | ||
154 | * All ports clients of this peer have opened. | ||
155 | */ | ||
156 | struct GNUNET_CONTAINER_MultiHashMap *open_ports; | ||
157 | |||
158 | /** | ||
159 | * Map from ports to channels where the ports were closed at the | ||
160 | * time we got the inbound connection. | ||
161 | * Indexed by port, contains `struct CadetChannel`. | ||
162 | */ | ||
163 | struct GNUNET_CONTAINER_MultiHashMap *loose_channels; | ||
164 | |||
165 | /** | ||
166 | * Map from PIDs to `struct CadetPeer` entries. | ||
167 | */ | ||
168 | struct GNUNET_CONTAINER_MultiPeerMap *peers; | ||
169 | |||
170 | /** | ||
171 | * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier` | ||
172 | * hash codes to `struct CadetConnection` objects. | ||
173 | */ | ||
174 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
175 | |||
176 | /** | ||
177 | * How many messages are needed to trigger an AXOLOTL ratchet advance. | ||
178 | */ | ||
179 | unsigned long long ratchet_messages; | ||
180 | |||
181 | /** | ||
182 | * How long until we trigger a ratched advance due to time. | ||
183 | */ | ||
184 | struct GNUNET_TIME_Relative ratchet_time; | ||
185 | |||
186 | /** | ||
187 | * How frequently do we send KEEPALIVE messages on idle connections? | ||
188 | */ | ||
189 | struct GNUNET_TIME_Relative keepalive_period; | ||
190 | |||
191 | /** | ||
192 | * Set to non-zero values to create random drops to test retransmissions. | ||
193 | */ | ||
194 | unsigned long long drop_percent; | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Send a message to a client. | ||
199 | * | ||
200 | * @param c client to get the message | ||
201 | * @param env envelope with the message | ||
202 | */ | ||
203 | void | ||
204 | GSC_send_to_client (struct CadetClient *c, | ||
205 | struct GNUNET_MQ_Envelope *env) | ||
206 | { | ||
207 | GNUNET_MQ_send (c->mq, | ||
208 | env); | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Return identifier for a client as a string. | ||
214 | * | ||
215 | * @param c client to identify | ||
216 | * @return string for debugging | ||
217 | */ | ||
218 | const char * | ||
219 | GSC_2s (struct CadetClient *c) | ||
220 | { | ||
221 | static char buf[32]; | ||
222 | |||
223 | GNUNET_snprintf (buf, | ||
224 | sizeof (buf), | ||
225 | "Client(%u)", | ||
226 | c->id); | ||
227 | return buf; | ||
228 | } | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Lookup channel of client @a c by @a ccn. | ||
233 | * | ||
234 | * @param c client to look in | ||
235 | * @param ccn channel ID to look up | ||
236 | * @return NULL if no such channel exists | ||
237 | */ | ||
238 | static struct CadetChannel * | ||
239 | lookup_channel (struct CadetClient *c, | ||
240 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
241 | { | ||
242 | return GNUNET_CONTAINER_multihashmap32_get (c->channels, | ||
243 | ntohl (ccn.channel_of_client)); | ||
244 | } | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Obtain the next LID to use for incoming connections to | ||
249 | * the given client. | ||
250 | * | ||
251 | * @param c client handle | ||
252 | */ | ||
253 | static struct GNUNET_CADET_ClientChannelNumber | ||
254 | client_get_next_ccn (struct CadetClient *c) | ||
255 | { | ||
256 | struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn; | ||
257 | |||
258 | /* increment until we have a free one... */ | ||
259 | while (NULL != | ||
260 | lookup_channel (c, | ||
261 | ccn)) | ||
262 | { | ||
263 | ccn.channel_of_client | ||
264 | = htonl (1 + (ntohl (ccn.channel_of_client))); | ||
265 | if (ntohl (ccn.channel_of_client) >= | ||
266 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
267 | ccn.channel_of_client = htonl (0); | ||
268 | } | ||
269 | c->next_ccn.channel_of_client | ||
270 | = htonl (1 + (ntohl (ccn.channel_of_client))); | ||
271 | return ccn; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Bind incoming channel to this client, and notify client about | ||
277 | * incoming connection. Caller is responsible for notifying the other | ||
278 | * peer about our acceptance of the channel. | ||
279 | * | ||
280 | * @param c client to bind to | ||
281 | * @param ch channel to be bound | ||
282 | * @param dest peer that establishes the connection | ||
283 | * @param port port number | ||
284 | * @param options options | ||
285 | * @return local channel number assigned to the new client | ||
286 | */ | ||
287 | struct GNUNET_CADET_ClientChannelNumber | ||
288 | GSC_bind (struct CadetClient *c, | ||
289 | struct CadetChannel *ch, | ||
290 | struct CadetPeer *dest, | ||
291 | const struct GNUNET_HashCode *port, | ||
292 | uint32_t options) | ||
293 | { | ||
294 | struct GNUNET_MQ_Envelope *env; | ||
295 | struct GNUNET_CADET_LocalChannelCreateMessage *cm; | ||
296 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
297 | |||
298 | ccn = client_get_next_ccn (c); | ||
299 | GNUNET_assert (GNUNET_YES == | ||
300 | GNUNET_CONTAINER_multihashmap32_put (c->channels, | ||
301 | ntohl (ccn.channel_of_client), | ||
302 | ch, | ||
303 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
304 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
305 | "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n", | ||
306 | GCCH_2s (ch), | ||
307 | GCP_2s (dest), | ||
308 | GNUNET_h2s (port), | ||
309 | (uint32_t) ntohl (options), | ||
310 | (uint32_t) ntohl (ccn.channel_of_client)); | ||
311 | /* notify local client about incoming connection! */ | ||
312 | env = GNUNET_MQ_msg (cm, | ||
313 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE); | ||
314 | cm->ccn = ccn; | ||
315 | cm->port = *port; | ||
316 | cm->opt = htonl (options); | ||
317 | cm->peer = *GCP_get_id (dest); | ||
318 | GSC_send_to_client (c, | ||
319 | env); | ||
320 | return ccn; | ||
321 | } | ||
322 | |||
323 | |||
324 | /** | ||
325 | * Callback invoked on all peers to destroy all tunnels | ||
326 | * that may still exist. | ||
327 | * | ||
328 | * @param cls NULL | ||
329 | * @param pid identify of a peer | ||
330 | * @param value a `struct CadetPeer` that may still have a tunnel | ||
331 | * @return #GNUNET_OK (iterate over all entries) | ||
332 | */ | ||
333 | static int | ||
334 | destroy_tunnels_now (void *cls, | ||
335 | const struct GNUNET_PeerIdentity *pid, | ||
336 | void *value) | ||
337 | { | ||
338 | struct CadetPeer *cp = value; | ||
339 | struct CadetTunnel *t = GCP_get_tunnel (cp, | ||
340 | GNUNET_NO); | ||
341 | |||
342 | if (NULL != t) | ||
343 | GCT_destroy_tunnel_now (t); | ||
344 | return GNUNET_OK; | ||
345 | } | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Callback invoked on all peers to destroy all tunnels | ||
350 | * that may still exist. | ||
351 | * | ||
352 | * @param cls NULL | ||
353 | * @param pid identify of a peer | ||
354 | * @param value a `struct CadetPeer` that may still have a tunnel | ||
355 | * @return #GNUNET_OK (iterate over all entries) | ||
356 | */ | ||
357 | static int | ||
358 | destroy_paths_now (void *cls, | ||
359 | const struct GNUNET_PeerIdentity *pid, | ||
360 | void *value) | ||
361 | { | ||
362 | struct CadetPeer *cp = value; | ||
363 | |||
364 | GCP_drop_owned_paths (cp); | ||
365 | return GNUNET_OK; | ||
366 | } | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Shutdown everything once the clients have disconnected. | ||
371 | */ | ||
372 | static void | ||
373 | shutdown_rest () | ||
374 | { | ||
375 | if (NULL != stats) | ||
376 | { | ||
377 | GNUNET_STATISTICS_destroy (stats, | ||
378 | GNUNET_NO); | ||
379 | stats = NULL; | ||
380 | } | ||
381 | if (NULL != open_ports) | ||
382 | { | ||
383 | GNUNET_CONTAINER_multihashmap_destroy (open_ports); | ||
384 | open_ports = NULL; | ||
385 | } | ||
386 | if (NULL != loose_channels) | ||
387 | { | ||
388 | GNUNET_CONTAINER_multihashmap_destroy (loose_channels); | ||
389 | loose_channels = NULL; | ||
390 | } | ||
391 | /* Destroy tunnels. Note that all channels must be destroyed first! */ | ||
392 | GCP_iterate_all (&destroy_tunnels_now, | ||
393 | NULL); | ||
394 | /* All tunnels, channels, connections and CORE must be down before this point. */ | ||
395 | GCP_iterate_all (&destroy_paths_now, | ||
396 | NULL); | ||
397 | /* All paths, tunnels, channels, connections and CORE must be down before this point. */ | ||
398 | GCP_destroy_all_peers (); | ||
399 | if (NULL != peers) | ||
400 | { | ||
401 | GNUNET_CONTAINER_multipeermap_destroy (peers); | ||
402 | peers = NULL; | ||
403 | } | ||
404 | if (NULL != connections) | ||
405 | { | ||
406 | GNUNET_CONTAINER_multishortmap_destroy (connections); | ||
407 | connections = NULL; | ||
408 | } | ||
409 | if (NULL != ats_ch) | ||
410 | { | ||
411 | GNUNET_ATS_connectivity_done (ats_ch); | ||
412 | ats_ch = NULL; | ||
413 | } | ||
414 | GCD_shutdown (); | ||
415 | GCH_shutdown (); | ||
416 | GNUNET_free_non_null (my_private_key); | ||
417 | my_private_key = NULL; | ||
418 | } | ||
419 | |||
420 | |||
421 | /** | ||
422 | * Task run during shutdown. | ||
423 | * | ||
424 | * @param cls unused | ||
425 | */ | ||
426 | static void | ||
427 | shutdown_task (void *cls) | ||
428 | { | ||
429 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
430 | "Shutting down\n"); | ||
431 | shutting_down = GNUNET_YES; | ||
432 | GCO_shutdown (); | ||
433 | if (NULL == clients_head) | ||
434 | shutdown_rest (); | ||
435 | } | ||
436 | |||
437 | |||
438 | /** | ||
439 | * We had a remote connection @a value to port @a port before | ||
440 | * client @a cls opened port @a port. Bind them now. | ||
441 | * | ||
442 | * @param cls the `struct CadetClient` | ||
443 | * @param port the port | ||
444 | * @param value the `struct CadetChannel` | ||
445 | * @return #GNUNET_YES (iterate over all such channels) | ||
446 | */ | ||
447 | static int | ||
448 | bind_loose_channel (void *cls, | ||
449 | const struct GNUNET_HashCode *port, | ||
450 | void *value) | ||
451 | { | ||
452 | struct CadetClient *c = cls; | ||
453 | struct CadetChannel *ch = value; | ||
454 | |||
455 | GCCH_bind (ch, | ||
456 | c); | ||
457 | GNUNET_assert (GNUNET_YES == | ||
458 | GNUNET_CONTAINER_multihashmap_remove (loose_channels, | ||
459 | port, | ||
460 | value)); | ||
461 | return GNUNET_YES; | ||
462 | } | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Handle port open request. Creates a mapping from the | ||
467 | * port to the respective client and checks whether we have | ||
468 | * loose channels trying to bind to the port. If so, those | ||
469 | * are bound. | ||
470 | * | ||
471 | * @param cls Identification of the client. | ||
472 | * @param pmsg The actual message. | ||
473 | */ | ||
474 | static void | ||
475 | handle_port_open (void *cls, | ||
476 | const struct GNUNET_CADET_PortMessage *pmsg) | ||
477 | { | ||
478 | struct CadetClient *c = cls; | ||
479 | |||
480 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
481 | "Open port %s requested by %s\n", | ||
482 | GNUNET_h2s (&pmsg->port), | ||
483 | GSC_2s (c)); | ||
484 | if (NULL == c->ports) | ||
485 | c->ports = GNUNET_CONTAINER_multihashmap_create (4, | ||
486 | GNUNET_NO); | ||
487 | if (GNUNET_OK != | ||
488 | GNUNET_CONTAINER_multihashmap_put (c->ports, | ||
489 | &pmsg->port, | ||
490 | c, | ||
491 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
492 | { | ||
493 | GNUNET_break (0); | ||
494 | GNUNET_SERVICE_client_drop (c->client); | ||
495 | return; | ||
496 | } | ||
497 | (void) GNUNET_CONTAINER_multihashmap_put (open_ports, | ||
498 | &pmsg->port, | ||
499 | c, | ||
500 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
501 | GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels, | ||
502 | &pmsg->port, | ||
503 | &bind_loose_channel, | ||
504 | c); | ||
505 | GNUNET_SERVICE_client_continue (c->client); | ||
506 | } | ||
507 | |||
508 | |||
509 | /** | ||
510 | * Handler for port close requests. Marks this port as closed | ||
511 | * (unless of course we have another client with the same port | ||
512 | * open). Note that existing channels accepted on the port are | ||
513 | * not affected. | ||
514 | * | ||
515 | * @param cls Identification of the client. | ||
516 | * @param pmsg The actual message. | ||
517 | */ | ||
518 | static void | ||
519 | handle_port_close (void *cls, | ||
520 | const struct GNUNET_CADET_PortMessage *pmsg) | ||
521 | { | ||
522 | struct CadetClient *c = cls; | ||
523 | |||
524 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
525 | "Closing port %s as requested by %s\n", | ||
526 | GNUNET_h2s (&pmsg->port), | ||
527 | GSC_2s (c)); | ||
528 | if (GNUNET_YES != | ||
529 | GNUNET_CONTAINER_multihashmap_remove (c->ports, | ||
530 | &pmsg->port, | ||
531 | c)) | ||
532 | { | ||
533 | GNUNET_break (0); | ||
534 | GNUNET_SERVICE_client_drop (c->client); | ||
535 | return; | ||
536 | } | ||
537 | GNUNET_assert (GNUNET_YES == | ||
538 | GNUNET_CONTAINER_multihashmap_remove (open_ports, | ||
539 | &pmsg->port, | ||
540 | c)); | ||
541 | GNUNET_SERVICE_client_continue (c->client); | ||
542 | } | ||
543 | |||
544 | |||
545 | /** | ||
546 | * Handler for requests for us creating a new channel to another peer and port. | ||
547 | * | ||
548 | * @param cls Identification of the client. | ||
549 | * @param tcm The actual message. | ||
550 | */ | ||
551 | static void | ||
552 | handle_channel_create (void *cls, | ||
553 | const struct GNUNET_CADET_LocalChannelCreateMessage *tcm) | ||
554 | { | ||
555 | struct CadetClient *c = cls; | ||
556 | struct CadetChannel *ch; | ||
557 | |||
558 | if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
559 | { | ||
560 | /* Channel ID not in allowed range. */ | ||
561 | GNUNET_break (0); | ||
562 | GNUNET_SERVICE_client_drop (c->client); | ||
563 | return; | ||
564 | } | ||
565 | ch = lookup_channel (c, | ||
566 | tcm->ccn); | ||
567 | if (NULL != ch) | ||
568 | { | ||
569 | /* Channel ID already in use. Not allowed. */ | ||
570 | GNUNET_break (0); | ||
571 | GNUNET_SERVICE_client_drop (c->client); | ||
572 | return; | ||
573 | } | ||
574 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
575 | "New channel to %s at port %s requested by %s\n", | ||
576 | GNUNET_i2s (&tcm->peer), | ||
577 | GNUNET_h2s (&tcm->port), | ||
578 | GSC_2s (c)); | ||
579 | |||
580 | /* Create channel */ | ||
581 | ch = GCCH_channel_local_new (c, | ||
582 | tcm->ccn, | ||
583 | GCP_get (&tcm->peer, | ||
584 | GNUNET_YES), | ||
585 | &tcm->port, | ||
586 | ntohl (tcm->opt)); | ||
587 | if (NULL == ch) | ||
588 | { | ||
589 | GNUNET_break (0); | ||
590 | GNUNET_SERVICE_client_drop (c->client); | ||
591 | return; | ||
592 | } | ||
593 | GNUNET_assert (GNUNET_YES == | ||
594 | GNUNET_CONTAINER_multihashmap32_put (c->channels, | ||
595 | ntohl (tcm->ccn.channel_of_client), | ||
596 | ch, | ||
597 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
598 | |||
599 | GNUNET_SERVICE_client_continue (c->client); | ||
600 | } | ||
601 | |||
602 | |||
603 | /** | ||
604 | * Handler for requests of destroying an existing channel. | ||
605 | * | ||
606 | * @param cls client identification of the client | ||
607 | * @param msg the actual message | ||
608 | */ | ||
609 | static void | ||
610 | handle_channel_destroy (void *cls, | ||
611 | const struct GNUNET_CADET_LocalChannelDestroyMessage *msg) | ||
612 | { | ||
613 | struct CadetClient *c = cls; | ||
614 | struct CadetChannel *ch; | ||
615 | |||
616 | ch = lookup_channel (c, | ||
617 | msg->ccn); | ||
618 | if (NULL == ch) | ||
619 | { | ||
620 | /* Client attempted to destroy unknown channel. | ||
621 | Can happen if the other side went down at the same time.*/ | ||
622 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
623 | "%s tried to destroy unknown channel %X\n", | ||
624 | GSC_2s(c), | ||
625 | (uint32_t) ntohl (msg->ccn.channel_of_client)); | ||
626 | return; | ||
627 | } | ||
628 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
629 | "%s is destroying %s\n", | ||
630 | GSC_2s(c), | ||
631 | GCCH_2s (ch)); | ||
632 | GNUNET_assert (GNUNET_YES == | ||
633 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
634 | ntohl (msg->ccn.channel_of_client), | ||
635 | ch)); | ||
636 | GCCH_channel_local_destroy (ch, | ||
637 | c, | ||
638 | msg->ccn); | ||
639 | GNUNET_SERVICE_client_continue (c->client); | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Check for client traffic data message is well-formed. | ||
645 | * | ||
646 | * @param cls identification of the client | ||
647 | * @param msg the actual message | ||
648 | * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not | ||
649 | */ | ||
650 | static int | ||
651 | check_local_data (void *cls, | ||
652 | const struct GNUNET_CADET_LocalData *msg) | ||
653 | { | ||
654 | size_t payload_size; | ||
655 | size_t payload_claimed_size; | ||
656 | const char *buf; | ||
657 | struct GNUNET_MessageHeader pa; | ||
658 | |||
659 | /* FIXME: what is the format we shall allow for @a msg? | ||
660 | ONE payload item or multiple? Seems current cadet_api | ||
661 | at least in theory allows more than one. Next-gen | ||
662 | cadet_api will likely no more, so we could then | ||
663 | simplify this mess again. */ | ||
664 | /* Sanity check for message size */ | ||
665 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
666 | buf = (const char *) &msg[1]; | ||
667 | while (payload_size >= sizeof (struct GNUNET_MessageHeader)) | ||
668 | { | ||
669 | /* need to memcpy() for alignment */ | ||
670 | GNUNET_memcpy (&pa, | ||
671 | buf, | ||
672 | sizeof (pa)); | ||
673 | payload_claimed_size = ntohs (pa.size); | ||
674 | if ( (payload_size < payload_claimed_size) || | ||
675 | (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) || | ||
676 | (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) ) | ||
677 | { | ||
678 | GNUNET_break (0); | ||
679 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
680 | "Local data of %u total size had sub-message %u at %u with %u bytes\n", | ||
681 | ntohs (msg->header.size), | ||
682 | ntohs (pa.type), | ||
683 | (unsigned int) (buf - (const char *) &msg[1]), | ||
684 | (unsigned int) payload_claimed_size); | ||
685 | return GNUNET_SYSERR; | ||
686 | } | ||
687 | payload_size -= payload_claimed_size; | ||
688 | buf += payload_claimed_size; | ||
689 | } | ||
690 | if (0 != payload_size) | ||
691 | { | ||
692 | GNUNET_break_op (0); | ||
693 | return GNUNET_SYSERR; | ||
694 | } | ||
695 | return GNUNET_OK; | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * Handler for client payload traffic to be send on a channel to | ||
701 | * another peer. | ||
702 | * | ||
703 | * @param cls identification of the client | ||
704 | * @param msg the actual message | ||
705 | */ | ||
706 | static void | ||
707 | handle_local_data (void *cls, | ||
708 | const struct GNUNET_CADET_LocalData *msg) | ||
709 | { | ||
710 | struct CadetClient *c = cls; | ||
711 | struct CadetChannel *ch; | ||
712 | size_t payload_size; | ||
713 | const char *buf; | ||
714 | |||
715 | ch = lookup_channel (c, | ||
716 | msg->ccn); | ||
717 | if (NULL == ch) | ||
718 | { | ||
719 | /* Channel does not exist (anymore) */ | ||
720 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
721 | "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n", | ||
722 | (unsigned int) ntohl (msg->ccn.channel_of_client)); | ||
723 | GNUNET_SERVICE_client_continue (c->client); | ||
724 | return; | ||
725 | } | ||
726 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
727 | GNUNET_STATISTICS_update (stats, | ||
728 | "# payload received from clients", | ||
729 | payload_size, | ||
730 | GNUNET_NO); | ||
731 | buf = (const char *) &msg[1]; | ||
732 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
733 | "Received %u bytes payload from %s for %s\n", | ||
734 | (unsigned int) payload_size, | ||
735 | GSC_2s (c), | ||
736 | GCCH_2s (ch)); | ||
737 | if (GNUNET_OK != | ||
738 | GCCH_handle_local_data (ch, | ||
739 | msg->ccn, | ||
740 | buf, | ||
741 | payload_size)) | ||
742 | { | ||
743 | GNUNET_SERVICE_client_drop (c->client); | ||
744 | return; | ||
745 | } | ||
746 | GNUNET_SERVICE_client_continue (c->client); | ||
747 | } | ||
748 | |||
749 | |||
750 | /** | ||
751 | * Handler for client's ACKs for payload traffic. | ||
752 | * | ||
753 | * @param cls identification of the client. | ||
754 | * @param msg The actual message. | ||
755 | */ | ||
756 | static void | ||
757 | handle_local_ack (void *cls, | ||
758 | const struct GNUNET_CADET_LocalAck *msg) | ||
759 | { | ||
760 | struct CadetClient *c = cls; | ||
761 | struct CadetChannel *ch; | ||
762 | |||
763 | ch = lookup_channel (c, | ||
764 | msg->ccn); | ||
765 | if (NULL == ch) | ||
766 | { | ||
767 | /* Channel does not exist (anymore) */ | ||
768 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
769 | "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n", | ||
770 | (unsigned int) ntohl (msg->ccn.channel_of_client)); | ||
771 | GNUNET_SERVICE_client_continue (c->client); | ||
772 | return; | ||
773 | } | ||
774 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
775 | "Got a local ACK from %s for %s\n", | ||
776 | GSC_2s(c), | ||
777 | GCCH_2s (ch)); | ||
778 | GCCH_handle_local_ack (ch, | ||
779 | msg->ccn); | ||
780 | GNUNET_SERVICE_client_continue (c->client); | ||
781 | } | ||
782 | |||
783 | |||
784 | /** | ||
785 | * Iterator over all peers to send a monitoring client info about each peer. | ||
786 | * | ||
787 | * @param cls Closure (). | ||
788 | * @param peer Peer ID (tunnel remote peer). | ||
789 | * @param value Peer info. | ||
790 | * @return #GNUNET_YES, to keep iterating. | ||
791 | */ | ||
792 | static int | ||
793 | get_all_peers_iterator (void *cls, | ||
794 | const struct GNUNET_PeerIdentity *peer, | ||
795 | void *value) | ||
796 | { | ||
797 | struct CadetClient *c = cls; | ||
798 | struct CadetPeer *p = value; | ||
799 | struct GNUNET_MQ_Envelope *env; | ||
800 | struct GNUNET_CADET_LocalInfoPeer *msg; | ||
801 | |||
802 | env = GNUNET_MQ_msg (msg, | ||
803 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
804 | msg->destination = *peer; | ||
805 | msg->paths = htons (GCP_count_paths (p)); | ||
806 | msg->tunnel = htons (NULL != GCP_get_tunnel (p, | ||
807 | GNUNET_NO)); | ||
808 | GNUNET_MQ_send (c->mq, | ||
809 | env); | ||
810 | return GNUNET_YES; | ||
811 | } | ||
812 | |||
813 | |||
814 | /** | ||
815 | * Handler for client's INFO PEERS request. | ||
816 | * | ||
817 | * @param cls Identification of the client. | ||
818 | * @param message The actual message. | ||
819 | */ | ||
820 | static void | ||
821 | handle_get_peers (void *cls, | ||
822 | const struct GNUNET_MessageHeader *message) | ||
823 | { | ||
824 | struct CadetClient *c = cls; | ||
825 | struct GNUNET_MQ_Envelope *env; | ||
826 | struct GNUNET_MessageHeader *reply; | ||
827 | |||
828 | GCP_iterate_all (&get_all_peers_iterator, | ||
829 | c); | ||
830 | env = GNUNET_MQ_msg (reply, | ||
831 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
832 | GNUNET_MQ_send (c->mq, | ||
833 | env); | ||
834 | GNUNET_SERVICE_client_continue (c->client); | ||
835 | } | ||
836 | |||
837 | |||
838 | /** | ||
839 | * Iterator over all paths of a peer to build an InfoPeer message. | ||
840 | * Message contains blocks of peers, first not included. | ||
841 | * | ||
842 | * @param cls message queue for transmission | ||
843 | * @param path Path itself | ||
844 | * @param off offset of the peer on @a path | ||
845 | * @return #GNUNET_YES if should keep iterating. | ||
846 | * #GNUNET_NO otherwise. | ||
847 | */ | ||
848 | static int | ||
849 | path_info_iterator (void *cls, | ||
850 | struct CadetPeerPath *path, | ||
851 | unsigned int off) | ||
852 | { | ||
853 | struct GNUNET_MQ_Handle *mq = cls; | ||
854 | struct GNUNET_MQ_Envelope *env; | ||
855 | struct GNUNET_MessageHeader *resp; | ||
856 | struct GNUNET_PeerIdentity *id; | ||
857 | uint16_t path_size; | ||
858 | unsigned int i; | ||
859 | unsigned int path_length; | ||
860 | |||
861 | path_length = GCPP_get_length (path); | ||
862 | path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1); | ||
863 | if (sizeof (*resp) + path_size > UINT16_MAX) | ||
864 | { | ||
865 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
866 | "Path of %u entries is too long for info message\n", | ||
867 | path_length); | ||
868 | return GNUNET_YES; | ||
869 | } | ||
870 | env = GNUNET_MQ_msg_extra (resp, | ||
871 | path_size, | ||
872 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); | ||
873 | id = (struct GNUNET_PeerIdentity *) &resp[1]; | ||
874 | |||
875 | /* Don't copy first peer. First peer is always the local one. Last | ||
876 | * peer is always the destination (leave as 0, EOL). | ||
877 | */ | ||
878 | for (i = 0; i < off; i++) | ||
879 | id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path, | ||
880 | i + 1)); | ||
881 | GNUNET_MQ_send (mq, | ||
882 | env); | ||
883 | return GNUNET_YES; | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Handler for client's SHOW_PEER request. | ||
889 | * | ||
890 | * @param cls Identification of the client. | ||
891 | * @param msg The actual message. | ||
892 | */ | ||
893 | static void | ||
894 | handle_show_peer (void *cls, | ||
895 | const struct GNUNET_CADET_LocalInfo *msg) | ||
896 | { | ||
897 | struct CadetClient *c = cls; | ||
898 | struct CadetPeer *p; | ||
899 | struct GNUNET_MQ_Envelope *env; | ||
900 | struct GNUNET_MessageHeader *resp; | ||
901 | |||
902 | p = GCP_get (&msg->peer, | ||
903 | GNUNET_NO); | ||
904 | if (NULL != p) | ||
905 | GCP_iterate_paths (p, | ||
906 | &path_info_iterator, | ||
907 | c->mq); | ||
908 | /* Send message with 0/0 to indicate the end */ | ||
909 | env = GNUNET_MQ_msg (resp, | ||
910 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END); | ||
911 | GNUNET_MQ_send (c->mq, | ||
912 | env); | ||
913 | GNUNET_SERVICE_client_continue (c->client); | ||
914 | } | ||
915 | |||
916 | |||
917 | /** | ||
918 | * Iterator over all tunnels to send a monitoring client info about each tunnel. | ||
919 | * | ||
920 | * @param cls Closure (). | ||
921 | * @param peer Peer ID (tunnel remote peer). | ||
922 | * @param value a `struct CadetPeer` | ||
923 | * @return #GNUNET_YES, to keep iterating. | ||
924 | */ | ||
925 | static int | ||
926 | get_all_tunnels_iterator (void *cls, | ||
927 | const struct GNUNET_PeerIdentity *peer, | ||
928 | void *value) | ||
929 | { | ||
930 | struct CadetClient *c = cls; | ||
931 | struct CadetPeer *p = value; | ||
932 | struct GNUNET_MQ_Envelope *env; | ||
933 | struct GNUNET_CADET_LocalInfoTunnel *msg; | ||
934 | struct CadetTunnel *t; | ||
935 | |||
936 | t = GCP_get_tunnel (p, | ||
937 | GNUNET_NO); | ||
938 | if (NULL == t) | ||
939 | return GNUNET_YES; | ||
940 | env = GNUNET_MQ_msg (msg, | ||
941 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
942 | msg->destination = *peer; | ||
943 | msg->channels = htonl (GCT_count_channels (t)); | ||
944 | msg->connections = htonl (GCT_count_any_connections (t)); | ||
945 | msg->cstate = htons (0); | ||
946 | msg->estate = htons ((uint16_t) GCT_get_estate (t)); | ||
947 | GNUNET_MQ_send (c->mq, | ||
948 | env); | ||
949 | return GNUNET_YES; | ||
950 | } | ||
951 | |||
952 | |||
953 | /** | ||
954 | * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request. | ||
955 | * | ||
956 | * @param cls client Identification of the client. | ||
957 | * @param message The actual message. | ||
958 | */ | ||
959 | static void | ||
960 | handle_info_tunnels (void *cls, | ||
961 | const struct GNUNET_MessageHeader *message) | ||
962 | { | ||
963 | struct CadetClient *c = cls; | ||
964 | struct GNUNET_MQ_Envelope *env; | ||
965 | struct GNUNET_MessageHeader *reply; | ||
966 | |||
967 | GCP_iterate_all (&get_all_tunnels_iterator, | ||
968 | c); | ||
969 | env = GNUNET_MQ_msg (reply, | ||
970 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
971 | GNUNET_MQ_send (c->mq, | ||
972 | env); | ||
973 | GNUNET_SERVICE_client_continue (c->client); | ||
974 | } | ||
975 | |||
976 | |||
977 | /** | ||
978 | * Update the message with information about the connection. | ||
979 | * | ||
980 | * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update | ||
981 | * @param ct a connection about which we should store information in @a cls | ||
982 | */ | ||
983 | static void | ||
984 | iter_connection (void *cls, | ||
985 | struct CadetTConnection *ct) | ||
986 | { | ||
987 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
988 | struct CadetConnection *cc = ct->cc; | ||
989 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h; | ||
990 | |||
991 | h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
992 | h[msg->connections++] = *(GCC_get_id (cc)); | ||
993 | } | ||
994 | |||
995 | |||
996 | /** | ||
997 | * Update the message with information about the channel. | ||
998 | * | ||
999 | * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update | ||
1000 | * @param ch a channel about which we should store information in @a cls | ||
1001 | */ | ||
1002 | static void | ||
1003 | iter_channel (void *cls, | ||
1004 | struct CadetChannel *ch) | ||
1005 | { | ||
1006 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
1007 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
1008 | struct GNUNET_CADET_ChannelTunnelNumber *chn | ||
1009 | = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections]; | ||
1010 | |||
1011 | chn[msg->channels++] = GCCH_get_id (ch); | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | /** | ||
1016 | * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request. | ||
1017 | * | ||
1018 | * @param cls Identification of the client. | ||
1019 | * @param msg The actual message. | ||
1020 | */ | ||
1021 | static void | ||
1022 | handle_info_tunnel (void *cls, | ||
1023 | const struct GNUNET_CADET_LocalInfo *msg) | ||
1024 | { | ||
1025 | struct CadetClient *c = cls; | ||
1026 | struct GNUNET_MQ_Envelope *env; | ||
1027 | struct GNUNET_CADET_LocalInfoTunnel *resp; | ||
1028 | struct CadetTunnel *t; | ||
1029 | struct CadetPeer *p; | ||
1030 | unsigned int ch_n; | ||
1031 | unsigned int c_n; | ||
1032 | |||
1033 | p = GCP_get (&msg->peer, | ||
1034 | GNUNET_NO); | ||
1035 | t = GCP_get_tunnel (p, | ||
1036 | GNUNET_NO); | ||
1037 | if (NULL == t) | ||
1038 | { | ||
1039 | /* We don't know the tunnel */ | ||
1040 | struct GNUNET_MQ_Envelope *env; | ||
1041 | struct GNUNET_CADET_LocalInfoTunnel *warn; | ||
1042 | |||
1043 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1044 | "Tunnel to %s unknown\n", | ||
1045 | GNUNET_i2s_full (&msg->peer)); | ||
1046 | env = GNUNET_MQ_msg (warn, | ||
1047 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1048 | warn->destination = msg->peer; | ||
1049 | GNUNET_MQ_send (c->mq, | ||
1050 | env); | ||
1051 | GNUNET_SERVICE_client_continue (c->client); | ||
1052 | return; | ||
1053 | } | ||
1054 | |||
1055 | /* Initialize context */ | ||
1056 | ch_n = GCT_count_channels (t); | ||
1057 | c_n = GCT_count_any_connections (t); | ||
1058 | env = GNUNET_MQ_msg_extra (resp, | ||
1059 | c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) + | ||
1060 | ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber), | ||
1061 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1062 | resp->destination = msg->peer; | ||
1063 | /* Do not reorder! #iter_channel needs counters in HBO! */ | ||
1064 | GCT_iterate_connections (t, | ||
1065 | &iter_connection, | ||
1066 | resp); | ||
1067 | GCT_iterate_channels (t, | ||
1068 | &iter_channel, | ||
1069 | resp); | ||
1070 | resp->connections = htonl (resp->connections); | ||
1071 | resp->channels = htonl (resp->channels); | ||
1072 | resp->cstate = htons (0); | ||
1073 | resp->estate = htons (GCT_get_estate (t)); | ||
1074 | GNUNET_MQ_send (c->mq, | ||
1075 | env); | ||
1076 | GNUNET_SERVICE_client_continue (c->client); | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | /** | ||
1081 | * Iterator over all peers to dump info for each peer. | ||
1082 | * | ||
1083 | * @param cls Closure (unused). | ||
1084 | * @param peer Peer ID (tunnel remote peer). | ||
1085 | * @param value Peer info. | ||
1086 | * | ||
1087 | * @return #GNUNET_YES, to keep iterating. | ||
1088 | */ | ||
1089 | static int | ||
1090 | show_peer_iterator (void *cls, | ||
1091 | const struct GNUNET_PeerIdentity *peer, | ||
1092 | void *value) | ||
1093 | { | ||
1094 | struct CadetPeer *p = value; | ||
1095 | struct CadetTunnel *t; | ||
1096 | |||
1097 | t = GCP_get_tunnel (p, | ||
1098 | GNUNET_NO); | ||
1099 | if (NULL != t) | ||
1100 | GCT_debug (t, | ||
1101 | GNUNET_ERROR_TYPE_ERROR); | ||
1102 | LOG (GNUNET_ERROR_TYPE_ERROR, "\n"); | ||
1103 | return GNUNET_YES; | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | /** | ||
1108 | * Handler for client's INFO_DUMP request. | ||
1109 | * | ||
1110 | * @param cls Identification of the client. | ||
1111 | * @param message The actual message. | ||
1112 | */ | ||
1113 | static void | ||
1114 | handle_info_dump (void *cls, | ||
1115 | const struct GNUNET_MessageHeader *message) | ||
1116 | { | ||
1117 | struct CadetClient *c = cls; | ||
1118 | |||
1119 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1120 | "Received dump info request from client %u\n", | ||
1121 | c->id); | ||
1122 | |||
1123 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1124 | "*************************** DUMP START ***************************\n"); | ||
1125 | for (struct CadetClient *ci = clients_head; | ||
1126 | NULL != ci; | ||
1127 | ci = ci->next) | ||
1128 | { | ||
1129 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1130 | "Client %u (%p), handle: %p, ports: %u, channels: %u\n", | ||
1131 | ci->id, | ||
1132 | ci, | ||
1133 | ci->client, | ||
1134 | (NULL != c->ports) | ||
1135 | ? GNUNET_CONTAINER_multihashmap_size (ci->ports) | ||
1136 | : 0, | ||
1137 | GNUNET_CONTAINER_multihashmap32_size (ci->channels)); | ||
1138 | } | ||
1139 | LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n"); | ||
1140 | GCP_iterate_all (&show_peer_iterator, | ||
1141 | NULL); | ||
1142 | |||
1143 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1144 | "**************************** DUMP END ****************************\n"); | ||
1145 | |||
1146 | GNUNET_SERVICE_client_continue (c->client); | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | |||
1151 | /** | ||
1152 | * Callback called when a client connects to the service. | ||
1153 | * | ||
1154 | * @param cls closure for the service | ||
1155 | * @param client the new client that connected to the service | ||
1156 | * @param mq the message queue used to send messages to the client | ||
1157 | * @return @a c | ||
1158 | */ | ||
1159 | static void * | ||
1160 | client_connect_cb (void *cls, | ||
1161 | struct GNUNET_SERVICE_Client *client, | ||
1162 | struct GNUNET_MQ_Handle *mq) | ||
1163 | { | ||
1164 | struct CadetClient *c; | ||
1165 | |||
1166 | c = GNUNET_new (struct CadetClient); | ||
1167 | c->client = client; | ||
1168 | c->mq = mq; | ||
1169 | c->id = next_client_id++; /* overflow not important: just for debug */ | ||
1170 | c->channels | ||
1171 | = GNUNET_CONTAINER_multihashmap32_create (32); | ||
1172 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
1173 | clients_tail, | ||
1174 | c); | ||
1175 | GNUNET_STATISTICS_update (stats, | ||
1176 | "# clients", | ||
1177 | +1, | ||
1178 | GNUNET_NO); | ||
1179 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1180 | "%s connected\n", | ||
1181 | GSC_2s (c)); | ||
1182 | return c; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | /** | ||
1187 | * A channel was destroyed by the other peer. Tell our client. | ||
1188 | * | ||
1189 | * @param c client that lost a channel | ||
1190 | * @param ccn channel identification number for the client | ||
1191 | * @param ch the channel object | ||
1192 | */ | ||
1193 | void | ||
1194 | GSC_handle_remote_channel_destroy (struct CadetClient *c, | ||
1195 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
1196 | struct CadetChannel *ch) | ||
1197 | { | ||
1198 | struct GNUNET_MQ_Envelope *env; | ||
1199 | struct GNUNET_CADET_LocalChannelDestroyMessage *tdm; | ||
1200 | |||
1201 | env = GNUNET_MQ_msg (tdm, | ||
1202 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); | ||
1203 | tdm->ccn = ccn; | ||
1204 | GSC_send_to_client (c, | ||
1205 | env); | ||
1206 | GNUNET_assert (GNUNET_YES == | ||
1207 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
1208 | ntohl (ccn.channel_of_client), | ||
1209 | ch)); | ||
1210 | } | ||
1211 | |||
1212 | |||
1213 | /** | ||
1214 | * A client that created a loose channel that was not bound to a port | ||
1215 | * disconnected, drop it from the #loose_channels list. | ||
1216 | * | ||
1217 | * @param port the port the channel was trying to bind to | ||
1218 | * @param ch the channel that was lost | ||
1219 | */ | ||
1220 | void | ||
1221 | GSC_drop_loose_channel (const struct GNUNET_HashCode *port, | ||
1222 | struct CadetChannel *ch) | ||
1223 | { | ||
1224 | GNUNET_assert (GNUNET_YES == | ||
1225 | GNUNET_CONTAINER_multihashmap_remove (loose_channels, | ||
1226 | port, | ||
1227 | ch)); | ||
1228 | } | ||
1229 | |||
1230 | |||
1231 | /** | ||
1232 | * Iterator for deleting each channel whose client endpoint disconnected. | ||
1233 | * | ||
1234 | * @param cls Closure (client that has disconnected). | ||
1235 | * @param key The local channel id in host byte order | ||
1236 | * @param value The value stored at the key (channel to destroy). | ||
1237 | * @return #GNUNET_OK, keep iterating. | ||
1238 | */ | ||
1239 | static int | ||
1240 | channel_destroy_iterator (void *cls, | ||
1241 | uint32_t key, | ||
1242 | void *value) | ||
1243 | { | ||
1244 | struct CadetClient *c = cls; | ||
1245 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
1246 | struct CadetChannel *ch = value; | ||
1247 | |||
1248 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1249 | "Destroying %s, due to %s disconnecting.\n", | ||
1250 | GCCH_2s (ch), | ||
1251 | GSC_2s (c)); | ||
1252 | ccn.channel_of_client = htonl (key); | ||
1253 | GCCH_channel_local_destroy (ch, | ||
1254 | c, | ||
1255 | ccn); | ||
1256 | GNUNET_assert (GNUNET_YES == | ||
1257 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
1258 | key, | ||
1259 | ch)); | ||
1260 | return GNUNET_OK; | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | /** | ||
1265 | * Remove client's ports from the global hashmap on disconnect. | ||
1266 | * | ||
1267 | * @param cls Closure (unused). | ||
1268 | * @param key the port. | ||
1269 | * @param value the `struct CadetClient` to remove | ||
1270 | * @return #GNUNET_OK, keep iterating. | ||
1271 | */ | ||
1272 | static int | ||
1273 | client_release_ports (void *cls, | ||
1274 | const struct GNUNET_HashCode *key, | ||
1275 | void *value) | ||
1276 | { | ||
1277 | struct CadetClient *c = value; | ||
1278 | |||
1279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1280 | "Closing port %s due to %s disconnect.\n", | ||
1281 | GNUNET_h2s (key), | ||
1282 | GSC_2s (c)); | ||
1283 | GNUNET_assert (GNUNET_YES == | ||
1284 | GNUNET_CONTAINER_multihashmap_remove (open_ports, | ||
1285 | key, | ||
1286 | value)); | ||
1287 | GNUNET_assert (GNUNET_YES == | ||
1288 | GNUNET_CONTAINER_multihashmap_remove (c->ports, | ||
1289 | key, | ||
1290 | value)); | ||
1291 | return GNUNET_OK; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | /** | ||
1296 | * Callback called when a client disconnected from the service | ||
1297 | * | ||
1298 | * @param cls closure for the service | ||
1299 | * @param client the client that disconnected | ||
1300 | * @param internal_cls should be equal to @a c | ||
1301 | */ | ||
1302 | static void | ||
1303 | client_disconnect_cb (void *cls, | ||
1304 | struct GNUNET_SERVICE_Client *client, | ||
1305 | void *internal_cls) | ||
1306 | { | ||
1307 | struct CadetClient *c = internal_cls; | ||
1308 | |||
1309 | GNUNET_assert (c->client == client); | ||
1310 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1311 | "%s is disconnecting.\n", | ||
1312 | GSC_2s (c)); | ||
1313 | if (NULL != c->channels) | ||
1314 | { | ||
1315 | GNUNET_CONTAINER_multihashmap32_iterate (c->channels, | ||
1316 | &channel_destroy_iterator, | ||
1317 | c); | ||
1318 | GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels)); | ||
1319 | GNUNET_CONTAINER_multihashmap32_destroy (c->channels); | ||
1320 | } | ||
1321 | if (NULL != c->ports) | ||
1322 | { | ||
1323 | GNUNET_CONTAINER_multihashmap_iterate (c->ports, | ||
1324 | &client_release_ports, | ||
1325 | c); | ||
1326 | GNUNET_CONTAINER_multihashmap_destroy (c->ports); | ||
1327 | } | ||
1328 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
1329 | clients_tail, | ||
1330 | c); | ||
1331 | GNUNET_STATISTICS_update (stats, | ||
1332 | "# clients", | ||
1333 | -1, | ||
1334 | GNUNET_NO); | ||
1335 | GNUNET_free (c); | ||
1336 | if ( (NULL == clients_head) && | ||
1337 | (GNUNET_YES == shutting_down) ) | ||
1338 | shutdown_rest (); | ||
1339 | } | ||
1340 | |||
1341 | |||
1342 | /** | ||
1343 | * Setup CADET internals. | ||
1344 | * | ||
1345 | * @param cls closure | ||
1346 | * @param server the initialized server | ||
1347 | * @param c configuration to use | ||
1348 | */ | ||
1349 | static void | ||
1350 | run (void *cls, | ||
1351 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1352 | struct GNUNET_SERVICE_Handle *service) | ||
1353 | { | ||
1354 | cfg = c; | ||
1355 | if (GNUNET_OK != | ||
1356 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1357 | "CADET", | ||
1358 | "RATCHET_MESSAGES", | ||
1359 | &ratchet_messages)) | ||
1360 | { | ||
1361 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1362 | "CADET", | ||
1363 | "RATCHET_MESSAGES", | ||
1364 | "needs to be a number"); | ||
1365 | ratchet_messages = 64; | ||
1366 | } | ||
1367 | if (GNUNET_OK != | ||
1368 | GNUNET_CONFIGURATION_get_value_time (c, | ||
1369 | "CADET", | ||
1370 | "RATCHET_TIME", | ||
1371 | &ratchet_time)) | ||
1372 | { | ||
1373 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1374 | "CADET", | ||
1375 | "RATCHET_TIME", | ||
1376 | "need delay value"); | ||
1377 | ratchet_time = GNUNET_TIME_UNIT_HOURS; | ||
1378 | } | ||
1379 | if (GNUNET_OK != | ||
1380 | GNUNET_CONFIGURATION_get_value_time (c, | ||
1381 | "CADET", | ||
1382 | "REFRESH_CONNECTION_TIME", | ||
1383 | &keepalive_period)) | ||
1384 | { | ||
1385 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1386 | "CADET", | ||
1387 | "REFRESH_CONNECTION_TIME", | ||
1388 | "need delay value"); | ||
1389 | keepalive_period = GNUNET_TIME_UNIT_MINUTES; | ||
1390 | } | ||
1391 | if (GNUNET_OK != | ||
1392 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1393 | "CADET", | ||
1394 | "DROP_PERCENT", | ||
1395 | &drop_percent)) | ||
1396 | { | ||
1397 | drop_percent = 0; | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1402 | LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); | ||
1403 | LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); | ||
1404 | LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); | ||
1405 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1406 | } | ||
1407 | my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); | ||
1408 | if (NULL == my_private_key) | ||
1409 | { | ||
1410 | GNUNET_break (0); | ||
1411 | GNUNET_SCHEDULER_shutdown (); | ||
1412 | return; | ||
1413 | } | ||
1414 | GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, | ||
1415 | &my_full_id.public_key); | ||
1416 | stats = GNUNET_STATISTICS_create ("cadet", | ||
1417 | c); | ||
1418 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1419 | NULL); | ||
1420 | ats_ch = GNUNET_ATS_connectivity_init (c); | ||
1421 | /* FIXME: optimize code to allow GNUNET_YES here! */ | ||
1422 | open_ports = GNUNET_CONTAINER_multihashmap_create (16, | ||
1423 | GNUNET_NO); | ||
1424 | loose_channels = GNUNET_CONTAINER_multihashmap_create (16, | ||
1425 | GNUNET_NO); | ||
1426 | peers = GNUNET_CONTAINER_multipeermap_create (16, | ||
1427 | GNUNET_YES); | ||
1428 | connections = GNUNET_CONTAINER_multishortmap_create (256, | ||
1429 | GNUNET_YES); | ||
1430 | GCH_init (c); | ||
1431 | GCD_init (c); | ||
1432 | GCO_init (c); | ||
1433 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1434 | "CADET started for peer %s\n", | ||
1435 | GNUNET_i2s (&my_full_id)); | ||
1436 | |||
1437 | } | ||
1438 | |||
1439 | |||
1440 | /** | ||
1441 | * Define "main" method using service macro. | ||
1442 | */ | ||
1443 | GNUNET_SERVICE_MAIN | ||
1444 | ("cadet", | ||
1445 | GNUNET_SERVICE_OPTION_NONE, | ||
1446 | &run, | ||
1447 | &client_connect_cb, | ||
1448 | &client_disconnect_cb, | ||
1449 | NULL, | ||
1450 | GNUNET_MQ_hd_fixed_size (port_open, | ||
1451 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN, | ||
1452 | struct GNUNET_CADET_PortMessage, | ||
1453 | NULL), | ||
1454 | GNUNET_MQ_hd_fixed_size (port_close, | ||
1455 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE, | ||
1456 | struct GNUNET_CADET_PortMessage, | ||
1457 | NULL), | ||
1458 | GNUNET_MQ_hd_fixed_size (channel_create, | ||
1459 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE, | ||
1460 | struct GNUNET_CADET_LocalChannelCreateMessage, | ||
1461 | NULL), | ||
1462 | GNUNET_MQ_hd_fixed_size (channel_destroy, | ||
1463 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY, | ||
1464 | struct GNUNET_CADET_LocalChannelDestroyMessage, | ||
1465 | NULL), | ||
1466 | GNUNET_MQ_hd_var_size (local_data, | ||
1467 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, | ||
1468 | struct GNUNET_CADET_LocalData, | ||
1469 | NULL), | ||
1470 | GNUNET_MQ_hd_fixed_size (local_ack, | ||
1471 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, | ||
1472 | struct GNUNET_CADET_LocalAck, | ||
1473 | NULL), | ||
1474 | GNUNET_MQ_hd_fixed_size (get_peers, | ||
1475 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, | ||
1476 | struct GNUNET_MessageHeader, | ||
1477 | NULL), | ||
1478 | GNUNET_MQ_hd_fixed_size (show_peer, | ||
1479 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, | ||
1480 | struct GNUNET_CADET_LocalInfo, | ||
1481 | NULL), | ||
1482 | GNUNET_MQ_hd_fixed_size (info_tunnels, | ||
1483 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, | ||
1484 | struct GNUNET_MessageHeader, | ||
1485 | NULL), | ||
1486 | GNUNET_MQ_hd_fixed_size (info_tunnel, | ||
1487 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, | ||
1488 | struct GNUNET_CADET_LocalInfo, | ||
1489 | NULL), | ||
1490 | GNUNET_MQ_hd_fixed_size (info_dump, | ||
1491 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP, | ||
1492 | struct GNUNET_MessageHeader, | ||
1493 | NULL), | ||
1494 | GNUNET_MQ_handler_end ()); | ||
1495 | |||
1496 | /* end of gnunet-service-cadet-new.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c deleted file mode 100644 index 43c905816..000000000 --- a/src/cadet/gnunet-service-cadet-new_channel.c +++ /dev/null | |||
@@ -1,2040 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/gnunet-service-cadet-new_channel.c | ||
22 | * @brief logical links between CADET clients | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - Congestion/flow control: | ||
28 | * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL! | ||
29 | * (and figure out how/where to use this!) | ||
30 | * + figure out flow control without ACKs (unreliable traffic!) | ||
31 | * - revisit handling of 'unbuffered' traffic! | ||
32 | * (need to push down through tunnel into connection selection) | ||
33 | * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe | ||
34 | * reserve more bits in 'options' to allow for buffer size control? | ||
35 | */ | ||
36 | #include "platform.h" | ||
37 | #include "gnunet_util_lib.h" | ||
38 | #include "cadet.h" | ||
39 | #include "gnunet_statistics_service.h" | ||
40 | #include "gnunet-service-cadet-new.h" | ||
41 | #include "gnunet-service-cadet-new_channel.h" | ||
42 | #include "gnunet-service-cadet-new_connection.h" | ||
43 | #include "gnunet-service-cadet-new_tunnels.h" | ||
44 | #include "gnunet-service-cadet-new_peer.h" | ||
45 | #include "gnunet-service-cadet-new_paths.h" | ||
46 | |||
47 | #define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__) | ||
48 | |||
49 | /** | ||
50 | * How long do we initially wait before retransmitting? | ||
51 | */ | ||
52 | #define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250) | ||
53 | |||
54 | /** | ||
55 | * How long do we wait before dropping state about incoming | ||
56 | * connection to closed port? | ||
57 | */ | ||
58 | #define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) | ||
59 | |||
60 | /** | ||
61 | * How long do we wait at least before retransmitting ever? | ||
62 | */ | ||
63 | #define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75) | ||
64 | |||
65 | /** | ||
66 | * Maximum message ID into the future we accept for out-of-order messages. | ||
67 | * If the message is more than this into the future, we drop it. This is | ||
68 | * important both to detect values that are actually in the past, as well | ||
69 | * as to limit adversarially triggerable memory consumption. | ||
70 | * | ||
71 | * Note that right now we have "max_pending_messages = 4" hard-coded in | ||
72 | * the logic below, so a value of 4 would suffice here. But we plan to | ||
73 | * allow larger windows in the future... | ||
74 | */ | ||
75 | #define MAX_OUT_OF_ORDER_DISTANCE 1024 | ||
76 | |||
77 | |||
78 | /** | ||
79 | * All the states a channel can be in. | ||
80 | */ | ||
81 | enum CadetChannelState | ||
82 | { | ||
83 | /** | ||
84 | * Uninitialized status, should never appear in operation. | ||
85 | */ | ||
86 | CADET_CHANNEL_NEW, | ||
87 | |||
88 | /** | ||
89 | * Channel is to a port that is not open, we're waiting for the | ||
90 | * port to be opened. | ||
91 | */ | ||
92 | CADET_CHANNEL_LOOSE, | ||
93 | |||
94 | /** | ||
95 | * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK. | ||
96 | */ | ||
97 | CADET_CHANNEL_OPEN_SENT, | ||
98 | |||
99 | /** | ||
100 | * Connection confirmed, ready to carry traffic. | ||
101 | */ | ||
102 | CADET_CHANNEL_READY | ||
103 | }; | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Info needed to retry a message in case it gets lost. | ||
108 | * Note that we DO use this structure also for unreliable | ||
109 | * messages. | ||
110 | */ | ||
111 | struct CadetReliableMessage | ||
112 | { | ||
113 | /** | ||
114 | * Double linked list, FIFO style | ||
115 | */ | ||
116 | struct CadetReliableMessage *next; | ||
117 | |||
118 | /** | ||
119 | * Double linked list, FIFO style | ||
120 | */ | ||
121 | struct CadetReliableMessage *prev; | ||
122 | |||
123 | /** | ||
124 | * Which channel is this message in? | ||
125 | */ | ||
126 | struct CadetChannel *ch; | ||
127 | |||
128 | /** | ||
129 | * Entry in the tunnels queue for this message, NULL if it has left | ||
130 | * the tunnel. Used to cancel transmission in case we receive an | ||
131 | * ACK in time. | ||
132 | */ | ||
133 | struct CadetTunnelQueueEntry *qe; | ||
134 | |||
135 | /** | ||
136 | * Data message we are trying to send. | ||
137 | */ | ||
138 | struct GNUNET_CADET_ChannelAppDataMessage *data_message; | ||
139 | |||
140 | /** | ||
141 | * How soon should we retry if we fail to get an ACK? | ||
142 | * Messages in the queue are sorted by this value. | ||
143 | */ | ||
144 | struct GNUNET_TIME_Absolute next_retry; | ||
145 | |||
146 | /** | ||
147 | * How long do we wait for an ACK after transmission? | ||
148 | * Use for the back-off calculation. | ||
149 | */ | ||
150 | struct GNUNET_TIME_Relative retry_delay; | ||
151 | |||
152 | /** | ||
153 | * Time when we first successfully transmitted the message | ||
154 | * (that is, set @e num_transmissions to 1). | ||
155 | */ | ||
156 | struct GNUNET_TIME_Absolute first_transmission_time; | ||
157 | |||
158 | /** | ||
159 | * Identifier of the connection that this message took when it | ||
160 | * was first transmitted. Only useful if @e num_transmissions is 1. | ||
161 | */ | ||
162 | struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken; | ||
163 | |||
164 | /** | ||
165 | * How often was this message transmitted? #GNUNET_SYSERR if there | ||
166 | * was an error transmitting the message, #GNUNET_NO if it was not | ||
167 | * yet transmitted ever, otherwise the number of (re) transmissions. | ||
168 | */ | ||
169 | int num_transmissions; | ||
170 | |||
171 | }; | ||
172 | |||
173 | |||
174 | /** | ||
175 | * List of received out-of-order data messages. | ||
176 | */ | ||
177 | struct CadetOutOfOrderMessage | ||
178 | { | ||
179 | /** | ||
180 | * Double linked list, FIFO style | ||
181 | */ | ||
182 | struct CadetOutOfOrderMessage *next; | ||
183 | |||
184 | /** | ||
185 | * Double linked list, FIFO style | ||
186 | */ | ||
187 | struct CadetOutOfOrderMessage *prev; | ||
188 | |||
189 | /** | ||
190 | * ID of the message (messages up to this point needed | ||
191 | * before we give this one to the client). | ||
192 | */ | ||
193 | struct ChannelMessageIdentifier mid; | ||
194 | |||
195 | /** | ||
196 | * The envelope with the payload of the out-of-order message | ||
197 | */ | ||
198 | struct GNUNET_MQ_Envelope *env; | ||
199 | |||
200 | }; | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Client endpoint of a `struct CadetChannel`. A channel may be a | ||
205 | * loopback channel, in which case it has two of these endpoints. | ||
206 | * Note that flow control also is required in both directions. | ||
207 | */ | ||
208 | struct CadetChannelClient | ||
209 | { | ||
210 | /** | ||
211 | * Client handle. Not by itself sufficient to designate | ||
212 | * the client endpoint, as the same client handle may | ||
213 | * be used for both the owner and the destination, and | ||
214 | * we thus also need the channel ID to identify the client. | ||
215 | */ | ||
216 | struct CadetClient *c; | ||
217 | |||
218 | /** | ||
219 | * Head of DLL of messages received out of order or while client was unready. | ||
220 | */ | ||
221 | struct CadetOutOfOrderMessage *head_recv; | ||
222 | |||
223 | /** | ||
224 | * Tail DLL of messages received out of order or while client was unready. | ||
225 | */ | ||
226 | struct CadetOutOfOrderMessage *tail_recv; | ||
227 | |||
228 | /** | ||
229 | * Local tunnel number for this client. | ||
230 | * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI, | ||
231 | * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
232 | */ | ||
233 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
234 | |||
235 | /** | ||
236 | * Number of entries currently in @a head_recv DLL. | ||
237 | */ | ||
238 | unsigned int num_recv; | ||
239 | |||
240 | /** | ||
241 | * Can we send data to the client? | ||
242 | */ | ||
243 | int client_ready; | ||
244 | |||
245 | }; | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Struct containing all information regarding a channel to a remote client. | ||
250 | */ | ||
251 | struct CadetChannel | ||
252 | { | ||
253 | /** | ||
254 | * Tunnel this channel is in. | ||
255 | */ | ||
256 | struct CadetTunnel *t; | ||
257 | |||
258 | /** | ||
259 | * Client owner of the tunnel, if any. | ||
260 | * (Used if this channel represends the initiating end of the tunnel.) | ||
261 | */ | ||
262 | struct CadetChannelClient *owner; | ||
263 | |||
264 | /** | ||
265 | * Client destination of the tunnel, if any. | ||
266 | * (Used if this channel represents the listening end of the tunnel.) | ||
267 | */ | ||
268 | struct CadetChannelClient *dest; | ||
269 | |||
270 | /** | ||
271 | * Last entry in the tunnel's queue relating to control messages | ||
272 | * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or | ||
273 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel | ||
274 | * transmission in case we receive updated information. | ||
275 | */ | ||
276 | struct CadetTunnelQueueEntry *last_control_qe; | ||
277 | |||
278 | /** | ||
279 | * Head of DLL of messages sent and not yet ACK'd. | ||
280 | */ | ||
281 | struct CadetReliableMessage *head_sent; | ||
282 | |||
283 | /** | ||
284 | * Tail of DLL of messages sent and not yet ACK'd. | ||
285 | */ | ||
286 | struct CadetReliableMessage *tail_sent; | ||
287 | |||
288 | /** | ||
289 | * Task to resend/poll in case no ACK is received. | ||
290 | */ | ||
291 | struct GNUNET_SCHEDULER_Task *retry_control_task; | ||
292 | |||
293 | /** | ||
294 | * Task to resend/poll in case no ACK is received. | ||
295 | */ | ||
296 | struct GNUNET_SCHEDULER_Task *retry_data_task; | ||
297 | |||
298 | /** | ||
299 | * Last time the channel was used | ||
300 | */ | ||
301 | struct GNUNET_TIME_Absolute timestamp; | ||
302 | |||
303 | /** | ||
304 | * Destination port of the channel. | ||
305 | */ | ||
306 | struct GNUNET_HashCode port; | ||
307 | |||
308 | /** | ||
309 | * Counter for exponential backoff. | ||
310 | */ | ||
311 | struct GNUNET_TIME_Relative retry_time; | ||
312 | |||
313 | /** | ||
314 | * Bitfield of already-received messages past @e mid_recv. | ||
315 | */ | ||
316 | uint64_t mid_futures; | ||
317 | |||
318 | /** | ||
319 | * Next MID expected for incoming traffic. | ||
320 | */ | ||
321 | struct ChannelMessageIdentifier mid_recv; | ||
322 | |||
323 | /** | ||
324 | * Next MID to use for outgoing traffic. | ||
325 | */ | ||
326 | struct ChannelMessageIdentifier mid_send; | ||
327 | |||
328 | /** | ||
329 | * Total (reliable) messages pending ACK for this channel. | ||
330 | */ | ||
331 | unsigned int pending_messages; | ||
332 | |||
333 | /** | ||
334 | * Maximum (reliable) messages pending ACK for this channel | ||
335 | * before we throttle the client. | ||
336 | */ | ||
337 | unsigned int max_pending_messages; | ||
338 | |||
339 | /** | ||
340 | * Number identifying this channel in its tunnel. | ||
341 | */ | ||
342 | struct GNUNET_CADET_ChannelTunnelNumber ctn; | ||
343 | |||
344 | /** | ||
345 | * Channel state. | ||
346 | */ | ||
347 | enum CadetChannelState state; | ||
348 | |||
349 | /** | ||
350 | * Count how many ACKs we skipped, used to prevent long | ||
351 | * sequences of ACK skipping. | ||
352 | */ | ||
353 | unsigned int skip_ack_series; | ||
354 | |||
355 | /** | ||
356 | * Is the tunnel bufferless (minimum latency)? | ||
357 | */ | ||
358 | int nobuffer; | ||
359 | |||
360 | /** | ||
361 | * Is the tunnel reliable? | ||
362 | */ | ||
363 | int reliable; | ||
364 | |||
365 | /** | ||
366 | * Is the tunnel out-of-order? | ||
367 | */ | ||
368 | int out_of_order; | ||
369 | |||
370 | /** | ||
371 | * Is this channel a loopback channel, where the destination is us again? | ||
372 | */ | ||
373 | int is_loopback; | ||
374 | |||
375 | /** | ||
376 | * Flag to signal the destruction of the channel. If this is set to | ||
377 | * #GNUNET_YES the channel will be destroyed once the queue is | ||
378 | * empty. | ||
379 | */ | ||
380 | int destroy; | ||
381 | |||
382 | }; | ||
383 | |||
384 | |||
385 | /** | ||
386 | * Get the static string for identification of the channel. | ||
387 | * | ||
388 | * @param ch Channel. | ||
389 | * | ||
390 | * @return Static string with the channel IDs. | ||
391 | */ | ||
392 | const char * | ||
393 | GCCH_2s (const struct CadetChannel *ch) | ||
394 | { | ||
395 | static char buf[128]; | ||
396 | |||
397 | GNUNET_snprintf (buf, | ||
398 | sizeof (buf), | ||
399 | "Channel %s:%s ctn:%X(%X/%X)", | ||
400 | (GNUNET_YES == ch->is_loopback) | ||
401 | ? "loopback" | ||
402 | : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))), | ||
403 | GNUNET_h2s (&ch->port), | ||
404 | ch->ctn, | ||
405 | (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client), | ||
406 | (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client)); | ||
407 | return buf; | ||
408 | } | ||
409 | |||
410 | |||
411 | /** | ||
412 | * Get the channel's public ID. | ||
413 | * | ||
414 | * @param ch Channel. | ||
415 | * | ||
416 | * @return ID used to identify the channel with the remote peer. | ||
417 | */ | ||
418 | struct GNUNET_CADET_ChannelTunnelNumber | ||
419 | GCCH_get_id (const struct CadetChannel *ch) | ||
420 | { | ||
421 | return ch->ctn; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Release memory associated with @a ccc | ||
427 | * | ||
428 | * @param ccc data structure to clean up | ||
429 | */ | ||
430 | static void | ||
431 | free_channel_client (struct CadetChannelClient *ccc) | ||
432 | { | ||
433 | struct CadetOutOfOrderMessage *com; | ||
434 | |||
435 | while (NULL != (com = ccc->head_recv)) | ||
436 | { | ||
437 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
438 | ccc->tail_recv, | ||
439 | com); | ||
440 | ccc->num_recv--; | ||
441 | GNUNET_MQ_discard (com->env); | ||
442 | GNUNET_free (com); | ||
443 | } | ||
444 | GNUNET_free (ccc); | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * Destroy the given channel. | ||
450 | * | ||
451 | * @param ch channel to destroy | ||
452 | */ | ||
453 | static void | ||
454 | channel_destroy (struct CadetChannel *ch) | ||
455 | { | ||
456 | struct CadetReliableMessage *crm; | ||
457 | |||
458 | while (NULL != (crm = ch->head_sent)) | ||
459 | { | ||
460 | GNUNET_assert (ch == crm->ch); | ||
461 | if (NULL != crm->qe) | ||
462 | { | ||
463 | GCT_send_cancel (crm->qe); | ||
464 | crm->qe = NULL; | ||
465 | } | ||
466 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, | ||
467 | ch->tail_sent, | ||
468 | crm); | ||
469 | GNUNET_free (crm->data_message); | ||
470 | GNUNET_free (crm); | ||
471 | } | ||
472 | if (NULL != ch->owner) | ||
473 | { | ||
474 | free_channel_client (ch->owner); | ||
475 | ch->owner = NULL; | ||
476 | } | ||
477 | if (NULL != ch->dest) | ||
478 | { | ||
479 | free_channel_client (ch->dest); | ||
480 | ch->dest = NULL; | ||
481 | } | ||
482 | if (NULL != ch->last_control_qe) | ||
483 | { | ||
484 | GCT_send_cancel (ch->last_control_qe); | ||
485 | ch->last_control_qe = NULL; | ||
486 | } | ||
487 | if (NULL != ch->retry_data_task) | ||
488 | { | ||
489 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
490 | ch->retry_data_task = NULL; | ||
491 | } | ||
492 | if (NULL != ch->retry_control_task) | ||
493 | { | ||
494 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
495 | ch->retry_control_task = NULL; | ||
496 | } | ||
497 | if (GNUNET_NO == ch->is_loopback) | ||
498 | { | ||
499 | GCT_remove_channel (ch->t, | ||
500 | ch, | ||
501 | ch->ctn); | ||
502 | ch->t = NULL; | ||
503 | } | ||
504 | GNUNET_free (ch); | ||
505 | } | ||
506 | |||
507 | |||
508 | /** | ||
509 | * Send a channel create message. | ||
510 | * | ||
511 | * @param cls Channel for which to send. | ||
512 | */ | ||
513 | static void | ||
514 | send_channel_open (void *cls); | ||
515 | |||
516 | |||
517 | /** | ||
518 | * Function called once the tunnel confirms that we sent the | ||
519 | * create message. Delays for a bit until we retry. | ||
520 | * | ||
521 | * @param cls our `struct CadetChannel`. | ||
522 | * @param cid identifier of the connection within the tunnel, NULL | ||
523 | * if transmission failed | ||
524 | */ | ||
525 | static void | ||
526 | channel_open_sent_cb (void *cls, | ||
527 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
528 | { | ||
529 | struct CadetChannel *ch = cls; | ||
530 | |||
531 | GNUNET_assert (NULL != ch->last_control_qe); | ||
532 | ch->last_control_qe = NULL; | ||
533 | ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time); | ||
534 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
535 | "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n", | ||
536 | GCCH_2s (ch), | ||
537 | GNUNET_STRINGS_relative_time_to_string (ch->retry_time, | ||
538 | GNUNET_YES)); | ||
539 | ch->retry_control_task | ||
540 | = GNUNET_SCHEDULER_add_delayed (ch->retry_time, | ||
541 | &send_channel_open, | ||
542 | ch); | ||
543 | } | ||
544 | |||
545 | |||
546 | /** | ||
547 | * Send a channel open message. | ||
548 | * | ||
549 | * @param cls Channel for which to send. | ||
550 | */ | ||
551 | static void | ||
552 | send_channel_open (void *cls) | ||
553 | { | ||
554 | struct CadetChannel *ch = cls; | ||
555 | struct GNUNET_CADET_ChannelOpenMessage msgcc; | ||
556 | uint32_t options; | ||
557 | |||
558 | ch->retry_control_task = NULL; | ||
559 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
560 | "Sending CHANNEL_OPEN message for %s\n", | ||
561 | GCCH_2s (ch)); | ||
562 | options = 0; | ||
563 | if (ch->nobuffer) | ||
564 | options |= GNUNET_CADET_OPTION_NOBUFFER; | ||
565 | if (ch->reliable) | ||
566 | options |= GNUNET_CADET_OPTION_RELIABLE; | ||
567 | if (ch->out_of_order) | ||
568 | options |= GNUNET_CADET_OPTION_OUT_OF_ORDER; | ||
569 | msgcc.header.size = htons (sizeof (msgcc)); | ||
570 | msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN); | ||
571 | msgcc.opt = htonl (options); | ||
572 | msgcc.port = ch->port; | ||
573 | msgcc.ctn = ch->ctn; | ||
574 | ch->state = CADET_CHANNEL_OPEN_SENT; | ||
575 | if (NULL != ch->last_control_qe) | ||
576 | GCT_send_cancel (ch->last_control_qe); | ||
577 | ch->last_control_qe = GCT_send (ch->t, | ||
578 | &msgcc.header, | ||
579 | &channel_open_sent_cb, | ||
580 | ch); | ||
581 | GNUNET_assert (NULL == ch->retry_control_task); | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * Function called once and only once after a channel was bound | ||
587 | * to its tunnel via #GCT_add_channel() is ready for transmission. | ||
588 | * Note that this is only the case for channels that this peer | ||
589 | * initiates, as for incoming channels we assume that they are | ||
590 | * ready for transmission immediately upon receiving the open | ||
591 | * message. Used to bootstrap the #GCT_send() process. | ||
592 | * | ||
593 | * @param ch the channel for which the tunnel is now ready | ||
594 | */ | ||
595 | void | ||
596 | GCCH_tunnel_up (struct CadetChannel *ch) | ||
597 | { | ||
598 | GNUNET_assert (NULL == ch->retry_control_task); | ||
599 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
600 | "Tunnel up, sending CHANNEL_OPEN on %s now\n", | ||
601 | GCCH_2s (ch)); | ||
602 | ch->retry_control_task | ||
603 | = GNUNET_SCHEDULER_add_now (&send_channel_open, | ||
604 | ch); | ||
605 | } | ||
606 | |||
607 | |||
608 | /** | ||
609 | * Create a new channel. | ||
610 | * | ||
611 | * @param owner local client owning the channel | ||
612 | * @param ccn local number of this channel at the @a owner | ||
613 | * @param destination peer to which we should build the channel | ||
614 | * @param port desired port at @a destination | ||
615 | * @param options options for the channel | ||
616 | * @return handle to the new channel | ||
617 | */ | ||
618 | struct CadetChannel * | ||
619 | GCCH_channel_local_new (struct CadetClient *owner, | ||
620 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
621 | struct CadetPeer *destination, | ||
622 | const struct GNUNET_HashCode *port, | ||
623 | uint32_t options) | ||
624 | { | ||
625 | struct CadetChannel *ch; | ||
626 | struct CadetChannelClient *ccco; | ||
627 | |||
628 | ccco = GNUNET_new (struct CadetChannelClient); | ||
629 | ccco->c = owner; | ||
630 | ccco->ccn = ccn; | ||
631 | ccco->client_ready = GNUNET_YES; | ||
632 | |||
633 | ch = GNUNET_new (struct CadetChannel); | ||
634 | ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */ | ||
635 | ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER)); | ||
636 | ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE)); | ||
637 | ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER)); | ||
638 | ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */ | ||
639 | ch->owner = ccco; | ||
640 | ch->port = *port; | ||
641 | if (0 == memcmp (&my_full_id, | ||
642 | GCP_get_id (destination), | ||
643 | sizeof (struct GNUNET_PeerIdentity))) | ||
644 | { | ||
645 | struct CadetClient *c; | ||
646 | |||
647 | ch->is_loopback = GNUNET_YES; | ||
648 | c = GNUNET_CONTAINER_multihashmap_get (open_ports, | ||
649 | port); | ||
650 | if (NULL == c) | ||
651 | { | ||
652 | /* port closed, wait for it to possibly open */ | ||
653 | ch->state = CADET_CHANNEL_LOOSE; | ||
654 | (void) GNUNET_CONTAINER_multihashmap_put (loose_channels, | ||
655 | port, | ||
656 | ch, | ||
657 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
658 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
659 | "Created loose incoming loopback channel to port %s\n", | ||
660 | GNUNET_h2s (&ch->port)); | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | GCCH_bind (ch, | ||
665 | c); | ||
666 | } | ||
667 | } | ||
668 | else | ||
669 | { | ||
670 | ch->t = GCP_get_tunnel (destination, | ||
671 | GNUNET_YES); | ||
672 | ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME; | ||
673 | ch->ctn = GCT_add_channel (ch->t, | ||
674 | ch); | ||
675 | } | ||
676 | GNUNET_STATISTICS_update (stats, | ||
677 | "# channels", | ||
678 | 1, | ||
679 | GNUNET_NO); | ||
680 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
681 | "Created channel to port %s at peer %s for %s using %s\n", | ||
682 | GNUNET_h2s (port), | ||
683 | GCP_2s (destination), | ||
684 | GSC_2s (owner), | ||
685 | (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t)); | ||
686 | return ch; | ||
687 | } | ||
688 | |||
689 | |||
690 | /** | ||
691 | * We had an incoming channel to a port that is closed. | ||
692 | * It has not been opened for a while, drop it. | ||
693 | * | ||
694 | * @param cls the channel to drop | ||
695 | */ | ||
696 | static void | ||
697 | timeout_closed_cb (void *cls) | ||
698 | { | ||
699 | struct CadetChannel *ch = cls; | ||
700 | |||
701 | ch->retry_control_task = NULL; | ||
702 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
703 | "Closing incoming channel to port %s from peer %s due to timeout\n", | ||
704 | GNUNET_h2s (&ch->port), | ||
705 | GCP_2s (GCT_get_destination (ch->t))); | ||
706 | channel_destroy (ch); | ||
707 | } | ||
708 | |||
709 | |||
710 | /** | ||
711 | * Create a new channel based on a request coming in over the network. | ||
712 | * | ||
713 | * @param t tunnel to the remote peer | ||
714 | * @param ctn identifier of this channel in the tunnel | ||
715 | * @param port desired local port | ||
716 | * @param options options for the channel | ||
717 | * @return handle to the new channel | ||
718 | */ | ||
719 | struct CadetChannel * | ||
720 | GCCH_channel_incoming_new (struct CadetTunnel *t, | ||
721 | struct GNUNET_CADET_ChannelTunnelNumber ctn, | ||
722 | const struct GNUNET_HashCode *port, | ||
723 | uint32_t options) | ||
724 | { | ||
725 | struct CadetChannel *ch; | ||
726 | struct CadetClient *c; | ||
727 | |||
728 | ch = GNUNET_new (struct CadetChannel); | ||
729 | ch->port = *port; | ||
730 | ch->t = t; | ||
731 | ch->ctn = ctn; | ||
732 | ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME; | ||
733 | ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER)); | ||
734 | ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE)); | ||
735 | ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER)); | ||
736 | ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */ | ||
737 | GNUNET_STATISTICS_update (stats, | ||
738 | "# channels", | ||
739 | 1, | ||
740 | GNUNET_NO); | ||
741 | |||
742 | c = GNUNET_CONTAINER_multihashmap_get (open_ports, | ||
743 | port); | ||
744 | if (NULL == c) | ||
745 | { | ||
746 | /* port closed, wait for it to possibly open */ | ||
747 | ch->state = CADET_CHANNEL_LOOSE; | ||
748 | (void) GNUNET_CONTAINER_multihashmap_put (loose_channels, | ||
749 | port, | ||
750 | ch, | ||
751 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
752 | GNUNET_assert (NULL == ch->retry_control_task); | ||
753 | ch->retry_control_task | ||
754 | = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT, | ||
755 | &timeout_closed_cb, | ||
756 | ch); | ||
757 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
758 | "Created loose incoming channel to port %s from peer %s\n", | ||
759 | GNUNET_h2s (&ch->port), | ||
760 | GCP_2s (GCT_get_destination (ch->t))); | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | GCCH_bind (ch, | ||
765 | c); | ||
766 | } | ||
767 | GNUNET_STATISTICS_update (stats, | ||
768 | "# channels", | ||
769 | 1, | ||
770 | GNUNET_NO); | ||
771 | return ch; | ||
772 | } | ||
773 | |||
774 | |||
775 | /** | ||
776 | * Function called once the tunnel confirms that we sent the | ||
777 | * ACK message. Just remembers it was sent, we do not expect | ||
778 | * ACKs for ACKs ;-). | ||
779 | * | ||
780 | * @param cls our `struct CadetChannel`. | ||
781 | * @param cid identifier of the connection within the tunnel, NULL | ||
782 | * if transmission failed | ||
783 | */ | ||
784 | static void | ||
785 | send_ack_cb (void *cls, | ||
786 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
787 | { | ||
788 | struct CadetChannel *ch = cls; | ||
789 | |||
790 | GNUNET_assert (NULL != ch->last_control_qe); | ||
791 | ch->last_control_qe = NULL; | ||
792 | } | ||
793 | |||
794 | |||
795 | /** | ||
796 | * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer. | ||
797 | * | ||
798 | * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for | ||
799 | */ | ||
800 | static void | ||
801 | send_channel_data_ack (struct CadetChannel *ch) | ||
802 | { | ||
803 | struct GNUNET_CADET_ChannelDataAckMessage msg; | ||
804 | |||
805 | if (GNUNET_NO == ch->reliable) | ||
806 | return; /* no ACKs */ | ||
807 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); | ||
808 | msg.header.size = htons (sizeof (msg)); | ||
809 | msg.ctn = ch->ctn; | ||
810 | msg.mid.mid = htonl (ntohl (ch->mid_recv.mid)); | ||
811 | msg.futures = GNUNET_htonll (ch->mid_futures); | ||
812 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
813 | "Sending DATA_ACK %u:%llX via %s\n", | ||
814 | (unsigned int) ntohl (msg.mid.mid), | ||
815 | (unsigned long long) ch->mid_futures, | ||
816 | GCCH_2s (ch)); | ||
817 | if (NULL != ch->last_control_qe) | ||
818 | GCT_send_cancel (ch->last_control_qe); | ||
819 | ch->last_control_qe = GCT_send (ch->t, | ||
820 | &msg.header, | ||
821 | &send_ack_cb, | ||
822 | ch); | ||
823 | } | ||
824 | |||
825 | |||
826 | /** | ||
827 | * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the | ||
828 | * connection is up. | ||
829 | * | ||
830 | * @param cls the `struct CadetChannel` | ||
831 | */ | ||
832 | static void | ||
833 | send_open_ack (void *cls) | ||
834 | { | ||
835 | struct CadetChannel *ch = cls; | ||
836 | struct GNUNET_CADET_ChannelManageMessage msg; | ||
837 | |||
838 | ch->retry_control_task = NULL; | ||
839 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
840 | "Sending CHANNEL_OPEN_ACK on %s\n", | ||
841 | GCCH_2s (ch)); | ||
842 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK); | ||
843 | msg.header.size = htons (sizeof (msg)); | ||
844 | msg.reserved = htonl (0); | ||
845 | msg.ctn = ch->ctn; | ||
846 | if (NULL != ch->last_control_qe) | ||
847 | GCT_send_cancel (ch->last_control_qe); | ||
848 | ch->last_control_qe = GCT_send (ch->t, | ||
849 | &msg.header, | ||
850 | &send_ack_cb, | ||
851 | ch); | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for | ||
857 | * this channel. If the binding was successful, (re)transmit the | ||
858 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK. | ||
859 | * | ||
860 | * @param ch channel that got the duplicate open | ||
861 | * @param cti identifier of the connection that delivered the message | ||
862 | */ | ||
863 | void | ||
864 | GCCH_handle_duplicate_open (struct CadetChannel *ch, | ||
865 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) | ||
866 | { | ||
867 | if (NULL == ch->dest) | ||
868 | { | ||
869 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
870 | "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n", | ||
871 | GCCH_2s (ch)); | ||
872 | return; | ||
873 | } | ||
874 | if (NULL != ch->retry_control_task) | ||
875 | { | ||
876 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
877 | "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n", | ||
878 | GCCH_2s (ch)); | ||
879 | return; | ||
880 | } | ||
881 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
882 | "Retransmitting CHANNEL_OPEN_ACK on %s\n", | ||
883 | GCCH_2s (ch)); | ||
884 | ch->retry_control_task | ||
885 | = GNUNET_SCHEDULER_add_now (&send_open_ack, | ||
886 | ch); | ||
887 | } | ||
888 | |||
889 | |||
890 | /** | ||
891 | * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages. | ||
892 | * | ||
893 | * @param ch channel the ack is for | ||
894 | * @param to_owner #GNUNET_YES to send to owner, | ||
895 | * #GNUNET_NO to send to dest | ||
896 | */ | ||
897 | static void | ||
898 | send_ack_to_client (struct CadetChannel *ch, | ||
899 | int to_owner) | ||
900 | { | ||
901 | struct GNUNET_MQ_Envelope *env; | ||
902 | struct GNUNET_CADET_LocalAck *ack; | ||
903 | struct CadetChannelClient *ccc; | ||
904 | |||
905 | ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest; | ||
906 | if (NULL == ccc) | ||
907 | { | ||
908 | /* This can happen if we are just getting ACKs after | ||
909 | our local client already disconnected. */ | ||
910 | GNUNET_assert (GNUNET_YES == ch->destroy); | ||
911 | return; | ||
912 | } | ||
913 | env = GNUNET_MQ_msg (ack, | ||
914 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); | ||
915 | ack->ccn = ccc->ccn; | ||
916 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
917 | "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n", | ||
918 | GSC_2s (ccc->c), | ||
919 | (GNUNET_YES == to_owner) ? "owner" : "dest", | ||
920 | ntohl (ack->ccn.channel_of_client), | ||
921 | ch->pending_messages, | ||
922 | ch->max_pending_messages); | ||
923 | GSC_send_to_client (ccc->c, | ||
924 | env); | ||
925 | } | ||
926 | |||
927 | |||
928 | /** | ||
929 | * A client is bound to the port that we have a channel | ||
930 | * open to. Send the acknowledgement for the connection | ||
931 | * request and establish the link with the client. | ||
932 | * | ||
933 | * @param ch open incoming channel | ||
934 | * @param c client listening on the respective port | ||
935 | */ | ||
936 | void | ||
937 | GCCH_bind (struct CadetChannel *ch, | ||
938 | struct CadetClient *c) | ||
939 | { | ||
940 | uint32_t options; | ||
941 | struct CadetChannelClient *cccd; | ||
942 | |||
943 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
944 | "Binding %s from %s to port %s of %s\n", | ||
945 | GCCH_2s (ch), | ||
946 | GCT_2s (ch->t), | ||
947 | GNUNET_h2s (&ch->port), | ||
948 | GSC_2s (c)); | ||
949 | if (NULL != ch->retry_control_task) | ||
950 | { | ||
951 | /* there might be a timeout task here */ | ||
952 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
953 | ch->retry_control_task = NULL; | ||
954 | } | ||
955 | options = 0; | ||
956 | if (ch->nobuffer) | ||
957 | options |= GNUNET_CADET_OPTION_NOBUFFER; | ||
958 | if (ch->reliable) | ||
959 | options |= GNUNET_CADET_OPTION_RELIABLE; | ||
960 | if (ch->out_of_order) | ||
961 | options |= GNUNET_CADET_OPTION_OUT_OF_ORDER; | ||
962 | cccd = GNUNET_new (struct CadetChannelClient); | ||
963 | GNUNET_assert (NULL == ch->dest); | ||
964 | ch->dest = cccd; | ||
965 | cccd->c = c; | ||
966 | cccd->client_ready = GNUNET_YES; | ||
967 | cccd->ccn = GSC_bind (c, | ||
968 | ch, | ||
969 | (GNUNET_YES == ch->is_loopback) | ||
970 | ? GCP_get (&my_full_id, | ||
971 | GNUNET_YES) | ||
972 | : GCT_get_destination (ch->t), | ||
973 | &ch->port, | ||
974 | options); | ||
975 | GNUNET_assert (ntohl (cccd->ccn.channel_of_client) < | ||
976 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
977 | ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */ | ||
978 | if (GNUNET_YES == ch->is_loopback) | ||
979 | { | ||
980 | ch->state = CADET_CHANNEL_OPEN_SENT; | ||
981 | GCCH_handle_channel_open_ack (ch, | ||
982 | NULL); | ||
983 | } | ||
984 | else | ||
985 | { | ||
986 | /* notify other peer that we accepted the connection */ | ||
987 | ch->state = CADET_CHANNEL_READY; | ||
988 | ch->retry_control_task | ||
989 | = GNUNET_SCHEDULER_add_now (&send_open_ack, | ||
990 | ch); | ||
991 | } | ||
992 | /* give client it's initial supply of ACKs */ | ||
993 | GNUNET_assert (ntohl (cccd->ccn.channel_of_client) < | ||
994 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
995 | for (unsigned int i=0;i<ch->max_pending_messages;i++) | ||
996 | send_ack_to_client (ch, | ||
997 | GNUNET_NO); | ||
998 | } | ||
999 | |||
1000 | |||
1001 | /** | ||
1002 | * One of our clients has disconnected, tell the other one that we | ||
1003 | * are finished. Done asynchronously to avoid concurrent modification | ||
1004 | * issues if this is the same client. | ||
1005 | * | ||
1006 | * @param cls the `struct CadetChannel` where one of the ends is now dead | ||
1007 | */ | ||
1008 | static void | ||
1009 | signal_remote_destroy_cb (void *cls) | ||
1010 | { | ||
1011 | struct CadetChannel *ch = cls; | ||
1012 | struct CadetChannelClient *ccc; | ||
1013 | |||
1014 | /* Find which end is left... */ | ||
1015 | ch->retry_control_task = NULL; | ||
1016 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; | ||
1017 | GSC_handle_remote_channel_destroy (ccc->c, | ||
1018 | ccc->ccn, | ||
1019 | ch); | ||
1020 | channel_destroy (ch); | ||
1021 | } | ||
1022 | |||
1023 | |||
1024 | /** | ||
1025 | * Destroy locally created channel. Called by the local client, so no | ||
1026 | * need to tell the client. | ||
1027 | * | ||
1028 | * @param ch channel to destroy | ||
1029 | * @param c client that caused the destruction | ||
1030 | * @param ccn client number of the client @a c | ||
1031 | */ | ||
1032 | void | ||
1033 | GCCH_channel_local_destroy (struct CadetChannel *ch, | ||
1034 | struct CadetClient *c, | ||
1035 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1036 | { | ||
1037 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1038 | "%s asks for destruction of %s\n", | ||
1039 | GSC_2s (c), | ||
1040 | GCCH_2s (ch)); | ||
1041 | GNUNET_assert (NULL != c); | ||
1042 | if ( (NULL != ch->owner) && | ||
1043 | (c == ch->owner->c) && | ||
1044 | (ccn.channel_of_client == ch->owner->ccn.channel_of_client) ) | ||
1045 | { | ||
1046 | free_channel_client (ch->owner); | ||
1047 | ch->owner = NULL; | ||
1048 | } | ||
1049 | else if ( (NULL != ch->dest) && | ||
1050 | (c == ch->dest->c) && | ||
1051 | (ccn.channel_of_client == ch->dest->ccn.channel_of_client) ) | ||
1052 | { | ||
1053 | free_channel_client (ch->dest); | ||
1054 | ch->dest = NULL; | ||
1055 | } | ||
1056 | else | ||
1057 | { | ||
1058 | GNUNET_assert (0); | ||
1059 | } | ||
1060 | |||
1061 | if (GNUNET_YES == ch->destroy) | ||
1062 | { | ||
1063 | /* other end already destroyed, with the local client gone, no need | ||
1064 | to finish transmissions, just destroy immediately. */ | ||
1065 | channel_destroy (ch); | ||
1066 | return; | ||
1067 | } | ||
1068 | if ( (NULL != ch->head_sent) && | ||
1069 | ( (NULL != ch->owner) || | ||
1070 | (NULL != ch->dest) ) ) | ||
1071 | { | ||
1072 | /* Wait for other end to destroy us as well, | ||
1073 | and otherwise allow send queue to be transmitted first */ | ||
1074 | ch->destroy = GNUNET_YES; | ||
1075 | return; | ||
1076 | } | ||
1077 | if ( (GNUNET_YES == ch->is_loopback) && | ||
1078 | ( (NULL != ch->owner) || | ||
1079 | (NULL != ch->dest) ) ) | ||
1080 | { | ||
1081 | if (NULL != ch->retry_control_task) | ||
1082 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
1083 | ch->retry_control_task | ||
1084 | = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb, | ||
1085 | ch); | ||
1086 | return; | ||
1087 | } | ||
1088 | if (GNUNET_NO == ch->is_loopback) | ||
1089 | { | ||
1090 | /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */ | ||
1091 | switch (ch->state) | ||
1092 | { | ||
1093 | case CADET_CHANNEL_NEW: | ||
1094 | /* We gave up on a channel that we created as a client to a remote | ||
1095 | target, but that never went anywhere. Nothing to do here. */ | ||
1096 | break; | ||
1097 | case CADET_CHANNEL_LOOSE: | ||
1098 | GSC_drop_loose_channel (&ch->port, | ||
1099 | ch); | ||
1100 | break; | ||
1101 | default: | ||
1102 | GCT_send_channel_destroy (ch->t, | ||
1103 | ch->ctn); | ||
1104 | } | ||
1105 | } | ||
1106 | /* Nothing left to do, just finish destruction */ | ||
1107 | channel_destroy (ch); | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | /** | ||
1112 | * We got an acknowledgement for the creation of the channel | ||
1113 | * (the port is open on the other side). Begin transmissions. | ||
1114 | * | ||
1115 | * @param ch channel to destroy | ||
1116 | * @param cti identifier of the connection that delivered the message | ||
1117 | */ | ||
1118 | void | ||
1119 | GCCH_handle_channel_open_ack (struct CadetChannel *ch, | ||
1120 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) | ||
1121 | { | ||
1122 | switch (ch->state) | ||
1123 | { | ||
1124 | case CADET_CHANNEL_NEW: | ||
1125 | /* this should be impossible */ | ||
1126 | GNUNET_break (0); | ||
1127 | break; | ||
1128 | case CADET_CHANNEL_LOOSE: | ||
1129 | /* This makes no sense. */ | ||
1130 | GNUNET_break_op (0); | ||
1131 | break; | ||
1132 | case CADET_CHANNEL_OPEN_SENT: | ||
1133 | if (NULL == ch->owner) | ||
1134 | { | ||
1135 | /* We're not the owner, wrong direction! */ | ||
1136 | GNUNET_break_op (0); | ||
1137 | return; | ||
1138 | } | ||
1139 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1140 | "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n", | ||
1141 | GCCH_2s (ch)); | ||
1142 | if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */ | ||
1143 | { | ||
1144 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
1145 | ch->retry_control_task = NULL; | ||
1146 | } | ||
1147 | ch->state = CADET_CHANNEL_READY; | ||
1148 | /* On first connect, send client as many ACKs as we allow messages | ||
1149 | to be buffered! */ | ||
1150 | for (unsigned int i=0;i<ch->max_pending_messages;i++) | ||
1151 | send_ack_to_client (ch, | ||
1152 | GNUNET_YES); | ||
1153 | break; | ||
1154 | case CADET_CHANNEL_READY: | ||
1155 | /* duplicate ACK, maybe we retried the CREATE. Ignore. */ | ||
1156 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1157 | "Received duplicate channel OPEN_ACK for %s\n", | ||
1158 | GCCH_2s (ch)); | ||
1159 | GNUNET_STATISTICS_update (stats, | ||
1160 | "# duplicate CREATE_ACKs", | ||
1161 | 1, | ||
1162 | GNUNET_NO); | ||
1163 | break; | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | |||
1168 | /** | ||
1169 | * Test if element @a e1 comes before element @a e2. | ||
1170 | * | ||
1171 | * @param cls closure, to a flag where we indicate duplicate packets | ||
1172 | * @param m1 a message of to sort | ||
1173 | * @param m2 another message to sort | ||
1174 | * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO | ||
1175 | */ | ||
1176 | static int | ||
1177 | is_before (void *cls, | ||
1178 | struct CadetOutOfOrderMessage *m1, | ||
1179 | struct CadetOutOfOrderMessage *m2) | ||
1180 | { | ||
1181 | int *duplicate = cls; | ||
1182 | uint32_t v1 = ntohl (m1->mid.mid); | ||
1183 | uint32_t v2 = ntohl (m2->mid.mid); | ||
1184 | uint32_t delta; | ||
1185 | |||
1186 | delta = v2 - v1; | ||
1187 | if (0 == delta) | ||
1188 | *duplicate = GNUNET_YES; | ||
1189 | if (delta > (uint32_t) INT_MAX) | ||
1190 | { | ||
1191 | /* in overflow range, we can safely assume we wrapped around */ | ||
1192 | return GNUNET_NO; | ||
1193 | } | ||
1194 | else | ||
1195 | { | ||
1196 | /* result is small, thus v2 > v1, thus m1 < m2 */ | ||
1197 | return GNUNET_YES; | ||
1198 | } | ||
1199 | } | ||
1200 | |||
1201 | |||
1202 | /** | ||
1203 | * We got payload data for a channel. Pass it on to the client | ||
1204 | * and send an ACK to the other end (once flow control allows it!) | ||
1205 | * | ||
1206 | * @param ch channel that got data | ||
1207 | * @param cti identifier of the connection that delivered the message | ||
1208 | * @param msg message that was received | ||
1209 | */ | ||
1210 | void | ||
1211 | GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | ||
1212 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1213 | const struct GNUNET_CADET_ChannelAppDataMessage *msg) | ||
1214 | { | ||
1215 | struct GNUNET_MQ_Envelope *env; | ||
1216 | struct GNUNET_CADET_LocalData *ld; | ||
1217 | struct CadetChannelClient *ccc; | ||
1218 | size_t payload_size; | ||
1219 | struct CadetOutOfOrderMessage *com; | ||
1220 | int duplicate; | ||
1221 | uint32_t mid_min; | ||
1222 | uint32_t mid_max; | ||
1223 | uint32_t mid_msg; | ||
1224 | uint32_t delta; | ||
1225 | |||
1226 | GNUNET_assert (GNUNET_NO == ch->is_loopback); | ||
1227 | if ( (GNUNET_YES == ch->destroy) && | ||
1228 | (NULL == ch->owner) && | ||
1229 | (NULL == ch->dest) ) | ||
1230 | { | ||
1231 | /* This client is gone, but we still have messages to send to | ||
1232 | the other end (which is why @a ch is not yet dead). However, | ||
1233 | we cannot pass messages to our client anymore. */ | ||
1234 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1235 | "Dropping incoming payload on %s as this end is already closed\n", | ||
1236 | GCCH_2s (ch)); | ||
1237 | /* send back DESTROY notification to stop further retransmissions! */ | ||
1238 | GCT_send_channel_destroy (ch->t, | ||
1239 | ch->ctn); | ||
1240 | return; | ||
1241 | } | ||
1242 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
1243 | env = GNUNET_MQ_msg_extra (ld, | ||
1244 | payload_size, | ||
1245 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); | ||
1246 | ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn; | ||
1247 | GNUNET_memcpy (&ld[1], | ||
1248 | &msg[1], | ||
1249 | payload_size); | ||
1250 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; | ||
1251 | if ( (GNUNET_YES == ccc->client_ready) && | ||
1252 | ( (GNUNET_YES == ch->out_of_order) || | ||
1253 | (msg->mid.mid == ch->mid_recv.mid) ) ) | ||
1254 | { | ||
1255 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1256 | "Giving %u bytes of payload with MID %u from %s to client %s\n", | ||
1257 | (unsigned int) payload_size, | ||
1258 | ntohl (msg->mid.mid), | ||
1259 | GCCH_2s (ch), | ||
1260 | GSC_2s (ccc->c)); | ||
1261 | ccc->client_ready = GNUNET_NO; | ||
1262 | GSC_send_to_client (ccc->c, | ||
1263 | env); | ||
1264 | ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid)); | ||
1265 | ch->mid_futures >>= 1; | ||
1266 | send_channel_data_ack (ch); | ||
1267 | return; | ||
1268 | } | ||
1269 | |||
1270 | if (GNUNET_YES == ch->reliable) | ||
1271 | { | ||
1272 | /* check if message ought to be dropped because it is ancient/too distant/duplicate */ | ||
1273 | mid_min = ntohl (ch->mid_recv.mid); | ||
1274 | mid_max = mid_min + ch->max_pending_messages; | ||
1275 | mid_msg = ntohl (msg->mid.mid); | ||
1276 | if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) || | ||
1277 | ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) ) | ||
1278 | { | ||
1279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1280 | "%s at %u drops ancient or far-future message %u\n", | ||
1281 | GCCH_2s (ch), | ||
1282 | (unsigned int) mid_min, | ||
1283 | ntohl (msg->mid.mid)); | ||
1284 | |||
1285 | GNUNET_STATISTICS_update (stats, | ||
1286 | "# duplicate DATA (ancient or future)", | ||
1287 | 1, | ||
1288 | GNUNET_NO); | ||
1289 | GNUNET_MQ_discard (env); | ||
1290 | send_channel_data_ack (ch); | ||
1291 | return; | ||
1292 | } | ||
1293 | /* mark bit for future ACKs */ | ||
1294 | delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */ | ||
1295 | if (delta < 64) | ||
1296 | { | ||
1297 | if (0 != (ch->mid_futures & (1LLU << delta))) | ||
1298 | { | ||
1299 | /* Duplicate within the queue, drop also */ | ||
1300 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1301 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | ||
1302 | (unsigned int) payload_size, | ||
1303 | GCCH_2s (ch), | ||
1304 | ntohl (msg->mid.mid)); | ||
1305 | GNUNET_STATISTICS_update (stats, | ||
1306 | "# duplicate DATA", | ||
1307 | 1, | ||
1308 | GNUNET_NO); | ||
1309 | GNUNET_MQ_discard (env); | ||
1310 | send_channel_data_ack (ch); | ||
1311 | return; | ||
1312 | } | ||
1313 | ch->mid_futures |= (1LLU << delta); | ||
1314 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1315 | "Marked bit %llX for mid %u (base: %u); now: %llX\n", | ||
1316 | (1LLU << delta), | ||
1317 | mid_msg, | ||
1318 | mid_min, | ||
1319 | ch->mid_futures); | ||
1320 | } | ||
1321 | } | ||
1322 | else /* ! ch->reliable */ | ||
1323 | { | ||
1324 | /* Channel is unreliable, so we do not ACK. But we also cannot | ||
1325 | allow buffering everything, so check if we have space... */ | ||
1326 | if (ccc->num_recv >= ch->max_pending_messages) | ||
1327 | { | ||
1328 | struct CadetOutOfOrderMessage *drop; | ||
1329 | |||
1330 | /* Yep, need to drop. Drop the oldest message in | ||
1331 | the buffer. */ | ||
1332 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1333 | "Queue full due slow client on %s, dropping oldest message\n", | ||
1334 | GCCH_2s (ch)); | ||
1335 | GNUNET_STATISTICS_update (stats, | ||
1336 | "# messages dropped due to slow client", | ||
1337 | 1, | ||
1338 | GNUNET_NO); | ||
1339 | drop = ccc->head_recv; | ||
1340 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1341 | ccc->tail_recv, | ||
1342 | drop); | ||
1343 | ccc->num_recv--; | ||
1344 | GNUNET_MQ_discard (drop->env); | ||
1345 | GNUNET_free (drop); | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | /* Insert message into sorted out-of-order queue */ | ||
1350 | com = GNUNET_new (struct CadetOutOfOrderMessage); | ||
1351 | com->mid = msg->mid; | ||
1352 | com->env = env; | ||
1353 | duplicate = GNUNET_NO; | ||
1354 | GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage, | ||
1355 | is_before, | ||
1356 | &duplicate, | ||
1357 | ccc->head_recv, | ||
1358 | ccc->tail_recv, | ||
1359 | com); | ||
1360 | ccc->num_recv++; | ||
1361 | if (GNUNET_YES == duplicate) | ||
1362 | { | ||
1363 | /* Duplicate within the queue, drop also (this is not covered by | ||
1364 | the case above if "delta" >= 64, which could be the case if | ||
1365 | max_pending_messages is also >= 64 or if our client is unready | ||
1366 | and we are seeing retransmissions of the message our client is | ||
1367 | blocked on. */ | ||
1368 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1369 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | ||
1370 | (unsigned int) payload_size, | ||
1371 | GCCH_2s (ch), | ||
1372 | ntohl (msg->mid.mid)); | ||
1373 | GNUNET_STATISTICS_update (stats, | ||
1374 | "# duplicate DATA", | ||
1375 | 1, | ||
1376 | GNUNET_NO); | ||
1377 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1378 | ccc->tail_recv, | ||
1379 | com); | ||
1380 | ccc->num_recv--; | ||
1381 | GNUNET_MQ_discard (com->env); | ||
1382 | GNUNET_free (com); | ||
1383 | send_channel_data_ack (ch); | ||
1384 | return; | ||
1385 | } | ||
1386 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1387 | "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n", | ||
1388 | (GNUNET_YES == ccc->client_ready) | ||
1389 | ? "out-of-order" | ||
1390 | : "client-not-ready", | ||
1391 | (unsigned int) payload_size, | ||
1392 | GCCH_2s (ch), | ||
1393 | ntohl (ccc->ccn.channel_of_client), | ||
1394 | ccc, | ||
1395 | ntohl (msg->mid.mid), | ||
1396 | ntohl (ch->mid_recv.mid)); | ||
1397 | /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and | ||
1398 | the sender may already be transmitting the previous one. Needs | ||
1399 | experimental evaluation to see if/when this ACK helps or | ||
1400 | hurts. (We might even want another option.) */ | ||
1401 | send_channel_data_ack (ch); | ||
1402 | } | ||
1403 | |||
1404 | |||
1405 | /** | ||
1406 | * Function called once the tunnel has sent one of our messages. | ||
1407 | * If the message is unreliable, simply frees the `crm`. If the | ||
1408 | * message was reliable, calculate retransmission time and | ||
1409 | * wait for ACK (or retransmit). | ||
1410 | * | ||
1411 | * @param cls the `struct CadetReliableMessage` that was sent | ||
1412 | * @param cid identifier of the connection within the tunnel, NULL | ||
1413 | * if transmission failed | ||
1414 | */ | ||
1415 | static void | ||
1416 | data_sent_cb (void *cls, | ||
1417 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); | ||
1418 | |||
1419 | |||
1420 | /** | ||
1421 | * We need to retry a transmission, the last one took too long to | ||
1422 | * be acknowledged. | ||
1423 | * | ||
1424 | * @param cls the `struct CadetChannel` where we need to retransmit | ||
1425 | */ | ||
1426 | static void | ||
1427 | retry_transmission (void *cls) | ||
1428 | { | ||
1429 | struct CadetChannel *ch = cls; | ||
1430 | struct CadetReliableMessage *crm = ch->head_sent; | ||
1431 | |||
1432 | ch->retry_data_task = NULL; | ||
1433 | GNUNET_assert (NULL == crm->qe); | ||
1434 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1435 | "Retrying transmission on %s of message %u\n", | ||
1436 | GCCH_2s (ch), | ||
1437 | (unsigned int) ntohl (crm->data_message->mid.mid)); | ||
1438 | crm->qe = GCT_send (ch->t, | ||
1439 | &crm->data_message->header, | ||
1440 | &data_sent_cb, | ||
1441 | crm); | ||
1442 | GNUNET_assert (NULL == ch->retry_data_task); | ||
1443 | } | ||
1444 | |||
1445 | |||
1446 | /** | ||
1447 | * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from | ||
1448 | * the queue and tell our client that it can send more. | ||
1449 | * | ||
1450 | * @param ch the channel that got the PLAINTEXT_DATA_ACK | ||
1451 | * @param cti identifier of the connection that delivered the message | ||
1452 | * @param crm the message that got acknowledged | ||
1453 | */ | ||
1454 | static void | ||
1455 | handle_matching_ack (struct CadetChannel *ch, | ||
1456 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1457 | struct CadetReliableMessage *crm) | ||
1458 | { | ||
1459 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, | ||
1460 | ch->tail_sent, | ||
1461 | crm); | ||
1462 | ch->pending_messages--; | ||
1463 | GNUNET_assert (ch->pending_messages < ch->max_pending_messages); | ||
1464 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1465 | "Received DATA_ACK on %s for message %u (%u ACKs pending)\n", | ||
1466 | GCCH_2s (ch), | ||
1467 | (unsigned int) ntohl (crm->data_message->mid.mid), | ||
1468 | ch->pending_messages); | ||
1469 | if (NULL != crm->qe) | ||
1470 | { | ||
1471 | GCT_send_cancel (crm->qe); | ||
1472 | crm->qe = NULL; | ||
1473 | } | ||
1474 | if ( (1 == crm->num_transmissions) && | ||
1475 | (NULL != cti) ) | ||
1476 | { | ||
1477 | GCC_ack_observed (cti); | ||
1478 | if (0 == memcmp (cti, | ||
1479 | &crm->connection_taken, | ||
1480 | sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier))) | ||
1481 | { | ||
1482 | GCC_latency_observed (cti, | ||
1483 | GNUNET_TIME_absolute_get_duration (crm->first_transmission_time)); | ||
1484 | } | ||
1485 | } | ||
1486 | GNUNET_free (crm->data_message); | ||
1487 | GNUNET_free (crm); | ||
1488 | send_ack_to_client (ch, | ||
1489 | (NULL == ch->owner) | ||
1490 | ? GNUNET_NO | ||
1491 | : GNUNET_YES); | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | /** | ||
1496 | * We got an acknowledgement for payload data for a channel. | ||
1497 | * Possibly resume transmissions. | ||
1498 | * | ||
1499 | * @param ch channel that got the ack | ||
1500 | * @param cti identifier of the connection that delivered the message | ||
1501 | * @param ack details about what was received | ||
1502 | */ | ||
1503 | void | ||
1504 | GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | ||
1505 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1506 | const struct GNUNET_CADET_ChannelDataAckMessage *ack) | ||
1507 | { | ||
1508 | struct CadetReliableMessage *crm; | ||
1509 | struct CadetReliableMessage *crmn; | ||
1510 | int found; | ||
1511 | uint32_t mid_base; | ||
1512 | uint64_t mid_mask; | ||
1513 | unsigned int delta; | ||
1514 | |||
1515 | GNUNET_break (GNUNET_NO == ch->is_loopback); | ||
1516 | if (GNUNET_NO == ch->reliable) | ||
1517 | { | ||
1518 | /* not expecting ACKs on unreliable channel, odd */ | ||
1519 | GNUNET_break_op (0); | ||
1520 | return; | ||
1521 | } | ||
1522 | /* mid_base is the MID of the next message that the | ||
1523 | other peer expects (i.e. that is missing!), everything | ||
1524 | LOWER (but excluding mid_base itself) was received. */ | ||
1525 | mid_base = ntohl (ack->mid.mid); | ||
1526 | mid_mask = GNUNET_htonll (ack->futures); | ||
1527 | found = GNUNET_NO; | ||
1528 | for (crm = ch->head_sent; | ||
1529 | NULL != crm; | ||
1530 | crm = crmn) | ||
1531 | { | ||
1532 | crmn = crm->next; | ||
1533 | delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base); | ||
1534 | if (delta >= UINT_MAX - ch->max_pending_messages) | ||
1535 | { | ||
1536 | /* overflow, means crm was a bit in the past, so this ACK counts for it. */ | ||
1537 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1538 | "Got DATA_ACK with base %u satisfying past message %u on %s\n", | ||
1539 | (unsigned int) mid_base, | ||
1540 | ntohl (crm->data_message->mid.mid), | ||
1541 | GCCH_2s (ch)); | ||
1542 | handle_matching_ack (ch, | ||
1543 | cti, | ||
1544 | crm); | ||
1545 | found = GNUNET_YES; | ||
1546 | continue; | ||
1547 | } | ||
1548 | delta--; | ||
1549 | if (delta >= 64) | ||
1550 | continue; | ||
1551 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1552 | "Testing bit %llX for mid %u (base: %u)\n", | ||
1553 | (1LLU << delta), | ||
1554 | ntohl (crm->data_message->mid.mid), | ||
1555 | mid_base); | ||
1556 | if (0 != (mid_mask & (1LLU << delta))) | ||
1557 | { | ||
1558 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1559 | "Got DATA_ACK with mask for %u on %s\n", | ||
1560 | ntohl (crm->data_message->mid.mid), | ||
1561 | GCCH_2s (ch)); | ||
1562 | handle_matching_ack (ch, | ||
1563 | cti, | ||
1564 | crm); | ||
1565 | found = GNUNET_YES; | ||
1566 | } | ||
1567 | } | ||
1568 | if (GNUNET_NO == found) | ||
1569 | { | ||
1570 | /* ACK for message we already dropped, might have been a | ||
1571 | duplicate ACK? Ignore. */ | ||
1572 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1573 | "Duplicate DATA_ACK on %s, ignoring\n", | ||
1574 | GCCH_2s (ch)); | ||
1575 | GNUNET_STATISTICS_update (stats, | ||
1576 | "# duplicate DATA_ACKs", | ||
1577 | 1, | ||
1578 | GNUNET_NO); | ||
1579 | return; | ||
1580 | } | ||
1581 | if (NULL != ch->retry_data_task) | ||
1582 | { | ||
1583 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
1584 | ch->retry_data_task = NULL; | ||
1585 | } | ||
1586 | if ( (NULL != ch->head_sent) && | ||
1587 | (NULL == ch->head_sent->qe) ) | ||
1588 | ch->retry_data_task | ||
1589 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, | ||
1590 | &retry_transmission, | ||
1591 | ch); | ||
1592 | } | ||
1593 | |||
1594 | |||
1595 | /** | ||
1596 | * Destroy channel, based on the other peer closing the | ||
1597 | * connection. Also needs to remove this channel from | ||
1598 | * the tunnel. | ||
1599 | * | ||
1600 | * @param ch channel to destroy | ||
1601 | * @param cti identifier of the connection that delivered the message, | ||
1602 | * NULL if we are simulating receiving a destroy due to shutdown | ||
1603 | */ | ||
1604 | void | ||
1605 | GCCH_handle_remote_destroy (struct CadetChannel *ch, | ||
1606 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) | ||
1607 | { | ||
1608 | struct CadetChannelClient *ccc; | ||
1609 | |||
1610 | GNUNET_assert (GNUNET_NO == ch->is_loopback); | ||
1611 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1612 | "Received remote channel DESTROY for %s\n", | ||
1613 | GCCH_2s (ch)); | ||
1614 | if (GNUNET_YES == ch->destroy) | ||
1615 | { | ||
1616 | /* Local client already gone, this is instant-death. */ | ||
1617 | channel_destroy (ch); | ||
1618 | return; | ||
1619 | } | ||
1620 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; | ||
1621 | if ( (NULL != ccc) && | ||
1622 | (NULL != ccc->head_recv) ) | ||
1623 | { | ||
1624 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1625 | "Lost end of transmission due to remote shutdown on %s\n", | ||
1626 | GCCH_2s (ch)); | ||
1627 | /* FIXME: change API to notify client about truncated transmission! */ | ||
1628 | } | ||
1629 | ch->destroy = GNUNET_YES; | ||
1630 | if (NULL != ccc) | ||
1631 | GSC_handle_remote_channel_destroy (ccc->c, | ||
1632 | ccc->ccn, | ||
1633 | ch); | ||
1634 | channel_destroy (ch); | ||
1635 | } | ||
1636 | |||
1637 | |||
1638 | /** | ||
1639 | * Test if element @a e1 comes before element @a e2. | ||
1640 | * | ||
1641 | * @param cls closure, to a flag where we indicate duplicate packets | ||
1642 | * @param crm1 an element of to sort | ||
1643 | * @param crm2 another element to sort | ||
1644 | * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO | ||
1645 | */ | ||
1646 | static int | ||
1647 | cmp_crm_by_next_retry (void *cls, | ||
1648 | struct CadetReliableMessage *crm1, | ||
1649 | struct CadetReliableMessage *crm2) | ||
1650 | { | ||
1651 | if (crm1->next_retry.abs_value_us < | ||
1652 | crm2->next_retry.abs_value_us) | ||
1653 | return GNUNET_YES; | ||
1654 | return GNUNET_NO; | ||
1655 | } | ||
1656 | |||
1657 | |||
1658 | /** | ||
1659 | * Function called once the tunnel has sent one of our messages. | ||
1660 | * If the message is unreliable, simply frees the `crm`. If the | ||
1661 | * message was reliable, calculate retransmission time and | ||
1662 | * wait for ACK (or retransmit). | ||
1663 | * | ||
1664 | * @param cls the `struct CadetReliableMessage` that was sent | ||
1665 | * @param cid identifier of the connection within the tunnel, NULL | ||
1666 | * if transmission failed | ||
1667 | */ | ||
1668 | static void | ||
1669 | data_sent_cb (void *cls, | ||
1670 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
1671 | { | ||
1672 | struct CadetReliableMessage *crm = cls; | ||
1673 | struct CadetChannel *ch = crm->ch; | ||
1674 | |||
1675 | GNUNET_assert (GNUNET_NO == ch->is_loopback); | ||
1676 | GNUNET_assert (NULL != crm->qe); | ||
1677 | crm->qe = NULL; | ||
1678 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, | ||
1679 | ch->tail_sent, | ||
1680 | crm); | ||
1681 | if (GNUNET_NO == ch->reliable) | ||
1682 | { | ||
1683 | GNUNET_free (crm->data_message); | ||
1684 | GNUNET_free (crm); | ||
1685 | ch->pending_messages--; | ||
1686 | send_ack_to_client (ch, | ||
1687 | (NULL == ch->owner) | ||
1688 | ? GNUNET_NO | ||
1689 | : GNUNET_YES); | ||
1690 | return; | ||
1691 | } | ||
1692 | if (NULL == cid) | ||
1693 | { | ||
1694 | /* There was an error sending. */ | ||
1695 | crm->num_transmissions = GNUNET_SYSERR; | ||
1696 | } | ||
1697 | else if (GNUNET_SYSERR != crm->num_transmissions) | ||
1698 | { | ||
1699 | /* Increment transmission counter, and possibly store @a cid | ||
1700 | if this was the first transmission. */ | ||
1701 | crm->num_transmissions++; | ||
1702 | if (1 == crm->num_transmissions) | ||
1703 | { | ||
1704 | crm->first_transmission_time = GNUNET_TIME_absolute_get (); | ||
1705 | crm->connection_taken = *cid; | ||
1706 | GCC_ack_expected (cid); | ||
1707 | } | ||
1708 | } | ||
1709 | if ( (0 == crm->retry_delay.rel_value_us) && | ||
1710 | (NULL != cid) ) | ||
1711 | { | ||
1712 | struct CadetConnection *cc = GCC_lookup (cid); | ||
1713 | |||
1714 | if (NULL != cc) | ||
1715 | crm->retry_delay = GCC_get_metrics (cc)->aged_latency; | ||
1716 | else | ||
1717 | crm->retry_delay = ch->retry_time; | ||
1718 | } | ||
1719 | crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay); | ||
1720 | crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay, | ||
1721 | MIN_RTT_DELAY); | ||
1722 | crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay); | ||
1723 | |||
1724 | GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage, | ||
1725 | cmp_crm_by_next_retry, | ||
1726 | NULL, | ||
1727 | ch->head_sent, | ||
1728 | ch->tail_sent, | ||
1729 | crm); | ||
1730 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1731 | "Message %u sent, next transmission on %s in %s\n", | ||
1732 | (unsigned int) ntohl (crm->data_message->mid.mid), | ||
1733 | GCCH_2s (ch), | ||
1734 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry), | ||
1735 | GNUNET_YES)); | ||
1736 | if (NULL == ch->head_sent->qe) | ||
1737 | { | ||
1738 | if (NULL != ch->retry_data_task) | ||
1739 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
1740 | ch->retry_data_task | ||
1741 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, | ||
1742 | &retry_transmission, | ||
1743 | ch); | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | |||
1748 | /** | ||
1749 | * Handle data given by a client. | ||
1750 | * | ||
1751 | * Check whether the client is allowed to send in this tunnel, save if | ||
1752 | * channel is reliable and send an ACK to the client if there is still | ||
1753 | * buffer space in the tunnel. | ||
1754 | * | ||
1755 | * @param ch Channel. | ||
1756 | * @param sender_ccn ccn of the sender | ||
1757 | * @param buf payload to transmit. | ||
1758 | * @param buf_len number of bytes in @a buf | ||
1759 | * @return #GNUNET_OK if everything goes well, | ||
1760 | * #GNUNET_SYSERR in case of an error. | ||
1761 | */ | ||
1762 | int | ||
1763 | GCCH_handle_local_data (struct CadetChannel *ch, | ||
1764 | struct GNUNET_CADET_ClientChannelNumber sender_ccn, | ||
1765 | const char *buf, | ||
1766 | size_t buf_len) | ||
1767 | { | ||
1768 | struct CadetReliableMessage *crm; | ||
1769 | |||
1770 | if (ch->pending_messages > ch->max_pending_messages) | ||
1771 | { | ||
1772 | GNUNET_break (0); | ||
1773 | return GNUNET_SYSERR; | ||
1774 | } | ||
1775 | if (GNUNET_YES == ch->destroy) | ||
1776 | { | ||
1777 | /* we are going down, drop messages */ | ||
1778 | return GNUNET_OK; | ||
1779 | } | ||
1780 | ch->pending_messages++; | ||
1781 | |||
1782 | if (GNUNET_YES == ch->is_loopback) | ||
1783 | { | ||
1784 | struct CadetChannelClient *receiver; | ||
1785 | struct GNUNET_MQ_Envelope *env; | ||
1786 | struct GNUNET_CADET_LocalData *ld; | ||
1787 | int ack_to_owner; | ||
1788 | |||
1789 | env = GNUNET_MQ_msg_extra (ld, | ||
1790 | buf_len, | ||
1791 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); | ||
1792 | if ( (NULL != ch->owner) && | ||
1793 | (sender_ccn.channel_of_client == | ||
1794 | ch->owner->ccn.channel_of_client) ) | ||
1795 | { | ||
1796 | receiver = ch->dest; | ||
1797 | ack_to_owner = GNUNET_YES; | ||
1798 | } | ||
1799 | else if ( (NULL != ch->dest) && | ||
1800 | (sender_ccn.channel_of_client == | ||
1801 | ch->dest->ccn.channel_of_client) ) | ||
1802 | { | ||
1803 | receiver = ch->owner; | ||
1804 | ack_to_owner = GNUNET_NO; | ||
1805 | } | ||
1806 | else | ||
1807 | { | ||
1808 | GNUNET_break (0); | ||
1809 | return GNUNET_SYSERR; | ||
1810 | } | ||
1811 | GNUNET_assert (NULL != receiver); | ||
1812 | ld->ccn = receiver->ccn; | ||
1813 | GNUNET_memcpy (&ld[1], | ||
1814 | buf, | ||
1815 | buf_len); | ||
1816 | if (GNUNET_YES == receiver->client_ready) | ||
1817 | { | ||
1818 | ch->pending_messages--; | ||
1819 | GSC_send_to_client (receiver->c, | ||
1820 | env); | ||
1821 | send_ack_to_client (ch, | ||
1822 | ack_to_owner); | ||
1823 | } | ||
1824 | else | ||
1825 | { | ||
1826 | struct CadetOutOfOrderMessage *oom; | ||
1827 | |||
1828 | oom = GNUNET_new (struct CadetOutOfOrderMessage); | ||
1829 | oom->env = env; | ||
1830 | GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv, | ||
1831 | receiver->tail_recv, | ||
1832 | oom); | ||
1833 | receiver->num_recv++; | ||
1834 | } | ||
1835 | return GNUNET_OK; | ||
1836 | } | ||
1837 | |||
1838 | /* Everything is correct, send the message. */ | ||
1839 | crm = GNUNET_malloc (sizeof (*crm)); | ||
1840 | crm->ch = ch; | ||
1841 | crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) | ||
1842 | + buf_len); | ||
1843 | crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len); | ||
1844 | crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA); | ||
1845 | ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1); | ||
1846 | crm->data_message->mid = ch->mid_send; | ||
1847 | crm->data_message->ctn = ch->ctn; | ||
1848 | GNUNET_memcpy (&crm->data_message[1], | ||
1849 | buf, | ||
1850 | buf_len); | ||
1851 | GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent, | ||
1852 | ch->tail_sent, | ||
1853 | crm); | ||
1854 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1855 | "Sending message %u from local client to %s with %u bytes\n", | ||
1856 | ntohl (crm->data_message->mid.mid), | ||
1857 | GCCH_2s (ch), | ||
1858 | buf_len); | ||
1859 | if (NULL != ch->retry_data_task) | ||
1860 | { | ||
1861 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
1862 | ch->retry_data_task = NULL; | ||
1863 | } | ||
1864 | crm->qe = GCT_send (ch->t, | ||
1865 | &crm->data_message->header, | ||
1866 | &data_sent_cb, | ||
1867 | crm); | ||
1868 | GNUNET_assert (NULL == ch->retry_data_task); | ||
1869 | return GNUNET_OK; | ||
1870 | } | ||
1871 | |||
1872 | |||
1873 | /** | ||
1874 | * Handle ACK from client on local channel. Means the client is ready | ||
1875 | * for more data, see if we have any for it. | ||
1876 | * | ||
1877 | * @param ch channel to destroy | ||
1878 | * @param client_ccn ccn of the client sending the ack | ||
1879 | */ | ||
1880 | void | ||
1881 | GCCH_handle_local_ack (struct CadetChannel *ch, | ||
1882 | struct GNUNET_CADET_ClientChannelNumber client_ccn) | ||
1883 | { | ||
1884 | struct CadetChannelClient *ccc; | ||
1885 | struct CadetOutOfOrderMessage *com; | ||
1886 | |||
1887 | if ( (NULL != ch->owner) && | ||
1888 | (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) ) | ||
1889 | ccc = ch->owner; | ||
1890 | else if ( (NULL != ch->dest) && | ||
1891 | (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) ) | ||
1892 | ccc = ch->dest; | ||
1893 | else | ||
1894 | GNUNET_assert (0); | ||
1895 | ccc->client_ready = GNUNET_YES; | ||
1896 | com = ccc->head_recv; | ||
1897 | if (NULL == com) | ||
1898 | { | ||
1899 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1900 | "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n", | ||
1901 | GSC_2s (ccc->c), | ||
1902 | ntohl (client_ccn.channel_of_client), | ||
1903 | GCCH_2s (ch), | ||
1904 | ntohl (ccc->ccn.channel_of_client), | ||
1905 | ccc); | ||
1906 | return; /* none pending */ | ||
1907 | } | ||
1908 | if (GNUNET_YES == ch->is_loopback) | ||
1909 | { | ||
1910 | int to_owner; | ||
1911 | |||
1912 | /* Messages are always in-order, just send */ | ||
1913 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1914 | ccc->tail_recv, | ||
1915 | com); | ||
1916 | ccc->num_recv--; | ||
1917 | GSC_send_to_client (ccc->c, | ||
1918 | com->env); | ||
1919 | /* Notify sender that we can receive more */ | ||
1920 | if ( (NULL != ch->owner) && | ||
1921 | (ccc->ccn.channel_of_client == | ||
1922 | ch->owner->ccn.channel_of_client) ) | ||
1923 | { | ||
1924 | to_owner = GNUNET_NO; | ||
1925 | } | ||
1926 | else | ||
1927 | { | ||
1928 | GNUNET_assert ( (NULL != ch->dest) && | ||
1929 | (ccc->ccn.channel_of_client == | ||
1930 | ch->dest->ccn.channel_of_client) ); | ||
1931 | to_owner = GNUNET_YES; | ||
1932 | } | ||
1933 | send_ack_to_client (ch, | ||
1934 | to_owner); | ||
1935 | GNUNET_free (com); | ||
1936 | return; | ||
1937 | } | ||
1938 | |||
1939 | if ( (com->mid.mid != ch->mid_recv.mid) && | ||
1940 | (GNUNET_NO == ch->out_of_order) && | ||
1941 | (GNUNET_YES == ch->reliable) ) | ||
1942 | { | ||
1943 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1944 | "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n", | ||
1945 | GSC_2s (ccc->c), | ||
1946 | ntohl (ccc->ccn.channel_of_client), | ||
1947 | ntohl (com->mid.mid), | ||
1948 | ntohl (ch->mid_recv.mid)); | ||
1949 | return; /* missing next one in-order */ | ||
1950 | } | ||
1951 | |||
1952 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1953 | "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n", | ||
1954 | ntohl (com->mid.mid), | ||
1955 | GSC_2s (ccc->c), | ||
1956 | ntohl (ccc->ccn.channel_of_client), | ||
1957 | GCCH_2s (ch)); | ||
1958 | |||
1959 | /* all good, pass next message to client */ | ||
1960 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1961 | ccc->tail_recv, | ||
1962 | com); | ||
1963 | ccc->num_recv--; | ||
1964 | /* FIXME: if unreliable, this is not aggressive | ||
1965 | enough, as it would be OK to have lost some! */ | ||
1966 | |||
1967 | ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid)); | ||
1968 | ch->mid_futures >>= 1; /* equivalent to division by 2 */ | ||
1969 | ccc->client_ready = GNUNET_NO; | ||
1970 | GSC_send_to_client (ccc->c, | ||
1971 | com->env); | ||
1972 | GNUNET_free (com); | ||
1973 | send_channel_data_ack (ch); | ||
1974 | if (NULL != ccc->head_recv) | ||
1975 | return; | ||
1976 | if (GNUNET_NO == ch->destroy) | ||
1977 | return; | ||
1978 | GCT_send_channel_destroy (ch->t, | ||
1979 | ch->ctn); | ||
1980 | channel_destroy (ch); | ||
1981 | } | ||
1982 | |||
1983 | |||
1984 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__) | ||
1985 | |||
1986 | |||
1987 | /** | ||
1988 | * Log channel info. | ||
1989 | * | ||
1990 | * @param ch Channel. | ||
1991 | * @param level Debug level to use. | ||
1992 | */ | ||
1993 | void | ||
1994 | GCCH_debug (struct CadetChannel *ch, | ||
1995 | enum GNUNET_ErrorType level) | ||
1996 | { | ||
1997 | int do_log; | ||
1998 | |||
1999 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | ||
2000 | "cadet-chn", | ||
2001 | __FILE__, __FUNCTION__, __LINE__); | ||
2002 | if (0 == do_log) | ||
2003 | return; | ||
2004 | |||
2005 | if (NULL == ch) | ||
2006 | { | ||
2007 | LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n"); | ||
2008 | return; | ||
2009 | } | ||
2010 | LOG2 (level, | ||
2011 | "CHN %s:%X (%p)\n", | ||
2012 | GCT_2s (ch->t), | ||
2013 | ch->ctn, | ||
2014 | ch); | ||
2015 | if (NULL != ch->owner) | ||
2016 | { | ||
2017 | LOG2 (level, | ||
2018 | "CHN origin %s ready %s local-id: %u\n", | ||
2019 | GSC_2s (ch->owner->c), | ||
2020 | ch->owner->client_ready ? "YES" : "NO", | ||
2021 | ntohl (ch->owner->ccn.channel_of_client)); | ||
2022 | } | ||
2023 | if (NULL != ch->dest) | ||
2024 | { | ||
2025 | LOG2 (level, | ||
2026 | "CHN destination %s ready %s local-id: %u\n", | ||
2027 | GSC_2s (ch->dest->c), | ||
2028 | ch->dest->client_ready ? "YES" : "NO", | ||
2029 | ntohl (ch->dest->ccn.channel_of_client)); | ||
2030 | } | ||
2031 | LOG2 (level, | ||
2032 | "CHN Message IDs recv: %d (%LLX), send: %d\n", | ||
2033 | ntohl (ch->mid_recv.mid), | ||
2034 | (unsigned long long) ch->mid_futures, | ||
2035 | ntohl (ch->mid_send.mid)); | ||
2036 | } | ||
2037 | |||
2038 | |||
2039 | |||
2040 | /* end of gnunet-service-cadet-new_channel.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h deleted file mode 100644 index 5167305a6..000000000 --- a/src/cadet/gnunet-service-cadet-new_channel.h +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | |||
2 | /* | ||
3 | This file is part of GNUnet. | ||
4 | Copyright (C) 2001-2017 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 3, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNUnet; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file cadet/gnunet-service-cadet-new_channel.h | ||
24 | * @brief GNUnet CADET service with encryption | ||
25 | * @author Bartlomiej Polot | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #ifndef GNUNET_SERVICE_CADET_CHANNEL_H | ||
29 | #define GNUNET_SERVICE_CADET_CHANNEL_H | ||
30 | |||
31 | #include "gnunet-service-cadet-new.h" | ||
32 | #include "gnunet-service-cadet-new_peer.h" | ||
33 | #include "cadet_protocol.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * A channel is a bidirectional connection between two CADET | ||
38 | * clients. Communiation can be reliable, unreliable, in-order | ||
39 | * or out-of-order. One client is the "local" client, this | ||
40 | * one initiated the connection. The other client is the | ||
41 | * "incoming" client, this one listened on a port to accept | ||
42 | * the connection from the "local" client. | ||
43 | */ | ||
44 | struct CadetChannel; | ||
45 | |||
46 | |||
47 | /** | ||
48 | * Get the static string for identification of the channel. | ||
49 | * | ||
50 | * @param ch Channel. | ||
51 | * | ||
52 | * @return Static string with the channel IDs. | ||
53 | */ | ||
54 | const char * | ||
55 | GCCH_2s (const struct CadetChannel *ch); | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Log channel info. | ||
60 | * | ||
61 | * @param ch Channel. | ||
62 | * @param level Debug level to use. | ||
63 | */ | ||
64 | void | ||
65 | GCCH_debug (struct CadetChannel *ch, | ||
66 | enum GNUNET_ErrorType level); | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Get the channel's public ID. | ||
71 | * | ||
72 | * @param ch Channel. | ||
73 | * | ||
74 | * @return ID used to identify the channel with the remote peer. | ||
75 | */ | ||
76 | struct GNUNET_CADET_ChannelTunnelNumber | ||
77 | GCCH_get_id (const struct CadetChannel *ch); | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Create a new channel. | ||
82 | * | ||
83 | * @param owner local client owning the channel | ||
84 | * @param owner_id local chid of this channel at the @a owner | ||
85 | * @param destination peer to which we should build the channel | ||
86 | * @param port desired port at @a destination | ||
87 | * @param options options for the channel | ||
88 | * @return handle to the new channel | ||
89 | */ | ||
90 | struct CadetChannel * | ||
91 | GCCH_channel_local_new (struct CadetClient *owner, | ||
92 | struct GNUNET_CADET_ClientChannelNumber owner_id, | ||
93 | struct CadetPeer *destination, | ||
94 | const struct GNUNET_HashCode *port, | ||
95 | uint32_t options); | ||
96 | |||
97 | |||
98 | /** | ||
99 | * A client is bound to the port that we have a channel | ||
100 | * open to. Send the acknowledgement for the connection | ||
101 | * request and establish the link with the client. | ||
102 | * | ||
103 | * @param ch open incoming channel | ||
104 | * @param c client listening on the respective port | ||
105 | */ | ||
106 | void | ||
107 | GCCH_bind (struct CadetChannel *ch, | ||
108 | struct CadetClient *c); | ||
109 | |||
110 | |||
111 | /** | ||
112 | * Destroy locally created channel. Called by the | ||
113 | * local client, so no need to tell the client. | ||
114 | * | ||
115 | * @param ch channel to destroy | ||
116 | * @param c client that caused the destruction | ||
117 | * @param ccn client number of the client @a c | ||
118 | */ | ||
119 | void | ||
120 | GCCH_channel_local_destroy (struct CadetChannel *ch, | ||
121 | struct CadetClient *c, | ||
122 | struct GNUNET_CADET_ClientChannelNumber ccn); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Function called once and only once after a channel was bound | ||
127 | * to its tunnel via #GCT_add_channel() is ready for transmission. | ||
128 | * Note that this is only the case for channels that this peer | ||
129 | * initiates, as for incoming channels we assume that they are | ||
130 | * ready for transmission immediately upon receiving the open | ||
131 | * message. Used to bootstrap the #GCT_send() process. | ||
132 | * | ||
133 | * @param ch the channel for which the tunnel is now ready | ||
134 | */ | ||
135 | void | ||
136 | GCCH_tunnel_up (struct CadetChannel *ch); | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Create a new channel based on a request coming in over the network. | ||
141 | * | ||
142 | * @param t tunnel to the remote peer | ||
143 | * @param chid identifier of this channel in the tunnel | ||
144 | * @param origin peer to who initiated the channel | ||
145 | * @param port desired local port | ||
146 | * @param options options for the channel | ||
147 | * @return handle to the new channel | ||
148 | */ | ||
149 | struct CadetChannel * | ||
150 | GCCH_channel_incoming_new (struct CadetTunnel *t, | ||
151 | struct GNUNET_CADET_ChannelTunnelNumber chid, | ||
152 | const struct GNUNET_HashCode *port, | ||
153 | uint32_t options); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for | ||
158 | * this channel. If the binding was successful, (re)transmit the | ||
159 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK. | ||
160 | * | ||
161 | * @param ch channel that got the duplicate open | ||
162 | * @param cti identifier of the connection that delivered the message | ||
163 | */ | ||
164 | void | ||
165 | GCCH_handle_duplicate_open (struct CadetChannel *ch, | ||
166 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); | ||
167 | |||
168 | |||
169 | |||
170 | /** | ||
171 | * We got payload data for a channel. Pass it on to the client. | ||
172 | * | ||
173 | * @param ch channel that got data | ||
174 | * @param cti identifier of the connection that delivered the message | ||
175 | * @param msg message that was received | ||
176 | */ | ||
177 | void | ||
178 | GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | ||
179 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
180 | const struct GNUNET_CADET_ChannelAppDataMessage *msg); | ||
181 | |||
182 | |||
183 | /** | ||
184 | * We got an acknowledgement for payload data for a channel. | ||
185 | * Possibly resume transmissions. | ||
186 | * | ||
187 | * @param ch channel that got the ack | ||
188 | * @param cti identifier of the connection that delivered the message | ||
189 | * @param ack details about what was received | ||
190 | */ | ||
191 | void | ||
192 | GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | ||
193 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
194 | const struct GNUNET_CADET_ChannelDataAckMessage *ack); | ||
195 | |||
196 | |||
197 | /** | ||
198 | * We got an acknowledgement for the creation of the channel | ||
199 | * (the port is open on the other side). Begin transmissions. | ||
200 | * | ||
201 | * @param ch channel to destroy | ||
202 | * @param cti identifier of the connection that delivered the message, | ||
203 | * NULL if the ACK was inferred because we got payload or are on loopback | ||
204 | */ | ||
205 | void | ||
206 | GCCH_handle_channel_open_ack (struct CadetChannel *ch, | ||
207 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Destroy channel, based on the other peer closing the | ||
212 | * connection. Also needs to remove this channel from | ||
213 | * the tunnel. | ||
214 | * | ||
215 | * FIXME: need to make it possible to defer destruction until we have | ||
216 | * received all messages up to the destroy, and right now the destroy | ||
217 | * message (and this API) fails to give is the information we need! | ||
218 | * | ||
219 | * FIXME: also need to know if the other peer got a destroy from | ||
220 | * us before! | ||
221 | * | ||
222 | * @param ch channel to destroy | ||
223 | * @param cti identifier of the connection that delivered the message, | ||
224 | * NULL during shutdown | ||
225 | */ | ||
226 | void | ||
227 | GCCH_handle_remote_destroy (struct CadetChannel *ch, | ||
228 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Handle data given by a client. | ||
233 | * | ||
234 | * Check whether the client is allowed to send in this tunnel, save if | ||
235 | * channel is reliable and send an ACK to the client if there is still | ||
236 | * buffer space in the tunnel. | ||
237 | * | ||
238 | * @param ch Channel. | ||
239 | * @param sender_ccn ccn of the sender | ||
240 | * @param buf payload to transmit. | ||
241 | * @param buf_len number of bytes in @a buf | ||
242 | * @return #GNUNET_OK if everything goes well, | ||
243 | * #GNUNET_SYSERR in case of an error. | ||
244 | */ | ||
245 | int | ||
246 | GCCH_handle_local_data (struct CadetChannel *ch, | ||
247 | struct GNUNET_CADET_ClientChannelNumber sender_ccn, | ||
248 | const char *buf, | ||
249 | size_t buf_len); | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Handle ACK from client on local channel. | ||
254 | * | ||
255 | * @param ch channel to destroy | ||
256 | * @param client_ccn ccn of the client sending the ack | ||
257 | */ | ||
258 | void | ||
259 | GCCH_handle_local_ack (struct CadetChannel *ch, | ||
260 | struct GNUNET_CADET_ClientChannelNumber client_ccn); | ||
261 | |||
262 | #endif | ||
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c deleted file mode 100644 index 6976e66e4..000000000 --- a/src/cadet/gnunet-service-cadet-new_connection.c +++ /dev/null | |||
@@ -1,1093 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet-new_connection.c | ||
23 | * @brief management of CORE-level end-to-end connections; establishes | ||
24 | * end-to-end routes and transmits messages along the route | ||
25 | * @author Bartlomiej Polot | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet-service-cadet-new.h" | ||
30 | #include "gnunet-service-cadet-new_channel.h" | ||
31 | #include "gnunet-service-cadet-new_connection.h" | ||
32 | #include "gnunet-service-cadet-new_paths.h" | ||
33 | #include "gnunet-service-cadet-new_peer.h" | ||
34 | #include "gnunet-service-cadet-new_tunnels.h" | ||
35 | #include "gnunet_cadet_service.h" | ||
36 | #include "gnunet_statistics_service.h" | ||
37 | #include "cadet_protocol.h" | ||
38 | |||
39 | |||
40 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__) | ||
41 | |||
42 | |||
43 | /** | ||
44 | * All the states a connection can be in. | ||
45 | */ | ||
46 | enum CadetConnectionState | ||
47 | { | ||
48 | /** | ||
49 | * Uninitialized status, we have not yet even gotten the message queue. | ||
50 | */ | ||
51 | CADET_CONNECTION_NEW, | ||
52 | |||
53 | /** | ||
54 | * Connection create message in queue, awaiting transmission by CORE. | ||
55 | */ | ||
56 | CADET_CONNECTION_SENDING_CREATE, | ||
57 | |||
58 | /** | ||
59 | * Connection create message sent, waiting for ACK. | ||
60 | */ | ||
61 | CADET_CONNECTION_SENT, | ||
62 | |||
63 | /** | ||
64 | * We are an inbound connection, and received a CREATE. Need to | ||
65 | * send an CREATE_ACK back. | ||
66 | */ | ||
67 | CADET_CONNECTION_CREATE_RECEIVED, | ||
68 | |||
69 | /** | ||
70 | * Connection confirmed, ready to carry traffic. | ||
71 | */ | ||
72 | CADET_CONNECTION_READY | ||
73 | |||
74 | }; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Low-level connection to a destination. | ||
79 | */ | ||
80 | struct CadetConnection | ||
81 | { | ||
82 | |||
83 | /** | ||
84 | * ID of the connection. | ||
85 | */ | ||
86 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
87 | |||
88 | /** | ||
89 | * To which peer does this connection go? | ||
90 | */ | ||
91 | struct CadetPeer *destination; | ||
92 | |||
93 | /** | ||
94 | * Which tunnel is using this connection? | ||
95 | */ | ||
96 | struct CadetTConnection *ct; | ||
97 | |||
98 | /** | ||
99 | * Path we are using to our destination. | ||
100 | */ | ||
101 | struct CadetPeerPath *path; | ||
102 | |||
103 | /** | ||
104 | * Pending message, NULL if we are ready to transmit. | ||
105 | */ | ||
106 | struct GNUNET_MQ_Envelope *env; | ||
107 | |||
108 | /** | ||
109 | * Handle for calling #GCP_request_mq_cancel() once we are finished. | ||
110 | */ | ||
111 | struct GCP_MessageQueueManager *mq_man; | ||
112 | |||
113 | /** | ||
114 | * Task for connection maintenance. | ||
115 | */ | ||
116 | struct GNUNET_SCHEDULER_Task *task; | ||
117 | |||
118 | /** | ||
119 | * Queue entry for keepalive messages. | ||
120 | */ | ||
121 | struct CadetTunnelQueueEntry *keepalive_qe; | ||
122 | |||
123 | /** | ||
124 | * Function to call once we are ready to transmit. | ||
125 | */ | ||
126 | GCC_ReadyCallback ready_cb; | ||
127 | |||
128 | /** | ||
129 | * Closure for @e ready_cb. | ||
130 | */ | ||
131 | void *ready_cb_cls; | ||
132 | |||
133 | /** | ||
134 | * How long do we wait before we try again with a CREATE message? | ||
135 | */ | ||
136 | struct GNUNET_TIME_Relative retry_delay; | ||
137 | |||
138 | /** | ||
139 | * Performance metrics for this connection. | ||
140 | */ | ||
141 | struct CadetConnectionMetrics metrics; | ||
142 | |||
143 | /** | ||
144 | * State of the connection. | ||
145 | */ | ||
146 | enum CadetConnectionState state; | ||
147 | |||
148 | /** | ||
149 | * Options for the route, control buffering. | ||
150 | */ | ||
151 | enum GNUNET_CADET_ChannelOption options; | ||
152 | |||
153 | /** | ||
154 | * How many latency observations did we make for this connection? | ||
155 | */ | ||
156 | unsigned int latency_datapoints; | ||
157 | |||
158 | /** | ||
159 | * Offset of our @e destination in @e path. | ||
160 | */ | ||
161 | unsigned int off; | ||
162 | |||
163 | /** | ||
164 | * Are we ready to transmit via @e mq_man right now? | ||
165 | */ | ||
166 | int mqm_ready; | ||
167 | |||
168 | }; | ||
169 | |||
170 | |||
171 | /** | ||
172 | * Lookup a connection by its identifier. | ||
173 | * | ||
174 | * @param cid identifier to resolve | ||
175 | * @return NULL if connection was not found | ||
176 | */ | ||
177 | struct CadetConnection * | ||
178 | GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
179 | { | ||
180 | return GNUNET_CONTAINER_multishortmap_get (connections, | ||
181 | &cid->connection_of_tunnel); | ||
182 | } | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Update the connection state. Also triggers the necessary | ||
187 | * MQM notifications. | ||
188 | * | ||
189 | * @param cc connection to update the state for | ||
190 | * @param new_state new state for @a cc | ||
191 | * @param new_mqm_ready new `mqm_ready` state for @a cc | ||
192 | */ | ||
193 | static void | ||
194 | update_state (struct CadetConnection *cc, | ||
195 | enum CadetConnectionState new_state, | ||
196 | int new_mqm_ready) | ||
197 | { | ||
198 | int old_ready; | ||
199 | int new_ready; | ||
200 | |||
201 | if ( (new_state == cc->state) && | ||
202 | (new_mqm_ready == cc->mqm_ready) ) | ||
203 | return; /* no change, nothing to do */ | ||
204 | old_ready = ( (CADET_CONNECTION_READY == cc->state) && | ||
205 | (GNUNET_YES == cc->mqm_ready) ); | ||
206 | new_ready = ( (CADET_CONNECTION_READY == new_state) && | ||
207 | (GNUNET_YES == new_mqm_ready) ); | ||
208 | cc->state = new_state; | ||
209 | cc->mqm_ready = new_mqm_ready; | ||
210 | if (old_ready != new_ready) | ||
211 | cc->ready_cb (cc->ready_cb_cls, | ||
212 | new_ready); | ||
213 | } | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Destroy a connection, part of the internal implementation. Called | ||
218 | * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel(). | ||
219 | * | ||
220 | * @param cc connection to destroy | ||
221 | */ | ||
222 | static void | ||
223 | GCC_destroy (struct CadetConnection *cc) | ||
224 | { | ||
225 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
226 | "Destroying %s\n", | ||
227 | GCC_2s (cc)); | ||
228 | if (NULL != cc->mq_man) | ||
229 | { | ||
230 | GCP_request_mq_cancel (cc->mq_man, | ||
231 | NULL); | ||
232 | cc->mq_man = NULL; | ||
233 | } | ||
234 | if (NULL != cc->task) | ||
235 | { | ||
236 | GNUNET_SCHEDULER_cancel (cc->task); | ||
237 | cc->task = NULL; | ||
238 | } | ||
239 | if (NULL != cc->keepalive_qe) | ||
240 | { | ||
241 | GCT_send_cancel (cc->keepalive_qe); | ||
242 | cc->keepalive_qe = NULL; | ||
243 | } | ||
244 | GCPP_del_connection (cc->path, | ||
245 | cc->off, | ||
246 | cc); | ||
247 | for (unsigned int i=0;i<cc->off;i++) | ||
248 | GCP_remove_connection (GCPP_get_peer_at_offset (cc->path, | ||
249 | i), | ||
250 | cc); | ||
251 | GNUNET_assert (GNUNET_YES == | ||
252 | GNUNET_CONTAINER_multishortmap_remove (connections, | ||
253 | &GCC_get_id (cc)->connection_of_tunnel, | ||
254 | cc)); | ||
255 | GNUNET_free (cc); | ||
256 | } | ||
257 | |||
258 | |||
259 | |||
260 | /** | ||
261 | * Destroy a connection, called when the CORE layer is already done | ||
262 | * (i.e. has received a BROKEN message), but if we still have to | ||
263 | * communicate the destruction of the connection to the tunnel (if one | ||
264 | * exists). | ||
265 | * | ||
266 | * @param cc connection to destroy | ||
267 | */ | ||
268 | void | ||
269 | GCC_destroy_without_core (struct CadetConnection *cc) | ||
270 | { | ||
271 | if (NULL != cc->ct) | ||
272 | { | ||
273 | GCT_connection_lost (cc->ct); | ||
274 | cc->ct = NULL; | ||
275 | } | ||
276 | GCC_destroy (cc); | ||
277 | } | ||
278 | |||
279 | |||
280 | /** | ||
281 | * Destroy a connection, called if the tunnel association with the | ||
282 | * connection was already broken, but we still need to notify the CORE | ||
283 | * layer about the breakage. | ||
284 | * | ||
285 | * @param cc connection to destroy | ||
286 | */ | ||
287 | void | ||
288 | GCC_destroy_without_tunnel (struct CadetConnection *cc) | ||
289 | { | ||
290 | cc->ct = NULL; | ||
291 | if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) && | ||
292 | (NULL != cc->mq_man) ) | ||
293 | { | ||
294 | struct GNUNET_MQ_Envelope *env; | ||
295 | struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg; | ||
296 | |||
297 | /* Need to notify next hop that we are down. */ | ||
298 | env = GNUNET_MQ_msg (destroy_msg, | ||
299 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); | ||
300 | destroy_msg->cid = cc->cid; | ||
301 | GCP_request_mq_cancel (cc->mq_man, | ||
302 | env); | ||
303 | cc->mq_man = NULL; | ||
304 | } | ||
305 | GCC_destroy (cc); | ||
306 | } | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Return the tunnel associated with this connection. | ||
311 | * | ||
312 | * @param cc connection to query | ||
313 | * @return corresponding entry in the tunnel's connection list | ||
314 | */ | ||
315 | struct CadetTConnection * | ||
316 | GCC_get_ct (struct CadetConnection *cc) | ||
317 | { | ||
318 | return cc->ct; | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Obtain performance @a metrics from @a cc. | ||
324 | * | ||
325 | * @param cc connection to query | ||
326 | * @return the metrics | ||
327 | */ | ||
328 | const struct CadetConnectionMetrics * | ||
329 | GCC_get_metrics (struct CadetConnection *cc) | ||
330 | { | ||
331 | return &cc->metrics; | ||
332 | } | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the | ||
337 | * tunnel to prevent it from timing out. | ||
338 | * | ||
339 | * @param cls the `struct CadetConnection` to keep alive. | ||
340 | */ | ||
341 | static void | ||
342 | send_keepalive (void *cls); | ||
343 | |||
344 | |||
345 | /** | ||
346 | * Keepalive was transmitted. Remember this, and possibly | ||
347 | * schedule the next one. | ||
348 | * | ||
349 | * @param cls the `struct CadetConnection` to keep alive. | ||
350 | * @param cid identifier of the connection within the tunnel, NULL | ||
351 | * if transmission failed | ||
352 | */ | ||
353 | static void | ||
354 | keepalive_done (void *cls, | ||
355 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
356 | { | ||
357 | struct CadetConnection *cc = cls; | ||
358 | |||
359 | cc->keepalive_qe = NULL; | ||
360 | if ( (GNUNET_YES == cc->mqm_ready) && | ||
361 | (NULL == cc->task) ) | ||
362 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
363 | &send_keepalive, | ||
364 | cc); | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the | ||
370 | * tunnel to prevent it from timing out. | ||
371 | * | ||
372 | * @param cls the `struct CadetConnection` to keep alive. | ||
373 | */ | ||
374 | static void | ||
375 | send_keepalive (void *cls) | ||
376 | { | ||
377 | struct CadetConnection *cc = cls; | ||
378 | struct GNUNET_MessageHeader msg; | ||
379 | |||
380 | cc->task = NULL; | ||
381 | if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t)) | ||
382 | { | ||
383 | /* Tunnel not yet ready, wait with keepalives... */ | ||
384 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
385 | &send_keepalive, | ||
386 | cc); | ||
387 | return; | ||
388 | } | ||
389 | GNUNET_assert (NULL != cc->ct); | ||
390 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
391 | GNUNET_assert (NULL == cc->keepalive_qe); | ||
392 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
393 | "Sending KEEPALIVE on behalf of %s via %s\n", | ||
394 | GCC_2s (cc), | ||
395 | GCT_2s (cc->ct->t)); | ||
396 | GNUNET_STATISTICS_update (stats, | ||
397 | "# keepalives sent", | ||
398 | 1, | ||
399 | GNUNET_NO); | ||
400 | msg.size = htons (sizeof (msg)); | ||
401 | msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE); | ||
402 | |||
403 | cc->keepalive_qe | ||
404 | = GCT_send (cc->ct->t, | ||
405 | &msg, | ||
406 | &keepalive_done, | ||
407 | cc); | ||
408 | } | ||
409 | |||
410 | |||
411 | /** | ||
412 | * We sent a message for which we expect to receive an ACK via | ||
413 | * the connection identified by @a cti. | ||
414 | * | ||
415 | * @param cid connection identifier where we expect an ACK | ||
416 | */ | ||
417 | void | ||
418 | GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
419 | { | ||
420 | struct CadetConnection *cc; | ||
421 | |||
422 | cc = GCC_lookup (cid); | ||
423 | if (NULL == cc) | ||
424 | return; /* whopise, connection alredy down? */ | ||
425 | cc->metrics.num_acked_transmissions++; | ||
426 | } | ||
427 | |||
428 | |||
429 | /** | ||
430 | * We observed an ACK for a message that was originally sent via | ||
431 | * the connection identified by @a cti. | ||
432 | * | ||
433 | * @param cti connection identifier where we got an ACK for a message | ||
434 | * that was originally sent via this connection (the ACK | ||
435 | * may have gotten back to us via a different connection). | ||
436 | */ | ||
437 | void | ||
438 | GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
439 | { | ||
440 | struct CadetConnection *cc; | ||
441 | |||
442 | cc = GCC_lookup (cid); | ||
443 | if (NULL == cc) | ||
444 | return; /* whopise, connection alredy down? */ | ||
445 | cc->metrics.num_successes++; | ||
446 | } | ||
447 | |||
448 | |||
449 | /** | ||
450 | * We observed some the given @a latency on the connection | ||
451 | * identified by @a cti. (The same connection was taken | ||
452 | * in both directions.) | ||
453 | * | ||
454 | * @param cid connection identifier where we measured latency | ||
455 | * @param latency the observed latency | ||
456 | */ | ||
457 | void | ||
458 | GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
459 | struct GNUNET_TIME_Relative latency) | ||
460 | { | ||
461 | struct CadetConnection *cc; | ||
462 | double weight; | ||
463 | double result; | ||
464 | |||
465 | cc = GCC_lookup (cid); | ||
466 | if (NULL == cc) | ||
467 | return; /* whopise, connection alredy down? */ | ||
468 | GNUNET_STATISTICS_update (stats, | ||
469 | "# latencies observed", | ||
470 | 1, | ||
471 | GNUNET_NO); | ||
472 | cc->latency_datapoints++; | ||
473 | if (cc->latency_datapoints >= 7) | ||
474 | weight = 7.0; | ||
475 | else | ||
476 | weight = cc->latency_datapoints; | ||
477 | /* Compute weighted average, giving at MOST weight 7 to the | ||
478 | existing values, or less if that value is based on fewer than 7 | ||
479 | measurements. */ | ||
480 | result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us; | ||
481 | result /= (weight + 1.0); | ||
482 | cc->metrics.aged_latency.rel_value_us = (uint64_t) result; | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying | ||
488 | * that the end-to-end connection is up. Process it. | ||
489 | * | ||
490 | * @param cc the connection that got the ACK. | ||
491 | */ | ||
492 | void | ||
493 | GCC_handle_connection_create_ack (struct CadetConnection *cc) | ||
494 | { | ||
495 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
496 | "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n", | ||
497 | GCC_2s (cc), | ||
498 | cc->state, | ||
499 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); | ||
500 | if (CADET_CONNECTION_READY == cc->state) | ||
501 | return; /* Duplicate ACK, ignore */ | ||
502 | if (NULL != cc->task) | ||
503 | { | ||
504 | GNUNET_SCHEDULER_cancel (cc->task); | ||
505 | cc->task = NULL; | ||
506 | } | ||
507 | cc->metrics.age = GNUNET_TIME_absolute_get (); | ||
508 | update_state (cc, | ||
509 | CADET_CONNECTION_READY, | ||
510 | cc->mqm_ready); | ||
511 | if ( (NULL == cc->keepalive_qe) && | ||
512 | (GNUNET_YES == cc->mqm_ready) && | ||
513 | (NULL == cc->task) ) | ||
514 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
515 | &send_keepalive, | ||
516 | cc); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Handle KX message. | ||
522 | * | ||
523 | * @param cc connection that received encrypted message | ||
524 | * @param msg the key exchange message | ||
525 | */ | ||
526 | void | ||
527 | GCC_handle_kx (struct CadetConnection *cc, | ||
528 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | ||
529 | { | ||
530 | if (CADET_CONNECTION_SENT == cc->state) | ||
531 | { | ||
532 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, | ||
533 | clearly something is working, so pretend we got an ACK. */ | ||
534 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
535 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", | ||
536 | GCC_2s (cc)); | ||
537 | GCC_handle_connection_create_ack (cc); | ||
538 | } | ||
539 | GCT_handle_kx (cc->ct, | ||
540 | msg); | ||
541 | } | ||
542 | |||
543 | |||
544 | /** | ||
545 | * Handle KX_AUTH message. | ||
546 | * | ||
547 | * @param cc connection that received encrypted message | ||
548 | * @param msg the key exchange message | ||
549 | */ | ||
550 | void | ||
551 | GCC_handle_kx_auth (struct CadetConnection *cc, | ||
552 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg) | ||
553 | { | ||
554 | if (CADET_CONNECTION_SENT == cc->state) | ||
555 | { | ||
556 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, | ||
557 | clearly something is working, so pretend we got an ACK. */ | ||
558 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
559 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", | ||
560 | GCC_2s (cc)); | ||
561 | GCC_handle_connection_create_ack (cc); | ||
562 | } | ||
563 | GCT_handle_kx_auth (cc->ct, | ||
564 | msg); | ||
565 | } | ||
566 | |||
567 | |||
568 | /** | ||
569 | * Handle encrypted message. | ||
570 | * | ||
571 | * @param cc connection that received encrypted message | ||
572 | * @param msg the encrypted message to decrypt | ||
573 | */ | ||
574 | void | ||
575 | GCC_handle_encrypted (struct CadetConnection *cc, | ||
576 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
577 | { | ||
578 | if (CADET_CONNECTION_SENT == cc->state) | ||
579 | { | ||
580 | /* We didn't get the CREATE_ACK, but instead got payload. That's fine, | ||
581 | clearly something is working, so pretend we got an ACK. */ | ||
582 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
583 | "Faking connection ACK for %s due to ENCRYPTED payload\n", | ||
584 | GCC_2s (cc)); | ||
585 | GCC_handle_connection_create_ack (cc); | ||
586 | } | ||
587 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); | ||
588 | GCT_handle_encrypted (cc->ct, | ||
589 | msg); | ||
590 | } | ||
591 | |||
592 | |||
593 | /** | ||
594 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the | ||
595 | * first hop. | ||
596 | * | ||
597 | * @param cls the `struct CadetConnection` to initiate | ||
598 | */ | ||
599 | static void | ||
600 | send_create (void *cls) | ||
601 | { | ||
602 | struct CadetConnection *cc = cls; | ||
603 | struct GNUNET_CADET_ConnectionCreateMessage *create_msg; | ||
604 | struct GNUNET_PeerIdentity *pids; | ||
605 | struct GNUNET_MQ_Envelope *env; | ||
606 | unsigned int path_length; | ||
607 | |||
608 | cc->task = NULL; | ||
609 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
610 | path_length = GCPP_get_length (cc->path); | ||
611 | env = GNUNET_MQ_msg_extra (create_msg, | ||
612 | (1 + path_length) * sizeof (struct GNUNET_PeerIdentity), | ||
613 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); | ||
614 | create_msg->options = htonl ((uint32_t) cc->options); | ||
615 | create_msg->cid = cc->cid; | ||
616 | pids = (struct GNUNET_PeerIdentity *) &create_msg[1]; | ||
617 | pids[0] = my_full_id; | ||
618 | for (unsigned int i=0;i<path_length;i++) | ||
619 | pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path, | ||
620 | i)); | ||
621 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
622 | "Sending CADET_CONNECTION_CREATE message for %s\n", | ||
623 | GCC_2s (cc)); | ||
624 | cc->env = env; | ||
625 | update_state (cc, | ||
626 | CADET_CONNECTION_SENT, | ||
627 | GNUNET_NO); | ||
628 | GCP_send (cc->mq_man, | ||
629 | env); | ||
630 | } | ||
631 | |||
632 | |||
633 | /** | ||
634 | * Send a CREATE_ACK message towards the origin. | ||
635 | * | ||
636 | * @param cls the `struct CadetConnection` to initiate | ||
637 | */ | ||
638 | static void | ||
639 | send_create_ack (void *cls) | ||
640 | { | ||
641 | struct CadetConnection *cc = cls; | ||
642 | struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg; | ||
643 | struct GNUNET_MQ_Envelope *env; | ||
644 | |||
645 | cc->task = NULL; | ||
646 | GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state); | ||
647 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
648 | "Sending CONNECTION_CREATE_ACK message for %s\n", | ||
649 | GCC_2s (cc)); | ||
650 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
651 | env = GNUNET_MQ_msg (ack_msg, | ||
652 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK); | ||
653 | ack_msg->cid = cc->cid; | ||
654 | cc->env = env; | ||
655 | update_state (cc, | ||
656 | CADET_CONNECTION_READY, | ||
657 | GNUNET_NO); | ||
658 | GCP_send (cc->mq_man, | ||
659 | env); | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a | ||
665 | * connection that we already have. Either our ACK got lost | ||
666 | * or something is fishy. Consider retransmitting the ACK. | ||
667 | * | ||
668 | * @param cc connection that got the duplicate CREATE | ||
669 | */ | ||
670 | void | ||
671 | GCC_handle_duplicate_create (struct CadetConnection *cc) | ||
672 | { | ||
673 | if (GNUNET_YES == cc->mqm_ready) | ||
674 | { | ||
675 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
676 | "Got duplicate CREATE for %s, scheduling another ACK (%s)\n", | ||
677 | GCC_2s (cc), | ||
678 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); | ||
679 | /* Revert back to the state of having only received the 'CREATE', | ||
680 | and immediately proceed to send the CREATE_ACK. */ | ||
681 | update_state (cc, | ||
682 | CADET_CONNECTION_CREATE_RECEIVED, | ||
683 | cc->mqm_ready); | ||
684 | if (NULL != cc->task) | ||
685 | GNUNET_SCHEDULER_cancel (cc->task); | ||
686 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | ||
687 | cc); | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | /* We are currently sending something else back, which | ||
692 | can only be an ACK or payload, either of which would | ||
693 | do. So actually no need to do anything. */ | ||
694 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
695 | "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n", | ||
696 | GCC_2s (cc)); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | |||
701 | /** | ||
702 | * There has been a change in the message queue existence for our | ||
703 | * peer at the first hop. Adjust accordingly. | ||
704 | * | ||
705 | * @param cls the `struct CadetConnection` | ||
706 | * @param available #GNUNET_YES if sending is now possible, | ||
707 | * #GNUNET_NO if sending is no longer possible | ||
708 | * #GNUNET_SYSERR if sending is no longer possible | ||
709 | * and the last envelope was discarded | ||
710 | */ | ||
711 | static void | ||
712 | manage_first_hop_mq (void *cls, | ||
713 | int available) | ||
714 | { | ||
715 | struct CadetConnection *cc = cls; | ||
716 | |||
717 | if (GNUNET_YES != available) | ||
718 | { | ||
719 | /* Connection is down, for now... */ | ||
720 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
721 | "Core MQ for %s went down\n", | ||
722 | GCC_2s (cc)); | ||
723 | update_state (cc, | ||
724 | CADET_CONNECTION_NEW, | ||
725 | GNUNET_NO); | ||
726 | cc->retry_delay = GNUNET_TIME_UNIT_ZERO; | ||
727 | if (NULL != cc->task) | ||
728 | { | ||
729 | GNUNET_SCHEDULER_cancel (cc->task); | ||
730 | cc->task = NULL; | ||
731 | } | ||
732 | return; | ||
733 | } | ||
734 | |||
735 | update_state (cc, | ||
736 | cc->state, | ||
737 | GNUNET_YES); | ||
738 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
739 | "Core MQ for %s became available in state %d\n", | ||
740 | GCC_2s (cc), | ||
741 | cc->state); | ||
742 | switch (cc->state) | ||
743 | { | ||
744 | case CADET_CONNECTION_NEW: | ||
745 | /* Transmit immediately */ | ||
746 | cc->task = GNUNET_SCHEDULER_add_now (&send_create, | ||
747 | cc); | ||
748 | break; | ||
749 | case CADET_CONNECTION_SENDING_CREATE: | ||
750 | /* Should not be possible to be called in this state. */ | ||
751 | GNUNET_assert (0); | ||
752 | break; | ||
753 | case CADET_CONNECTION_SENT: | ||
754 | /* Retry a bit later... */ | ||
755 | cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay); | ||
756 | cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay, | ||
757 | &send_create, | ||
758 | cc); | ||
759 | break; | ||
760 | case CADET_CONNECTION_CREATE_RECEIVED: | ||
761 | /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */ | ||
762 | cc->metrics.age = GNUNET_TIME_absolute_get (); | ||
763 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | ||
764 | cc); | ||
765 | break; | ||
766 | case CADET_CONNECTION_READY: | ||
767 | if ( (NULL == cc->keepalive_qe) && | ||
768 | (GNUNET_YES == cc->mqm_ready) && | ||
769 | (NULL == cc->task) ) | ||
770 | { | ||
771 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
772 | "Scheduling keepalive for %s in %s\n", | ||
773 | GCC_2s (cc), | ||
774 | GNUNET_STRINGS_relative_time_to_string (keepalive_period, | ||
775 | GNUNET_YES)); | ||
776 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
777 | &send_keepalive, | ||
778 | cc); | ||
779 | } | ||
780 | break; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | |||
785 | /** | ||
786 | * Create a connection to @a destination via @a path and notify @a cb | ||
787 | * whenever we are ready for more data. Shared logic independent of | ||
788 | * who is initiating the connection. | ||
789 | * | ||
790 | * @param destination where to go | ||
791 | * @param path which path to take (may not be the full path) | ||
792 | * @param off offset of @a destination on @a path | ||
793 | * @param options options for the connection | ||
794 | * @param ct which tunnel uses this connection | ||
795 | * @param init_state initial state for the connection | ||
796 | * @param ready_cb function to call when ready to transmit | ||
797 | * @param ready_cb_cls closure for @a cb | ||
798 | * @return handle to the connection | ||
799 | */ | ||
800 | static struct CadetConnection * | ||
801 | connection_create (struct CadetPeer *destination, | ||
802 | struct CadetPeerPath *path, | ||
803 | unsigned int off, | ||
804 | enum GNUNET_CADET_ChannelOption options, | ||
805 | struct CadetTConnection *ct, | ||
806 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
807 | enum CadetConnectionState init_state, | ||
808 | GCC_ReadyCallback ready_cb, | ||
809 | void *ready_cb_cls) | ||
810 | { | ||
811 | struct CadetConnection *cc; | ||
812 | struct CadetPeer *first_hop; | ||
813 | |||
814 | cc = GNUNET_new (struct CadetConnection); | ||
815 | cc->options = options; | ||
816 | cc->state = init_state; | ||
817 | cc->ct = ct; | ||
818 | cc->cid = *cid; | ||
819 | GNUNET_assert (GNUNET_OK == | ||
820 | GNUNET_CONTAINER_multishortmap_put (connections, | ||
821 | &GCC_get_id (cc)->connection_of_tunnel, | ||
822 | cc, | ||
823 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
824 | cc->ready_cb = ready_cb; | ||
825 | cc->ready_cb_cls = ready_cb_cls; | ||
826 | cc->path = path; | ||
827 | cc->off = off; | ||
828 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
829 | "Creating %s using path %s\n", | ||
830 | GCC_2s (cc), | ||
831 | GCPP_2s (path)); | ||
832 | GCPP_add_connection (path, | ||
833 | off, | ||
834 | cc); | ||
835 | for (unsigned int i=0;i<off;i++) | ||
836 | GCP_add_connection (GCPP_get_peer_at_offset (path, | ||
837 | i), | ||
838 | cc); | ||
839 | |||
840 | first_hop = GCPP_get_peer_at_offset (path, | ||
841 | 0); | ||
842 | cc->mq_man = GCP_request_mq (first_hop, | ||
843 | &manage_first_hop_mq, | ||
844 | cc); | ||
845 | return cc; | ||
846 | } | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Create a connection to @a destination via @a path and | ||
851 | * notify @a cb whenever we are ready for more data. This | ||
852 | * is an inbound tunnel, so we must use the existing @a cid | ||
853 | * | ||
854 | * @param destination where to go | ||
855 | * @param path which path to take (may not be the full path) | ||
856 | * @param options options for the connection | ||
857 | * @param ct which tunnel uses this connection | ||
858 | * @param ready_cb function to call when ready to transmit | ||
859 | * @param ready_cb_cls closure for @a cb | ||
860 | * @return handle to the connection, NULL if we already have | ||
861 | * a connection that takes precedence on @a path | ||
862 | */ | ||
863 | struct CadetConnection * | ||
864 | GCC_create_inbound (struct CadetPeer *destination, | ||
865 | struct CadetPeerPath *path, | ||
866 | enum GNUNET_CADET_ChannelOption options, | ||
867 | struct CadetTConnection *ct, | ||
868 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
869 | GCC_ReadyCallback ready_cb, | ||
870 | void *ready_cb_cls) | ||
871 | { | ||
872 | struct CadetConnection *cc; | ||
873 | unsigned int off; | ||
874 | |||
875 | off = GCPP_find_peer (path, | ||
876 | destination); | ||
877 | GNUNET_assert (UINT_MAX != off); | ||
878 | cc = GCPP_get_connection (path, | ||
879 | destination, | ||
880 | off); | ||
881 | if (NULL != cc) | ||
882 | { | ||
883 | int cmp; | ||
884 | |||
885 | cmp = memcmp (cid, | ||
886 | &cc->cid, | ||
887 | sizeof (*cid)); | ||
888 | if (0 == cmp) | ||
889 | { | ||
890 | /* Two peers picked the SAME random connection identifier at the | ||
891 | same time for the same path? Must be malicious. Drop | ||
892 | connection (existing and inbound), even if it is the only | ||
893 | one. */ | ||
894 | GNUNET_break_op (0); | ||
895 | GCT_connection_lost (cc->ct); | ||
896 | GCC_destroy_without_tunnel (cc); | ||
897 | return NULL; | ||
898 | } | ||
899 | if (0 < cmp) | ||
900 | { | ||
901 | /* drop existing */ | ||
902 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
903 | "Got two connections on %s, dropping my existing %s\n", | ||
904 | GCPP_2s (path), | ||
905 | GCC_2s (cc)); | ||
906 | GCT_connection_lost (cc->ct); | ||
907 | GCC_destroy_without_tunnel (cc); | ||
908 | } | ||
909 | else | ||
910 | { | ||
911 | /* keep existing */ | ||
912 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
913 | "Got two connections on %s, keeping my existing %s\n", | ||
914 | GCPP_2s (path), | ||
915 | GCC_2s (cc)); | ||
916 | return NULL; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | return connection_create (destination, | ||
921 | path, | ||
922 | off, | ||
923 | options, | ||
924 | ct, | ||
925 | cid, | ||
926 | CADET_CONNECTION_CREATE_RECEIVED, | ||
927 | ready_cb, | ||
928 | ready_cb_cls); | ||
929 | } | ||
930 | |||
931 | |||
932 | /** | ||
933 | * Create a connection to @a destination via @a path and | ||
934 | * notify @a cb whenever we are ready for more data. | ||
935 | * | ||
936 | * @param destination where to go | ||
937 | * @param path which path to take (may not be the full path) | ||
938 | * @param off offset of @a destination on @a path | ||
939 | * @param options options for the connection | ||
940 | * @param ct tunnel that uses the connection | ||
941 | * @param ready_cb function to call when ready to transmit | ||
942 | * @param ready_cb_cls closure for @a cb | ||
943 | * @return handle to the connection | ||
944 | */ | ||
945 | struct CadetConnection * | ||
946 | GCC_create (struct CadetPeer *destination, | ||
947 | struct CadetPeerPath *path, | ||
948 | unsigned int off, | ||
949 | enum GNUNET_CADET_ChannelOption options, | ||
950 | struct CadetTConnection *ct, | ||
951 | GCC_ReadyCallback ready_cb, | ||
952 | void *ready_cb_cls) | ||
953 | { | ||
954 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
955 | |||
956 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, | ||
957 | &cid, | ||
958 | sizeof (cid)); | ||
959 | return connection_create (destination, | ||
960 | path, | ||
961 | off, | ||
962 | options, | ||
963 | ct, | ||
964 | &cid, | ||
965 | CADET_CONNECTION_NEW, | ||
966 | ready_cb, | ||
967 | ready_cb_cls); | ||
968 | } | ||
969 | |||
970 | |||
971 | /** | ||
972 | * Transmit message @a msg via connection @a cc. Must only be called | ||
973 | * (once) after the connection has signalled that it is ready via the | ||
974 | * `ready_cb`. Clients can also use #GCC_is_ready() to check if the | ||
975 | * connection is right now ready for transmission. | ||
976 | * | ||
977 | * @param cc connection identification | ||
978 | * @param env envelope with message to transmit; must NOT | ||
979 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
980 | */ | ||
981 | void | ||
982 | GCC_transmit (struct CadetConnection *cc, | ||
983 | struct GNUNET_MQ_Envelope *env) | ||
984 | { | ||
985 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
986 | "Scheduling message for transmission on %s\n", | ||
987 | GCC_2s (cc)); | ||
988 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
989 | GNUNET_assert (CADET_CONNECTION_READY == cc->state); | ||
990 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); | ||
991 | cc->mqm_ready = GNUNET_NO; | ||
992 | if (NULL != cc->task) | ||
993 | { | ||
994 | GNUNET_SCHEDULER_cancel (cc->task); | ||
995 | cc->task = NULL; | ||
996 | } | ||
997 | GCP_send (cc->mq_man, | ||
998 | env); | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | /** | ||
1003 | * Obtain the path used by this connection. | ||
1004 | * | ||
1005 | * @param cc connection | ||
1006 | * @return path to @a cc | ||
1007 | */ | ||
1008 | struct CadetPeerPath * | ||
1009 | GCC_get_path (struct CadetConnection *cc) | ||
1010 | { | ||
1011 | return cc->path; | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | /** | ||
1016 | * Obtain unique ID for the connection. | ||
1017 | * | ||
1018 | * @param cc connection. | ||
1019 | * @return unique number of the connection | ||
1020 | */ | ||
1021 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * | ||
1022 | GCC_get_id (struct CadetConnection *cc) | ||
1023 | { | ||
1024 | return &cc->cid; | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | /** | ||
1029 | * Get a (static) string for a connection. | ||
1030 | * | ||
1031 | * @param cc Connection. | ||
1032 | */ | ||
1033 | const char * | ||
1034 | GCC_2s (const struct CadetConnection *cc) | ||
1035 | { | ||
1036 | static char buf[128]; | ||
1037 | |||
1038 | if (NULL == cc) | ||
1039 | return "Connection(NULL)"; | ||
1040 | |||
1041 | if (NULL != cc->ct) | ||
1042 | { | ||
1043 | GNUNET_snprintf (buf, | ||
1044 | sizeof (buf), | ||
1045 | "Connection %s (%s)", | ||
1046 | GNUNET_sh2s (&cc->cid.connection_of_tunnel), | ||
1047 | GCT_2s (cc->ct->t)); | ||
1048 | return buf; | ||
1049 | } | ||
1050 | GNUNET_snprintf (buf, | ||
1051 | sizeof (buf), | ||
1052 | "Connection %s", | ||
1053 | GNUNET_sh2s (&cc->cid.connection_of_tunnel)); | ||
1054 | return buf; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__) | ||
1059 | |||
1060 | |||
1061 | /** | ||
1062 | * Log connection info. | ||
1063 | * | ||
1064 | * @param cc connection | ||
1065 | * @param level Debug level to use. | ||
1066 | */ | ||
1067 | void | ||
1068 | GCC_debug (struct CadetConnection *cc, | ||
1069 | enum GNUNET_ErrorType level) | ||
1070 | { | ||
1071 | int do_log; | ||
1072 | |||
1073 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | ||
1074 | "cadet-con", | ||
1075 | __FILE__, __FUNCTION__, __LINE__); | ||
1076 | if (0 == do_log) | ||
1077 | return; | ||
1078 | if (NULL == cc) | ||
1079 | { | ||
1080 | LOG2 (level, | ||
1081 | "Connection (NULL)\n"); | ||
1082 | return; | ||
1083 | } | ||
1084 | LOG2 (level, | ||
1085 | "%s to %s via path %s in state %d is %s\n", | ||
1086 | GCC_2s (cc), | ||
1087 | GCP_2s (cc->destination), | ||
1088 | GCPP_2s (cc->path), | ||
1089 | cc->state, | ||
1090 | (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy"); | ||
1091 | } | ||
1092 | |||
1093 | /* end of gnunet-service-cadet-new_connection.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h deleted file mode 100644 index e48b208fd..000000000 --- a/src/cadet/gnunet-service-cadet-new_connection.h +++ /dev/null | |||
@@ -1,339 +0,0 @@ | |||
1 | |||
2 | /* | ||
3 | This file is part of GNUnet. | ||
4 | Copyright (C) 2001-2017 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 3, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNUnet; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file cadet/gnunet-service-cadet-new_connection.h | ||
24 | * @brief A connection is a live end-to-end messaging mechanism | ||
25 | * where the peers are identified by a path and know how | ||
26 | * to forward along the route using a connection identifier | ||
27 | * for routing the data. | ||
28 | * @author Bartlomiej Polot | ||
29 | * @author Christian Grothoff | ||
30 | */ | ||
31 | #ifndef GNUNET_SERVICE_CADET_CONNECTION_H | ||
32 | #define GNUNET_SERVICE_CADET_CONNECTION_H | ||
33 | |||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "gnunet-service-cadet-new.h" | ||
36 | #include "gnunet-service-cadet-new_peer.h" | ||
37 | #include "cadet_protocol.h" | ||
38 | |||
39 | |||
40 | /** | ||
41 | * Function called to notify tunnel about change in our readyness. | ||
42 | * | ||
43 | * @param cls closure | ||
44 | * @param is_ready #GNUNET_YES if the connection is now ready for transmission, | ||
45 | * #GNUNET_NO if the connection is no longer ready for transmission | ||
46 | */ | ||
47 | typedef void | ||
48 | (*GCC_ReadyCallback)(void *cls, | ||
49 | int is_ready); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Destroy a connection, called when the CORE layer is already done | ||
54 | * (i.e. has received a BROKEN message), but if we still have to | ||
55 | * communicate the destruction of the connection to the tunnel (if one | ||
56 | * exists). | ||
57 | * | ||
58 | * @param cc connection to destroy | ||
59 | */ | ||
60 | void | ||
61 | GCC_destroy_without_core (struct CadetConnection *cc); | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Destroy a connection, called if the tunnel association with the | ||
66 | * connection was already broken, but we still need to notify the CORE | ||
67 | * layer about the breakage. | ||
68 | * | ||
69 | * @param cc connection to destroy | ||
70 | */ | ||
71 | void | ||
72 | GCC_destroy_without_tunnel (struct CadetConnection *cc); | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Lookup a connection by its identifier. | ||
77 | * | ||
78 | * @param cid identifier to resolve | ||
79 | * @return NULL if connection was not found | ||
80 | */ | ||
81 | struct CadetConnection * | ||
82 | GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); | ||
83 | |||
84 | |||
85 | /** | ||
86 | * Create a connection to @a destination via @a path and | ||
87 | * notify @a cb whenever we are ready for more data. | ||
88 | * | ||
89 | * @param destination where to go | ||
90 | * @param path which path to take (may not be the full path) | ||
91 | * @param off offset of @a destination on @a path | ||
92 | * @param options options for the connection | ||
93 | * @param ct which tunnel uses this connection | ||
94 | * @param ready_cb function to call when ready to transmit | ||
95 | * @param ready_cb_cls closure for @a cb | ||
96 | * @return handle to the connection | ||
97 | */ | ||
98 | struct CadetConnection * | ||
99 | GCC_create (struct CadetPeer *destination, | ||
100 | struct CadetPeerPath *path, | ||
101 | unsigned int off, | ||
102 | enum GNUNET_CADET_ChannelOption options, | ||
103 | struct CadetTConnection *ct, | ||
104 | GCC_ReadyCallback ready_cb, | ||
105 | void *ready_cb_cls); | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Create a connection to @a destination via @a path and | ||
110 | * notify @a cb whenever we are ready for more data. This | ||
111 | * is an inbound tunnel, so we must use the existing @a cid | ||
112 | * | ||
113 | * @param destination where to go | ||
114 | * @param path which path to take (may not be the full path) | ||
115 | * @param options options for the connection | ||
116 | * @param ct which tunnel uses this connection | ||
117 | * @param ready_cb function to call when ready to transmit | ||
118 | * @param ready_cb_cls closure for @a cb | ||
119 | * @return handle to the connection, NULL if we already have | ||
120 | * a connection that takes precedence on @a path | ||
121 | */ | ||
122 | struct CadetConnection * | ||
123 | GCC_create_inbound (struct CadetPeer *destination, | ||
124 | struct CadetPeerPath *path, | ||
125 | enum GNUNET_CADET_ChannelOption options, | ||
126 | struct CadetTConnection *ct, | ||
127 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
128 | GCC_ReadyCallback ready_cb, | ||
129 | void *ready_cb_cls); | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Transmit message @a msg via connection @a cc. Must only be called | ||
134 | * (once) after the connection has signalled that it is ready via the | ||
135 | * `ready_cb`. Clients can also use #GCC_is_ready() to check if the | ||
136 | * connection is right now ready for transmission. | ||
137 | * | ||
138 | * @param cc connection identification | ||
139 | * @param env envelope with message to transmit; | ||
140 | * the #GNUNET_MQ_notify_send() must not have yet been used | ||
141 | * for the envelope. Also, the message better match the | ||
142 | * connection identifier of this connection... | ||
143 | */ | ||
144 | void | ||
145 | GCC_transmit (struct CadetConnection *cc, | ||
146 | struct GNUNET_MQ_Envelope *env); | ||
147 | |||
148 | |||
149 | /** | ||
150 | * A CREATE_ACK was received for this connection, process it. | ||
151 | * | ||
152 | * @param cc the connection that got the ACK. | ||
153 | */ | ||
154 | void | ||
155 | GCC_handle_connection_create_ack (struct CadetConnection *cc); | ||
156 | |||
157 | |||
158 | /** | ||
159 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a | ||
160 | * connection that we already have. Either our ACK got lost | ||
161 | * or something is fishy. Consider retransmitting the ACK. | ||
162 | * | ||
163 | * @param cc connection that got the duplicate CREATE | ||
164 | */ | ||
165 | void | ||
166 | GCC_handle_duplicate_create (struct CadetConnection *cc); | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Handle KX message. | ||
171 | * | ||
172 | * @param cc connection that received encrypted message | ||
173 | * @param msg the key exchange message | ||
174 | */ | ||
175 | void | ||
176 | GCC_handle_kx (struct CadetConnection *cc, | ||
177 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Handle KX_AUTH message. | ||
182 | * | ||
183 | * @param cc connection that received encrypted message | ||
184 | * @param msg the key exchange message | ||
185 | */ | ||
186 | void | ||
187 | GCC_handle_kx_auth (struct CadetConnection *cc, | ||
188 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg); | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Performance metrics for a connection. | ||
193 | */ | ||
194 | struct CadetConnectionMetrics | ||
195 | { | ||
196 | |||
197 | /** | ||
198 | * Our current best estimate of the latency, based on a weighted | ||
199 | * average of at least @a latency_datapoints values. | ||
200 | */ | ||
201 | struct GNUNET_TIME_Relative aged_latency; | ||
202 | |||
203 | /** | ||
204 | * When was this connection first established? (by us sending or | ||
205 | * receiving the CREATE_ACK for the first time) | ||
206 | */ | ||
207 | struct GNUNET_TIME_Absolute age; | ||
208 | |||
209 | /** | ||
210 | * When was this connection last used? (by us sending or | ||
211 | * receiving a PAYLOAD message on it) | ||
212 | */ | ||
213 | struct GNUNET_TIME_Absolute last_use; | ||
214 | |||
215 | /** | ||
216 | * How many packets that ought to generate an ACK did we send via | ||
217 | * this connection? | ||
218 | */ | ||
219 | unsigned long long num_acked_transmissions; | ||
220 | |||
221 | /** | ||
222 | * Number of packets that were sent via this connection did actually | ||
223 | * receive an ACK? (Note: ACKs may be transmitted and lost via | ||
224 | * other connections, so this value should only be interpreted | ||
225 | * relative to @e num_acked_transmissions and in relation to other | ||
226 | * connections.) | ||
227 | */ | ||
228 | unsigned long long num_successes; | ||
229 | |||
230 | }; | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Obtain performance @a metrics from @a cc. | ||
235 | * | ||
236 | * @param cc connection to query | ||
237 | * @return the metrics | ||
238 | */ | ||
239 | const struct CadetConnectionMetrics * | ||
240 | GCC_get_metrics (struct CadetConnection *cc); | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Handle encrypted message. | ||
245 | * | ||
246 | * @param cc connection that received encrypted message | ||
247 | * @param msg the encrypted message to decrypt | ||
248 | */ | ||
249 | void | ||
250 | GCC_handle_encrypted (struct CadetConnection *cc, | ||
251 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg); | ||
252 | |||
253 | |||
254 | /** | ||
255 | * We sent a message for which we expect to receive an ACK via | ||
256 | * the connection identified by @a cti. | ||
257 | * | ||
258 | * @param cid connection identifier where we expect an ACK | ||
259 | */ | ||
260 | void | ||
261 | GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); | ||
262 | |||
263 | |||
264 | /** | ||
265 | * We observed an ACK for a message that was originally sent via | ||
266 | * the connection identified by @a cti. | ||
267 | * | ||
268 | * @param cid connection identifier where we got an ACK for a message | ||
269 | * that was originally sent via this connection (the ACK | ||
270 | * may have gotten back to us via a different connection). | ||
271 | */ | ||
272 | void | ||
273 | GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); | ||
274 | |||
275 | |||
276 | /** | ||
277 | * We observed some the given @a latency on the connection | ||
278 | * identified by @a cti. (The same connection was taken | ||
279 | * in both directions.) | ||
280 | * | ||
281 | * @param cti connection identifier where we measured latency | ||
282 | * @param latency the observed latency | ||
283 | */ | ||
284 | void | ||
285 | GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
286 | struct GNUNET_TIME_Relative latency); | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Return the tunnel associated with this connection. | ||
291 | * | ||
292 | * @param cc connection to query | ||
293 | * @return corresponding entry in the tunnel's connection list | ||
294 | */ | ||
295 | struct CadetTConnection * | ||
296 | GCC_get_ct (struct CadetConnection *cc); | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Obtain the path used by this connection. | ||
301 | * | ||
302 | * @param cc connection | ||
303 | * @return path to @a cc | ||
304 | */ | ||
305 | struct CadetPeerPath * | ||
306 | GCC_get_path (struct CadetConnection *cc); | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Obtain unique ID for the connection. | ||
311 | * | ||
312 | * @param cc connection. | ||
313 | * @return unique number of the connection | ||
314 | */ | ||
315 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * | ||
316 | GCC_get_id (struct CadetConnection *cc); | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Get a (static) string for a connection. | ||
321 | * | ||
322 | * @param cc Connection. | ||
323 | */ | ||
324 | const char * | ||
325 | GCC_2s (const struct CadetConnection *cc); | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Log connection info. | ||
330 | * | ||
331 | * @param cc connection | ||
332 | * @param level Debug level to use. | ||
333 | */ | ||
334 | void | ||
335 | GCC_debug (struct CadetConnection *cc, | ||
336 | enum GNUNET_ErrorType level); | ||
337 | |||
338 | |||
339 | #endif | ||
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c deleted file mode 100644 index 849562f23..000000000 --- a/src/cadet/gnunet-service-cadet-new_dht.c +++ /dev/null | |||
@@ -1,351 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/gnunet-service-cadet-new_dht.c | ||
22 | * @brief Information we track per peer. | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_dht_service.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet-service-cadet-new.h" | ||
32 | #include "gnunet-service-cadet-new_dht.h" | ||
33 | #include "gnunet-service-cadet-new_hello.h" | ||
34 | #include "gnunet-service-cadet-new_peer.h" | ||
35 | #include "gnunet-service-cadet-new_paths.h" | ||
36 | |||
37 | /** | ||
38 | * How long do we wait before first announcing our presence to the DHT. | ||
39 | * Used to wait for our HELLO to be available. Note that we also get | ||
40 | * notifications when our HELLO is ready, so this is just the maximum | ||
41 | * we wait for the first notification. | ||
42 | */ | ||
43 | #define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) | ||
44 | |||
45 | /** | ||
46 | * How long do we wait after we get an updated HELLO before publishing? | ||
47 | * Allows for the HELLO to be updated again quickly, for example in | ||
48 | * case multiple addresses changed and we got a partial update. | ||
49 | */ | ||
50 | #define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100) | ||
51 | |||
52 | |||
53 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Handle for DHT searches. | ||
58 | */ | ||
59 | struct GCD_search_handle | ||
60 | { | ||
61 | /** | ||
62 | * DHT_GET handle. | ||
63 | */ | ||
64 | struct GNUNET_DHT_GetHandle *dhtget; | ||
65 | |||
66 | }; | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Handle to use DHT. | ||
71 | */ | ||
72 | static struct GNUNET_DHT_Handle *dht_handle; | ||
73 | |||
74 | /** | ||
75 | * How often to PUT own ID in the DHT. | ||
76 | */ | ||
77 | static struct GNUNET_TIME_Relative id_announce_time; | ||
78 | |||
79 | /** | ||
80 | * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put(). | ||
81 | */ | ||
82 | static unsigned long long dht_replication_level; | ||
83 | |||
84 | /** | ||
85 | * Task to periodically announce itself in the network. | ||
86 | */ | ||
87 | static struct GNUNET_SCHEDULER_Task *announce_id_task; | ||
88 | |||
89 | /** | ||
90 | * Delay for the next ID announce. | ||
91 | */ | ||
92 | static struct GNUNET_TIME_Relative announce_delay; | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Function to process paths received for a new peer addition. The recorded | ||
97 | * paths form the initial tunnel, which can be optimized later. | ||
98 | * Called on each result obtained for the DHT search. | ||
99 | * | ||
100 | * @param cls closure | ||
101 | * @param exp when will this value expire | ||
102 | * @param key key of the result | ||
103 | * @param get_path path of the get request | ||
104 | * @param get_path_length lenght of @a get_path | ||
105 | * @param put_path path of the put request | ||
106 | * @param put_path_length length of the @a put_path | ||
107 | * @param type type of the result | ||
108 | * @param size number of bytes in data | ||
109 | * @param data pointer to the result data | ||
110 | */ | ||
111 | static void | ||
112 | dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, | ||
113 | const struct GNUNET_HashCode *key, | ||
114 | const struct GNUNET_PeerIdentity *get_path, | ||
115 | unsigned int get_path_length, | ||
116 | const struct GNUNET_PeerIdentity *put_path, | ||
117 | unsigned int put_path_length, | ||
118 | enum GNUNET_BLOCK_Type type, | ||
119 | size_t size, | ||
120 | const void *data) | ||
121 | { | ||
122 | const struct GNUNET_HELLO_Message *hello = data; | ||
123 | struct CadetPeer *peer; | ||
124 | |||
125 | GCPP_try_path_from_dht (get_path, | ||
126 | get_path_length, | ||
127 | put_path, | ||
128 | put_path_length); | ||
129 | if ( (size >= sizeof (struct GNUNET_HELLO_Message)) && | ||
130 | (ntohs (hello->header.size) == size) && | ||
131 | (size == GNUNET_HELLO_size (hello)) ) | ||
132 | { | ||
133 | peer = GCP_get (&put_path[0], | ||
134 | GNUNET_YES); | ||
135 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
136 | "Got HELLO for %s\n", | ||
137 | GCP_2s (peer)); | ||
138 | GCP_set_hello (peer, | ||
139 | hello); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Periodically announce self id in the DHT | ||
146 | * | ||
147 | * @param cls closure | ||
148 | */ | ||
149 | static void | ||
150 | announce_id (void *cls) | ||
151 | { | ||
152 | struct GNUNET_HashCode phash; | ||
153 | const struct GNUNET_HELLO_Message *hello; | ||
154 | size_t size; | ||
155 | struct GNUNET_TIME_Absolute expiration; | ||
156 | struct GNUNET_TIME_Relative next_put; | ||
157 | |||
158 | hello = GCH_get_mine (); | ||
159 | size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0; | ||
160 | if (0 == size) | ||
161 | { | ||
162 | expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), | ||
163 | announce_delay); | ||
164 | announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay); | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | expiration = GNUNET_HELLO_get_last_expiration (hello); | ||
169 | announce_delay = GNUNET_TIME_UNIT_SECONDS; | ||
170 | } | ||
171 | |||
172 | /* Call again in id_announce_time, unless HELLO expires first, | ||
173 | * but wait at least 1s. */ | ||
174 | next_put | ||
175 | = GNUNET_TIME_absolute_get_remaining (expiration); | ||
176 | next_put | ||
177 | = GNUNET_TIME_relative_min (next_put, | ||
178 | id_announce_time); | ||
179 | next_put | ||
180 | = GNUNET_TIME_relative_max (next_put, | ||
181 | GNUNET_TIME_UNIT_SECONDS); | ||
182 | announce_id_task | ||
183 | = GNUNET_SCHEDULER_add_delayed (next_put, | ||
184 | &announce_id, | ||
185 | cls); | ||
186 | GNUNET_STATISTICS_update (stats, | ||
187 | "# DHT announce", | ||
188 | 1, | ||
189 | GNUNET_NO); | ||
190 | memset (&phash, | ||
191 | 0, | ||
192 | sizeof (phash)); | ||
193 | GNUNET_memcpy (&phash, | ||
194 | &my_full_id, | ||
195 | sizeof (my_full_id)); | ||
196 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
197 | "Announcing my HELLO (%u bytes) in the DHT\n", | ||
198 | size); | ||
199 | GNUNET_DHT_put (dht_handle, /* DHT handle */ | ||
200 | &phash, /* Key to use */ | ||
201 | dht_replication_level, /* Replication level */ | ||
202 | GNUNET_DHT_RO_RECORD_ROUTE | ||
203 | | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ | ||
204 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ | ||
205 | size, /* Size of the data */ | ||
206 | (const char *) hello, /* Data itself */ | ||
207 | expiration, /* Data expiration */ | ||
208 | NULL, /* Continuation */ | ||
209 | NULL); /* Continuation closure */ | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Function called by the HELLO subsystem whenever OUR hello | ||
215 | * changes. Re-triggers the DHT PUT immediately. | ||
216 | */ | ||
217 | void | ||
218 | GCD_hello_update () | ||
219 | { | ||
220 | if (NULL == announce_id_task) | ||
221 | return; /* too early */ | ||
222 | GNUNET_SCHEDULER_cancel (announce_id_task); | ||
223 | announce_id_task | ||
224 | = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY, | ||
225 | &announce_id, | ||
226 | NULL); | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Initialize the DHT subsystem. | ||
232 | * | ||
233 | * @param c Configuration. | ||
234 | */ | ||
235 | void | ||
236 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c) | ||
237 | { | ||
238 | if (GNUNET_OK != | ||
239 | GNUNET_CONFIGURATION_get_value_number (c, | ||
240 | "CADET", | ||
241 | "DHT_REPLICATION_LEVEL", | ||
242 | &dht_replication_level)) | ||
243 | { | ||
244 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
245 | "CADET", | ||
246 | "DHT_REPLICATION_LEVEL", | ||
247 | "USING DEFAULT"); | ||
248 | dht_replication_level = 3; | ||
249 | } | ||
250 | |||
251 | if (GNUNET_OK != | ||
252 | GNUNET_CONFIGURATION_get_value_time (c, | ||
253 | "CADET", | ||
254 | "ID_ANNOUNCE_TIME", | ||
255 | &id_announce_time)) | ||
256 | { | ||
257 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | ||
258 | "CADET", | ||
259 | "ID_ANNOUNCE_TIME", | ||
260 | "MISSING"); | ||
261 | GNUNET_SCHEDULER_shutdown (); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | dht_handle = GNUNET_DHT_connect (c, | ||
266 | 64); | ||
267 | GNUNET_break (NULL != dht_handle); | ||
268 | announce_delay = GNUNET_TIME_UNIT_SECONDS; | ||
269 | announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY, | ||
270 | &announce_id, | ||
271 | NULL); | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Shut down the DHT subsystem. | ||
277 | */ | ||
278 | void | ||
279 | GCD_shutdown (void) | ||
280 | { | ||
281 | if (NULL != dht_handle) | ||
282 | { | ||
283 | GNUNET_DHT_disconnect (dht_handle); | ||
284 | dht_handle = NULL; | ||
285 | } | ||
286 | if (NULL != announce_id_task) | ||
287 | { | ||
288 | GNUNET_SCHEDULER_cancel (announce_id_task); | ||
289 | announce_id_task = NULL; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | |||
294 | /** | ||
295 | * Search DHT for paths to @a peeR_id | ||
296 | * | ||
297 | * @param peer_id peer to search for | ||
298 | * @return handle to abort search | ||
299 | */ | ||
300 | struct GCD_search_handle * | ||
301 | GCD_search (const struct GNUNET_PeerIdentity *peer_id) | ||
302 | { | ||
303 | struct GNUNET_HashCode phash; | ||
304 | struct GCD_search_handle *h; | ||
305 | |||
306 | GNUNET_STATISTICS_update (stats, | ||
307 | "# DHT search", | ||
308 | 1, | ||
309 | GNUNET_NO); | ||
310 | memset (&phash, | ||
311 | 0, | ||
312 | sizeof (phash)); | ||
313 | GNUNET_memcpy (&phash, | ||
314 | peer_id, | ||
315 | sizeof (*peer_id)); | ||
316 | |||
317 | h = GNUNET_new (struct GCD_search_handle); | ||
318 | h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ | ||
319 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ | ||
320 | &phash, /* key to search */ | ||
321 | dht_replication_level, /* replication level */ | ||
322 | GNUNET_DHT_RO_RECORD_ROUTE | | ||
323 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
324 | NULL, /* xquery */ | ||
325 | 0, /* xquery bits */ | ||
326 | &dht_get_id_handler, | ||
327 | h); | ||
328 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
329 | "Starting DHT GET for peer %s (%p)\n", | ||
330 | GNUNET_i2s (peer_id), | ||
331 | h); | ||
332 | return h; | ||
333 | } | ||
334 | |||
335 | |||
336 | /** | ||
337 | * Stop DHT search started with #GCD_search(). | ||
338 | * | ||
339 | * @param h handle to search to stop | ||
340 | */ | ||
341 | void | ||
342 | GCD_search_stop (struct GCD_search_handle *h) | ||
343 | { | ||
344 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
345 | "Stopping DHT GET %p\n", | ||
346 | h); | ||
347 | GNUNET_DHT_get_stop (h->dhtget); | ||
348 | GNUNET_free (h); | ||
349 | } | ||
350 | |||
351 | /* end of gnunet-service-cadet_dht.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h deleted file mode 100644 index 5d7ab29a0..000000000 --- a/src/cadet/gnunet-service-cadet-new_dht.h +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet_dht.h | ||
23 | * @brief cadet service; dealing with DHT requests and results | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * All functions in this file should use the prefix GCD (Gnunet Cadet Dht) | ||
28 | */ | ||
29 | #ifndef GNUNET_SERVICE_CADET_DHT_H | ||
30 | #define GNUNET_SERVICE_CADET_DHT_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" | ||
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "platform.h" | ||
41 | #include "gnunet_util_lib.h" | ||
42 | |||
43 | /** | ||
44 | * Handle for DHT search operation. | ||
45 | */ | ||
46 | struct GCD_search_handle; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Initialize the DHT subsystem. | ||
51 | * | ||
52 | * @param c Configuration. | ||
53 | */ | ||
54 | void | ||
55 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c); | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Shut down the DHT subsystem. | ||
60 | */ | ||
61 | void | ||
62 | GCD_shutdown (void); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Function called by the HELLO subsystem whenever OUR hello | ||
67 | * changes. Re-triggers the DHT PUT immediately. | ||
68 | */ | ||
69 | void | ||
70 | GCD_hello_update (void); | ||
71 | |||
72 | /** | ||
73 | * Search DHT for paths to @a peeR_id | ||
74 | * | ||
75 | * @param peer_id peer to search for | ||
76 | * @return handle to abort search | ||
77 | */ | ||
78 | struct GCD_search_handle * | ||
79 | GCD_search (const struct GNUNET_PeerIdentity *peer_id); | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Stop DHT search started with #GCD_search(). | ||
84 | * | ||
85 | * @param h handle to search to stop | ||
86 | */ | ||
87 | void | ||
88 | GCD_search_stop (struct GCD_search_handle *h); | ||
89 | |||
90 | |||
91 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
92 | { | ||
93 | #endif | ||
94 | #ifdef __cplusplus | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | /* ifndef GNUNET_CADET_SERVICE_DHT_H */ | ||
99 | #endif | ||
100 | /* end of gnunet-service-cadet_dht.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c deleted file mode 100644 index a24325ada..000000000 --- a/src/cadet/gnunet-service-cadet-new_hello.c +++ /dev/null | |||
@@ -1,152 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2014, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/gnunet-service-cadet-new_hello.c | ||
22 | * @brief spread knowledge about how to contact other peers from PEERINFO | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - is most of this necessary/helpful? | ||
28 | * - should we not simply restrict this to OUR hello? | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | |||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_peerinfo_service.h" | ||
35 | #include "cadet_protocol.h" | ||
36 | #include "gnunet-service-cadet-new.h" | ||
37 | #include "gnunet-service-cadet-new_dht.h" | ||
38 | #include "gnunet-service-cadet-new_hello.h" | ||
39 | #include "gnunet-service-cadet-new_peer.h" | ||
40 | |||
41 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) | ||
42 | |||
43 | /** | ||
44 | * Hello message of local peer. | ||
45 | */ | ||
46 | static struct GNUNET_HELLO_Message *mine; | ||
47 | |||
48 | /** | ||
49 | * Handle to peerinfo service. | ||
50 | */ | ||
51 | static struct GNUNET_PEERINFO_Handle *peerinfo; | ||
52 | |||
53 | /** | ||
54 | * Iterator context. | ||
55 | */ | ||
56 | static struct GNUNET_PEERINFO_NotifyContext *nc; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Process each hello message received from peerinfo. | ||
61 | * | ||
62 | * @param cls Closure (unused). | ||
63 | * @param peer Identity of the peer. | ||
64 | * @param hello Hello of the peer. | ||
65 | * @param err_msg Error message. | ||
66 | */ | ||
67 | static void | ||
68 | got_hello (void *cls, | ||
69 | const struct GNUNET_PeerIdentity *id, | ||
70 | const struct GNUNET_HELLO_Message *hello, | ||
71 | const char *err_msg) | ||
72 | { | ||
73 | struct CadetPeer *peer; | ||
74 | |||
75 | if ( (NULL == id) || | ||
76 | (NULL == hello) ) | ||
77 | return; | ||
78 | if (0 == memcmp (id, | ||
79 | &my_full_id, | ||
80 | sizeof (struct GNUNET_PeerIdentity))) | ||
81 | { | ||
82 | GNUNET_free_non_null (mine); | ||
83 | mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header); | ||
84 | GCD_hello_update (); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
89 | "Hello for %s (%d bytes), expires on %s\n", | ||
90 | GNUNET_i2s (id), | ||
91 | GNUNET_HELLO_size (hello), | ||
92 | GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello))); | ||
93 | peer = GCP_get (id, | ||
94 | GNUNET_YES); | ||
95 | GCP_set_hello (peer, | ||
96 | hello); | ||
97 | } | ||
98 | |||
99 | |||
100 | /** | ||
101 | * Initialize the hello subsystem. | ||
102 | * | ||
103 | * @param c Configuration. | ||
104 | */ | ||
105 | void | ||
106 | GCH_init (const struct GNUNET_CONFIGURATION_Handle *c) | ||
107 | { | ||
108 | GNUNET_assert (NULL == nc); | ||
109 | peerinfo = GNUNET_PEERINFO_connect (c); | ||
110 | nc = GNUNET_PEERINFO_notify (c, | ||
111 | GNUNET_NO, | ||
112 | &got_hello, | ||
113 | NULL); | ||
114 | } | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Shut down the hello subsystem. | ||
119 | */ | ||
120 | void | ||
121 | GCH_shutdown () | ||
122 | { | ||
123 | if (NULL != nc) | ||
124 | { | ||
125 | GNUNET_PEERINFO_notify_cancel (nc); | ||
126 | nc = NULL; | ||
127 | } | ||
128 | if (NULL != peerinfo) | ||
129 | { | ||
130 | GNUNET_PEERINFO_disconnect (peerinfo); | ||
131 | peerinfo = NULL; | ||
132 | } | ||
133 | if (NULL != mine) | ||
134 | { | ||
135 | GNUNET_free (mine); | ||
136 | mine = NULL; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Get own hello message. | ||
143 | * | ||
144 | * @return Own hello message. | ||
145 | */ | ||
146 | const struct GNUNET_HELLO_Message * | ||
147 | GCH_get_mine (void) | ||
148 | { | ||
149 | return mine; | ||
150 | } | ||
151 | |||
152 | /* end of gnunet-service-cadet-new_hello.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h deleted file mode 100644 index 4291ae985..000000000 --- a/src/cadet/gnunet-service-cadet-new_hello.h +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2014, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet_hello.h | ||
23 | * @brief cadet service; dealing with hello messages | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * All functions in this file should use the prefix GCH (Gnunet Cadet Hello) | ||
28 | */ | ||
29 | |||
30 | #ifndef GNUNET_SERVICE_CADET_HELLO_H | ||
31 | #define GNUNET_SERVICE_CADET_HELLO_H | ||
32 | |||
33 | #ifdef __cplusplus | ||
34 | extern "C" | ||
35 | { | ||
36 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
37 | } | ||
38 | #endif | ||
39 | #endif | ||
40 | |||
41 | #include "platform.h" | ||
42 | #include "gnunet_util_lib.h" | ||
43 | #include "gnunet_hello_lib.h" | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Initialize the hello subsystem. | ||
48 | * | ||
49 | * @param c Configuration. | ||
50 | */ | ||
51 | void | ||
52 | GCH_init (const struct GNUNET_CONFIGURATION_Handle *c); | ||
53 | |||
54 | |||
55 | /** | ||
56 | * Shut down the hello subsystem. | ||
57 | */ | ||
58 | void | ||
59 | GCH_shutdown (void); | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Get own hello message. | ||
64 | * | ||
65 | * @return Own hello message. | ||
66 | */ | ||
67 | const struct GNUNET_HELLO_Message * | ||
68 | GCH_get_mine (void); | ||
69 | |||
70 | |||
71 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
72 | { | ||
73 | #endif | ||
74 | #ifdef __cplusplus | ||
75 | } | ||
76 | #endif | ||
77 | |||
78 | /* ifndef GNUNET_CADET_SERVICE_HELLO_H */ | ||
79 | #endif | ||
80 | /* end of gnunet-cadet-service_hello.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c deleted file mode 100644 index 29aef6895..000000000 --- a/src/cadet/gnunet-service-cadet-new_peer.c +++ /dev/null | |||
@@ -1,1478 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet-new_peer.c | ||
23 | * @brief Information we track per peer. | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * TODO: | ||
28 | * - optimize stopping/restarting DHT search to situations | ||
29 | * where we actually need it (i.e. not if we have a direct connection, | ||
30 | * or if we already have plenty of good short ones, or maybe even | ||
31 | * to take a break if we have some connections and have searched a lot (?)) | ||
32 | */ | ||
33 | #include "platform.h" | ||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "gnunet_hello_lib.h" | ||
36 | #include "gnunet_signatures.h" | ||
37 | #include "gnunet_transport_service.h" | ||
38 | #include "gnunet_ats_service.h" | ||
39 | #include "gnunet_core_service.h" | ||
40 | #include "gnunet_statistics_service.h" | ||
41 | #include "cadet_protocol.h" | ||
42 | #include "gnunet-service-cadet-new.h" | ||
43 | #include "gnunet-service-cadet-new_connection.h" | ||
44 | #include "gnunet-service-cadet-new_dht.h" | ||
45 | #include "gnunet-service-cadet-new_peer.h" | ||
46 | #include "gnunet-service-cadet-new_paths.h" | ||
47 | #include "gnunet-service-cadet-new_tunnels.h" | ||
48 | |||
49 | |||
50 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__) | ||
51 | |||
52 | |||
53 | /** | ||
54 | * How long do we wait until tearing down an idle peer? | ||
55 | */ | ||
56 | #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
57 | |||
58 | /** | ||
59 | * How long do we keep paths around if we no longer care about the peer? | ||
60 | */ | ||
61 | #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) | ||
62 | |||
63 | |||
64 | |||
65 | |||
66 | /** | ||
67 | * Data structure used to track whom we have to notify about changes | ||
68 | * to our message queue. | ||
69 | */ | ||
70 | struct GCP_MessageQueueManager | ||
71 | { | ||
72 | |||
73 | /** | ||
74 | * Kept in a DLL. | ||
75 | */ | ||
76 | struct GCP_MessageQueueManager *next; | ||
77 | |||
78 | /** | ||
79 | * Kept in a DLL. | ||
80 | */ | ||
81 | struct GCP_MessageQueueManager *prev; | ||
82 | |||
83 | /** | ||
84 | * Function to call with updated message queue object. | ||
85 | */ | ||
86 | GCP_MessageQueueNotificationCallback cb; | ||
87 | |||
88 | /** | ||
89 | * Closure for @e cb. | ||
90 | */ | ||
91 | void *cb_cls; | ||
92 | |||
93 | /** | ||
94 | * The peer this is for. | ||
95 | */ | ||
96 | struct CadetPeer *cp; | ||
97 | |||
98 | /** | ||
99 | * Envelope this manager would like to transmit once it is its turn. | ||
100 | */ | ||
101 | struct GNUNET_MQ_Envelope *env; | ||
102 | |||
103 | }; | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Struct containing all information regarding a given peer | ||
108 | */ | ||
109 | struct CadetPeer | ||
110 | { | ||
111 | /** | ||
112 | * ID of the peer | ||
113 | */ | ||
114 | struct GNUNET_PeerIdentity pid; | ||
115 | |||
116 | /** | ||
117 | * Last time we heard from this peer (currently not used!) | ||
118 | */ | ||
119 | struct GNUNET_TIME_Absolute last_contactXXX; | ||
120 | |||
121 | /** | ||
122 | * Array of DLLs of paths traversing the peer, organized by the | ||
123 | * offset of the peer on the larger path. | ||
124 | */ | ||
125 | struct CadetPeerPathEntry **path_heads; | ||
126 | |||
127 | /** | ||
128 | * Array of DLL of paths traversing the peer, organized by the | ||
129 | * offset of the peer on the larger path. | ||
130 | */ | ||
131 | struct CadetPeerPathEntry **path_tails; | ||
132 | |||
133 | /** | ||
134 | * Notifications to call when @e core_mq changes. | ||
135 | */ | ||
136 | struct GCP_MessageQueueManager *mqm_head; | ||
137 | |||
138 | /** | ||
139 | * Notifications to call when @e core_mq changes. | ||
140 | */ | ||
141 | struct GCP_MessageQueueManager *mqm_tail; | ||
142 | |||
143 | /** | ||
144 | * Pointer to first "ready" entry in @e mqm_head. | ||
145 | */ | ||
146 | struct GCP_MessageQueueManager *mqm_ready_ptr; | ||
147 | |||
148 | /** | ||
149 | * MIN-heap of paths owned by this peer (they also end at this | ||
150 | * peer). Ordered by desirability. | ||
151 | */ | ||
152 | struct GNUNET_CONTAINER_Heap *path_heap; | ||
153 | |||
154 | /** | ||
155 | * Handle to stop the DHT search for paths to this peer | ||
156 | */ | ||
157 | struct GCD_search_handle *search_h; | ||
158 | |||
159 | /** | ||
160 | * Task to clean up @e path_heap asynchronously. | ||
161 | */ | ||
162 | struct GNUNET_SCHEDULER_Task *heap_cleanup_task; | ||
163 | |||
164 | /** | ||
165 | * Task to destroy this entry. | ||
166 | */ | ||
167 | struct GNUNET_SCHEDULER_Task *destroy_task; | ||
168 | |||
169 | /** | ||
170 | * Tunnel to this peer, if any. | ||
171 | */ | ||
172 | struct CadetTunnel *t; | ||
173 | |||
174 | /** | ||
175 | * Connections that go through this peer; indexed by tid. | ||
176 | */ | ||
177 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
178 | |||
179 | /** | ||
180 | * Handle for core transmissions. | ||
181 | */ | ||
182 | struct GNUNET_MQ_Handle *core_mq; | ||
183 | |||
184 | /** | ||
185 | * Hello message of the peer. | ||
186 | */ | ||
187 | struct GNUNET_HELLO_Message *hello; | ||
188 | |||
189 | /** | ||
190 | * Handle to us offering the HELLO to the transport. | ||
191 | */ | ||
192 | struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer; | ||
193 | |||
194 | /** | ||
195 | * Handle to our ATS request asking ATS to suggest an address | ||
196 | * to TRANSPORT for this peer (to establish a direct link). | ||
197 | */ | ||
198 | struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion; | ||
199 | |||
200 | /** | ||
201 | * How many messages are in the queue to this peer. | ||
202 | */ | ||
203 | unsigned int queue_n; | ||
204 | |||
205 | /** | ||
206 | * How many paths do we have to this peer (in all @e path_heads DLLs combined). | ||
207 | */ | ||
208 | unsigned int num_paths; | ||
209 | |||
210 | /** | ||
211 | * Sum over all of the offsets of all of the paths in the @a path_heads DLLs. | ||
212 | * Used to speed-up @GCP_get_desirability_of_path() calculation. | ||
213 | */ | ||
214 | unsigned int off_sum; | ||
215 | |||
216 | /** | ||
217 | * Number of message queue managers of this peer that have a message in waiting. | ||
218 | * | ||
219 | * Used to quickly see if we need to bother scanning the @e msm_head DLL. | ||
220 | * TODO: could be replaced by another DLL that would then allow us to avoid | ||
221 | * the O(n)-scan of the DLL for ready entries! | ||
222 | */ | ||
223 | unsigned int mqm_ready_counter; | ||
224 | |||
225 | /** | ||
226 | * Current length of the @e path_heads and @path_tails arrays. | ||
227 | * The arrays should be grown as needed. | ||
228 | */ | ||
229 | unsigned int path_dll_length; | ||
230 | |||
231 | }; | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Get the static string for a peer ID. | ||
236 | * | ||
237 | * @param cp Peer. | ||
238 | * @return Static string for it's ID. | ||
239 | */ | ||
240 | const char * | ||
241 | GCP_2s (const struct CadetPeer *cp) | ||
242 | { | ||
243 | static char buf[32]; | ||
244 | |||
245 | GNUNET_snprintf (buf, | ||
246 | sizeof (buf), | ||
247 | "P(%s)", | ||
248 | GNUNET_i2s (&cp->pid)); | ||
249 | return buf; | ||
250 | } | ||
251 | |||
252 | |||
253 | /** | ||
254 | * Calculate how desirable a path is for @a cp if @a cp | ||
255 | * is at offset @a off. | ||
256 | * | ||
257 | * The 'desirability_table.c' program can be used to compute a list of | ||
258 | * sample outputs for different scenarios. Basically, we score paths | ||
259 | * lower if there are many alternatives, and higher if they are | ||
260 | * shorter than average, and very high if they are much shorter than | ||
261 | * average and without many alternatives. | ||
262 | * | ||
263 | * @param cp a peer reachable via a path | ||
264 | * @param off offset of @a cp in the path | ||
265 | * @return score how useful a path is to reach @a cp, | ||
266 | * positive scores mean path is more desirable | ||
267 | */ | ||
268 | double | ||
269 | GCP_get_desirability_of_path (struct CadetPeer *cp, | ||
270 | unsigned int off) | ||
271 | { | ||
272 | unsigned int num_alts = cp->num_paths; | ||
273 | unsigned int off_sum; | ||
274 | double avg_sum; | ||
275 | double path_delta; | ||
276 | double weight_alts; | ||
277 | |||
278 | GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */ | ||
279 | GNUNET_assert (0 != cp->path_dll_length); | ||
280 | |||
281 | /* We maintain 'off_sum' in 'peer' and thereby | ||
282 | avoid the SLOW recalculation each time. Kept here | ||
283 | just to document what is going on. */ | ||
284 | #if SLOW | ||
285 | off_sum = 0; | ||
286 | for (unsigned int j=0;j<cp->path_dll_length;j++) | ||
287 | for (struct CadetPeerPathEntry *pe = cp->path_heads[j]; | ||
288 | NULL != pe; | ||
289 | pe = pe->next) | ||
290 | off_sum += j; | ||
291 | GNUNET_assert (off_sum == cp->off_sum); | ||
292 | #else | ||
293 | off_sum = cp->off_sum; | ||
294 | #endif | ||
295 | avg_sum = off_sum * 1.0 / cp->path_dll_length; | ||
296 | path_delta = off - avg_sum; | ||
297 | /* path_delta positiv: path off of peer above average (bad path for peer), | ||
298 | path_delta negativ: path off of peer below average (good path for peer) */ | ||
299 | if (path_delta <= - 1.0) | ||
300 | weight_alts = - num_alts / path_delta; /* discount alternative paths */ | ||
301 | else if (path_delta >= 1.0) | ||
302 | weight_alts = num_alts * path_delta; /* overcount alternative paths */ | ||
303 | else | ||
304 | weight_alts = num_alts; /* count alternative paths normally */ | ||
305 | |||
306 | |||
307 | /* off+1: long paths are generally harder to find and thus count | ||
308 | a bit more as they get longer. However, above-average paths | ||
309 | still need to count less, hence the squaring of that factor. */ | ||
310 | return (off + 1.0) / (weight_alts * weight_alts); | ||
311 | } | ||
312 | |||
313 | |||
314 | /** | ||
315 | * This peer is no longer be needed, clean it up now. | ||
316 | * | ||
317 | * @param cls peer to clean up | ||
318 | */ | ||
319 | static void | ||
320 | destroy_peer (void *cls) | ||
321 | { | ||
322 | struct CadetPeer *cp = cls; | ||
323 | |||
324 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
325 | "Destroying state about peer %s\n", | ||
326 | GCP_2s (cp)); | ||
327 | cp->destroy_task = NULL; | ||
328 | GNUNET_assert (NULL == cp->t); | ||
329 | GNUNET_assert (NULL == cp->core_mq); | ||
330 | GNUNET_assert (0 == cp->num_paths); | ||
331 | for (unsigned int i=0;i<cp->path_dll_length;i++) | ||
332 | GNUNET_assert (NULL == cp->path_heads[i]); | ||
333 | GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)); | ||
334 | GNUNET_assert (GNUNET_YES == | ||
335 | GNUNET_CONTAINER_multipeermap_remove (peers, | ||
336 | &cp->pid, | ||
337 | cp)); | ||
338 | GNUNET_free_non_null (cp->path_heads); | ||
339 | GNUNET_free_non_null (cp->path_tails); | ||
340 | cp->path_dll_length = 0; | ||
341 | if (NULL != cp->search_h) | ||
342 | { | ||
343 | GCD_search_stop (cp->search_h); | ||
344 | cp->search_h = NULL; | ||
345 | } | ||
346 | /* FIXME: clean up search_delayedXXX! */ | ||
347 | |||
348 | if (NULL != cp->hello_offer) | ||
349 | { | ||
350 | GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer); | ||
351 | cp->hello_offer = NULL; | ||
352 | } | ||
353 | if (NULL != cp->connectivity_suggestion) | ||
354 | { | ||
355 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
356 | cp->connectivity_suggestion = NULL; | ||
357 | } | ||
358 | GNUNET_CONTAINER_multishortmap_destroy (cp->connections); | ||
359 | if (NULL != cp->path_heap) | ||
360 | { | ||
361 | GNUNET_CONTAINER_heap_destroy (cp->path_heap); | ||
362 | cp->path_heap = NULL; | ||
363 | } | ||
364 | if (NULL != cp->heap_cleanup_task) | ||
365 | { | ||
366 | GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task); | ||
367 | cp->heap_cleanup_task = NULL; | ||
368 | } | ||
369 | GNUNET_free_non_null (cp->hello); | ||
370 | /* Peer should not be freed if paths exist; if there are no paths, | ||
371 | there ought to be no connections, and without connections, no | ||
372 | notifications. Thus we can assert that mqm_head is empty at this | ||
373 | point. */ | ||
374 | GNUNET_assert (NULL == cp->mqm_head); | ||
375 | GNUNET_assert (NULL == cp->mqm_ready_ptr); | ||
376 | GNUNET_free (cp); | ||
377 | } | ||
378 | |||
379 | |||
380 | /** | ||
381 | * This peer is now on more "active" duty, activate processes related to it. | ||
382 | * | ||
383 | * @param cp the more-active peer | ||
384 | */ | ||
385 | static void | ||
386 | consider_peer_activate (struct CadetPeer *cp) | ||
387 | { | ||
388 | uint32_t strength; | ||
389 | |||
390 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
391 | "Updating peer %s activation state (%u connections)%s%s\n", | ||
392 | GCP_2s (cp), | ||
393 | GNUNET_CONTAINER_multishortmap_size (cp->connections), | ||
394 | (NULL == cp->t) ? "" : " with tunnel", | ||
395 | (NULL == cp->core_mq) ? "" : " with CORE link"); | ||
396 | if (NULL != cp->destroy_task) | ||
397 | { | ||
398 | /* It's active, do not destory! */ | ||
399 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
400 | cp->destroy_task = NULL; | ||
401 | } | ||
402 | if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) && | ||
403 | (NULL == cp->t) ) | ||
404 | { | ||
405 | /* We're just on a path or directly connected; don't bother too much */ | ||
406 | if (NULL != cp->connectivity_suggestion) | ||
407 | { | ||
408 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
409 | cp->connectivity_suggestion = NULL; | ||
410 | } | ||
411 | if (NULL != cp->search_h) | ||
412 | { | ||
413 | GCD_search_stop (cp->search_h); | ||
414 | cp->search_h = NULL; | ||
415 | } | ||
416 | return; | ||
417 | } | ||
418 | if (NULL == cp->core_mq) | ||
419 | { | ||
420 | /* Lacks direct connection, try to create one by querying the DHT */ | ||
421 | if ( (NULL == cp->search_h) && | ||
422 | (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) ) | ||
423 | cp->search_h | ||
424 | = GCD_search (&cp->pid); | ||
425 | } | ||
426 | else | ||
427 | { | ||
428 | /* Have direct connection, stop DHT search if active */ | ||
429 | if (NULL != cp->search_h) | ||
430 | { | ||
431 | GCD_search_stop (cp->search_h); | ||
432 | cp->search_h = NULL; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | /* If we have a tunnel, our urge for connections is much bigger */ | ||
437 | strength = (NULL != cp->t) ? 32 : 1; | ||
438 | if (NULL != cp->connectivity_suggestion) | ||
439 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
440 | cp->connectivity_suggestion | ||
441 | = GNUNET_ATS_connectivity_suggest (ats_ch, | ||
442 | &cp->pid, | ||
443 | strength); | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * This peer may no longer be needed, consider cleaning it up. | ||
449 | * | ||
450 | * @param cp peer to clean up | ||
451 | */ | ||
452 | static void | ||
453 | consider_peer_destroy (struct CadetPeer *cp); | ||
454 | |||
455 | |||
456 | /** | ||
457 | * We really no longere care about a peer, stop hogging memory with paths to it. | ||
458 | * Afterwards, see if there is more to be cleaned up about this peer. | ||
459 | * | ||
460 | * @param cls a `struct CadetPeer`. | ||
461 | */ | ||
462 | static void | ||
463 | drop_paths (void *cls) | ||
464 | { | ||
465 | struct CadetPeer *cp = cls; | ||
466 | struct CadetPeerPath *path; | ||
467 | |||
468 | cp->destroy_task = NULL; | ||
469 | while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap))) | ||
470 | GCPP_release (path); | ||
471 | consider_peer_destroy (cp); | ||
472 | } | ||
473 | |||
474 | |||
475 | /** | ||
476 | * This peer may no longer be needed, consider cleaning it up. | ||
477 | * | ||
478 | * @param cp peer to clean up | ||
479 | */ | ||
480 | static void | ||
481 | consider_peer_destroy (struct CadetPeer *cp) | ||
482 | { | ||
483 | struct GNUNET_TIME_Relative exp; | ||
484 | |||
485 | if (NULL != cp->destroy_task) | ||
486 | { | ||
487 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
488 | cp->destroy_task = NULL; | ||
489 | } | ||
490 | if (NULL != cp->t) | ||
491 | return; /* still relevant! */ | ||
492 | if (NULL != cp->core_mq) | ||
493 | return; /* still relevant! */ | ||
494 | if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections)) | ||
495 | return; /* still relevant! */ | ||
496 | if ( (NULL != cp->path_heap) && | ||
497 | (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) ) | ||
498 | { | ||
499 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT, | ||
500 | &drop_paths, | ||
501 | cp); | ||
502 | return; | ||
503 | } | ||
504 | if (0 != cp->num_paths) | ||
505 | return; /* still relevant! */ | ||
506 | if (NULL != cp->hello) | ||
507 | { | ||
508 | /* relevant only until HELLO expires */ | ||
509 | exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello)); | ||
510 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp, | ||
511 | &destroy_peer, | ||
512 | cp); | ||
513 | return; | ||
514 | } | ||
515 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT, | ||
516 | &destroy_peer, | ||
517 | cp); | ||
518 | } | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Set the message queue to @a mq for peer @a cp and notify watchers. | ||
523 | * | ||
524 | * @param cp peer to modify | ||
525 | * @param mq message queue to set (can be NULL) | ||
526 | */ | ||
527 | void | ||
528 | GCP_set_mq (struct CadetPeer *cp, | ||
529 | struct GNUNET_MQ_Handle *mq) | ||
530 | { | ||
531 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
532 | "Message queue for peer %s is now %p\n", | ||
533 | GCP_2s (cp), | ||
534 | mq); | ||
535 | cp->core_mq = mq; | ||
536 | for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next; | ||
537 | NULL != mqm; | ||
538 | mqm = next) | ||
539 | { | ||
540 | /* Save next pointer in case mqm gets freed by the callback */ | ||
541 | next = mqm->next; | ||
542 | if (NULL == mq) | ||
543 | { | ||
544 | if (NULL != mqm->env) | ||
545 | { | ||
546 | GNUNET_MQ_discard (mqm->env); | ||
547 | mqm->env = NULL; | ||
548 | mqm->cb (mqm->cb_cls, | ||
549 | GNUNET_SYSERR); | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | mqm->cb (mqm->cb_cls, | ||
554 | GNUNET_NO); | ||
555 | } | ||
556 | } | ||
557 | else | ||
558 | { | ||
559 | GNUNET_assert (NULL == mqm->env); | ||
560 | mqm->cb (mqm->cb_cls, | ||
561 | GNUNET_YES); | ||
562 | } | ||
563 | } | ||
564 | if ( (NULL != mq) || | ||
565 | (NULL != cp->t) ) | ||
566 | consider_peer_activate (cp); | ||
567 | else | ||
568 | consider_peer_destroy (cp); | ||
569 | |||
570 | if ( (NULL != mq) && | ||
571 | (NULL != cp->t) ) | ||
572 | { | ||
573 | /* have a new, direct path to the target, notify tunnel */ | ||
574 | struct CadetPeerPath *path; | ||
575 | |||
576 | path = GCPP_get_path_from_route (1, | ||
577 | &cp->pid); | ||
578 | GCT_consider_path (cp->t, | ||
579 | path, | ||
580 | 0); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * Debug function should NEVER return true in production code, useful to | ||
587 | * simulate losses for testcases. | ||
588 | * | ||
589 | * @return #GNUNET_YES or #GNUNET_NO with the decision to drop. | ||
590 | */ | ||
591 | static int | ||
592 | should_I_drop (void) | ||
593 | { | ||
594 | if (0 == drop_percent) | ||
595 | return GNUNET_NO; | ||
596 | if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
597 | 101) < drop_percent) | ||
598 | return GNUNET_YES; | ||
599 | return GNUNET_NO; | ||
600 | } | ||
601 | |||
602 | |||
603 | /** | ||
604 | * Function called when CORE took one of the messages from | ||
605 | * a message queue manager and transmitted it. | ||
606 | * | ||
607 | * @param cls the `struct CadetPeeer` where we made progress | ||
608 | */ | ||
609 | static void | ||
610 | mqm_send_done (void *cls); | ||
611 | |||
612 | |||
613 | /** | ||
614 | * Transmit current envelope from this @a mqm. | ||
615 | * | ||
616 | * @param mqm mqm to transmit message for now | ||
617 | */ | ||
618 | static void | ||
619 | mqm_execute (struct GCP_MessageQueueManager *mqm) | ||
620 | { | ||
621 | struct CadetPeer *cp = mqm->cp; | ||
622 | |||
623 | /* Move ready pointer to the next entry that might be ready. */ | ||
624 | if ( (mqm == cp->mqm_ready_ptr) && | ||
625 | (NULL != mqm->next) ) | ||
626 | cp->mqm_ready_ptr = mqm->next; | ||
627 | /* Move entry to the end of the DLL, to be fair. */ | ||
628 | if (mqm != cp->mqm_tail) | ||
629 | { | ||
630 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
631 | cp->mqm_tail, | ||
632 | mqm); | ||
633 | GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head, | ||
634 | cp->mqm_tail, | ||
635 | mqm); | ||
636 | } | ||
637 | cp->mqm_ready_counter--; | ||
638 | if (GNUNET_YES == should_I_drop ()) | ||
639 | { | ||
640 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
641 | "DROPPING message to peer %s from MQM %p\n", | ||
642 | GCP_2s (cp), | ||
643 | mqm); | ||
644 | GNUNET_MQ_discard (mqm->env); | ||
645 | mqm->env = NULL; | ||
646 | mqm_send_done (cp); | ||
647 | } | ||
648 | else | ||
649 | { | ||
650 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
651 | "Sending to peer %s from MQM %p\n", | ||
652 | GCP_2s (cp), | ||
653 | mqm); | ||
654 | GNUNET_MQ_send (cp->core_mq, | ||
655 | mqm->env); | ||
656 | mqm->env = NULL; | ||
657 | } | ||
658 | mqm->cb (mqm->cb_cls, | ||
659 | GNUNET_YES); | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * Find the next ready message in the queue (starting | ||
665 | * the search from the `cp->mqm_ready_ptr`) and if possible | ||
666 | * execute the transmission. | ||
667 | * | ||
668 | * @param cp peer to try to send the next ready message to | ||
669 | */ | ||
670 | static void | ||
671 | send_next_ready (struct CadetPeer *cp) | ||
672 | { | ||
673 | struct GCP_MessageQueueManager *mqm; | ||
674 | |||
675 | if (0 == cp->mqm_ready_counter) | ||
676 | return; | ||
677 | while ( (NULL != (mqm = cp->mqm_ready_ptr)) && | ||
678 | (NULL == mqm->env) ) | ||
679 | cp->mqm_ready_ptr = mqm->next; | ||
680 | if (NULL == mqm) | ||
681 | return; /* nothing to do */ | ||
682 | mqm_execute (mqm); | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Function called when CORE took one of the messages from | ||
688 | * a message queue manager and transmitted it. | ||
689 | * | ||
690 | * @param cls the `struct CadetPeeer` where we made progress | ||
691 | */ | ||
692 | static void | ||
693 | mqm_send_done (void *cls) | ||
694 | { | ||
695 | struct CadetPeer *cp = cls; | ||
696 | |||
697 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
698 | "Sending to peer %s completed\n", | ||
699 | GCP_2s (cp)); | ||
700 | send_next_ready (cp); | ||
701 | } | ||
702 | |||
703 | |||
704 | /** | ||
705 | * Send the message in @a env to @a cp. | ||
706 | * | ||
707 | * @param mqm the message queue manager to use for transmission | ||
708 | * @param env envelope with the message to send; must NOT | ||
709 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
710 | */ | ||
711 | void | ||
712 | GCP_send (struct GCP_MessageQueueManager *mqm, | ||
713 | struct GNUNET_MQ_Envelope *env) | ||
714 | { | ||
715 | struct CadetPeer *cp = mqm->cp; | ||
716 | |||
717 | GNUNET_assert (NULL != env); | ||
718 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
719 | "Queueing message to peer %s in MQM %p\n", | ||
720 | GCP_2s (cp), | ||
721 | mqm); | ||
722 | GNUNET_assert (NULL != cp->core_mq); | ||
723 | GNUNET_assert (NULL == mqm->env); | ||
724 | GNUNET_MQ_notify_sent (env, | ||
725 | &mqm_send_done, | ||
726 | cp); | ||
727 | mqm->env = env; | ||
728 | cp->mqm_ready_counter++; | ||
729 | if (mqm != cp->mqm_ready_ptr) | ||
730 | cp->mqm_ready_ptr = cp->mqm_head; | ||
731 | if (1 == cp->mqm_ready_counter) | ||
732 | cp->mqm_ready_ptr = mqm; | ||
733 | if (0 != GNUNET_MQ_get_length (cp->core_mq)) | ||
734 | return; | ||
735 | send_next_ready (cp); | ||
736 | } | ||
737 | |||
738 | |||
739 | /** | ||
740 | * Function called to destroy a peer now. | ||
741 | * | ||
742 | * @param cls NULL | ||
743 | * @param pid identity of the peer (unused) | ||
744 | * @param value the `struct CadetPeer` to clean up | ||
745 | * @return #GNUNET_OK (continue to iterate) | ||
746 | */ | ||
747 | static int | ||
748 | destroy_iterator_cb (void *cls, | ||
749 | const struct GNUNET_PeerIdentity *pid, | ||
750 | void *value) | ||
751 | { | ||
752 | struct CadetPeer *cp = value; | ||
753 | |||
754 | if (NULL != cp->destroy_task) | ||
755 | { | ||
756 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
757 | cp->destroy_task = NULL; | ||
758 | } | ||
759 | destroy_peer (cp); | ||
760 | return GNUNET_OK; | ||
761 | } | ||
762 | |||
763 | |||
764 | /** | ||
765 | * Clean up all entries about all peers. | ||
766 | * Must only be called after all tunnels, CORE-connections and | ||
767 | * connections are down. | ||
768 | */ | ||
769 | void | ||
770 | GCP_destroy_all_peers () | ||
771 | { | ||
772 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
773 | "Destroying all peers now\n"); | ||
774 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
775 | &destroy_iterator_cb, | ||
776 | NULL); | ||
777 | } | ||
778 | |||
779 | |||
780 | /** | ||
781 | * Drop all paths owned by this peer, and do not | ||
782 | * allow new ones to be added: We are shutting down. | ||
783 | * | ||
784 | * @param cp peer to drop paths to | ||
785 | */ | ||
786 | void | ||
787 | GCP_drop_owned_paths (struct CadetPeer *cp) | ||
788 | { | ||
789 | struct CadetPeerPath *path; | ||
790 | |||
791 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
792 | "Destroying all paths to %s\n", | ||
793 | GCP_2s (cp)); | ||
794 | while (NULL != (path = | ||
795 | GNUNET_CONTAINER_heap_remove_root (cp->path_heap))) | ||
796 | GCPP_release (path); | ||
797 | GNUNET_CONTAINER_heap_destroy (cp->path_heap); | ||
798 | cp->path_heap = NULL; | ||
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Add an entry to the DLL of all of the paths that this peer is on. | ||
804 | * | ||
805 | * @param cp peer to modify | ||
806 | * @param entry an entry on a path | ||
807 | * @param off offset of this peer on the path | ||
808 | */ | ||
809 | void | ||
810 | GCP_path_entry_add (struct CadetPeer *cp, | ||
811 | struct CadetPeerPathEntry *entry, | ||
812 | unsigned int off) | ||
813 | { | ||
814 | GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path, | ||
815 | off)); | ||
816 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
817 | "Discovered that peer %s is on path %s at offset %u\n", | ||
818 | GCP_2s (cp), | ||
819 | GCPP_2s (entry->path), | ||
820 | off); | ||
821 | if (off >= cp->path_dll_length) | ||
822 | { | ||
823 | unsigned int len = cp->path_dll_length; | ||
824 | |||
825 | GNUNET_array_grow (cp->path_heads, | ||
826 | len, | ||
827 | off + 4); | ||
828 | GNUNET_array_grow (cp->path_tails, | ||
829 | cp->path_dll_length, | ||
830 | off + 4); | ||
831 | } | ||
832 | GNUNET_CONTAINER_DLL_insert (cp->path_heads[off], | ||
833 | cp->path_tails[off], | ||
834 | entry); | ||
835 | cp->off_sum += off; | ||
836 | cp->num_paths++; | ||
837 | |||
838 | /* If we have a tunnel to this peer, tell the tunnel that there is a | ||
839 | new path available. */ | ||
840 | if (NULL != cp->t) | ||
841 | GCT_consider_path (cp->t, | ||
842 | entry->path, | ||
843 | off); | ||
844 | |||
845 | if ( (NULL != cp->search_h) && | ||
846 | (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ) | ||
847 | { | ||
848 | /* Now I have enough paths, stop search */ | ||
849 | GCD_search_stop (cp->search_h); | ||
850 | cp->search_h = NULL; | ||
851 | } | ||
852 | if (NULL != cp->destroy_task) | ||
853 | { | ||
854 | /* paths changed, this resets the destroy timeout counter | ||
855 | and aborts a destroy task that may no longer be valid | ||
856 | to have (as we now have more paths via this peer). */ | ||
857 | consider_peer_destroy (cp); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | |||
862 | /** | ||
863 | * Remove an entry from the DLL of all of the paths that this peer is on. | ||
864 | * | ||
865 | * @param cp peer to modify | ||
866 | * @param entry an entry on a path | ||
867 | * @param off offset of this peer on the path | ||
868 | */ | ||
869 | void | ||
870 | GCP_path_entry_remove (struct CadetPeer *cp, | ||
871 | struct CadetPeerPathEntry *entry, | ||
872 | unsigned int off) | ||
873 | { | ||
874 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
875 | "Removing knowledge about peer %s beging on path %s at offset %u\n", | ||
876 | GCP_2s (cp), | ||
877 | GCPP_2s (entry->path), | ||
878 | off); | ||
879 | GNUNET_CONTAINER_DLL_remove (cp->path_heads[off], | ||
880 | cp->path_tails[off], | ||
881 | entry); | ||
882 | GNUNET_assert (0 < cp->num_paths); | ||
883 | cp->off_sum -= off; | ||
884 | cp->num_paths--; | ||
885 | if ( (NULL == cp->core_mq) && | ||
886 | (NULL != cp->t) && | ||
887 | (NULL == cp->search_h) && | ||
888 | (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) ) | ||
889 | cp->search_h | ||
890 | = GCD_search (&cp->pid); | ||
891 | if (NULL == cp->destroy_task) | ||
892 | { | ||
893 | /* paths changed, we might now be ready for destruction, check again */ | ||
894 | consider_peer_destroy (cp); | ||
895 | } | ||
896 | } | ||
897 | |||
898 | |||
899 | /** | ||
900 | * Prune down the number of paths to this peer, we seem to | ||
901 | * have way too many. | ||
902 | * | ||
903 | * @param cls the `struct CadetPeer` to maintain the path heap for | ||
904 | */ | ||
905 | static void | ||
906 | path_heap_cleanup (void *cls) | ||
907 | { | ||
908 | struct CadetPeer *cp = cls; | ||
909 | struct CadetPeerPath *root; | ||
910 | |||
911 | cp->heap_cleanup_task = NULL; | ||
912 | while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >= | ||
913 | 2 * DESIRED_CONNECTIONS_PER_TUNNEL) | ||
914 | { | ||
915 | /* Now we have way too many, drop least desirable UNLESS it is in use! | ||
916 | (Note that this intentionally keeps highly desireable, but currently | ||
917 | unused paths around in the hope that we might be able to switch, even | ||
918 | if the number of paths exceeds the threshold.) */ | ||
919 | root = GNUNET_CONTAINER_heap_peek (cp->path_heap); | ||
920 | GNUNET_assert (NULL != root); | ||
921 | if (NULL != | ||
922 | GCPP_get_connection (root, | ||
923 | cp, | ||
924 | GCPP_get_length (root) - 1)) | ||
925 | break; /* can't fix */ | ||
926 | /* Got plenty of paths to this destination, and this is a low-quality | ||
927 | one that we don't care about. Allow it to die. */ | ||
928 | GNUNET_assert (root == | ||
929 | GNUNET_CONTAINER_heap_remove_root (cp->path_heap)); | ||
930 | GCPP_release (root); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | |||
935 | /** | ||
936 | * Try adding a @a path to this @a peer. If the peer already | ||
937 | * has plenty of paths, return NULL. | ||
938 | * | ||
939 | * @param cp peer to which the @a path leads to | ||
940 | * @param path a path looking for an owner; may not be fully initialized yet! | ||
941 | * @param off offset of @a cp in @a path | ||
942 | * @param force force attaching the path | ||
943 | * @return NULL if this peer does not care to become a new owner, | ||
944 | * otherwise the node in the peer's path heap for the @a path. | ||
945 | */ | ||
946 | struct GNUNET_CONTAINER_HeapNode * | ||
947 | GCP_attach_path (struct CadetPeer *cp, | ||
948 | struct CadetPeerPath *path, | ||
949 | unsigned int off, | ||
950 | int force) | ||
951 | { | ||
952 | GNUNET_CONTAINER_HeapCostType desirability; | ||
953 | struct CadetPeerPath *root; | ||
954 | GNUNET_CONTAINER_HeapCostType root_desirability; | ||
955 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
956 | |||
957 | GNUNET_assert (off == GCPP_get_length (path) - 1); | ||
958 | GNUNET_assert (cp == GCPP_get_peer_at_offset (path, | ||
959 | off)); | ||
960 | if (NULL == cp->path_heap) | ||
961 | { | ||
962 | /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */ | ||
963 | GNUNET_assert (GNUNET_NO == force); | ||
964 | return NULL; | ||
965 | } | ||
966 | desirability = GCPP_get_desirability (path); | ||
967 | if (GNUNET_NO == force) | ||
968 | { | ||
969 | /* FIXME: desirability is not yet initialized; tricky! */ | ||
970 | if (GNUNET_NO == | ||
971 | GNUNET_CONTAINER_heap_peek2 (cp->path_heap, | ||
972 | (void **) &root, | ||
973 | &root_desirability)) | ||
974 | { | ||
975 | root = NULL; | ||
976 | root_desirability = 0; | ||
977 | } | ||
978 | |||
979 | if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) && | ||
980 | (desirability < root_desirability) ) | ||
981 | { | ||
982 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
983 | "Decided to not attach path %p to peer %s due to undesirability\n", | ||
984 | GCPP_2s (path), | ||
985 | GCP_2s (cp)); | ||
986 | return NULL; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
991 | "Attaching path %s to peer %s (%s)\n", | ||
992 | GCPP_2s (path), | ||
993 | GCP_2s (cp), | ||
994 | (GNUNET_NO == force) ? "desirable" : "forced"); | ||
995 | |||
996 | /* Yes, we'd like to add this path, add to our heap */ | ||
997 | hn = GNUNET_CONTAINER_heap_insert (cp->path_heap, | ||
998 | path, | ||
999 | desirability); | ||
1000 | |||
1001 | /* Consider maybe dropping other paths because of the new one */ | ||
1002 | if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >= | ||
1003 | 2 * DESIRED_CONNECTIONS_PER_TUNNEL) && | ||
1004 | (NULL != cp->heap_cleanup_task) ) | ||
1005 | cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup, | ||
1006 | cp); | ||
1007 | return hn; | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | /** | ||
1012 | * This peer can no longer own @a path as the path | ||
1013 | * has been extended and a peer further down the line | ||
1014 | * is now the new owner. | ||
1015 | * | ||
1016 | * @param cp old owner of the @a path | ||
1017 | * @param path path where the ownership is lost | ||
1018 | * @param hn note in @a cp's path heap that must be deleted | ||
1019 | */ | ||
1020 | void | ||
1021 | GCP_detach_path (struct CadetPeer *cp, | ||
1022 | struct CadetPeerPath *path, | ||
1023 | struct GNUNET_CONTAINER_HeapNode *hn) | ||
1024 | { | ||
1025 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1026 | "Detatching path %s from peer %s\n", | ||
1027 | GCPP_2s (path), | ||
1028 | GCP_2s (cp)); | ||
1029 | GNUNET_assert (path == | ||
1030 | GNUNET_CONTAINER_heap_remove_node (hn)); | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | /** | ||
1035 | * Add a @a connection to this @a cp. | ||
1036 | * | ||
1037 | * @param cp peer via which the @a connection goes | ||
1038 | * @param cc the connection to add | ||
1039 | */ | ||
1040 | void | ||
1041 | GCP_add_connection (struct CadetPeer *cp, | ||
1042 | struct CadetConnection *cc) | ||
1043 | { | ||
1044 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1045 | "Adding connection %s to peer %s\n", | ||
1046 | GCC_2s (cc), | ||
1047 | GCP_2s (cp)); | ||
1048 | GNUNET_assert (GNUNET_OK == | ||
1049 | GNUNET_CONTAINER_multishortmap_put (cp->connections, | ||
1050 | &GCC_get_id (cc)->connection_of_tunnel, | ||
1051 | cc, | ||
1052 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1053 | if (NULL != cp->destroy_task) | ||
1054 | { | ||
1055 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
1056 | cp->destroy_task = NULL; | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | /** | ||
1062 | * Remove a @a connection that went via this @a cp. | ||
1063 | * | ||
1064 | * @param cp peer via which the @a connection went | ||
1065 | * @param cc the connection to remove | ||
1066 | */ | ||
1067 | void | ||
1068 | GCP_remove_connection (struct CadetPeer *cp, | ||
1069 | struct CadetConnection *cc) | ||
1070 | { | ||
1071 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1072 | "Removing connection %s from peer %s\n", | ||
1073 | GCC_2s (cc), | ||
1074 | GCP_2s (cp)); | ||
1075 | GNUNET_assert (GNUNET_YES == | ||
1076 | GNUNET_CONTAINER_multishortmap_remove (cp->connections, | ||
1077 | &GCC_get_id (cc)->connection_of_tunnel, | ||
1078 | cc)); | ||
1079 | consider_peer_destroy (cp); | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | /** | ||
1084 | * Retrieve the CadetPeer stucture associated with the | ||
1085 | * peer. Optionally create one and insert it in the appropriate | ||
1086 | * structures if the peer is not known yet. | ||
1087 | * | ||
1088 | * @param peer_id Full identity of the peer. | ||
1089 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
1090 | * #GNUNET_NO to return NULL if peer is unknown. | ||
1091 | * @return Existing or newly created peer structure. | ||
1092 | * NULL if unknown and not requested @a create | ||
1093 | */ | ||
1094 | struct CadetPeer * | ||
1095 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, | ||
1096 | int create) | ||
1097 | { | ||
1098 | struct CadetPeer *cp; | ||
1099 | |||
1100 | cp = GNUNET_CONTAINER_multipeermap_get (peers, | ||
1101 | peer_id); | ||
1102 | if (NULL != cp) | ||
1103 | return cp; | ||
1104 | if (GNUNET_NO == create) | ||
1105 | return NULL; | ||
1106 | cp = GNUNET_new (struct CadetPeer); | ||
1107 | cp->pid = *peer_id; | ||
1108 | cp->connections = GNUNET_CONTAINER_multishortmap_create (32, | ||
1109 | GNUNET_YES); | ||
1110 | cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1111 | GNUNET_assert (GNUNET_YES == | ||
1112 | GNUNET_CONTAINER_multipeermap_put (peers, | ||
1113 | &cp->pid, | ||
1114 | cp, | ||
1115 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1116 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1117 | "Creating peer %s\n", | ||
1118 | GCP_2s (cp)); | ||
1119 | return cp; | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | /** | ||
1124 | * Obtain the peer identity for a `struct CadetPeer`. | ||
1125 | * | ||
1126 | * @param cp our peer handle | ||
1127 | * @return the peer identity | ||
1128 | */ | ||
1129 | const struct GNUNET_PeerIdentity * | ||
1130 | GCP_get_id (struct CadetPeer *cp) | ||
1131 | { | ||
1132 | return &cp->pid; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /** | ||
1137 | * Iterate over all known peers. | ||
1138 | * | ||
1139 | * @param iter Iterator. | ||
1140 | * @param cls Closure for @c iter. | ||
1141 | */ | ||
1142 | void | ||
1143 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, | ||
1144 | void *cls) | ||
1145 | { | ||
1146 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
1147 | iter, | ||
1148 | cls); | ||
1149 | } | ||
1150 | |||
1151 | |||
1152 | /** | ||
1153 | * Count the number of known paths toward the peer. | ||
1154 | * | ||
1155 | * @param cp Peer to get path info. | ||
1156 | * @return Number of known paths. | ||
1157 | */ | ||
1158 | unsigned int | ||
1159 | GCP_count_paths (const struct CadetPeer *cp) | ||
1160 | { | ||
1161 | return cp->num_paths; | ||
1162 | } | ||
1163 | |||
1164 | |||
1165 | /** | ||
1166 | * Iterate over the paths to a peer. | ||
1167 | * | ||
1168 | * @param cp Peer to get path info. | ||
1169 | * @param callback Function to call for every path. | ||
1170 | * @param callback_cls Closure for @a callback. | ||
1171 | * @return Number of iterated paths. | ||
1172 | */ | ||
1173 | unsigned int | ||
1174 | GCP_iterate_paths (struct CadetPeer *cp, | ||
1175 | GCP_PathIterator callback, | ||
1176 | void *callback_cls) | ||
1177 | { | ||
1178 | unsigned int ret = 0; | ||
1179 | |||
1180 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1181 | "Iterating over paths to peer %s%s\n", | ||
1182 | GCP_2s (cp), | ||
1183 | (NULL == cp->core_mq) ? "" : " including direct link"); | ||
1184 | if (NULL != cp->core_mq) | ||
1185 | { | ||
1186 | struct CadetPeerPath *path; | ||
1187 | |||
1188 | path = GCPP_get_path_from_route (1, | ||
1189 | &cp->pid); | ||
1190 | ret++; | ||
1191 | if (GNUNET_NO == | ||
1192 | callback (callback_cls, | ||
1193 | path, | ||
1194 | 0)) | ||
1195 | return ret; | ||
1196 | } | ||
1197 | for (unsigned int i=0;i<cp->path_dll_length;i++) | ||
1198 | { | ||
1199 | for (struct CadetPeerPathEntry *pe = cp->path_heads[i]; | ||
1200 | NULL != pe; | ||
1201 | pe = pe->next) | ||
1202 | { | ||
1203 | ret++; | ||
1204 | if (GNUNET_NO == | ||
1205 | callback (callback_cls, | ||
1206 | pe->path, | ||
1207 | i)) | ||
1208 | return ret; | ||
1209 | } | ||
1210 | } | ||
1211 | return ret; | ||
1212 | } | ||
1213 | |||
1214 | |||
1215 | /** | ||
1216 | * Iterate over the paths to @a cp where | ||
1217 | * @a cp is at distance @a dist from us. | ||
1218 | * | ||
1219 | * @param cp Peer to get path info. | ||
1220 | * @param dist desired distance of @a cp to us on the path | ||
1221 | * @param callback Function to call for every path. | ||
1222 | * @param callback_cls Closure for @a callback. | ||
1223 | * @return Number of iterated paths. | ||
1224 | */ | ||
1225 | unsigned int | ||
1226 | GCP_iterate_paths_at (struct CadetPeer *cp, | ||
1227 | unsigned int dist, | ||
1228 | GCP_PathIterator callback, | ||
1229 | void *callback_cls) | ||
1230 | { | ||
1231 | unsigned int ret = 0; | ||
1232 | |||
1233 | if (dist >= cp->path_dll_length) | ||
1234 | { | ||
1235 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1236 | "Asked to look for paths at distance %u, but maximum for me is < %u\n", | ||
1237 | dist, | ||
1238 | cp->path_dll_length); | ||
1239 | return 0; | ||
1240 | } | ||
1241 | for (struct CadetPeerPathEntry *pe = cp->path_heads[dist]; | ||
1242 | NULL != pe; | ||
1243 | pe = pe->next) | ||
1244 | { | ||
1245 | if (GNUNET_NO == | ||
1246 | callback (callback_cls, | ||
1247 | pe->path, | ||
1248 | dist)) | ||
1249 | return ret; | ||
1250 | ret++; | ||
1251 | } | ||
1252 | return ret; | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | /** | ||
1257 | * Get the tunnel towards a peer. | ||
1258 | * | ||
1259 | * @param cp Peer to get from. | ||
1260 | * @param create #GNUNET_YES to create a tunnel if we do not have one | ||
1261 | * @return Tunnel towards peer. | ||
1262 | */ | ||
1263 | struct CadetTunnel * | ||
1264 | GCP_get_tunnel (struct CadetPeer *cp, | ||
1265 | int create) | ||
1266 | { | ||
1267 | if (NULL == cp) | ||
1268 | return NULL; | ||
1269 | if ( (NULL != cp->t) || | ||
1270 | (GNUNET_NO == create) ) | ||
1271 | return cp->t; | ||
1272 | cp->t = GCT_create_tunnel (cp); | ||
1273 | consider_peer_activate (cp); | ||
1274 | return cp->t; | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | /** | ||
1279 | * Hello offer was passed to the transport service. Mark it | ||
1280 | * as done. | ||
1281 | * | ||
1282 | * @param cls the `struct CadetPeer` where the offer completed | ||
1283 | */ | ||
1284 | static void | ||
1285 | hello_offer_done (void *cls) | ||
1286 | { | ||
1287 | struct CadetPeer *cp = cls; | ||
1288 | |||
1289 | cp->hello_offer = NULL; | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /** | ||
1294 | * We got a HELLO for a @a peer, remember it, and possibly | ||
1295 | * trigger adequate actions (like trying to connect). | ||
1296 | * | ||
1297 | * @param cp the peer we got a HELLO for | ||
1298 | * @param hello the HELLO to remember | ||
1299 | */ | ||
1300 | void | ||
1301 | GCP_set_hello (struct CadetPeer *cp, | ||
1302 | const struct GNUNET_HELLO_Message *hello) | ||
1303 | { | ||
1304 | struct GNUNET_HELLO_Message *mrg; | ||
1305 | |||
1306 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1307 | "Got %u byte HELLO for peer %s\n", | ||
1308 | (unsigned int) GNUNET_HELLO_size (hello), | ||
1309 | GCP_2s (cp)); | ||
1310 | if (NULL != cp->hello_offer) | ||
1311 | { | ||
1312 | GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer); | ||
1313 | cp->hello_offer = NULL; | ||
1314 | } | ||
1315 | if (NULL != cp->hello) | ||
1316 | { | ||
1317 | mrg = GNUNET_HELLO_merge (hello, | ||
1318 | cp->hello); | ||
1319 | GNUNET_free (cp->hello); | ||
1320 | cp->hello = mrg; | ||
1321 | } | ||
1322 | else | ||
1323 | { | ||
1324 | cp->hello = GNUNET_memdup (hello, | ||
1325 | GNUNET_HELLO_size (hello)); | ||
1326 | } | ||
1327 | cp->hello_offer | ||
1328 | = GNUNET_TRANSPORT_offer_hello (cfg, | ||
1329 | GNUNET_HELLO_get_header (cp->hello) , | ||
1330 | &hello_offer_done, | ||
1331 | cp); | ||
1332 | /* New HELLO means cp's destruction time may change... */ | ||
1333 | consider_peer_destroy (cp); | ||
1334 | } | ||
1335 | |||
1336 | |||
1337 | /** | ||
1338 | * The tunnel to the given peer no longer exists, remove it from our | ||
1339 | * data structures, and possibly clean up the peer itself. | ||
1340 | * | ||
1341 | * @param cp the peer affected | ||
1342 | * @param t the dead tunnel | ||
1343 | */ | ||
1344 | void | ||
1345 | GCP_drop_tunnel (struct CadetPeer *cp, | ||
1346 | struct CadetTunnel *t) | ||
1347 | { | ||
1348 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1349 | "Dropping tunnel %s to peer %s\n", | ||
1350 | GCT_2s (t), | ||
1351 | GCP_2s (cp)); | ||
1352 | GNUNET_assert (cp->t == t); | ||
1353 | cp->t = NULL; | ||
1354 | consider_peer_destroy (cp); | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | /** | ||
1359 | * Test if @a cp has a core-level connection | ||
1360 | * | ||
1361 | * @param cp peer to test | ||
1362 | * @return #GNUNET_YES if @a cp has a core-level connection | ||
1363 | */ | ||
1364 | int | ||
1365 | GCP_has_core_connection (struct CadetPeer *cp) | ||
1366 | { | ||
1367 | return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO; | ||
1368 | } | ||
1369 | |||
1370 | |||
1371 | /** | ||
1372 | * Start message queue change notifications. | ||
1373 | * | ||
1374 | * @param cp peer to notify for | ||
1375 | * @param cb function to call if mq becomes available or unavailable | ||
1376 | * @param cb_cls closure for @a cb | ||
1377 | * @return handle to cancel request | ||
1378 | */ | ||
1379 | struct GCP_MessageQueueManager * | ||
1380 | GCP_request_mq (struct CadetPeer *cp, | ||
1381 | GCP_MessageQueueNotificationCallback cb, | ||
1382 | void *cb_cls) | ||
1383 | { | ||
1384 | struct GCP_MessageQueueManager *mqm; | ||
1385 | |||
1386 | mqm = GNUNET_new (struct GCP_MessageQueueManager); | ||
1387 | mqm->cb = cb; | ||
1388 | mqm->cb_cls = cb_cls; | ||
1389 | mqm->cp = cp; | ||
1390 | GNUNET_CONTAINER_DLL_insert (cp->mqm_head, | ||
1391 | cp->mqm_tail, | ||
1392 | mqm); | ||
1393 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1394 | "Creating MQM %p for peer %s\n", | ||
1395 | mqm, | ||
1396 | GCP_2s (cp)); | ||
1397 | if (NULL != cp->core_mq) | ||
1398 | cb (cb_cls, | ||
1399 | GNUNET_YES); | ||
1400 | return mqm; | ||
1401 | } | ||
1402 | |||
1403 | |||
1404 | /** | ||
1405 | * Stops message queue change notifications. | ||
1406 | * | ||
1407 | * @param mqm handle matching request to cancel | ||
1408 | * @param last_env final message to transmit, or NULL | ||
1409 | */ | ||
1410 | void | ||
1411 | GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm, | ||
1412 | struct GNUNET_MQ_Envelope *last_env) | ||
1413 | { | ||
1414 | struct CadetPeer *cp = mqm->cp; | ||
1415 | |||
1416 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1417 | "Destroying MQM %p for peer %s%s\n", | ||
1418 | mqm, | ||
1419 | GCP_2s (cp), | ||
1420 | (NULL == last_env) ? "" : " with last ditch transmission"); | ||
1421 | if (NULL != mqm->env) | ||
1422 | GNUNET_MQ_discard (mqm->env); | ||
1423 | if (NULL != last_env) | ||
1424 | { | ||
1425 | if (NULL != cp->core_mq) | ||
1426 | { | ||
1427 | GNUNET_MQ_notify_sent (last_env, | ||
1428 | &mqm_send_done, | ||
1429 | cp); | ||
1430 | GNUNET_MQ_send (cp->core_mq, | ||
1431 | last_env); | ||
1432 | } | ||
1433 | else | ||
1434 | { | ||
1435 | GNUNET_MQ_discard (last_env); | ||
1436 | } | ||
1437 | } | ||
1438 | if (cp->mqm_ready_ptr == mqm) | ||
1439 | cp->mqm_ready_ptr = mqm->next; | ||
1440 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
1441 | cp->mqm_tail, | ||
1442 | mqm); | ||
1443 | GNUNET_free (mqm); | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | /** | ||
1448 | * Send the message in @a env to @a cp, overriding queueing logic. | ||
1449 | * This function should only be used to send error messages outside | ||
1450 | * of flow and congestion control, similar to ICMP. Note that | ||
1451 | * the envelope may be silently discarded as well. | ||
1452 | * | ||
1453 | * @param cp peer to send the message to | ||
1454 | * @param env envelope with the message to send | ||
1455 | */ | ||
1456 | void | ||
1457 | GCP_send_ooo (struct CadetPeer *cp, | ||
1458 | struct GNUNET_MQ_Envelope *env) | ||
1459 | { | ||
1460 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1461 | "Sending message to %s out of management\n", | ||
1462 | GCP_2s (cp)); | ||
1463 | if (NULL == cp->core_mq) | ||
1464 | { | ||
1465 | GNUNET_MQ_discard (env); | ||
1466 | return; | ||
1467 | } | ||
1468 | GNUNET_MQ_notify_sent (env, | ||
1469 | &mqm_send_done, | ||
1470 | cp); | ||
1471 | GNUNET_MQ_send (cp->core_mq, | ||
1472 | env); | ||
1473 | } | ||
1474 | |||
1475 | |||
1476 | |||
1477 | |||
1478 | /* end of gnunet-service-cadet-new_peer.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h deleted file mode 100644 index e1d6fc33a..000000000 --- a/src/cadet/gnunet-service-cadet-new_peer.h +++ /dev/null | |||
@@ -1,394 +0,0 @@ | |||
1 | |||
2 | /* | ||
3 | This file is part of GNUnet. | ||
4 | Copyright (C) 2001-2017 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 3, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNUnet; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file cadet/gnunet-service-cadet-new_peer.h | ||
24 | * @brief Information we track per peer. | ||
25 | * @author Bartlomiej Polot | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #ifndef GNUNET_SERVICE_CADET_PEER_H | ||
29 | #define GNUNET_SERVICE_CADET_PEER_H | ||
30 | |||
31 | #include "gnunet-service-cadet-new.h" | ||
32 | #include "gnunet_hello_lib.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Get the static string for a peer ID. | ||
37 | * | ||
38 | * @param peer Peer. | ||
39 | * | ||
40 | * @return Static string for it's ID. | ||
41 | */ | ||
42 | const char * | ||
43 | GCP_2s (const struct CadetPeer *peer); | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Retrieve the CadetPeer stucture associated with the | ||
48 | * peer. Optionally create one and insert it in the appropriate | ||
49 | * structures if the peer is not known yet. | ||
50 | * | ||
51 | * @param peer_id Full identity of the peer. | ||
52 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
53 | * #GNUNET_NO to return NULL if peer is unknown. | ||
54 | * @return Existing or newly created peer structure. | ||
55 | * NULL if unknown and not requested @a create | ||
56 | */ | ||
57 | struct CadetPeer * | ||
58 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, | ||
59 | int create); | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Calculate how desirable a path is for @a cp if | ||
64 | * @a cp is at offset @a off in the path. | ||
65 | * | ||
66 | * @param cp a peer reachable via a path | ||
67 | * @param off offset of @a cp in a path | ||
68 | * @return score how useful a path is to reach @a cp, | ||
69 | * positive scores mean path is more desirable | ||
70 | */ | ||
71 | double | ||
72 | GCP_get_desirability_of_path (struct CadetPeer *cp, | ||
73 | unsigned int off); | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Obtain the peer identity for a `struct CadetPeer`. | ||
78 | * | ||
79 | * @param cp our peer handle | ||
80 | * @return the peer identity | ||
81 | */ | ||
82 | const struct GNUNET_PeerIdentity * | ||
83 | GCP_get_id (struct CadetPeer *cp); | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Iterate over all known peers. | ||
88 | * | ||
89 | * @param iter Iterator. | ||
90 | * @param cls Closure for @c iter. | ||
91 | */ | ||
92 | void | ||
93 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, | ||
94 | void *cls); | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Count the number of known paths toward the peer. | ||
99 | * | ||
100 | * @param cp Peer to get path info. | ||
101 | * @return Number of known paths. | ||
102 | */ | ||
103 | unsigned int | ||
104 | GCP_count_paths (const struct CadetPeer *cp); | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Drop all paths owned by this peer, and do not | ||
109 | * allow new ones to be added: We are shutting down. | ||
110 | * | ||
111 | * @param cp peer to drop paths to | ||
112 | */ | ||
113 | void | ||
114 | GCP_drop_owned_paths (struct CadetPeer *cp); | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Peer path iterator. | ||
119 | * | ||
120 | * @param cls Closure. | ||
121 | * @param path Path itself | ||
122 | * @param off offset of the target peer in @a path | ||
123 | * @return #GNUNET_YES if should keep iterating. | ||
124 | * #GNUNET_NO otherwise. | ||
125 | */ | ||
126 | typedef int | ||
127 | (*GCP_PathIterator) (void *cls, | ||
128 | struct CadetPeerPath *path, | ||
129 | unsigned int off); | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Iterate over the paths to a peer. | ||
134 | * | ||
135 | * @param cp Peer to get path info. | ||
136 | * @param callback Function to call for every path. | ||
137 | * @param callback_cls Closure for @a callback. | ||
138 | * @return Number of iterated paths. | ||
139 | */ | ||
140 | unsigned int | ||
141 | GCP_iterate_paths (struct CadetPeer *cp, | ||
142 | GCP_PathIterator callback, | ||
143 | void *callback_cls); | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Iterate over the paths to @a peer where | ||
148 | * @a peer is at distance @a dist from us. | ||
149 | * | ||
150 | * @param cp Peer to get path info. | ||
151 | * @param dist desired distance of @a peer to us on the path | ||
152 | * @param callback Function to call for every path. | ||
153 | * @param callback_cls Closure for @a callback. | ||
154 | * @return Number of iterated paths. | ||
155 | */ | ||
156 | unsigned int | ||
157 | GCP_iterate_paths_at (struct CadetPeer *cp, | ||
158 | unsigned int dist, | ||
159 | GCP_PathIterator callback, | ||
160 | void *callback_cls); | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Remove an entry from the DLL of all of the paths that this peer is on. | ||
165 | * | ||
166 | * @param cp peer to modify | ||
167 | * @param entry an entry on a path | ||
168 | * @param off offset of this peer on the path | ||
169 | */ | ||
170 | void | ||
171 | GCP_path_entry_remove (struct CadetPeer *cp, | ||
172 | struct CadetPeerPathEntry *entry, | ||
173 | unsigned int off); | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Add an entry to the DLL of all of the paths that this peer is on. | ||
178 | * | ||
179 | * @param cp peer to modify | ||
180 | * @param entry an entry on a path | ||
181 | * @param off offset of this peer on the path | ||
182 | */ | ||
183 | void | ||
184 | GCP_path_entry_add (struct CadetPeer *cp, | ||
185 | struct CadetPeerPathEntry *entry, | ||
186 | unsigned int off); | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Get the tunnel towards a peer. | ||
191 | * | ||
192 | * @param cp Peer to get from. | ||
193 | * @param create #GNUNET_YES to create a tunnel if we do not have one | ||
194 | * @return Tunnel towards peer. | ||
195 | */ | ||
196 | struct CadetTunnel * | ||
197 | GCP_get_tunnel (struct CadetPeer *cp, | ||
198 | int create); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * The tunnel to the given peer no longer exists, remove it from our | ||
203 | * data structures, and possibly clean up the peer itself. | ||
204 | * | ||
205 | * @param cp the peer affected | ||
206 | * @param t the dead tunnel | ||
207 | */ | ||
208 | void | ||
209 | GCP_drop_tunnel (struct CadetPeer *cp, | ||
210 | struct CadetTunnel *t); | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Try adding a @a path to this @a cp. If the peer already | ||
215 | * has plenty of paths, return NULL. | ||
216 | * | ||
217 | * @param cp peer to which the @a path leads to | ||
218 | * @param path a path looking for an owner; may not be fully initialized yet! | ||
219 | * @param off offset of @a cp in @a path | ||
220 | * @param force for attaching the path | ||
221 | * @return NULL if this peer does not care to become a new owner, | ||
222 | * otherwise the node in the peer's path heap for the @a path. | ||
223 | */ | ||
224 | struct GNUNET_CONTAINER_HeapNode * | ||
225 | GCP_attach_path (struct CadetPeer *cp, | ||
226 | struct CadetPeerPath *path, | ||
227 | unsigned int off, | ||
228 | int force); | ||
229 | |||
230 | |||
231 | /** | ||
232 | * This peer can no longer own @a path as the path | ||
233 | * has been extended and a peer further down the line | ||
234 | * is now the new owner. | ||
235 | * | ||
236 | * @param cp old owner of the @a path | ||
237 | * @param path path where the ownership is lost | ||
238 | * @param hn note in @a cp's path heap that must be deleted | ||
239 | */ | ||
240 | void | ||
241 | GCP_detach_path (struct CadetPeer *cp, | ||
242 | struct CadetPeerPath *path, | ||
243 | struct GNUNET_CONTAINER_HeapNode *hn); | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Add a @a connection to this @a cp. | ||
248 | * | ||
249 | * @param cp peer via which the @a connection goes | ||
250 | * @param cc the connection to add | ||
251 | */ | ||
252 | void | ||
253 | GCP_add_connection (struct CadetPeer *cp, | ||
254 | struct CadetConnection *cc); | ||
255 | |||
256 | |||
257 | /** | ||
258 | * Remove a @a connection that went via this @a cp. | ||
259 | * | ||
260 | * @param cp peer via which the @a connection went | ||
261 | * @param cc the connection to remove | ||
262 | */ | ||
263 | void | ||
264 | GCP_remove_connection (struct CadetPeer *cp, | ||
265 | struct CadetConnection *cc); | ||
266 | |||
267 | |||
268 | /** | ||
269 | * We got a HELLO for a @a cp, remember it, and possibly | ||
270 | * trigger adequate actions (like trying to connect). | ||
271 | * | ||
272 | * @param cp the peer we got a HELLO for | ||
273 | * @param hello the HELLO to remember | ||
274 | */ | ||
275 | void | ||
276 | GCP_set_hello (struct CadetPeer *cp, | ||
277 | const struct GNUNET_HELLO_Message *hello); | ||
278 | |||
279 | |||
280 | /** | ||
281 | * Clean up all entries about all peers. | ||
282 | * Must only be called after all tunnels, CORE-connections and | ||
283 | * connections are down. | ||
284 | */ | ||
285 | void | ||
286 | GCP_destroy_all_peers (void); | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Data structure used to track whom we have to notify about changes | ||
291 | * in our ability to transmit to a given peer. | ||
292 | * | ||
293 | * All queue managers will be given equal chance for sending messages | ||
294 | * to @a cp. This construct this guarantees fairness for access to @a | ||
295 | * cp among the different message queues. Each connection or route | ||
296 | * will have its respective message queue managers for each direction. | ||
297 | */ | ||
298 | struct GCP_MessageQueueManager; | ||
299 | |||
300 | |||
301 | /** | ||
302 | * Function to call with updated message queue object. | ||
303 | * | ||
304 | * @param cls closure | ||
305 | * @param available #GNUNET_YES if sending is now possible, | ||
306 | * #GNUNET_NO if sending is no longer possible | ||
307 | * #GNUNET_SYSERR if sending is no longer possible | ||
308 | * and the last envelope was discarded | ||
309 | */ | ||
310 | typedef void | ||
311 | (*GCP_MessageQueueNotificationCallback)(void *cls, | ||
312 | int available); | ||
313 | |||
314 | |||
315 | /** | ||
316 | * Start message queue change notifications. Will create a new slot | ||
317 | * to manage the message queue to the given @a cp. | ||
318 | * | ||
319 | * @param cp peer to notify for | ||
320 | * @param cb function to call if mq becomes available or unavailable | ||
321 | * @param cb_cls closure for @a cb | ||
322 | * @return handle to cancel request | ||
323 | */ | ||
324 | struct GCP_MessageQueueManager * | ||
325 | GCP_request_mq (struct CadetPeer *cp, | ||
326 | GCP_MessageQueueNotificationCallback cb, | ||
327 | void *cb_cls); | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Test if @a cp has a core-level connection | ||
332 | * | ||
333 | * @param cp peer to test | ||
334 | * @return #GNUNET_YES if @a cp has a core-level connection | ||
335 | */ | ||
336 | int | ||
337 | GCP_has_core_connection (struct CadetPeer *cp); | ||
338 | |||
339 | |||
340 | /** | ||
341 | * Send the message in @a env via a @a mqm. Must only be called at | ||
342 | * most once after the respective | ||
343 | * #GCP_MessageQueueNotificationCallback was called with `available` | ||
344 | * set to #GNUNET_YES, and not after the callback was called with | ||
345 | * `available` set to #GNUNET_NO or #GNUNET_SYSERR. | ||
346 | * | ||
347 | * @param mqm message queue manager for the transmission | ||
348 | * @param env envelope with the message to send; must NOT | ||
349 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
350 | */ | ||
351 | void | ||
352 | GCP_send (struct GCP_MessageQueueManager *mqm, | ||
353 | struct GNUNET_MQ_Envelope *env); | ||
354 | |||
355 | |||
356 | /** | ||
357 | * Send the message in @a env to @a cp, overriding queueing logic. | ||
358 | * This function should only be used to send error messages outside | ||
359 | * of flow and congestion control, similar to ICMP. Note that | ||
360 | * the envelope may be silently discarded as well. | ||
361 | * | ||
362 | * @param cp peer to send the message to | ||
363 | * @param env envelope with the message to send | ||
364 | */ | ||
365 | void | ||
366 | GCP_send_ooo (struct CadetPeer *cp, | ||
367 | struct GNUNET_MQ_Envelope *env); | ||
368 | |||
369 | |||
370 | /** | ||
371 | * Stops message queue change notifications and sends a last message. | ||
372 | * In practice, this is implemented by sending that @a last_env | ||
373 | * message immediately (if any), ignoring queue order. | ||
374 | * | ||
375 | * @param mqm handle matching request to cancel | ||
376 | * @param last_env final message to transmit, or NULL | ||
377 | */ | ||
378 | void | ||
379 | GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm, | ||
380 | struct GNUNET_MQ_Envelope *last_env); | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Set the message queue to @a mq for peer @a cp and notify watchers. | ||
385 | * | ||
386 | * @param cp peer to modify | ||
387 | * @param mq message queue to set (can be NULL) | ||
388 | */ | ||
389 | void | ||
390 | GCP_set_mq (struct CadetPeer *cp, | ||
391 | struct GNUNET_MQ_Handle *mq); | ||
392 | |||
393 | |||
394 | #endif | ||
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c index 3a07f0ee5..a7e1fca47 100644 --- a/src/cadet/gnunet-service-cadet.c +++ b/src/cadet/gnunet-service-cadet.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2001-2013 GNUnet e.V. | 3 | Copyright (C) 2001-2013, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -22,38 +22,82 @@ | |||
22 | * @file cadet/gnunet-service-cadet.c | 22 | * @file cadet/gnunet-service-cadet.c |
23 | * @brief GNUnet CADET service with encryption | 23 | * @brief GNUnet CADET service with encryption |
24 | * @author Bartlomiej Polot | 24 | * @author Bartlomiej Polot |
25 | * | 25 | * @author Christian Grothoff |
26 | * FIXME in progress: | ||
27 | * - rekey - reliability interaction | ||
28 | * - channel retransmit timing | ||
29 | * | ||
30 | * TODO: | ||
31 | * - relay corking down to core | ||
32 | * - set ttl relative to path length | ||
33 | * TODO END | ||
34 | * | 26 | * |
35 | * Dictionary: | 27 | * Dictionary: |
36 | * - peer: other cadet instance. If there is direct connection it's a neighbor. | 28 | * - peer: other cadet instance. If there is direct connection it's a neighbor. |
37 | * - tunnel: encrypted connection to a peer, neighbor or not. | ||
38 | * - channel: connection between two clients, on the same or different peers. | ||
39 | * have properties like reliability. | ||
40 | * - path: series of directly connected peer from one peer to another. | 29 | * - path: series of directly connected peer from one peer to another. |
41 | * - connection: path which is being used in a tunnel. | 30 | * - connection: path which is being used in a tunnel. |
31 | * - tunnel: encrypted connection to a peer, neighbor or not. | ||
32 | * - channel: logical link between two clients, on the same or different peers. | ||
33 | * have properties like reliability. | ||
42 | */ | 34 | */ |
43 | 35 | ||
44 | #include "platform.h" | 36 | #include "platform.h" |
45 | #include "gnunet_util_lib.h" | 37 | #include "gnunet_util_lib.h" |
46 | #include "cadet.h" | 38 | #include "cadet.h" |
47 | #include "gnunet_statistics_service.h" | 39 | #include "gnunet_statistics_service.h" |
48 | 40 | #include "gnunet-service-cadet.h" | |
49 | #include "gnunet-service-cadet_local.h" | ||
50 | #include "gnunet-service-cadet_channel.h" | 41 | #include "gnunet-service-cadet_channel.h" |
51 | #include "gnunet-service-cadet_connection.h" | 42 | #include "gnunet-service-cadet_connection.h" |
52 | #include "gnunet-service-cadet_tunnel.h" | 43 | #include "gnunet-service-cadet_core.h" |
53 | #include "gnunet-service-cadet_dht.h" | 44 | #include "gnunet-service-cadet_dht.h" |
54 | #include "gnunet-service-cadet_peer.h" | ||
55 | #include "gnunet-service-cadet_hello.h" | 45 | #include "gnunet-service-cadet_hello.h" |
46 | #include "gnunet-service-cadet_tunnels.h" | ||
47 | #include "gnunet-service-cadet_peer.h" | ||
48 | #include "gnunet-service-cadet_paths.h" | ||
49 | |||
50 | #define LOG(level, ...) GNUNET_log (level,__VA_ARGS__) | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Struct containing information about a client of the service | ||
55 | */ | ||
56 | struct CadetClient | ||
57 | { | ||
58 | /** | ||
59 | * Linked list next | ||
60 | */ | ||
61 | struct CadetClient *next; | ||
62 | |||
63 | /** | ||
64 | * Linked list prev | ||
65 | */ | ||
66 | struct CadetClient *prev; | ||
67 | |||
68 | /** | ||
69 | * Tunnels that belong to this client, indexed by local id, | ||
70 | * value is a `struct CadetChannel`. | ||
71 | */ | ||
72 | struct GNUNET_CONTAINER_MultiHashMap32 *channels; | ||
73 | |||
74 | /** | ||
75 | * Handle to communicate with the client | ||
76 | */ | ||
77 | struct GNUNET_MQ_Handle *mq; | ||
78 | |||
79 | /** | ||
80 | * Client handle. | ||
81 | */ | ||
82 | struct GNUNET_SERVICE_Client *client; | ||
83 | |||
84 | /** | ||
85 | * Ports that this client has declared interest in. | ||
86 | * Indexed by port, contains *Client. | ||
87 | */ | ||
88 | struct GNUNET_CONTAINER_MultiHashMap *ports; | ||
56 | 89 | ||
90 | /** | ||
91 | * Channel ID to use for the next incoming channel for this client. | ||
92 | * Wraps around (in theory). | ||
93 | */ | ||
94 | struct GNUNET_CADET_ClientChannelNumber next_ccn; | ||
95 | |||
96 | /** | ||
97 | * ID of the client, mainly for debug messages. Purely internal to this file. | ||
98 | */ | ||
99 | unsigned int id; | ||
100 | }; | ||
57 | 101 | ||
58 | /******************************************************************************/ | 102 | /******************************************************************************/ |
59 | /*********************** GLOBAL VARIABLES ****************************/ | 103 | /*********************** GLOBAL VARIABLES ****************************/ |
@@ -62,37 +106,317 @@ | |||
62 | /****************************** Global variables ******************************/ | 106 | /****************************** Global variables ******************************/ |
63 | 107 | ||
64 | /** | 108 | /** |
109 | * Handle to our configuration. | ||
110 | */ | ||
111 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
112 | |||
113 | /** | ||
65 | * Handle to the statistics service. | 114 | * Handle to the statistics service. |
66 | */ | 115 | */ |
67 | struct GNUNET_STATISTICS_Handle *stats; | 116 | struct GNUNET_STATISTICS_Handle *stats; |
68 | 117 | ||
69 | /** | 118 | /** |
70 | * Local peer own ID (memory efficient handle). | 119 | * Handle to communicate with ATS. |
71 | */ | 120 | */ |
72 | GNUNET_PEER_Id myid; | 121 | struct GNUNET_ATS_ConnectivityHandle *ats_ch; |
73 | 122 | ||
74 | /** | 123 | /** |
75 | * Local peer own ID (full value). | 124 | * Local peer own ID. |
76 | */ | 125 | */ |
77 | struct GNUNET_PeerIdentity my_full_id; | 126 | struct GNUNET_PeerIdentity my_full_id; |
78 | 127 | ||
128 | /** | ||
129 | * Own private key. | ||
130 | */ | ||
131 | struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; | ||
79 | 132 | ||
80 | /** | 133 | /** |
81 | * Signal that shutdown is happening: prevent recover measures. | 134 | * Signal that shutdown is happening: prevent recovery measures. |
82 | */ | 135 | */ |
83 | int shutting_down; | 136 | int shutting_down; |
84 | 137 | ||
85 | /*************************** Static global variables **************************/ | 138 | /** |
139 | * DLL with all the clients, head. | ||
140 | */ | ||
141 | static struct CadetClient *clients_head; | ||
86 | 142 | ||
87 | /** | 143 | /** |
88 | * Own private key. | 144 | * DLL with all the clients, tail. |
89 | */ | 145 | */ |
90 | static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; | 146 | static struct CadetClient *clients_tail; |
91 | 147 | ||
148 | /** | ||
149 | * Next ID to assign to a client. | ||
150 | */ | ||
151 | static unsigned int next_client_id; | ||
152 | |||
153 | /** | ||
154 | * All ports clients of this peer have opened. | ||
155 | */ | ||
156 | struct GNUNET_CONTAINER_MultiHashMap *open_ports; | ||
157 | |||
158 | /** | ||
159 | * Map from ports to channels where the ports were closed at the | ||
160 | * time we got the inbound connection. | ||
161 | * Indexed by port, contains `struct CadetChannel`. | ||
162 | */ | ||
163 | struct GNUNET_CONTAINER_MultiHashMap *loose_channels; | ||
164 | |||
165 | /** | ||
166 | * Map from PIDs to `struct CadetPeer` entries. | ||
167 | */ | ||
168 | struct GNUNET_CONTAINER_MultiPeerMap *peers; | ||
169 | |||
170 | /** | ||
171 | * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier` | ||
172 | * hash codes to `struct CadetConnection` objects. | ||
173 | */ | ||
174 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
175 | |||
176 | /** | ||
177 | * How many messages are needed to trigger an AXOLOTL ratchet advance. | ||
178 | */ | ||
179 | unsigned long long ratchet_messages; | ||
180 | |||
181 | /** | ||
182 | * How long until we trigger a ratched advance due to time. | ||
183 | */ | ||
184 | struct GNUNET_TIME_Relative ratchet_time; | ||
185 | |||
186 | /** | ||
187 | * How frequently do we send KEEPALIVE messages on idle connections? | ||
188 | */ | ||
189 | struct GNUNET_TIME_Relative keepalive_period; | ||
190 | |||
191 | /** | ||
192 | * Set to non-zero values to create random drops to test retransmissions. | ||
193 | */ | ||
194 | unsigned long long drop_percent; | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Send a message to a client. | ||
199 | * | ||
200 | * @param c client to get the message | ||
201 | * @param env envelope with the message | ||
202 | */ | ||
203 | void | ||
204 | GSC_send_to_client (struct CadetClient *c, | ||
205 | struct GNUNET_MQ_Envelope *env) | ||
206 | { | ||
207 | GNUNET_MQ_send (c->mq, | ||
208 | env); | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Return identifier for a client as a string. | ||
214 | * | ||
215 | * @param c client to identify | ||
216 | * @return string for debugging | ||
217 | */ | ||
218 | const char * | ||
219 | GSC_2s (struct CadetClient *c) | ||
220 | { | ||
221 | static char buf[32]; | ||
222 | |||
223 | GNUNET_snprintf (buf, | ||
224 | sizeof (buf), | ||
225 | "Client(%u)", | ||
226 | c->id); | ||
227 | return buf; | ||
228 | } | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Lookup channel of client @a c by @a ccn. | ||
233 | * | ||
234 | * @param c client to look in | ||
235 | * @param ccn channel ID to look up | ||
236 | * @return NULL if no such channel exists | ||
237 | */ | ||
238 | static struct CadetChannel * | ||
239 | lookup_channel (struct CadetClient *c, | ||
240 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
241 | { | ||
242 | return GNUNET_CONTAINER_multihashmap32_get (c->channels, | ||
243 | ntohl (ccn.channel_of_client)); | ||
244 | } | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Obtain the next LID to use for incoming connections to | ||
249 | * the given client. | ||
250 | * | ||
251 | * @param c client handle | ||
252 | */ | ||
253 | static struct GNUNET_CADET_ClientChannelNumber | ||
254 | client_get_next_ccn (struct CadetClient *c) | ||
255 | { | ||
256 | struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn; | ||
257 | |||
258 | /* increment until we have a free one... */ | ||
259 | while (NULL != | ||
260 | lookup_channel (c, | ||
261 | ccn)) | ||
262 | { | ||
263 | ccn.channel_of_client | ||
264 | = htonl (1 + (ntohl (ccn.channel_of_client))); | ||
265 | if (ntohl (ccn.channel_of_client) >= | ||
266 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
267 | ccn.channel_of_client = htonl (0); | ||
268 | } | ||
269 | c->next_ccn.channel_of_client | ||
270 | = htonl (1 + (ntohl (ccn.channel_of_client))); | ||
271 | return ccn; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Bind incoming channel to this client, and notify client about | ||
277 | * incoming connection. Caller is responsible for notifying the other | ||
278 | * peer about our acceptance of the channel. | ||
279 | * | ||
280 | * @param c client to bind to | ||
281 | * @param ch channel to be bound | ||
282 | * @param dest peer that establishes the connection | ||
283 | * @param port port number | ||
284 | * @param options options | ||
285 | * @return local channel number assigned to the new client | ||
286 | */ | ||
287 | struct GNUNET_CADET_ClientChannelNumber | ||
288 | GSC_bind (struct CadetClient *c, | ||
289 | struct CadetChannel *ch, | ||
290 | struct CadetPeer *dest, | ||
291 | const struct GNUNET_HashCode *port, | ||
292 | uint32_t options) | ||
293 | { | ||
294 | struct GNUNET_MQ_Envelope *env; | ||
295 | struct GNUNET_CADET_LocalChannelCreateMessage *cm; | ||
296 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
297 | |||
298 | ccn = client_get_next_ccn (c); | ||
299 | GNUNET_assert (GNUNET_YES == | ||
300 | GNUNET_CONTAINER_multihashmap32_put (c->channels, | ||
301 | ntohl (ccn.channel_of_client), | ||
302 | ch, | ||
303 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
304 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
305 | "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n", | ||
306 | GCCH_2s (ch), | ||
307 | GCP_2s (dest), | ||
308 | GNUNET_h2s (port), | ||
309 | (uint32_t) ntohl (options), | ||
310 | (uint32_t) ntohl (ccn.channel_of_client)); | ||
311 | /* notify local client about incoming connection! */ | ||
312 | env = GNUNET_MQ_msg (cm, | ||
313 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE); | ||
314 | cm->ccn = ccn; | ||
315 | cm->port = *port; | ||
316 | cm->opt = htonl (options); | ||
317 | cm->peer = *GCP_get_id (dest); | ||
318 | GSC_send_to_client (c, | ||
319 | env); | ||
320 | return ccn; | ||
321 | } | ||
322 | |||
323 | |||
324 | /** | ||
325 | * Callback invoked on all peers to destroy all tunnels | ||
326 | * that may still exist. | ||
327 | * | ||
328 | * @param cls NULL | ||
329 | * @param pid identify of a peer | ||
330 | * @param value a `struct CadetPeer` that may still have a tunnel | ||
331 | * @return #GNUNET_OK (iterate over all entries) | ||
332 | */ | ||
333 | static int | ||
334 | destroy_tunnels_now (void *cls, | ||
335 | const struct GNUNET_PeerIdentity *pid, | ||
336 | void *value) | ||
337 | { | ||
338 | struct CadetPeer *cp = value; | ||
339 | struct CadetTunnel *t = GCP_get_tunnel (cp, | ||
340 | GNUNET_NO); | ||
341 | |||
342 | if (NULL != t) | ||
343 | GCT_destroy_tunnel_now (t); | ||
344 | return GNUNET_OK; | ||
345 | } | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Callback invoked on all peers to destroy all tunnels | ||
350 | * that may still exist. | ||
351 | * | ||
352 | * @param cls NULL | ||
353 | * @param pid identify of a peer | ||
354 | * @param value a `struct CadetPeer` that may still have a tunnel | ||
355 | * @return #GNUNET_OK (iterate over all entries) | ||
356 | */ | ||
357 | static int | ||
358 | destroy_paths_now (void *cls, | ||
359 | const struct GNUNET_PeerIdentity *pid, | ||
360 | void *value) | ||
361 | { | ||
362 | struct CadetPeer *cp = value; | ||
363 | |||
364 | GCP_drop_owned_paths (cp); | ||
365 | return GNUNET_OK; | ||
366 | } | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Shutdown everything once the clients have disconnected. | ||
371 | */ | ||
372 | static void | ||
373 | shutdown_rest () | ||
374 | { | ||
375 | if (NULL != stats) | ||
376 | { | ||
377 | GNUNET_STATISTICS_destroy (stats, | ||
378 | GNUNET_NO); | ||
379 | stats = NULL; | ||
380 | } | ||
381 | if (NULL != open_ports) | ||
382 | { | ||
383 | GNUNET_CONTAINER_multihashmap_destroy (open_ports); | ||
384 | open_ports = NULL; | ||
385 | } | ||
386 | if (NULL != loose_channels) | ||
387 | { | ||
388 | GNUNET_CONTAINER_multihashmap_destroy (loose_channels); | ||
389 | loose_channels = NULL; | ||
390 | } | ||
391 | /* Destroy tunnels. Note that all channels must be destroyed first! */ | ||
392 | GCP_iterate_all (&destroy_tunnels_now, | ||
393 | NULL); | ||
394 | /* All tunnels, channels, connections and CORE must be down before this point. */ | ||
395 | GCP_iterate_all (&destroy_paths_now, | ||
396 | NULL); | ||
397 | /* All paths, tunnels, channels, connections and CORE must be down before this point. */ | ||
398 | GCP_destroy_all_peers (); | ||
399 | if (NULL != peers) | ||
400 | { | ||
401 | GNUNET_CONTAINER_multipeermap_destroy (peers); | ||
402 | peers = NULL; | ||
403 | } | ||
404 | if (NULL != connections) | ||
405 | { | ||
406 | GNUNET_CONTAINER_multishortmap_destroy (connections); | ||
407 | connections = NULL; | ||
408 | } | ||
409 | if (NULL != ats_ch) | ||
410 | { | ||
411 | GNUNET_ATS_connectivity_done (ats_ch); | ||
412 | ats_ch = NULL; | ||
413 | } | ||
414 | GCD_shutdown (); | ||
415 | GCH_shutdown (); | ||
416 | GNUNET_free_non_null (my_private_key); | ||
417 | my_private_key = NULL; | ||
418 | } | ||
92 | 419 | ||
93 | /******************************************************************************/ | ||
94 | /************************ MAIN FUNCTIONS ****************************/ | ||
95 | /******************************************************************************/ | ||
96 | 420 | ||
97 | /** | 421 | /** |
98 | * Task run during shutdown. | 422 | * Task run during shutdown. |
@@ -102,83 +426,1071 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; | |||
102 | static void | 426 | static void |
103 | shutdown_task (void *cls) | 427 | shutdown_task (void *cls) |
104 | { | 428 | { |
105 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); | 429 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
106 | 430 | "Shutting down\n"); | |
107 | shutting_down = GNUNET_YES; | 431 | shutting_down = GNUNET_YES; |
432 | GCO_shutdown (); | ||
433 | if (NULL == clients_head) | ||
434 | shutdown_rest (); | ||
435 | } | ||
108 | 436 | ||
109 | GML_shutdown (); | ||
110 | GCH_shutdown (); | ||
111 | GCC_shutdown (); | ||
112 | GCT_shutdown (); | ||
113 | GCD_shutdown (); | ||
114 | GCP_shutdown (); | ||
115 | 437 | ||
116 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | 438 | /** |
117 | stats = NULL; | 439 | * We had a remote connection @a value to port @a port before |
118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); | 440 | * client @a cls opened port @a port. Bind them now. |
441 | * | ||
442 | * @param cls the `struct CadetClient` | ||
443 | * @param port the port | ||
444 | * @param value the `struct CadetChannel` | ||
445 | * @return #GNUNET_YES (iterate over all such channels) | ||
446 | */ | ||
447 | static int | ||
448 | bind_loose_channel (void *cls, | ||
449 | const struct GNUNET_HashCode *port, | ||
450 | void *value) | ||
451 | { | ||
452 | struct CadetClient *c = cls; | ||
453 | struct CadetChannel *ch = value; | ||
454 | |||
455 | GCCH_bind (ch, | ||
456 | c); | ||
457 | GNUNET_assert (GNUNET_YES == | ||
458 | GNUNET_CONTAINER_multihashmap_remove (loose_channels, | ||
459 | port, | ||
460 | value)); | ||
461 | return GNUNET_YES; | ||
119 | } | 462 | } |
120 | 463 | ||
121 | 464 | ||
122 | /** | 465 | /** |
123 | * Process cadet requests. | 466 | * Handle port open request. Creates a mapping from the |
467 | * port to the respective client and checks whether we have | ||
468 | * loose channels trying to bind to the port. If so, those | ||
469 | * are bound. | ||
124 | * | 470 | * |
125 | * @param cls closure | 471 | * @param cls Identification of the client. |
126 | * @param server the initialized server | 472 | * @param pmsg The actual message. |
127 | * @param c configuration to use | ||
128 | */ | 473 | */ |
129 | static void | 474 | static void |
130 | run (void *cls, struct GNUNET_SERVER_Handle *server, | 475 | handle_port_open (void *cls, |
131 | const struct GNUNET_CONFIGURATION_Handle *c) | 476 | const struct GNUNET_CADET_PortMessage *pmsg) |
132 | { | 477 | { |
133 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); | 478 | struct CadetClient *c = cls; |
134 | 479 | ||
135 | stats = GNUNET_STATISTICS_create ("cadet", c); | 480 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
481 | "Open port %s requested by %s\n", | ||
482 | GNUNET_h2s (&pmsg->port), | ||
483 | GSC_2s (c)); | ||
484 | if (NULL == c->ports) | ||
485 | c->ports = GNUNET_CONTAINER_multihashmap_create (4, | ||
486 | GNUNET_NO); | ||
487 | if (GNUNET_OK != | ||
488 | GNUNET_CONTAINER_multihashmap_put (c->ports, | ||
489 | &pmsg->port, | ||
490 | c, | ||
491 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
492 | { | ||
493 | GNUNET_break (0); | ||
494 | GNUNET_SERVICE_client_drop (c->client); | ||
495 | return; | ||
496 | } | ||
497 | (void) GNUNET_CONTAINER_multihashmap_put (open_ports, | ||
498 | &pmsg->port, | ||
499 | c, | ||
500 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
501 | GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels, | ||
502 | &pmsg->port, | ||
503 | &bind_loose_channel, | ||
504 | c); | ||
505 | GNUNET_SERVICE_client_continue (c->client); | ||
506 | } | ||
136 | 507 | ||
137 | /* Scheduled the task to clean up when shutdown is called */ | ||
138 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
139 | NULL); | ||
140 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n"); | ||
141 | my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); | ||
142 | GNUNET_assert (NULL != my_private_key); | ||
143 | GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key); | ||
144 | myid = GNUNET_PEER_intern (&my_full_id); | ||
145 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
146 | "STARTING SERVICE (cadet) for peer [%s]\n", | ||
147 | GNUNET_i2s (&my_full_id)); | ||
148 | 508 | ||
149 | GML_init (server); /* Local clients */ | 509 | /** |
150 | GCH_init (c); /* Hellos */ | 510 | * Handler for port close requests. Marks this port as closed |
151 | GCC_init (c); /* Connections */ | 511 | * (unless of course we have another client with the same port |
152 | GCP_init (c); /* Peers */ | 512 | * open). Note that existing channels accepted on the port are |
153 | GCD_init (c); /* DHT */ | 513 | * not affected. |
154 | GCT_init (c, my_private_key); /* Tunnels */ | 514 | * |
515 | * @param cls Identification of the client. | ||
516 | * @param pmsg The actual message. | ||
517 | */ | ||
518 | static void | ||
519 | handle_port_close (void *cls, | ||
520 | const struct GNUNET_CADET_PortMessage *pmsg) | ||
521 | { | ||
522 | struct CadetClient *c = cls; | ||
155 | 523 | ||
156 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); | 524 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
525 | "Closing port %s as requested by %s\n", | ||
526 | GNUNET_h2s (&pmsg->port), | ||
527 | GSC_2s (c)); | ||
528 | if (GNUNET_YES != | ||
529 | GNUNET_CONTAINER_multihashmap_remove (c->ports, | ||
530 | &pmsg->port, | ||
531 | c)) | ||
532 | { | ||
533 | GNUNET_break (0); | ||
534 | GNUNET_SERVICE_client_drop (c->client); | ||
535 | return; | ||
536 | } | ||
537 | GNUNET_assert (GNUNET_YES == | ||
538 | GNUNET_CONTAINER_multihashmap_remove (open_ports, | ||
539 | &pmsg->port, | ||
540 | c)); | ||
541 | GNUNET_SERVICE_client_continue (c->client); | ||
157 | } | 542 | } |
158 | 543 | ||
159 | 544 | ||
160 | /** | 545 | /** |
161 | * The main function for the cadet service. | 546 | * Handler for requests for us creating a new channel to another peer and port. |
162 | * | 547 | * |
163 | * @param argc number of arguments from the command line | 548 | * @param cls Identification of the client. |
164 | * @param argv command line arguments | 549 | * @param tcm The actual message. |
165 | * @return 0 ok, 1 on error | ||
166 | */ | 550 | */ |
167 | int | 551 | static void |
168 | main (int argc, char *const *argv) | 552 | handle_channel_create (void *cls, |
553 | const struct GNUNET_CADET_LocalChannelCreateMessage *tcm) | ||
169 | { | 554 | { |
170 | int r; | 555 | struct CadetClient *c = cls; |
556 | struct CadetChannel *ch; | ||
171 | 557 | ||
172 | shutting_down = GNUNET_NO; | 558 | if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) |
173 | r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run, | 559 | { |
174 | NULL); | 560 | /* Channel ID not in allowed range. */ |
175 | GNUNET_free (my_private_key); | 561 | GNUNET_break (0); |
562 | GNUNET_SERVICE_client_drop (c->client); | ||
563 | return; | ||
564 | } | ||
565 | ch = lookup_channel (c, | ||
566 | tcm->ccn); | ||
567 | if (NULL != ch) | ||
568 | { | ||
569 | /* Channel ID already in use. Not allowed. */ | ||
570 | GNUNET_break (0); | ||
571 | GNUNET_SERVICE_client_drop (c->client); | ||
572 | return; | ||
573 | } | ||
574 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
575 | "New channel to %s at port %s requested by %s\n", | ||
576 | GNUNET_i2s (&tcm->peer), | ||
577 | GNUNET_h2s (&tcm->port), | ||
578 | GSC_2s (c)); | ||
176 | 579 | ||
177 | if (GNUNET_OK != r) | 580 | /* Create channel */ |
581 | ch = GCCH_channel_local_new (c, | ||
582 | tcm->ccn, | ||
583 | GCP_get (&tcm->peer, | ||
584 | GNUNET_YES), | ||
585 | &tcm->port, | ||
586 | ntohl (tcm->opt)); | ||
587 | if (NULL == ch) | ||
178 | { | 588 | { |
179 | FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n"); | 589 | GNUNET_break (0); |
180 | return 1; | 590 | GNUNET_SERVICE_client_drop (c->client); |
591 | return; | ||
181 | } | 592 | } |
593 | GNUNET_assert (GNUNET_YES == | ||
594 | GNUNET_CONTAINER_multihashmap32_put (c->channels, | ||
595 | ntohl (tcm->ccn.channel_of_client), | ||
596 | ch, | ||
597 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
182 | 598 | ||
183 | return 0; | 599 | GNUNET_SERVICE_client_continue (c->client); |
184 | } | 600 | } |
601 | |||
602 | |||
603 | /** | ||
604 | * Handler for requests of destroying an existing channel. | ||
605 | * | ||
606 | * @param cls client identification of the client | ||
607 | * @param msg the actual message | ||
608 | */ | ||
609 | static void | ||
610 | handle_channel_destroy (void *cls, | ||
611 | const struct GNUNET_CADET_LocalChannelDestroyMessage *msg) | ||
612 | { | ||
613 | struct CadetClient *c = cls; | ||
614 | struct CadetChannel *ch; | ||
615 | |||
616 | ch = lookup_channel (c, | ||
617 | msg->ccn); | ||
618 | if (NULL == ch) | ||
619 | { | ||
620 | /* Client attempted to destroy unknown channel. | ||
621 | Can happen if the other side went down at the same time.*/ | ||
622 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
623 | "%s tried to destroy unknown channel %X\n", | ||
624 | GSC_2s(c), | ||
625 | (uint32_t) ntohl (msg->ccn.channel_of_client)); | ||
626 | return; | ||
627 | } | ||
628 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
629 | "%s is destroying %s\n", | ||
630 | GSC_2s(c), | ||
631 | GCCH_2s (ch)); | ||
632 | GNUNET_assert (GNUNET_YES == | ||
633 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
634 | ntohl (msg->ccn.channel_of_client), | ||
635 | ch)); | ||
636 | GCCH_channel_local_destroy (ch, | ||
637 | c, | ||
638 | msg->ccn); | ||
639 | GNUNET_SERVICE_client_continue (c->client); | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Check for client traffic data message is well-formed. | ||
645 | * | ||
646 | * @param cls identification of the client | ||
647 | * @param msg the actual message | ||
648 | * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not | ||
649 | */ | ||
650 | static int | ||
651 | check_local_data (void *cls, | ||
652 | const struct GNUNET_CADET_LocalData *msg) | ||
653 | { | ||
654 | size_t payload_size; | ||
655 | size_t payload_claimed_size; | ||
656 | const char *buf; | ||
657 | struct GNUNET_MessageHeader pa; | ||
658 | |||
659 | /* FIXME: what is the format we shall allow for @a msg? | ||
660 | ONE payload item or multiple? Seems current cadet_api | ||
661 | at least in theory allows more than one. Next-gen | ||
662 | cadet_api will likely no more, so we could then | ||
663 | simplify this mess again. */ | ||
664 | /* Sanity check for message size */ | ||
665 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
666 | buf = (const char *) &msg[1]; | ||
667 | while (payload_size >= sizeof (struct GNUNET_MessageHeader)) | ||
668 | { | ||
669 | /* need to memcpy() for alignment */ | ||
670 | GNUNET_memcpy (&pa, | ||
671 | buf, | ||
672 | sizeof (pa)); | ||
673 | payload_claimed_size = ntohs (pa.size); | ||
674 | if ( (payload_size < payload_claimed_size) || | ||
675 | (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) || | ||
676 | (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) ) | ||
677 | { | ||
678 | GNUNET_break (0); | ||
679 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
680 | "Local data of %u total size had sub-message %u at %u with %u bytes\n", | ||
681 | ntohs (msg->header.size), | ||
682 | ntohs (pa.type), | ||
683 | (unsigned int) (buf - (const char *) &msg[1]), | ||
684 | (unsigned int) payload_claimed_size); | ||
685 | return GNUNET_SYSERR; | ||
686 | } | ||
687 | payload_size -= payload_claimed_size; | ||
688 | buf += payload_claimed_size; | ||
689 | } | ||
690 | if (0 != payload_size) | ||
691 | { | ||
692 | GNUNET_break_op (0); | ||
693 | return GNUNET_SYSERR; | ||
694 | } | ||
695 | return GNUNET_OK; | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * Handler for client payload traffic to be send on a channel to | ||
701 | * another peer. | ||
702 | * | ||
703 | * @param cls identification of the client | ||
704 | * @param msg the actual message | ||
705 | */ | ||
706 | static void | ||
707 | handle_local_data (void *cls, | ||
708 | const struct GNUNET_CADET_LocalData *msg) | ||
709 | { | ||
710 | struct CadetClient *c = cls; | ||
711 | struct CadetChannel *ch; | ||
712 | size_t payload_size; | ||
713 | const char *buf; | ||
714 | |||
715 | ch = lookup_channel (c, | ||
716 | msg->ccn); | ||
717 | if (NULL == ch) | ||
718 | { | ||
719 | /* Channel does not exist (anymore) */ | ||
720 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
721 | "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n", | ||
722 | (unsigned int) ntohl (msg->ccn.channel_of_client)); | ||
723 | GNUNET_SERVICE_client_continue (c->client); | ||
724 | return; | ||
725 | } | ||
726 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
727 | GNUNET_STATISTICS_update (stats, | ||
728 | "# payload received from clients", | ||
729 | payload_size, | ||
730 | GNUNET_NO); | ||
731 | buf = (const char *) &msg[1]; | ||
732 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
733 | "Received %u bytes payload from %s for %s\n", | ||
734 | (unsigned int) payload_size, | ||
735 | GSC_2s (c), | ||
736 | GCCH_2s (ch)); | ||
737 | if (GNUNET_OK != | ||
738 | GCCH_handle_local_data (ch, | ||
739 | msg->ccn, | ||
740 | buf, | ||
741 | payload_size)) | ||
742 | { | ||
743 | GNUNET_SERVICE_client_drop (c->client); | ||
744 | return; | ||
745 | } | ||
746 | GNUNET_SERVICE_client_continue (c->client); | ||
747 | } | ||
748 | |||
749 | |||
750 | /** | ||
751 | * Handler for client's ACKs for payload traffic. | ||
752 | * | ||
753 | * @param cls identification of the client. | ||
754 | * @param msg The actual message. | ||
755 | */ | ||
756 | static void | ||
757 | handle_local_ack (void *cls, | ||
758 | const struct GNUNET_CADET_LocalAck *msg) | ||
759 | { | ||
760 | struct CadetClient *c = cls; | ||
761 | struct CadetChannel *ch; | ||
762 | |||
763 | ch = lookup_channel (c, | ||
764 | msg->ccn); | ||
765 | if (NULL == ch) | ||
766 | { | ||
767 | /* Channel does not exist (anymore) */ | ||
768 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
769 | "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n", | ||
770 | (unsigned int) ntohl (msg->ccn.channel_of_client)); | ||
771 | GNUNET_SERVICE_client_continue (c->client); | ||
772 | return; | ||
773 | } | ||
774 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
775 | "Got a local ACK from %s for %s\n", | ||
776 | GSC_2s(c), | ||
777 | GCCH_2s (ch)); | ||
778 | GCCH_handle_local_ack (ch, | ||
779 | msg->ccn); | ||
780 | GNUNET_SERVICE_client_continue (c->client); | ||
781 | } | ||
782 | |||
783 | |||
784 | /** | ||
785 | * Iterator over all peers to send a monitoring client info about each peer. | ||
786 | * | ||
787 | * @param cls Closure (). | ||
788 | * @param peer Peer ID (tunnel remote peer). | ||
789 | * @param value Peer info. | ||
790 | * @return #GNUNET_YES, to keep iterating. | ||
791 | */ | ||
792 | static int | ||
793 | get_all_peers_iterator (void *cls, | ||
794 | const struct GNUNET_PeerIdentity *peer, | ||
795 | void *value) | ||
796 | { | ||
797 | struct CadetClient *c = cls; | ||
798 | struct CadetPeer *p = value; | ||
799 | struct GNUNET_MQ_Envelope *env; | ||
800 | struct GNUNET_CADET_LocalInfoPeer *msg; | ||
801 | |||
802 | env = GNUNET_MQ_msg (msg, | ||
803 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
804 | msg->destination = *peer; | ||
805 | msg->paths = htons (GCP_count_paths (p)); | ||
806 | msg->tunnel = htons (NULL != GCP_get_tunnel (p, | ||
807 | GNUNET_NO)); | ||
808 | GNUNET_MQ_send (c->mq, | ||
809 | env); | ||
810 | return GNUNET_YES; | ||
811 | } | ||
812 | |||
813 | |||
814 | /** | ||
815 | * Handler for client's INFO PEERS request. | ||
816 | * | ||
817 | * @param cls Identification of the client. | ||
818 | * @param message The actual message. | ||
819 | */ | ||
820 | static void | ||
821 | handle_get_peers (void *cls, | ||
822 | const struct GNUNET_MessageHeader *message) | ||
823 | { | ||
824 | struct CadetClient *c = cls; | ||
825 | struct GNUNET_MQ_Envelope *env; | ||
826 | struct GNUNET_MessageHeader *reply; | ||
827 | |||
828 | GCP_iterate_all (&get_all_peers_iterator, | ||
829 | c); | ||
830 | env = GNUNET_MQ_msg (reply, | ||
831 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
832 | GNUNET_MQ_send (c->mq, | ||
833 | env); | ||
834 | GNUNET_SERVICE_client_continue (c->client); | ||
835 | } | ||
836 | |||
837 | |||
838 | /** | ||
839 | * Iterator over all paths of a peer to build an InfoPeer message. | ||
840 | * Message contains blocks of peers, first not included. | ||
841 | * | ||
842 | * @param cls message queue for transmission | ||
843 | * @param path Path itself | ||
844 | * @param off offset of the peer on @a path | ||
845 | * @return #GNUNET_YES if should keep iterating. | ||
846 | * #GNUNET_NO otherwise. | ||
847 | */ | ||
848 | static int | ||
849 | path_info_iterator (void *cls, | ||
850 | struct CadetPeerPath *path, | ||
851 | unsigned int off) | ||
852 | { | ||
853 | struct GNUNET_MQ_Handle *mq = cls; | ||
854 | struct GNUNET_MQ_Envelope *env; | ||
855 | struct GNUNET_MessageHeader *resp; | ||
856 | struct GNUNET_PeerIdentity *id; | ||
857 | uint16_t path_size; | ||
858 | unsigned int i; | ||
859 | unsigned int path_length; | ||
860 | |||
861 | path_length = GCPP_get_length (path); | ||
862 | path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1); | ||
863 | if (sizeof (*resp) + path_size > UINT16_MAX) | ||
864 | { | ||
865 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
866 | "Path of %u entries is too long for info message\n", | ||
867 | path_length); | ||
868 | return GNUNET_YES; | ||
869 | } | ||
870 | env = GNUNET_MQ_msg_extra (resp, | ||
871 | path_size, | ||
872 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); | ||
873 | id = (struct GNUNET_PeerIdentity *) &resp[1]; | ||
874 | |||
875 | /* Don't copy first peer. First peer is always the local one. Last | ||
876 | * peer is always the destination (leave as 0, EOL). | ||
877 | */ | ||
878 | for (i = 0; i < off; i++) | ||
879 | id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path, | ||
880 | i + 1)); | ||
881 | GNUNET_MQ_send (mq, | ||
882 | env); | ||
883 | return GNUNET_YES; | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Handler for client's SHOW_PEER request. | ||
889 | * | ||
890 | * @param cls Identification of the client. | ||
891 | * @param msg The actual message. | ||
892 | */ | ||
893 | static void | ||
894 | handle_show_peer (void *cls, | ||
895 | const struct GNUNET_CADET_LocalInfo *msg) | ||
896 | { | ||
897 | struct CadetClient *c = cls; | ||
898 | struct CadetPeer *p; | ||
899 | struct GNUNET_MQ_Envelope *env; | ||
900 | struct GNUNET_MessageHeader *resp; | ||
901 | |||
902 | p = GCP_get (&msg->peer, | ||
903 | GNUNET_NO); | ||
904 | if (NULL != p) | ||
905 | GCP_iterate_paths (p, | ||
906 | &path_info_iterator, | ||
907 | c->mq); | ||
908 | /* Send message with 0/0 to indicate the end */ | ||
909 | env = GNUNET_MQ_msg (resp, | ||
910 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END); | ||
911 | GNUNET_MQ_send (c->mq, | ||
912 | env); | ||
913 | GNUNET_SERVICE_client_continue (c->client); | ||
914 | } | ||
915 | |||
916 | |||
917 | /** | ||
918 | * Iterator over all tunnels to send a monitoring client info about each tunnel. | ||
919 | * | ||
920 | * @param cls Closure (). | ||
921 | * @param peer Peer ID (tunnel remote peer). | ||
922 | * @param value a `struct CadetPeer` | ||
923 | * @return #GNUNET_YES, to keep iterating. | ||
924 | */ | ||
925 | static int | ||
926 | get_all_tunnels_iterator (void *cls, | ||
927 | const struct GNUNET_PeerIdentity *peer, | ||
928 | void *value) | ||
929 | { | ||
930 | struct CadetClient *c = cls; | ||
931 | struct CadetPeer *p = value; | ||
932 | struct GNUNET_MQ_Envelope *env; | ||
933 | struct GNUNET_CADET_LocalInfoTunnel *msg; | ||
934 | struct CadetTunnel *t; | ||
935 | |||
936 | t = GCP_get_tunnel (p, | ||
937 | GNUNET_NO); | ||
938 | if (NULL == t) | ||
939 | return GNUNET_YES; | ||
940 | env = GNUNET_MQ_msg (msg, | ||
941 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
942 | msg->destination = *peer; | ||
943 | msg->channels = htonl (GCT_count_channels (t)); | ||
944 | msg->connections = htonl (GCT_count_any_connections (t)); | ||
945 | msg->cstate = htons (0); | ||
946 | msg->estate = htons ((uint16_t) GCT_get_estate (t)); | ||
947 | GNUNET_MQ_send (c->mq, | ||
948 | env); | ||
949 | return GNUNET_YES; | ||
950 | } | ||
951 | |||
952 | |||
953 | /** | ||
954 | * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request. | ||
955 | * | ||
956 | * @param cls client Identification of the client. | ||
957 | * @param message The actual message. | ||
958 | */ | ||
959 | static void | ||
960 | handle_info_tunnels (void *cls, | ||
961 | const struct GNUNET_MessageHeader *message) | ||
962 | { | ||
963 | struct CadetClient *c = cls; | ||
964 | struct GNUNET_MQ_Envelope *env; | ||
965 | struct GNUNET_MessageHeader *reply; | ||
966 | |||
967 | GCP_iterate_all (&get_all_tunnels_iterator, | ||
968 | c); | ||
969 | env = GNUNET_MQ_msg (reply, | ||
970 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
971 | GNUNET_MQ_send (c->mq, | ||
972 | env); | ||
973 | GNUNET_SERVICE_client_continue (c->client); | ||
974 | } | ||
975 | |||
976 | |||
977 | /** | ||
978 | * Update the message with information about the connection. | ||
979 | * | ||
980 | * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update | ||
981 | * @param ct a connection about which we should store information in @a cls | ||
982 | */ | ||
983 | static void | ||
984 | iter_connection (void *cls, | ||
985 | struct CadetTConnection *ct) | ||
986 | { | ||
987 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
988 | struct CadetConnection *cc = ct->cc; | ||
989 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h; | ||
990 | |||
991 | h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
992 | h[msg->connections++] = *(GCC_get_id (cc)); | ||
993 | } | ||
994 | |||
995 | |||
996 | /** | ||
997 | * Update the message with information about the channel. | ||
998 | * | ||
999 | * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update | ||
1000 | * @param ch a channel about which we should store information in @a cls | ||
1001 | */ | ||
1002 | static void | ||
1003 | iter_channel (void *cls, | ||
1004 | struct CadetChannel *ch) | ||
1005 | { | ||
1006 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
1007 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
1008 | struct GNUNET_CADET_ChannelTunnelNumber *chn | ||
1009 | = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections]; | ||
1010 | |||
1011 | chn[msg->channels++] = GCCH_get_id (ch); | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | /** | ||
1016 | * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request. | ||
1017 | * | ||
1018 | * @param cls Identification of the client. | ||
1019 | * @param msg The actual message. | ||
1020 | */ | ||
1021 | static void | ||
1022 | handle_info_tunnel (void *cls, | ||
1023 | const struct GNUNET_CADET_LocalInfo *msg) | ||
1024 | { | ||
1025 | struct CadetClient *c = cls; | ||
1026 | struct GNUNET_MQ_Envelope *env; | ||
1027 | struct GNUNET_CADET_LocalInfoTunnel *resp; | ||
1028 | struct CadetTunnel *t; | ||
1029 | struct CadetPeer *p; | ||
1030 | unsigned int ch_n; | ||
1031 | unsigned int c_n; | ||
1032 | |||
1033 | p = GCP_get (&msg->peer, | ||
1034 | GNUNET_NO); | ||
1035 | t = GCP_get_tunnel (p, | ||
1036 | GNUNET_NO); | ||
1037 | if (NULL == t) | ||
1038 | { | ||
1039 | /* We don't know the tunnel */ | ||
1040 | struct GNUNET_MQ_Envelope *env; | ||
1041 | struct GNUNET_CADET_LocalInfoTunnel *warn; | ||
1042 | |||
1043 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1044 | "Tunnel to %s unknown\n", | ||
1045 | GNUNET_i2s_full (&msg->peer)); | ||
1046 | env = GNUNET_MQ_msg (warn, | ||
1047 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1048 | warn->destination = msg->peer; | ||
1049 | GNUNET_MQ_send (c->mq, | ||
1050 | env); | ||
1051 | GNUNET_SERVICE_client_continue (c->client); | ||
1052 | return; | ||
1053 | } | ||
1054 | |||
1055 | /* Initialize context */ | ||
1056 | ch_n = GCT_count_channels (t); | ||
1057 | c_n = GCT_count_any_connections (t); | ||
1058 | env = GNUNET_MQ_msg_extra (resp, | ||
1059 | c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) + | ||
1060 | ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber), | ||
1061 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1062 | resp->destination = msg->peer; | ||
1063 | /* Do not reorder! #iter_channel needs counters in HBO! */ | ||
1064 | GCT_iterate_connections (t, | ||
1065 | &iter_connection, | ||
1066 | resp); | ||
1067 | GCT_iterate_channels (t, | ||
1068 | &iter_channel, | ||
1069 | resp); | ||
1070 | resp->connections = htonl (resp->connections); | ||
1071 | resp->channels = htonl (resp->channels); | ||
1072 | resp->cstate = htons (0); | ||
1073 | resp->estate = htons (GCT_get_estate (t)); | ||
1074 | GNUNET_MQ_send (c->mq, | ||
1075 | env); | ||
1076 | GNUNET_SERVICE_client_continue (c->client); | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | /** | ||
1081 | * Iterator over all peers to dump info for each peer. | ||
1082 | * | ||
1083 | * @param cls Closure (unused). | ||
1084 | * @param peer Peer ID (tunnel remote peer). | ||
1085 | * @param value Peer info. | ||
1086 | * | ||
1087 | * @return #GNUNET_YES, to keep iterating. | ||
1088 | */ | ||
1089 | static int | ||
1090 | show_peer_iterator (void *cls, | ||
1091 | const struct GNUNET_PeerIdentity *peer, | ||
1092 | void *value) | ||
1093 | { | ||
1094 | struct CadetPeer *p = value; | ||
1095 | struct CadetTunnel *t; | ||
1096 | |||
1097 | t = GCP_get_tunnel (p, | ||
1098 | GNUNET_NO); | ||
1099 | if (NULL != t) | ||
1100 | GCT_debug (t, | ||
1101 | GNUNET_ERROR_TYPE_ERROR); | ||
1102 | LOG (GNUNET_ERROR_TYPE_ERROR, "\n"); | ||
1103 | return GNUNET_YES; | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | /** | ||
1108 | * Handler for client's INFO_DUMP request. | ||
1109 | * | ||
1110 | * @param cls Identification of the client. | ||
1111 | * @param message The actual message. | ||
1112 | */ | ||
1113 | static void | ||
1114 | handle_info_dump (void *cls, | ||
1115 | const struct GNUNET_MessageHeader *message) | ||
1116 | { | ||
1117 | struct CadetClient *c = cls; | ||
1118 | |||
1119 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1120 | "Received dump info request from client %u\n", | ||
1121 | c->id); | ||
1122 | |||
1123 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1124 | "*************************** DUMP START ***************************\n"); | ||
1125 | for (struct CadetClient *ci = clients_head; | ||
1126 | NULL != ci; | ||
1127 | ci = ci->next) | ||
1128 | { | ||
1129 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1130 | "Client %u (%p), handle: %p, ports: %u, channels: %u\n", | ||
1131 | ci->id, | ||
1132 | ci, | ||
1133 | ci->client, | ||
1134 | (NULL != c->ports) | ||
1135 | ? GNUNET_CONTAINER_multihashmap_size (ci->ports) | ||
1136 | : 0, | ||
1137 | GNUNET_CONTAINER_multihashmap32_size (ci->channels)); | ||
1138 | } | ||
1139 | LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n"); | ||
1140 | GCP_iterate_all (&show_peer_iterator, | ||
1141 | NULL); | ||
1142 | |||
1143 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1144 | "**************************** DUMP END ****************************\n"); | ||
1145 | |||
1146 | GNUNET_SERVICE_client_continue (c->client); | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | |||
1151 | /** | ||
1152 | * Callback called when a client connects to the service. | ||
1153 | * | ||
1154 | * @param cls closure for the service | ||
1155 | * @param client the new client that connected to the service | ||
1156 | * @param mq the message queue used to send messages to the client | ||
1157 | * @return @a c | ||
1158 | */ | ||
1159 | static void * | ||
1160 | client_connect_cb (void *cls, | ||
1161 | struct GNUNET_SERVICE_Client *client, | ||
1162 | struct GNUNET_MQ_Handle *mq) | ||
1163 | { | ||
1164 | struct CadetClient *c; | ||
1165 | |||
1166 | c = GNUNET_new (struct CadetClient); | ||
1167 | c->client = client; | ||
1168 | c->mq = mq; | ||
1169 | c->id = next_client_id++; /* overflow not important: just for debug */ | ||
1170 | c->channels | ||
1171 | = GNUNET_CONTAINER_multihashmap32_create (32); | ||
1172 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
1173 | clients_tail, | ||
1174 | c); | ||
1175 | GNUNET_STATISTICS_update (stats, | ||
1176 | "# clients", | ||
1177 | +1, | ||
1178 | GNUNET_NO); | ||
1179 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1180 | "%s connected\n", | ||
1181 | GSC_2s (c)); | ||
1182 | return c; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | /** | ||
1187 | * A channel was destroyed by the other peer. Tell our client. | ||
1188 | * | ||
1189 | * @param c client that lost a channel | ||
1190 | * @param ccn channel identification number for the client | ||
1191 | * @param ch the channel object | ||
1192 | */ | ||
1193 | void | ||
1194 | GSC_handle_remote_channel_destroy (struct CadetClient *c, | ||
1195 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
1196 | struct CadetChannel *ch) | ||
1197 | { | ||
1198 | struct GNUNET_MQ_Envelope *env; | ||
1199 | struct GNUNET_CADET_LocalChannelDestroyMessage *tdm; | ||
1200 | |||
1201 | env = GNUNET_MQ_msg (tdm, | ||
1202 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); | ||
1203 | tdm->ccn = ccn; | ||
1204 | GSC_send_to_client (c, | ||
1205 | env); | ||
1206 | GNUNET_assert (GNUNET_YES == | ||
1207 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
1208 | ntohl (ccn.channel_of_client), | ||
1209 | ch)); | ||
1210 | } | ||
1211 | |||
1212 | |||
1213 | /** | ||
1214 | * A client that created a loose channel that was not bound to a port | ||
1215 | * disconnected, drop it from the #loose_channels list. | ||
1216 | * | ||
1217 | * @param port the port the channel was trying to bind to | ||
1218 | * @param ch the channel that was lost | ||
1219 | */ | ||
1220 | void | ||
1221 | GSC_drop_loose_channel (const struct GNUNET_HashCode *port, | ||
1222 | struct CadetChannel *ch) | ||
1223 | { | ||
1224 | GNUNET_assert (GNUNET_YES == | ||
1225 | GNUNET_CONTAINER_multihashmap_remove (loose_channels, | ||
1226 | port, | ||
1227 | ch)); | ||
1228 | } | ||
1229 | |||
1230 | |||
1231 | /** | ||
1232 | * Iterator for deleting each channel whose client endpoint disconnected. | ||
1233 | * | ||
1234 | * @param cls Closure (client that has disconnected). | ||
1235 | * @param key The local channel id in host byte order | ||
1236 | * @param value The value stored at the key (channel to destroy). | ||
1237 | * @return #GNUNET_OK, keep iterating. | ||
1238 | */ | ||
1239 | static int | ||
1240 | channel_destroy_iterator (void *cls, | ||
1241 | uint32_t key, | ||
1242 | void *value) | ||
1243 | { | ||
1244 | struct CadetClient *c = cls; | ||
1245 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
1246 | struct CadetChannel *ch = value; | ||
1247 | |||
1248 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1249 | "Destroying %s, due to %s disconnecting.\n", | ||
1250 | GCCH_2s (ch), | ||
1251 | GSC_2s (c)); | ||
1252 | ccn.channel_of_client = htonl (key); | ||
1253 | GCCH_channel_local_destroy (ch, | ||
1254 | c, | ||
1255 | ccn); | ||
1256 | GNUNET_assert (GNUNET_YES == | ||
1257 | GNUNET_CONTAINER_multihashmap32_remove (c->channels, | ||
1258 | key, | ||
1259 | ch)); | ||
1260 | return GNUNET_OK; | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | /** | ||
1265 | * Remove client's ports from the global hashmap on disconnect. | ||
1266 | * | ||
1267 | * @param cls Closure (unused). | ||
1268 | * @param key the port. | ||
1269 | * @param value the `struct CadetClient` to remove | ||
1270 | * @return #GNUNET_OK, keep iterating. | ||
1271 | */ | ||
1272 | static int | ||
1273 | client_release_ports (void *cls, | ||
1274 | const struct GNUNET_HashCode *key, | ||
1275 | void *value) | ||
1276 | { | ||
1277 | struct CadetClient *c = value; | ||
1278 | |||
1279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1280 | "Closing port %s due to %s disconnect.\n", | ||
1281 | GNUNET_h2s (key), | ||
1282 | GSC_2s (c)); | ||
1283 | GNUNET_assert (GNUNET_YES == | ||
1284 | GNUNET_CONTAINER_multihashmap_remove (open_ports, | ||
1285 | key, | ||
1286 | value)); | ||
1287 | GNUNET_assert (GNUNET_YES == | ||
1288 | GNUNET_CONTAINER_multihashmap_remove (c->ports, | ||
1289 | key, | ||
1290 | value)); | ||
1291 | return GNUNET_OK; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | /** | ||
1296 | * Callback called when a client disconnected from the service | ||
1297 | * | ||
1298 | * @param cls closure for the service | ||
1299 | * @param client the client that disconnected | ||
1300 | * @param internal_cls should be equal to @a c | ||
1301 | */ | ||
1302 | static void | ||
1303 | client_disconnect_cb (void *cls, | ||
1304 | struct GNUNET_SERVICE_Client *client, | ||
1305 | void *internal_cls) | ||
1306 | { | ||
1307 | struct CadetClient *c = internal_cls; | ||
1308 | |||
1309 | GNUNET_assert (c->client == client); | ||
1310 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1311 | "%s is disconnecting.\n", | ||
1312 | GSC_2s (c)); | ||
1313 | if (NULL != c->channels) | ||
1314 | { | ||
1315 | GNUNET_CONTAINER_multihashmap32_iterate (c->channels, | ||
1316 | &channel_destroy_iterator, | ||
1317 | c); | ||
1318 | GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels)); | ||
1319 | GNUNET_CONTAINER_multihashmap32_destroy (c->channels); | ||
1320 | } | ||
1321 | if (NULL != c->ports) | ||
1322 | { | ||
1323 | GNUNET_CONTAINER_multihashmap_iterate (c->ports, | ||
1324 | &client_release_ports, | ||
1325 | c); | ||
1326 | GNUNET_CONTAINER_multihashmap_destroy (c->ports); | ||
1327 | } | ||
1328 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
1329 | clients_tail, | ||
1330 | c); | ||
1331 | GNUNET_STATISTICS_update (stats, | ||
1332 | "# clients", | ||
1333 | -1, | ||
1334 | GNUNET_NO); | ||
1335 | GNUNET_free (c); | ||
1336 | if ( (NULL == clients_head) && | ||
1337 | (GNUNET_YES == shutting_down) ) | ||
1338 | shutdown_rest (); | ||
1339 | } | ||
1340 | |||
1341 | |||
1342 | /** | ||
1343 | * Setup CADET internals. | ||
1344 | * | ||
1345 | * @param cls closure | ||
1346 | * @param server the initialized server | ||
1347 | * @param c configuration to use | ||
1348 | */ | ||
1349 | static void | ||
1350 | run (void *cls, | ||
1351 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1352 | struct GNUNET_SERVICE_Handle *service) | ||
1353 | { | ||
1354 | cfg = c; | ||
1355 | if (GNUNET_OK != | ||
1356 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1357 | "CADET", | ||
1358 | "RATCHET_MESSAGES", | ||
1359 | &ratchet_messages)) | ||
1360 | { | ||
1361 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1362 | "CADET", | ||
1363 | "RATCHET_MESSAGES", | ||
1364 | "needs to be a number"); | ||
1365 | ratchet_messages = 64; | ||
1366 | } | ||
1367 | if (GNUNET_OK != | ||
1368 | GNUNET_CONFIGURATION_get_value_time (c, | ||
1369 | "CADET", | ||
1370 | "RATCHET_TIME", | ||
1371 | &ratchet_time)) | ||
1372 | { | ||
1373 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1374 | "CADET", | ||
1375 | "RATCHET_TIME", | ||
1376 | "need delay value"); | ||
1377 | ratchet_time = GNUNET_TIME_UNIT_HOURS; | ||
1378 | } | ||
1379 | if (GNUNET_OK != | ||
1380 | GNUNET_CONFIGURATION_get_value_time (c, | ||
1381 | "CADET", | ||
1382 | "REFRESH_CONNECTION_TIME", | ||
1383 | &keepalive_period)) | ||
1384 | { | ||
1385 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1386 | "CADET", | ||
1387 | "REFRESH_CONNECTION_TIME", | ||
1388 | "need delay value"); | ||
1389 | keepalive_period = GNUNET_TIME_UNIT_MINUTES; | ||
1390 | } | ||
1391 | if (GNUNET_OK != | ||
1392 | GNUNET_CONFIGURATION_get_value_number (c, | ||
1393 | "CADET", | ||
1394 | "DROP_PERCENT", | ||
1395 | &drop_percent)) | ||
1396 | { | ||
1397 | drop_percent = 0; | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1402 | LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); | ||
1403 | LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); | ||
1404 | LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); | ||
1405 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1406 | } | ||
1407 | my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); | ||
1408 | if (NULL == my_private_key) | ||
1409 | { | ||
1410 | GNUNET_break (0); | ||
1411 | GNUNET_SCHEDULER_shutdown (); | ||
1412 | return; | ||
1413 | } | ||
1414 | GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, | ||
1415 | &my_full_id.public_key); | ||
1416 | stats = GNUNET_STATISTICS_create ("cadet", | ||
1417 | c); | ||
1418 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1419 | NULL); | ||
1420 | ats_ch = GNUNET_ATS_connectivity_init (c); | ||
1421 | /* FIXME: optimize code to allow GNUNET_YES here! */ | ||
1422 | open_ports = GNUNET_CONTAINER_multihashmap_create (16, | ||
1423 | GNUNET_NO); | ||
1424 | loose_channels = GNUNET_CONTAINER_multihashmap_create (16, | ||
1425 | GNUNET_NO); | ||
1426 | peers = GNUNET_CONTAINER_multipeermap_create (16, | ||
1427 | GNUNET_YES); | ||
1428 | connections = GNUNET_CONTAINER_multishortmap_create (256, | ||
1429 | GNUNET_YES); | ||
1430 | GCH_init (c); | ||
1431 | GCD_init (c); | ||
1432 | GCO_init (c); | ||
1433 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1434 | "CADET started for peer %s\n", | ||
1435 | GNUNET_i2s (&my_full_id)); | ||
1436 | |||
1437 | } | ||
1438 | |||
1439 | |||
1440 | /** | ||
1441 | * Define "main" method using service macro. | ||
1442 | */ | ||
1443 | GNUNET_SERVICE_MAIN | ||
1444 | ("cadet", | ||
1445 | GNUNET_SERVICE_OPTION_NONE, | ||
1446 | &run, | ||
1447 | &client_connect_cb, | ||
1448 | &client_disconnect_cb, | ||
1449 | NULL, | ||
1450 | GNUNET_MQ_hd_fixed_size (port_open, | ||
1451 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN, | ||
1452 | struct GNUNET_CADET_PortMessage, | ||
1453 | NULL), | ||
1454 | GNUNET_MQ_hd_fixed_size (port_close, | ||
1455 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE, | ||
1456 | struct GNUNET_CADET_PortMessage, | ||
1457 | NULL), | ||
1458 | GNUNET_MQ_hd_fixed_size (channel_create, | ||
1459 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE, | ||
1460 | struct GNUNET_CADET_LocalChannelCreateMessage, | ||
1461 | NULL), | ||
1462 | GNUNET_MQ_hd_fixed_size (channel_destroy, | ||
1463 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY, | ||
1464 | struct GNUNET_CADET_LocalChannelDestroyMessage, | ||
1465 | NULL), | ||
1466 | GNUNET_MQ_hd_var_size (local_data, | ||
1467 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, | ||
1468 | struct GNUNET_CADET_LocalData, | ||
1469 | NULL), | ||
1470 | GNUNET_MQ_hd_fixed_size (local_ack, | ||
1471 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, | ||
1472 | struct GNUNET_CADET_LocalAck, | ||
1473 | NULL), | ||
1474 | GNUNET_MQ_hd_fixed_size (get_peers, | ||
1475 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, | ||
1476 | struct GNUNET_MessageHeader, | ||
1477 | NULL), | ||
1478 | GNUNET_MQ_hd_fixed_size (show_peer, | ||
1479 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, | ||
1480 | struct GNUNET_CADET_LocalInfo, | ||
1481 | NULL), | ||
1482 | GNUNET_MQ_hd_fixed_size (info_tunnels, | ||
1483 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, | ||
1484 | struct GNUNET_MessageHeader, | ||
1485 | NULL), | ||
1486 | GNUNET_MQ_hd_fixed_size (info_tunnel, | ||
1487 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, | ||
1488 | struct GNUNET_CADET_LocalInfo, | ||
1489 | NULL), | ||
1490 | GNUNET_MQ_hd_fixed_size (info_dump, | ||
1491 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP, | ||
1492 | struct GNUNET_MessageHeader, | ||
1493 | NULL), | ||
1494 | GNUNET_MQ_handler_end ()); | ||
1495 | |||
1496 | /* end of gnunet-service-cadet-new.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet.h index bee5c67cc..2f2d7baf3 100644 --- a/src/cadet/gnunet-service-cadet-new.h +++ b/src/cadet/gnunet-service-cadet.h | |||
@@ -20,7 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * @file cadet/gnunet-service-cadet-new.h | 23 | * @file cadet/gnunet-service-cadet.h |
24 | * @brief Information we track per peer. | 24 | * @brief Information we track per peer. |
25 | * @author Bartlomiej Polot | 25 | * @author Bartlomiej Polot |
26 | * @author Christian Grothoff | 26 | * @author Christian Grothoff |
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c index 7b7c6e57c..68e29b66b 100644 --- a/src/cadet/gnunet-service-cadet_channel.c +++ b/src/cadet/gnunet-service-cadet_channel.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 3 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -17,31 +17,63 @@ | |||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | 20 | /** | |
21 | 21 | * @file cadet/gnunet-service-cadet_channel.c | |
22 | * @brief logical links between CADET clients | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - Congestion/flow control: | ||
28 | * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL! | ||
29 | * (and figure out how/where to use this!) | ||
30 | * + figure out flow control without ACKs (unreliable traffic!) | ||
31 | * - revisit handling of 'unbuffered' traffic! | ||
32 | * (need to push down through tunnel into connection selection) | ||
33 | * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe | ||
34 | * reserve more bits in 'options' to allow for buffer size control? | ||
35 | */ | ||
22 | #include "platform.h" | 36 | #include "platform.h" |
23 | #include "gnunet_util_lib.h" | 37 | #include "cadet.h" |
24 | |||
25 | #include "gnunet_statistics_service.h" | 38 | #include "gnunet_statistics_service.h" |
39 | #include "gnunet-service-cadet_channel.h" | ||
40 | #include "gnunet-service-cadet_connection.h" | ||
41 | #include "gnunet-service-cadet_tunnels.h" | ||
42 | #include "gnunet-service-cadet_paths.h" | ||
26 | 43 | ||
27 | #include "cadet.h" | 44 | #define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__) |
28 | #include "cadet_protocol.h" | ||
29 | 45 | ||
30 | #include "gnunet-service-cadet_channel.h" | 46 | /** |
31 | #include "gnunet-service-cadet_local.h" | 47 | * How long do we initially wait before retransmitting? |
32 | #include "gnunet-service-cadet_tunnel.h" | 48 | */ |
33 | #include "gnunet-service-cadet_peer.h" | 49 | #define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250) |
34 | 50 | ||
35 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__) | 51 | /** |
36 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__) | 52 | * How long do we wait before dropping state about incoming |
53 | * connection to closed port? | ||
54 | */ | ||
55 | #define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) | ||
37 | 56 | ||
38 | #define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\ | 57 | /** |
39 | GNUNET_TIME_UNIT_MILLISECONDS, 250) | 58 | * How long do we wait at least before retransmitting ever? |
40 | #define CADET_RETRANSMIT_MARGIN 4 | 59 | */ |
60 | #define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75) | ||
61 | |||
62 | /** | ||
63 | * Maximum message ID into the future we accept for out-of-order messages. | ||
64 | * If the message is more than this into the future, we drop it. This is | ||
65 | * important both to detect values that are actually in the past, as well | ||
66 | * as to limit adversarially triggerable memory consumption. | ||
67 | * | ||
68 | * Note that right now we have "max_pending_messages = 4" hard-coded in | ||
69 | * the logic below, so a value of 4 would suffice here. But we plan to | ||
70 | * allow larger windows in the future... | ||
71 | */ | ||
72 | #define MAX_OUT_OF_ORDER_DISTANCE 1024 | ||
41 | 73 | ||
42 | 74 | ||
43 | /** | 75 | /** |
44 | * All the states a connection can be in. | 76 | * All the states a channel can be in. |
45 | */ | 77 | */ |
46 | enum CadetChannelState | 78 | enum CadetChannelState |
47 | { | 79 | { |
@@ -51,9 +83,15 @@ enum CadetChannelState | |||
51 | CADET_CHANNEL_NEW, | 83 | CADET_CHANNEL_NEW, |
52 | 84 | ||
53 | /** | 85 | /** |
54 | * Connection create message sent, waiting for ACK. | 86 | * Channel is to a port that is not open, we're waiting for the |
87 | * port to be opened. | ||
88 | */ | ||
89 | CADET_CHANNEL_LOOSE, | ||
90 | |||
91 | /** | ||
92 | * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK. | ||
55 | */ | 93 | */ |
56 | CADET_CHANNEL_SENT, | 94 | CADET_CHANNEL_OPEN_SENT, |
57 | 95 | ||
58 | /** | 96 | /** |
59 | * Connection confirmed, ready to carry traffic. | 97 | * Connection confirmed, ready to carry traffic. |
@@ -63,138 +101,144 @@ enum CadetChannelState | |||
63 | 101 | ||
64 | 102 | ||
65 | /** | 103 | /** |
66 | * Info holder for channel messages in queues. | 104 | * Info needed to retry a message in case it gets lost. |
105 | * Note that we DO use this structure also for unreliable | ||
106 | * messages. | ||
67 | */ | 107 | */ |
68 | struct CadetChannelQueue | 108 | struct CadetReliableMessage |
69 | { | 109 | { |
70 | /** | 110 | /** |
71 | * Tunnel Queue. | 111 | * Double linked list, FIFO style |
72 | */ | 112 | */ |
73 | struct CadetTunnelQueue *tq; | 113 | struct CadetReliableMessage *next; |
74 | 114 | ||
75 | /** | 115 | /** |
76 | * Message type (DATA/DATA_ACK) | 116 | * Double linked list, FIFO style |
77 | */ | 117 | */ |
78 | uint16_t type; | 118 | struct CadetReliableMessage *prev; |
79 | 119 | ||
80 | /** | 120 | /** |
81 | * Message copy (for DATAs, to start retransmission timer) | 121 | * Which channel is this message in? |
82 | */ | 122 | */ |
83 | struct CadetReliableMessage *copy; | 123 | struct CadetChannel *ch; |
84 | 124 | ||
85 | /** | 125 | /** |
86 | * Reliability (for DATA_ACKs, to access rel->ack_q) | 126 | * Entry in the tunnels queue for this message, NULL if it has left |
127 | * the tunnel. Used to cancel transmission in case we receive an | ||
128 | * ACK in time. | ||
87 | */ | 129 | */ |
88 | struct CadetChannelReliability *rel; | 130 | struct CadetTunnelQueueEntry *qe; |
89 | }; | ||
90 | |||
91 | 131 | ||
92 | /** | ||
93 | * Info needed to retry a message in case it gets lost. | ||
94 | */ | ||
95 | struct CadetReliableMessage | ||
96 | { | ||
97 | /** | 132 | /** |
98 | * Double linked list, FIFO style | 133 | * Data message we are trying to send. |
99 | */ | 134 | */ |
100 | struct CadetReliableMessage *next; | 135 | struct GNUNET_CADET_ChannelAppDataMessage *data_message; |
101 | struct CadetReliableMessage *prev; | ||
102 | 136 | ||
103 | /** | 137 | /** |
104 | * Type of message (payload, channel management). | 138 | * How soon should we retry if we fail to get an ACK? |
139 | * Messages in the queue are sorted by this value. | ||
105 | */ | 140 | */ |
106 | int16_t type; | 141 | struct GNUNET_TIME_Absolute next_retry; |
107 | 142 | ||
108 | /** | 143 | /** |
109 | * Tunnel Reliability queue this message is in. | 144 | * How long do we wait for an ACK after transmission? |
145 | * Use for the back-off calculation. | ||
110 | */ | 146 | */ |
111 | struct CadetChannelReliability *rel; | 147 | struct GNUNET_TIME_Relative retry_delay; |
112 | 148 | ||
113 | /** | 149 | /** |
114 | * ID of the message (ACK needed to free) | 150 | * Time when we first successfully transmitted the message |
151 | * (that is, set @e num_transmissions to 1). | ||
115 | */ | 152 | */ |
116 | uint32_t mid; | 153 | struct GNUNET_TIME_Absolute first_transmission_time; |
117 | 154 | ||
118 | /** | 155 | /** |
119 | * Tunnel Queue. | 156 | * Identifier of the connection that this message took when it |
157 | * was first transmitted. Only useful if @e num_transmissions is 1. | ||
120 | */ | 158 | */ |
121 | struct CadetChannelQueue *chq; | 159 | struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken; |
122 | 160 | ||
123 | /** | 161 | /** |
124 | * When was this message issued (to calculate ACK delay) | 162 | * How often was this message transmitted? #GNUNET_SYSERR if there |
163 | * was an error transmitting the message, #GNUNET_NO if it was not | ||
164 | * yet transmitted ever, otherwise the number of (re) transmissions. | ||
125 | */ | 165 | */ |
126 | struct GNUNET_TIME_Absolute timestamp; | 166 | int num_transmissions; |
127 | 167 | ||
128 | /* struct GNUNET_CADET_ChannelAppDataMessage with payload */ | ||
129 | }; | 168 | }; |
130 | 169 | ||
131 | 170 | ||
132 | /** | 171 | /** |
133 | * Info about the traffic state for a client in a channel. | 172 | * List of received out-of-order data messages. |
134 | */ | 173 | */ |
135 | struct CadetChannelReliability | 174 | struct CadetOutOfOrderMessage |
136 | { | 175 | { |
137 | /** | 176 | /** |
138 | * Channel this is about. | 177 | * Double linked list, FIFO style |
139 | */ | 178 | */ |
140 | struct CadetChannel *ch; | 179 | struct CadetOutOfOrderMessage *next; |
141 | 180 | ||
142 | /** | 181 | /** |
143 | * DLL of messages sent and not yet ACK'd. | 182 | * Double linked list, FIFO style |
144 | */ | 183 | */ |
145 | struct CadetReliableMessage *head_sent; | 184 | struct CadetOutOfOrderMessage *prev; |
146 | struct CadetReliableMessage *tail_sent; | ||
147 | 185 | ||
148 | /** | 186 | /** |
149 | * DLL of messages received out of order. | 187 | * ID of the message (messages up to this point needed |
188 | * before we give this one to the client). | ||
150 | */ | 189 | */ |
151 | struct CadetReliableMessage *head_recv; | 190 | struct ChannelMessageIdentifier mid; |
152 | struct CadetReliableMessage *tail_recv; | ||
153 | 191 | ||
154 | /** | 192 | /** |
155 | * Messages received. | 193 | * The envelope with the payload of the out-of-order message |
156 | */ | 194 | */ |
157 | unsigned int n_recv; | 195 | struct GNUNET_MQ_Envelope *env; |
158 | 196 | ||
159 | /** | 197 | }; |
160 | * Next MID to use for outgoing traffic. | ||
161 | */ | ||
162 | uint32_t mid_send; | ||
163 | 198 | ||
164 | /** | ||
165 | * Next MID expected for incoming traffic. | ||
166 | */ | ||
167 | uint32_t mid_recv; | ||
168 | 199 | ||
200 | /** | ||
201 | * Client endpoint of a `struct CadetChannel`. A channel may be a | ||
202 | * loopback channel, in which case it has two of these endpoints. | ||
203 | * Note that flow control also is required in both directions. | ||
204 | */ | ||
205 | struct CadetChannelClient | ||
206 | { | ||
169 | /** | 207 | /** |
170 | * Handle for queued unique data CREATE, DATA_ACK. | 208 | * Client handle. Not by itself sufficient to designate |
209 | * the client endpoint, as the same client handle may | ||
210 | * be used for both the owner and the destination, and | ||
211 | * we thus also need the channel ID to identify the client. | ||
171 | */ | 212 | */ |
172 | struct CadetChannelQueue *uniq; | 213 | struct CadetClient *c; |
173 | 214 | ||
174 | /** | 215 | /** |
175 | * Can we send data to the client? | 216 | * Head of DLL of messages received out of order or while client was unready. |
176 | */ | 217 | */ |
177 | int client_ready; | 218 | struct CadetOutOfOrderMessage *head_recv; |
178 | 219 | ||
179 | /** | 220 | /** |
180 | * Can the client send data to us? | 221 | * Tail DLL of messages received out of order or while client was unready. |
181 | */ | 222 | */ |
182 | int client_allowed; | 223 | struct CadetOutOfOrderMessage *tail_recv; |
183 | 224 | ||
184 | /** | 225 | /** |
185 | * Task to resend/poll in case no ACK is received. | 226 | * Local tunnel number for this client. |
227 | * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI, | ||
228 | * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
186 | */ | 229 | */ |
187 | struct GNUNET_SCHEDULER_Task * retry_task; | 230 | struct GNUNET_CADET_ClientChannelNumber ccn; |
188 | 231 | ||
189 | /** | 232 | /** |
190 | * Counter for exponential backoff. | 233 | * Number of entries currently in @a head_recv DLL. |
191 | */ | 234 | */ |
192 | struct GNUNET_TIME_Relative retry_timer; | 235 | unsigned int num_recv; |
193 | 236 | ||
194 | /** | 237 | /** |
195 | * How long does it usually take to get an ACK. | 238 | * Can we send data to the client? |
196 | */ | 239 | */ |
197 | struct GNUNET_TIME_Relative expected_delay; | 240 | int client_ready; |
241 | |||
198 | }; | 242 | }; |
199 | 243 | ||
200 | 244 | ||
@@ -209,41 +253,44 @@ struct CadetChannel | |||
209 | struct CadetTunnel *t; | 253 | struct CadetTunnel *t; |
210 | 254 | ||
211 | /** | 255 | /** |
212 | * Destination port of the channel. | 256 | * Client owner of the tunnel, if any. |
257 | * (Used if this channel represends the initiating end of the tunnel.) | ||
213 | */ | 258 | */ |
214 | struct GNUNET_HashCode port; | 259 | struct CadetChannelClient *owner; |
215 | 260 | ||
216 | /** | 261 | /** |
217 | * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | 262 | * Client destination of the tunnel, if any. |
263 | * (Used if this channel represents the listening end of the tunnel.) | ||
218 | */ | 264 | */ |
219 | struct GNUNET_CADET_ChannelTunnelNumber gid; | 265 | struct CadetChannelClient *dest; |
220 | 266 | ||
221 | /** | 267 | /** |
222 | * Local tunnel number for root (owner) client. | 268 | * Last entry in the tunnel's queue relating to control messages |
223 | * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 ) | 269 | * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or |
270 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel | ||
271 | * transmission in case we receive updated information. | ||
224 | */ | 272 | */ |
225 | struct GNUNET_CADET_ClientChannelNumber lid_root; | 273 | struct CadetTunnelQueueEntry *last_control_qe; |
226 | 274 | ||
227 | /** | 275 | /** |
228 | * Local tunnel number for local destination clients (incoming number) | 276 | * Head of DLL of messages sent and not yet ACK'd. |
229 | * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0). | ||
230 | */ | 277 | */ |
231 | struct GNUNET_CADET_ClientChannelNumber lid_dest; | 278 | struct CadetReliableMessage *head_sent; |
232 | 279 | ||
233 | /** | 280 | /** |
234 | * Channel state. | 281 | * Tail of DLL of messages sent and not yet ACK'd. |
235 | */ | 282 | */ |
236 | enum CadetChannelState state; | 283 | struct CadetReliableMessage *tail_sent; |
237 | 284 | ||
238 | /** | 285 | /** |
239 | * Is the tunnel bufferless (minimum latency)? | 286 | * Task to resend/poll in case no ACK is received. |
240 | */ | 287 | */ |
241 | int nobuffer; | 288 | struct GNUNET_SCHEDULER_Task *retry_control_task; |
242 | 289 | ||
243 | /** | 290 | /** |
244 | * Is the tunnel reliable? | 291 | * Task to resend/poll in case no ACK is received. |
245 | */ | 292 | */ |
246 | int reliable; | 293 | struct GNUNET_SCHEDULER_Task *retry_data_task; |
247 | 294 | ||
248 | /** | 295 | /** |
249 | * Last time the channel was used | 296 | * Last time the channel was used |
@@ -251,21 +298,29 @@ struct CadetChannel | |||
251 | struct GNUNET_TIME_Absolute timestamp; | 298 | struct GNUNET_TIME_Absolute timestamp; |
252 | 299 | ||
253 | /** | 300 | /** |
254 | * Client owner of the tunnel, if any | 301 | * Destination port of the channel. |
255 | */ | 302 | */ |
256 | struct CadetClient *root; | 303 | struct GNUNET_HashCode port; |
257 | 304 | ||
258 | /** | 305 | /** |
259 | * Client destination of the tunnel, if any. | 306 | * Counter for exponential backoff. |
260 | */ | 307 | */ |
261 | struct CadetClient *dest; | 308 | struct GNUNET_TIME_Relative retry_time; |
262 | 309 | ||
263 | /** | 310 | /** |
264 | * Flag to signal the destruction of the channel. | 311 | * Bitfield of already-received messages past @e mid_recv. |
265 | * If this is set to #GNUNET_YES the channel will be destroyed | ||
266 | * when the queue is empty. | ||
267 | */ | 312 | */ |
268 | int destroy; | 313 | uint64_t mid_futures; |
314 | |||
315 | /** | ||
316 | * Next MID expected for incoming traffic. | ||
317 | */ | ||
318 | struct ChannelMessageIdentifier mid_recv; | ||
319 | |||
320 | /** | ||
321 | * Next MID to use for outgoing traffic. | ||
322 | */ | ||
323 | struct ChannelMessageIdentifier mid_send; | ||
269 | 324 | ||
270 | /** | 325 | /** |
271 | * Total (reliable) messages pending ACK for this channel. | 326 | * Total (reliable) messages pending ACK for this channel. |
@@ -273,2290 +328,1710 @@ struct CadetChannel | |||
273 | unsigned int pending_messages; | 328 | unsigned int pending_messages; |
274 | 329 | ||
275 | /** | 330 | /** |
276 | * Reliability data. | 331 | * Maximum (reliable) messages pending ACK for this channel |
277 | * Only present (non-NULL) at the owner of a tunnel. | 332 | * before we throttle the client. |
278 | */ | 333 | */ |
279 | struct CadetChannelReliability *root_rel; | 334 | unsigned int max_pending_messages; |
280 | 335 | ||
281 | /** | 336 | /** |
282 | * Reliability data. | 337 | * Number identifying this channel in its tunnel. |
283 | * Only present (non-NULL) at the destination of a tunnel. | ||
284 | */ | 338 | */ |
285 | struct CadetChannelReliability *dest_rel; | 339 | struct GNUNET_CADET_ChannelTunnelNumber ctn; |
286 | 340 | ||
287 | }; | 341 | /** |
342 | * Channel state. | ||
343 | */ | ||
344 | enum CadetChannelState state; | ||
288 | 345 | ||
346 | /** | ||
347 | * Count how many ACKs we skipped, used to prevent long | ||
348 | * sequences of ACK skipping. | ||
349 | */ | ||
350 | unsigned int skip_ack_series; | ||
289 | 351 | ||
290 | /******************************************************************************/ | 352 | /** |
291 | /******************************* GLOBALS ***********************************/ | 353 | * Is the tunnel bufferless (minimum latency)? |
292 | /******************************************************************************/ | 354 | */ |
355 | int nobuffer; | ||
293 | 356 | ||
294 | /** | 357 | /** |
295 | * Global handle to the statistics service. | 358 | * Is the tunnel reliable? |
296 | */ | 359 | */ |
297 | extern struct GNUNET_STATISTICS_Handle *stats; | 360 | int reliable; |
298 | 361 | ||
299 | /** | 362 | /** |
300 | * Local peer own ID (memory efficient handle). | 363 | * Is the tunnel out-of-order? |
301 | */ | 364 | */ |
302 | extern GNUNET_PEER_Id myid; | 365 | int out_of_order; |
303 | 366 | ||
367 | /** | ||
368 | * Is this channel a loopback channel, where the destination is us again? | ||
369 | */ | ||
370 | int is_loopback; | ||
304 | 371 | ||
305 | /******************************************************************************/ | 372 | /** |
306 | /******************************** STATIC ***********************************/ | 373 | * Flag to signal the destruction of the channel. If this is set to |
307 | /******************************************************************************/ | 374 | * #GNUNET_YES the channel will be destroyed once the queue is |
375 | * empty. | ||
376 | */ | ||
377 | int destroy; | ||
308 | 378 | ||
379 | }; | ||
309 | 380 | ||
310 | /** | ||
311 | * Destroy a reliable message after it has been acknowledged, either by | ||
312 | * direct mid ACK or bitfield. Updates the appropriate data structures and | ||
313 | * timers and frees all memory. | ||
314 | * | ||
315 | * @param copy Message that is no longer needed: remote peer got it. | ||
316 | * @param update_time Is the timing information relevant? | ||
317 | * If this message is ACK in a batch the timing information | ||
318 | * is skewed by the retransmission, count only for the | ||
319 | * retransmitted message. | ||
320 | * | ||
321 | * @return #GNUNET_YES if channel was destroyed as a result of the call, | ||
322 | * #GNUNET_NO otherwise. | ||
323 | */ | ||
324 | static int | ||
325 | rel_message_free (struct CadetReliableMessage *copy, int update_time); | ||
326 | 381 | ||
327 | /** | 382 | /** |
328 | * send a channel create message. | 383 | * Get the static string for identification of the channel. |
329 | * | 384 | * |
330 | * @param ch Channel for which to send. | 385 | * @param ch Channel. |
331 | */ | ||
332 | static void | ||
333 | send_create (struct CadetChannel *ch); | ||
334 | |||
335 | /** | ||
336 | * Confirm we got a channel create, FWD ack. | ||
337 | * | 386 | * |
338 | * @param ch The channel to confirm. | 387 | * @return Static string with the channel IDs. |
339 | * @param fwd Should we send a FWD ACK? (going dest->root) | ||
340 | */ | 388 | */ |
341 | static void | 389 | const char * |
342 | send_ack (struct CadetChannel *ch, int fwd); | 390 | GCCH_2s (const struct CadetChannel *ch) |
343 | 391 | { | |
392 | static char buf[128]; | ||
393 | |||
394 | GNUNET_snprintf (buf, | ||
395 | sizeof (buf), | ||
396 | "Channel %s:%s ctn:%X(%X/%X)", | ||
397 | (GNUNET_YES == ch->is_loopback) | ||
398 | ? "loopback" | ||
399 | : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))), | ||
400 | GNUNET_h2s (&ch->port), | ||
401 | ch->ctn, | ||
402 | (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client), | ||
403 | (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client)); | ||
404 | return buf; | ||
405 | } | ||
344 | 406 | ||
345 | 407 | ||
346 | /** | 408 | /** |
347 | * Test if the channel is loopback: both root and dest are on the local peer. | 409 | * Get the channel's public ID. |
348 | * | 410 | * |
349 | * @param ch Channel to test. | 411 | * @param ch Channel. |
350 | * | 412 | * |
351 | * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. | 413 | * @return ID used to identify the channel with the remote peer. |
352 | */ | 414 | */ |
353 | static int | 415 | struct GNUNET_CADET_ChannelTunnelNumber |
354 | is_loopback (const struct CadetChannel *ch) | 416 | GCCH_get_id (const struct CadetChannel *ch) |
355 | { | 417 | { |
356 | if (NULL != ch->t) | 418 | return ch->ctn; |
357 | return GCT_is_loopback (ch->t); | ||
358 | |||
359 | return (NULL != ch->root && NULL != ch->dest); | ||
360 | } | 419 | } |
361 | 420 | ||
362 | 421 | ||
363 | /** | 422 | /** |
364 | * Save a copy of the data message for later retransmission. | 423 | * Release memory associated with @a ccc |
365 | * | 424 | * |
366 | * @param msg Message to copy. | 425 | * @param ccc data structure to clean up |
367 | * @param mid Message ID. | ||
368 | * @param rel Reliability data for retransmission. | ||
369 | */ | 426 | */ |
370 | static struct CadetReliableMessage * | 427 | static void |
371 | copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid, | 428 | free_channel_client (struct CadetChannelClient *ccc) |
372 | struct CadetChannelReliability *rel) | ||
373 | { | 429 | { |
374 | struct CadetReliableMessage *copy; | 430 | struct CadetOutOfOrderMessage *com; |
375 | uint16_t size; | ||
376 | 431 | ||
377 | size = ntohs (msg->header.size); | 432 | while (NULL != (com = ccc->head_recv)) |
378 | copy = GNUNET_malloc (sizeof (*copy) + size); | 433 | { |
379 | copy->mid = mid; | 434 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
380 | copy->rel = rel; | 435 | ccc->tail_recv, |
381 | copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA; | 436 | com); |
382 | GNUNET_memcpy (©[1], msg, size); | 437 | ccc->num_recv--; |
383 | 438 | GNUNET_MQ_discard (com->env); | |
384 | return copy; | 439 | GNUNET_free (com); |
440 | } | ||
441 | GNUNET_free (ccc); | ||
385 | } | 442 | } |
386 | 443 | ||
444 | |||
387 | /** | 445 | /** |
388 | * We have received a message out of order, or the client is not ready. | 446 | * Destroy the given channel. |
389 | * Buffer it until we receive an ACK from the client or the missing | ||
390 | * message from the channel. | ||
391 | * | 447 | * |
392 | * @param msg Message to buffer (MUST be of type CADET_DATA). | 448 | * @param ch channel to destroy |
393 | * @param rel Reliability data to the corresponding direction. | ||
394 | */ | 449 | */ |
395 | static void | 450 | static void |
396 | add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg, | 451 | channel_destroy (struct CadetChannel *ch) |
397 | struct CadetChannelReliability *rel) | ||
398 | { | 452 | { |
399 | struct CadetReliableMessage *copy; | 453 | struct CadetReliableMessage *crm; |
400 | struct CadetReliableMessage *prev; | ||
401 | uint32_t mid; | ||
402 | |||
403 | mid = ntohl (msg->mid); | ||
404 | 454 | ||
405 | LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data MID %u (%u)\n", | 455 | while (NULL != (crm = ch->head_sent)) |
406 | mid, rel->n_recv); | ||
407 | |||
408 | rel->n_recv++; | ||
409 | |||
410 | // FIXME do something better than O(n), although n < 64... | ||
411 | // FIXME start from the end (most messages are the latest ones) | ||
412 | for (prev = rel->head_recv; NULL != prev; prev = prev->next) | ||
413 | { | 456 | { |
414 | LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid); | 457 | GNUNET_assert (ch == crm->ch); |
415 | if (prev->mid == mid) | 458 | if (NULL != crm->qe) |
416 | { | 459 | { |
417 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n"); | 460 | GCT_send_cancel (crm->qe); |
418 | rel->n_recv--; | 461 | crm->qe = NULL; |
419 | return; | ||
420 | } | ||
421 | else if (GC_is_pid_bigger (prev->mid, mid)) | ||
422 | { | ||
423 | LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n"); | ||
424 | copy = copy_message (msg, mid, rel); | ||
425 | GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv, | ||
426 | prev, copy); | ||
427 | return; | ||
428 | } | 462 | } |
463 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, | ||
464 | ch->tail_sent, | ||
465 | crm); | ||
466 | GNUNET_free (crm->data_message); | ||
467 | GNUNET_free (crm); | ||
468 | } | ||
469 | if (NULL != ch->owner) | ||
470 | { | ||
471 | free_channel_client (ch->owner); | ||
472 | ch->owner = NULL; | ||
429 | } | 473 | } |
430 | copy = copy_message (msg, mid, rel); | 474 | if (NULL != ch->dest) |
431 | LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (now: %u)\n", rel->n_recv); | 475 | { |
432 | GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy); | 476 | free_channel_client (ch->dest); |
433 | LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); | 477 | ch->dest = NULL; |
478 | } | ||
479 | if (NULL != ch->last_control_qe) | ||
480 | { | ||
481 | GCT_send_cancel (ch->last_control_qe); | ||
482 | ch->last_control_qe = NULL; | ||
483 | } | ||
484 | if (NULL != ch->retry_data_task) | ||
485 | { | ||
486 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
487 | ch->retry_data_task = NULL; | ||
488 | } | ||
489 | if (NULL != ch->retry_control_task) | ||
490 | { | ||
491 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
492 | ch->retry_control_task = NULL; | ||
493 | } | ||
494 | if (GNUNET_NO == ch->is_loopback) | ||
495 | { | ||
496 | GCT_remove_channel (ch->t, | ||
497 | ch, | ||
498 | ch->ctn); | ||
499 | ch->t = NULL; | ||
500 | } | ||
501 | GNUNET_free (ch); | ||
434 | } | 502 | } |
435 | 503 | ||
436 | 504 | ||
437 | /** | 505 | /** |
438 | * Add a destination client to a channel, initializing all data structures | 506 | * Send a channel create message. |
439 | * in the channel and the client. | ||
440 | * | 507 | * |
441 | * @param ch Channel to which add the destination. | 508 | * @param cls Channel for which to send. |
442 | * @param c Client which to add to the channel. | ||
443 | */ | 509 | */ |
444 | static void | 510 | static void |
445 | add_destination (struct CadetChannel *ch, struct CadetClient *c) | 511 | send_channel_open (void *cls); |
446 | { | ||
447 | if (NULL != ch->dest) | ||
448 | { | ||
449 | GNUNET_break (0); | ||
450 | return; | ||
451 | } | ||
452 | |||
453 | /* Assign local id as destination */ | ||
454 | ch->lid_dest = GML_get_next_ccn (c); | ||
455 | |||
456 | /* Store in client's hashmap */ | ||
457 | GML_channel_add (c, ch->lid_dest, ch); | ||
458 | |||
459 | GNUNET_break (NULL == ch->dest_rel); | ||
460 | ch->dest_rel = GNUNET_new (struct CadetChannelReliability); | ||
461 | ch->dest_rel->ch = ch; | ||
462 | ch->dest_rel->expected_delay.rel_value_us = 0; | ||
463 | ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME; | ||
464 | |||
465 | ch->dest = c; | ||
466 | } | ||
467 | 512 | ||
468 | 513 | ||
469 | /** | 514 | /** |
470 | * Set options in a channel, extracted from a bit flag field. | 515 | * Function called once the tunnel confirms that we sent the |
516 | * create message. Delays for a bit until we retry. | ||
471 | * | 517 | * |
472 | * @param ch Channel to set options to. | 518 | * @param cls our `struct CadetChannel`. |
473 | * @param options Bit array in host byte order. | 519 | * @param cid identifier of the connection within the tunnel, NULL |
520 | * if transmission failed | ||
474 | */ | 521 | */ |
475 | static void | 522 | static void |
476 | channel_set_options (struct CadetChannel *ch, uint32_t options) | 523 | channel_open_sent_cb (void *cls, |
524 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
477 | { | 525 | { |
478 | ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? | 526 | struct CadetChannel *ch = cls; |
479 | GNUNET_YES : GNUNET_NO; | 527 | |
480 | ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? | 528 | GNUNET_assert (NULL != ch->last_control_qe); |
481 | GNUNET_YES : GNUNET_NO; | 529 | ch->last_control_qe = NULL; |
530 | ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time); | ||
531 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
532 | "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n", | ||
533 | GCCH_2s (ch), | ||
534 | GNUNET_STRINGS_relative_time_to_string (ch->retry_time, | ||
535 | GNUNET_YES)); | ||
536 | ch->retry_control_task | ||
537 | = GNUNET_SCHEDULER_add_delayed (ch->retry_time, | ||
538 | &send_channel_open, | ||
539 | ch); | ||
482 | } | 540 | } |
483 | 541 | ||
484 | 542 | ||
485 | /** | 543 | /** |
486 | * Get a bit flag field with the options of a channel. | 544 | * Send a channel open message. |
487 | * | 545 | * |
488 | * @param ch Channel to get options from. | 546 | * @param cls Channel for which to send. |
489 | * | ||
490 | * @return Bit array in host byte order. | ||
491 | */ | 547 | */ |
492 | static uint32_t | 548 | static void |
493 | channel_get_options (struct CadetChannel *ch) | 549 | send_channel_open (void *cls) |
494 | { | 550 | { |
551 | struct CadetChannel *ch = cls; | ||
552 | struct GNUNET_CADET_ChannelOpenMessage msgcc; | ||
495 | uint32_t options; | 553 | uint32_t options; |
496 | 554 | ||
555 | ch->retry_control_task = NULL; | ||
556 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
557 | "Sending CHANNEL_OPEN message for %s\n", | ||
558 | GCCH_2s (ch)); | ||
497 | options = 0; | 559 | options = 0; |
498 | if (ch->nobuffer) | 560 | if (ch->nobuffer) |
499 | options |= GNUNET_CADET_OPTION_NOBUFFER; | 561 | options |= GNUNET_CADET_OPTION_NOBUFFER; |
500 | if (ch->reliable) | 562 | if (ch->reliable) |
501 | options |= GNUNET_CADET_OPTION_RELIABLE; | 563 | options |= GNUNET_CADET_OPTION_RELIABLE; |
502 | 564 | if (ch->out_of_order) | |
503 | return options; | 565 | options |= GNUNET_CADET_OPTION_OUT_OF_ORDER; |
566 | msgcc.header.size = htons (sizeof (msgcc)); | ||
567 | msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN); | ||
568 | msgcc.opt = htonl (options); | ||
569 | msgcc.port = ch->port; | ||
570 | msgcc.ctn = ch->ctn; | ||
571 | ch->state = CADET_CHANNEL_OPEN_SENT; | ||
572 | if (NULL != ch->last_control_qe) | ||
573 | GCT_send_cancel (ch->last_control_qe); | ||
574 | ch->last_control_qe = GCT_send (ch->t, | ||
575 | &msgcc.header, | ||
576 | &channel_open_sent_cb, | ||
577 | ch); | ||
578 | GNUNET_assert (NULL == ch->retry_control_task); | ||
504 | } | 579 | } |
505 | 580 | ||
506 | 581 | ||
507 | /** | 582 | /** |
508 | * Notify a client that the channel is no longer valid. | 583 | * Function called once and only once after a channel was bound |
509 | * | 584 | * to its tunnel via #GCT_add_channel() is ready for transmission. |
510 | * @param ch Channel that is destroyed. | 585 | * Note that this is only the case for channels that this peer |
511 | * @param local_only Should we avoid sending it to other peers? | 586 | * initiates, as for incoming channels we assume that they are |
587 | * ready for transmission immediately upon receiving the open | ||
588 | * message. Used to bootstrap the #GCT_send() process. | ||
589 | * | ||
590 | * @param ch the channel for which the tunnel is now ready | ||
512 | */ | 591 | */ |
513 | static void | 592 | void |
514 | send_destroy (struct CadetChannel *ch, int local_only) | 593 | GCCH_tunnel_up (struct CadetChannel *ch) |
515 | { | 594 | { |
516 | struct GNUNET_CADET_ChannelManageMessage msg; | 595 | GNUNET_assert (NULL == ch->retry_control_task); |
517 | 596 | LOG (GNUNET_ERROR_TYPE_DEBUG, | |
518 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); | 597 | "Tunnel up, sending CHANNEL_OPEN on %s now\n", |
519 | msg.header.size = htons (sizeof (msg)); | 598 | GCCH_2s (ch)); |
520 | msg.ctn = ch->gid; | 599 | ch->retry_control_task |
521 | 600 | = GNUNET_SCHEDULER_add_now (&send_channel_open, | |
522 | /* If root is not NULL, notify. | 601 | ch); |
523 | * If it's NULL, check lid_root. When a local destroy comes in, root | ||
524 | * is set to NULL but lid_root is left untouched. In this case, do nothing, | ||
525 | * the client is the one who requested the channel to be destroyed. | ||
526 | */ | ||
527 | if (NULL != ch->root) | ||
528 | GML_send_channel_destroy (ch->root, ch->lid_root); | ||
529 | else if (0 == ch->lid_root.channel_of_client && GNUNET_NO == local_only) | ||
530 | GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); | ||
531 | |||
532 | if (NULL != ch->dest) | ||
533 | GML_send_channel_destroy (ch->dest, ch->lid_dest); | ||
534 | else if (0 == ch->lid_dest.channel_of_client && GNUNET_NO == local_only) | ||
535 | GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL); | ||
536 | } | 602 | } |
537 | 603 | ||
538 | 604 | ||
539 | /** | 605 | /** |
540 | * Notify the destination client that a new incoming channel was created. | 606 | * Create a new channel. |
541 | * | 607 | * |
542 | * @param ch Channel that was created. | 608 | * @param owner local client owning the channel |
609 | * @param ccn local number of this channel at the @a owner | ||
610 | * @param destination peer to which we should build the channel | ||
611 | * @param port desired port at @a destination | ||
612 | * @param options options for the channel | ||
613 | * @return handle to the new channel | ||
543 | */ | 614 | */ |
544 | static void | 615 | struct CadetChannel * |
545 | send_client_create (struct CadetChannel *ch) | 616 | GCCH_channel_local_new (struct CadetClient *owner, |
617 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
618 | struct CadetPeer *destination, | ||
619 | const struct GNUNET_HashCode *port, | ||
620 | uint32_t options) | ||
546 | { | 621 | { |
547 | uint32_t opt; | 622 | struct CadetChannel *ch; |
548 | 623 | struct CadetChannelClient *ccco; | |
549 | if (NULL == ch->dest) | ||
550 | return; | ||
551 | |||
552 | opt = 0; | ||
553 | opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0; | ||
554 | opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0; | ||
555 | GML_send_channel_create (ch->dest, | ||
556 | ch->lid_dest, | ||
557 | &ch->port, | ||
558 | opt, | ||
559 | GCT_get_destination (ch->t)); | ||
560 | |||
561 | } | ||
562 | 624 | ||
625 | ccco = GNUNET_new (struct CadetChannelClient); | ||
626 | ccco->c = owner; | ||
627 | ccco->ccn = ccn; | ||
628 | ccco->client_ready = GNUNET_YES; | ||
563 | 629 | ||
564 | /** | 630 | ch = GNUNET_new (struct CadetChannel); |
565 | * Send data to a client. | 631 | ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */ |
566 | * | 632 | ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER)); |
567 | * If the client is ready, send directly, otherwise buffer while listening | 633 | ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE)); |
568 | * for a local ACK. | 634 | ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER)); |
569 | * | 635 | ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */ |
570 | * @param ch Channel | 636 | ch->owner = ccco; |
571 | * @param msg Message. | 637 | ch->port = *port; |
572 | * @param fwd Is this a fwd (root->dest) message? | 638 | if (0 == memcmp (&my_full_id, |
573 | */ | 639 | GCP_get_id (destination), |
574 | static void | 640 | sizeof (struct GNUNET_PeerIdentity))) |
575 | send_client_data (struct CadetChannel *ch, | 641 | { |
576 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | 642 | struct CadetClient *c; |
577 | int fwd) | 643 | |
578 | { | 644 | ch->is_loopback = GNUNET_YES; |
579 | if (fwd) | 645 | c = GNUNET_CONTAINER_multihashmap_get (open_ports, |
580 | { | 646 | port); |
581 | if (ch->dest_rel->client_ready) | 647 | if (NULL == c) |
582 | { | 648 | { |
583 | GML_send_data (ch->dest, msg, ch->lid_dest); | 649 | /* port closed, wait for it to possibly open */ |
584 | ch->dest_rel->client_ready = GNUNET_NO; | 650 | ch->state = CADET_CHANNEL_LOOSE; |
585 | ch->dest_rel->mid_recv++; | 651 | (void) GNUNET_CONTAINER_multihashmap_put (loose_channels, |
652 | port, | ||
653 | ch, | ||
654 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
655 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
656 | "Created loose incoming loopback channel to port %s\n", | ||
657 | GNUNET_h2s (&ch->port)); | ||
586 | } | 658 | } |
587 | else | 659 | else |
588 | add_buffered_data (msg, ch->dest_rel); | 660 | { |
661 | GCCH_bind (ch, | ||
662 | c); | ||
663 | } | ||
589 | } | 664 | } |
590 | else | 665 | else |
591 | { | 666 | { |
592 | if (ch->root_rel->client_ready) | 667 | ch->t = GCP_get_tunnel (destination, |
593 | { | 668 | GNUNET_YES); |
594 | GML_send_data (ch->root, msg, ch->lid_root); | 669 | ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME; |
595 | ch->root_rel->client_ready = GNUNET_NO; | 670 | ch->ctn = GCT_add_channel (ch->t, |
596 | ch->root_rel->mid_recv++; | 671 | ch); |
597 | } | ||
598 | else | ||
599 | add_buffered_data (msg, ch->root_rel); | ||
600 | } | 672 | } |
673 | GNUNET_STATISTICS_update (stats, | ||
674 | "# channels", | ||
675 | 1, | ||
676 | GNUNET_NO); | ||
677 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
678 | "Created channel to port %s at peer %s for %s using %s\n", | ||
679 | GNUNET_h2s (port), | ||
680 | GCP_2s (destination), | ||
681 | GSC_2s (owner), | ||
682 | (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t)); | ||
683 | return ch; | ||
601 | } | 684 | } |
602 | 685 | ||
603 | 686 | ||
604 | /** | 687 | /** |
605 | * Send a buffered message to the client, for in order delivery or | 688 | * We had an incoming channel to a port that is closed. |
606 | * as result of client ACK. | 689 | * It has not been opened for a while, drop it. |
607 | * | 690 | * |
608 | * @param ch Channel on which to empty the message buffer. | 691 | * @param cls the channel to drop |
609 | * @param c Client to send to. | ||
610 | * @param fwd Is this to send FWD data?. | ||
611 | */ | 692 | */ |
612 | static void | 693 | static void |
613 | send_client_buffered_data (struct CadetChannel *ch, | 694 | timeout_closed_cb (void *cls) |
614 | struct CadetClient *c, | ||
615 | int fwd) | ||
616 | { | 695 | { |
617 | struct CadetReliableMessage *copy; | 696 | struct CadetChannel *ch = cls; |
618 | struct CadetChannelReliability *rel; | ||
619 | |||
620 | LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); | ||
621 | rel = fwd ? ch->dest_rel : ch->root_rel; | ||
622 | if (GNUNET_NO == rel->client_ready) | ||
623 | { | ||
624 | LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); | ||
625 | return; | ||
626 | } | ||
627 | 697 | ||
628 | copy = rel->head_recv; | 698 | ch->retry_control_task = NULL; |
629 | /* We never buffer channel management messages */ | 699 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
630 | if (NULL != copy) | 700 | "Closing incoming channel to port %s from peer %s due to timeout\n", |
631 | { | 701 | GNUNET_h2s (&ch->port), |
632 | if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) | 702 | GCP_2s (GCT_get_destination (ch->t))); |
633 | { | 703 | channel_destroy (ch); |
634 | struct GNUNET_CADET_ChannelAppDataMessage *msg = (struct GNUNET_CADET_ChannelAppDataMessage *) ©[1]; | ||
635 | |||
636 | LOG (GNUNET_ERROR_TYPE_DEBUG, " have %u! now expecting %u\n", | ||
637 | copy->mid, rel->mid_recv + 1); | ||
638 | send_client_data (ch, msg, fwd); | ||
639 | rel->n_recv--; | ||
640 | GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); | ||
641 | LOG (GNUNET_ERROR_TYPE_DEBUG, " free copy recv MID %u (%p), %u left\n", | ||
642 | copy->mid, copy, rel->n_recv); | ||
643 | GNUNET_free (copy); | ||
644 | GCCH_send_data_ack (ch, fwd); | ||
645 | } | ||
646 | else | ||
647 | { | ||
648 | LOG (GNUNET_ERROR_TYPE_DEBUG, " reliable && don't have %u, next is %u\n", | ||
649 | rel->mid_recv, copy->mid); | ||
650 | if (GNUNET_YES == ch->destroy) | ||
651 | { | ||
652 | /* We don't have the next data piece and the remote peer has closed the | ||
653 | * channel. We won't receive it anymore, so just destroy the channel. | ||
654 | * FIXME: wait some time to allow other connections to | ||
655 | * deliver missing messages | ||
656 | */ | ||
657 | send_destroy (ch, GNUNET_YES); | ||
658 | GCCH_destroy (ch); | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n"); | ||
663 | } | 704 | } |
664 | 705 | ||
665 | 706 | ||
666 | /** | 707 | /** |
667 | * Allow a client to send more data. | 708 | * Create a new channel based on a request coming in over the network. |
668 | * | ||
669 | * In case the client was already allowed to send data, do nothing. | ||
670 | * | 709 | * |
671 | * @param ch Channel. | 710 | * @param t tunnel to the remote peer |
672 | * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) | 711 | * @param ctn identifier of this channel in the tunnel |
712 | * @param port desired local port | ||
713 | * @param options options for the channel | ||
714 | * @return handle to the new channel | ||
673 | */ | 715 | */ |
674 | static void | 716 | struct CadetChannel * |
675 | send_client_ack (struct CadetChannel *ch, int fwd) | 717 | GCCH_channel_incoming_new (struct CadetTunnel *t, |
718 | struct GNUNET_CADET_ChannelTunnelNumber ctn, | ||
719 | const struct GNUNET_HashCode *port, | ||
720 | uint32_t options) | ||
676 | { | 721 | { |
677 | struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; | 722 | struct CadetChannel *ch; |
678 | struct CadetClient *c = fwd ? ch->root : ch->dest; | 723 | struct CadetClient *c; |
724 | |||
725 | ch = GNUNET_new (struct CadetChannel); | ||
726 | ch->port = *port; | ||
727 | ch->t = t; | ||
728 | ch->ctn = ctn; | ||
729 | ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME; | ||
730 | ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER)); | ||
731 | ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE)); | ||
732 | ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER)); | ||
733 | ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */ | ||
734 | GNUNET_STATISTICS_update (stats, | ||
735 | "# channels", | ||
736 | 1, | ||
737 | GNUNET_NO); | ||
679 | 738 | ||
739 | c = GNUNET_CONTAINER_multihashmap_get (open_ports, | ||
740 | port); | ||
680 | if (NULL == c) | 741 | if (NULL == c) |
681 | { | 742 | { |
682 | GNUNET_break (GNUNET_NO != ch->destroy); | 743 | /* port closed, wait for it to possibly open */ |
683 | return; | 744 | ch->state = CADET_CHANNEL_LOOSE; |
745 | (void) GNUNET_CONTAINER_multihashmap_put (loose_channels, | ||
746 | port, | ||
747 | ch, | ||
748 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
749 | GNUNET_assert (NULL == ch->retry_control_task); | ||
750 | ch->retry_control_task | ||
751 | = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT, | ||
752 | &timeout_closed_cb, | ||
753 | ch); | ||
754 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
755 | "Created loose incoming channel to port %s from peer %s\n", | ||
756 | GNUNET_h2s (&ch->port), | ||
757 | GCP_2s (GCT_get_destination (ch->t))); | ||
684 | } | 758 | } |
685 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 759 | else |
686 | " sending %s ack to client on channel %s\n", | ||
687 | GC_f2s (fwd), GCCH_2s (ch)); | ||
688 | |||
689 | if (NULL == rel) | ||
690 | { | 760 | { |
691 | GNUNET_break (0); | 761 | GCCH_bind (ch, |
692 | return; | 762 | c); |
693 | } | 763 | } |
694 | 764 | GNUNET_STATISTICS_update (stats, | |
695 | if (GNUNET_YES == rel->client_allowed) | 765 | "# channels", |
696 | { | 766 | 1, |
697 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); | 767 | GNUNET_NO); |
698 | return; | 768 | return ch; |
699 | } | ||
700 | rel->client_allowed = GNUNET_YES; | ||
701 | |||
702 | GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest); | ||
703 | } | 769 | } |
704 | 770 | ||
705 | 771 | ||
706 | /** | 772 | /** |
707 | * Notify the root that the destination rejected the channel. | 773 | * Function called once the tunnel confirms that we sent the |
774 | * ACK message. Just remembers it was sent, we do not expect | ||
775 | * ACKs for ACKs ;-). | ||
708 | * | 776 | * |
709 | * @param ch Rejected channel. | 777 | * @param cls our `struct CadetChannel`. |
778 | * @param cid identifier of the connection within the tunnel, NULL | ||
779 | * if transmission failed | ||
710 | */ | 780 | */ |
711 | static void | 781 | static void |
712 | send_client_nack (struct CadetChannel *ch) | 782 | send_ack_cb (void *cls, |
783 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
713 | { | 784 | { |
714 | if (NULL == ch->root) | 785 | struct CadetChannel *ch = cls; |
715 | { | 786 | |
716 | GNUNET_break (0); | 787 | GNUNET_assert (NULL != ch->last_control_qe); |
717 | return; | 788 | ch->last_control_qe = NULL; |
718 | } | ||
719 | GML_send_channel_nack (ch->root, ch->lid_root); | ||
720 | } | 789 | } |
721 | 790 | ||
722 | 791 | ||
723 | /** | 792 | /** |
724 | * We haven't received an ACK after a certain time: restransmit the message. | 793 | * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer. |
725 | * | 794 | * |
726 | * @param cls Closure (CadetChannelReliability with the message to restransmit) | 795 | * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for |
727 | */ | 796 | */ |
728 | static void | 797 | static void |
729 | channel_retransmit_message (void *cls) | 798 | send_channel_data_ack (struct CadetChannel *ch) |
730 | { | 799 | { |
731 | struct CadetChannelReliability *rel = cls; | 800 | struct GNUNET_CADET_ChannelDataAckMessage msg; |
732 | struct CadetReliableMessage *copy; | ||
733 | struct CadetChannel *ch; | ||
734 | struct GNUNET_CADET_ChannelAppDataMessage *payload; | ||
735 | int fwd; | ||
736 | |||
737 | rel->retry_task = NULL; | ||
738 | ch = rel->ch; | ||
739 | copy = rel->head_sent; | ||
740 | if (NULL == copy) | ||
741 | { | ||
742 | GNUNET_break (0); // FIXME tripped in rps testcase | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | payload = (struct GNUNET_CADET_ChannelAppDataMessage *) ©[1]; | ||
747 | fwd = (rel == ch->root_rel); | ||
748 | |||
749 | /* Message not found in the queue that we are going to use. */ | ||
750 | LOG (GNUNET_ERROR_TYPE_DEBUG, "RETRANSMIT MID %u\n", copy->mid); | ||
751 | 801 | ||
752 | GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy); | 802 | if (GNUNET_NO == ch->reliable) |
753 | GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); | 803 | return; /* no ACKs */ |
804 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); | ||
805 | msg.header.size = htons (sizeof (msg)); | ||
806 | msg.ctn = ch->ctn; | ||
807 | msg.mid.mid = htonl (ntohl (ch->mid_recv.mid)); | ||
808 | msg.futures = GNUNET_htonll (ch->mid_futures); | ||
809 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
810 | "Sending DATA_ACK %u:%llX via %s\n", | ||
811 | (unsigned int) ntohl (msg.mid.mid), | ||
812 | (unsigned long long) ch->mid_futures, | ||
813 | GCCH_2s (ch)); | ||
814 | if (NULL != ch->last_control_qe) | ||
815 | GCT_send_cancel (ch->last_control_qe); | ||
816 | ch->last_control_qe = GCT_send (ch->t, | ||
817 | &msg.header, | ||
818 | &send_ack_cb, | ||
819 | ch); | ||
754 | } | 820 | } |
755 | 821 | ||
756 | 822 | ||
757 | /** | 823 | /** |
758 | * We haven't received an Channel ACK after a certain time: resend the CREATE. | 824 | * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the |
825 | * connection is up. | ||
759 | * | 826 | * |
760 | * @param cls Closure (CadetChannelReliability of the channel to recreate) | 827 | * @param cls the `struct CadetChannel` |
761 | */ | 828 | */ |
762 | static void | 829 | static void |
763 | channel_recreate (void *cls) | 830 | send_open_ack (void *cls) |
764 | { | 831 | { |
765 | struct CadetChannelReliability *rel = cls; | 832 | struct CadetChannel *ch = cls; |
766 | 833 | struct GNUNET_CADET_ChannelManageMessage msg; | |
767 | rel->retry_task = NULL; | ||
768 | LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n"); | ||
769 | GNUNET_STATISTICS_update (stats, | ||
770 | "# data retransmitted", 1, GNUNET_NO); | ||
771 | 834 | ||
772 | if (rel == rel->ch->root_rel) | 835 | ch->retry_control_task = NULL; |
773 | { | 836 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
774 | send_create (rel->ch); | 837 | "Sending CHANNEL_OPEN_ACK on %s\n", |
775 | } | 838 | GCCH_2s (ch)); |
776 | else if (rel == rel->ch->dest_rel) | 839 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK); |
777 | { | 840 | msg.header.size = htons (sizeof (msg)); |
778 | send_ack (rel->ch, GNUNET_YES); | 841 | msg.reserved = htonl (0); |
779 | } | 842 | msg.ctn = ch->ctn; |
780 | else | 843 | if (NULL != ch->last_control_qe) |
781 | { | 844 | GCT_send_cancel (ch->last_control_qe); |
782 | GNUNET_break (0); | 845 | ch->last_control_qe = GCT_send (ch->t, |
783 | } | 846 | &msg.header, |
847 | &send_ack_cb, | ||
848 | ch); | ||
784 | } | 849 | } |
785 | 850 | ||
786 | 851 | ||
787 | /** | 852 | /** |
788 | * Message has been sent: start retransmission timer. | 853 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for |
854 | * this channel. If the binding was successful, (re)transmit the | ||
855 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK. | ||
789 | * | 856 | * |
790 | * @param cls Closure (queue structure). | 857 | * @param ch channel that got the duplicate open |
791 | * @param t Tunnel. | 858 | * @param cti identifier of the connection that delivered the message |
792 | * @param q Queue handler (no longer valid). | ||
793 | * @param type Type of message. | ||
794 | * @param size Size of the message. | ||
795 | */ | 859 | */ |
796 | static void | 860 | void |
797 | ch_message_sent (void *cls, | 861 | GCCH_handle_duplicate_open (struct CadetChannel *ch, |
798 | struct CadetTunnel *t, | 862 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) |
799 | struct CadetTunnelQueue *q, | ||
800 | uint16_t type, size_t size) | ||
801 | { | 863 | { |
802 | struct CadetChannelQueue *chq = cls; | 864 | if (NULL == ch->dest) |
803 | struct CadetReliableMessage *copy = chq->copy; | ||
804 | struct CadetChannelReliability *rel; | ||
805 | |||
806 | LOG (GNUNET_ERROR_TYPE_DEBUG, "channel_message_sent callback %s\n", | ||
807 | GC_m2s (chq->type)); | ||
808 | |||
809 | switch (chq->type) | ||
810 | { | 865 | { |
811 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: | 866 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
812 | LOG (GNUNET_ERROR_TYPE_DEBUG, "data MID %u sent\n", copy->mid); | 867 | "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n", |
813 | GNUNET_assert (chq == copy->chq); | 868 | GCCH_2s (ch)); |
814 | copy->timestamp = GNUNET_TIME_absolute_get (); | 869 | return; |
815 | rel = copy->rel; | ||
816 | if (NULL == rel->retry_task) | ||
817 | { | ||
818 | LOG (GNUNET_ERROR_TYPE_DEBUG, " scheduling retry in %d * %s\n", | ||
819 | CADET_RETRANSMIT_MARGIN, | ||
820 | GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, | ||
821 | GNUNET_YES)); | ||
822 | if (0 != rel->expected_delay.rel_value_us) | ||
823 | { | ||
824 | rel->retry_timer = | ||
825 | GNUNET_TIME_relative_saturating_multiply (rel->expected_delay, | ||
826 | CADET_RETRANSMIT_MARGIN); | ||
827 | } | ||
828 | else | ||
829 | { | ||
830 | rel->retry_timer = CADET_RETRANSMIT_TIME; | ||
831 | } | ||
832 | LOG (GNUNET_ERROR_TYPE_DEBUG, " using delay %s\n", | ||
833 | GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, | ||
834 | GNUNET_NO)); | ||
835 | rel->retry_task = | ||
836 | GNUNET_SCHEDULER_add_delayed (rel->retry_timer, | ||
837 | &channel_retransmit_message, rel); | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | LOG (GNUNET_ERROR_TYPE_DEBUG, "retry running %p\n", rel->retry_task); | ||
842 | } | ||
843 | copy->chq = NULL; | ||
844 | break; | ||
845 | |||
846 | |||
847 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: | ||
848 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: | ||
849 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: | ||
850 | LOG (GNUNET_ERROR_TYPE_DEBUG, "sent %s\n", GC_m2s (chq->type)); | ||
851 | rel = chq->rel; | ||
852 | GNUNET_assert (rel->uniq == chq); | ||
853 | rel->uniq = NULL; | ||
854 | |||
855 | if (CADET_CHANNEL_READY != rel->ch->state | ||
856 | && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK != type | ||
857 | && GNUNET_NO == rel->ch->destroy) | ||
858 | { | ||
859 | GNUNET_assert (NULL == rel->retry_task); | ||
860 | LOG (GNUNET_ERROR_TYPE_DEBUG, "STD BACKOFF %s\n", | ||
861 | GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, | ||
862 | GNUNET_NO)); | ||
863 | rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer); | ||
864 | rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer, | ||
865 | &channel_recreate, rel); | ||
866 | } | ||
867 | break; | ||
868 | |||
869 | default: | ||
870 | GNUNET_break (0); | ||
871 | } | 870 | } |
872 | 871 | if (NULL != ch->retry_control_task) | |
873 | GNUNET_free (chq); | 872 | { |
873 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
874 | "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n", | ||
875 | GCCH_2s (ch)); | ||
876 | return; | ||
877 | } | ||
878 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
879 | "Retransmitting CHANNEL_OPEN_ACK on %s\n", | ||
880 | GCCH_2s (ch)); | ||
881 | ch->retry_control_task | ||
882 | = GNUNET_SCHEDULER_add_now (&send_open_ack, | ||
883 | ch); | ||
874 | } | 884 | } |
875 | 885 | ||
876 | 886 | ||
877 | /** | 887 | /** |
878 | * send a channel create message. | 888 | * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages. |
879 | * | 889 | * |
880 | * @param ch Channel for which to send. | 890 | * @param ch channel the ack is for |
891 | * @param to_owner #GNUNET_YES to send to owner, | ||
892 | * #GNUNET_NO to send to dest | ||
881 | */ | 893 | */ |
882 | static void | 894 | static void |
883 | send_create (struct CadetChannel *ch) | 895 | send_ack_to_client (struct CadetChannel *ch, |
896 | int to_owner) | ||
884 | { | 897 | { |
885 | struct GNUNET_CADET_ChannelOpenMessage msgcc; | 898 | struct GNUNET_MQ_Envelope *env; |
899 | struct GNUNET_CADET_LocalAck *ack; | ||
900 | struct CadetChannelClient *ccc; | ||
886 | 901 | ||
887 | msgcc.header.size = htons (sizeof (msgcc)); | 902 | ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest; |
888 | msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN); | 903 | if (NULL == ccc) |
889 | msgcc.ctn = ch->gid; | 904 | { |
890 | msgcc.port = ch->port; | 905 | /* This can happen if we are just getting ACKs after |
891 | msgcc.opt = htonl (channel_get_options (ch)); | 906 | our local client already disconnected. */ |
892 | 907 | GNUNET_assert (GNUNET_YES == ch->destroy); | |
893 | GCCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL); | 908 | return; |
909 | } | ||
910 | env = GNUNET_MQ_msg (ack, | ||
911 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); | ||
912 | ack->ccn = ccc->ccn; | ||
913 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
914 | "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n", | ||
915 | GSC_2s (ccc->c), | ||
916 | (GNUNET_YES == to_owner) ? "owner" : "dest", | ||
917 | ntohl (ack->ccn.channel_of_client), | ||
918 | ch->pending_messages, | ||
919 | ch->max_pending_messages); | ||
920 | GSC_send_to_client (ccc->c, | ||
921 | env); | ||
894 | } | 922 | } |
895 | 923 | ||
896 | 924 | ||
897 | /** | 925 | /** |
898 | * Confirm we got a channel create or FWD ack. | 926 | * A client is bound to the port that we have a channel |
927 | * open to. Send the acknowledgement for the connection | ||
928 | * request and establish the link with the client. | ||
899 | * | 929 | * |
900 | * @param ch The channel to confirm. | 930 | * @param ch open incoming channel |
901 | * @param fwd Should we send a FWD ACK? (going dest->root) | 931 | * @param c client listening on the respective port |
902 | */ | 932 | */ |
903 | static void | 933 | void |
904 | send_ack (struct CadetChannel *ch, int fwd) | 934 | GCCH_bind (struct CadetChannel *ch, |
935 | struct CadetClient *c) | ||
905 | { | 936 | { |
906 | struct GNUNET_CADET_ChannelManageMessage msg; | 937 | uint32_t options; |
938 | struct CadetChannelClient *cccd; | ||
907 | 939 | ||
908 | msg.header.size = htons (sizeof (msg)); | ||
909 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK); | ||
910 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 940 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
911 | " sending channel %s ack for channel %s\n", | 941 | "Binding %s from %s to port %s of %s\n", |
912 | GC_f2s (fwd), GCCH_2s (ch)); | 942 | GCCH_2s (ch), |
913 | 943 | GCT_2s (ch->t), | |
914 | msg.ctn =ch->gid; | 944 | GNUNET_h2s (&ch->port), |
915 | GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); | 945 | GSC_2s (c)); |
946 | if (NULL != ch->retry_control_task) | ||
947 | { | ||
948 | /* there might be a timeout task here */ | ||
949 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); | ||
950 | ch->retry_control_task = NULL; | ||
951 | } | ||
952 | options = 0; | ||
953 | if (ch->nobuffer) | ||
954 | options |= GNUNET_CADET_OPTION_NOBUFFER; | ||
955 | if (ch->reliable) | ||
956 | options |= GNUNET_CADET_OPTION_RELIABLE; | ||
957 | if (ch->out_of_order) | ||
958 | options |= GNUNET_CADET_OPTION_OUT_OF_ORDER; | ||
959 | cccd = GNUNET_new (struct CadetChannelClient); | ||
960 | GNUNET_assert (NULL == ch->dest); | ||
961 | ch->dest = cccd; | ||
962 | cccd->c = c; | ||
963 | cccd->client_ready = GNUNET_YES; | ||
964 | cccd->ccn = GSC_bind (c, | ||
965 | ch, | ||
966 | (GNUNET_YES == ch->is_loopback) | ||
967 | ? GCP_get (&my_full_id, | ||
968 | GNUNET_YES) | ||
969 | : GCT_get_destination (ch->t), | ||
970 | &ch->port, | ||
971 | options); | ||
972 | GNUNET_assert (ntohl (cccd->ccn.channel_of_client) < | ||
973 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
974 | ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */ | ||
975 | if (GNUNET_YES == ch->is_loopback) | ||
976 | { | ||
977 | ch->state = CADET_CHANNEL_OPEN_SENT; | ||
978 | GCCH_handle_channel_open_ack (ch, | ||
979 | NULL); | ||
980 | } | ||
981 | else | ||
982 | { | ||
983 | /* notify other peer that we accepted the connection */ | ||
984 | ch->state = CADET_CHANNEL_READY; | ||
985 | ch->retry_control_task | ||
986 | = GNUNET_SCHEDULER_add_now (&send_open_ack, | ||
987 | ch); | ||
988 | } | ||
989 | /* give client it's initial supply of ACKs */ | ||
990 | GNUNET_assert (ntohl (cccd->ccn.channel_of_client) < | ||
991 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
992 | for (unsigned int i=0;i<ch->max_pending_messages;i++) | ||
993 | send_ack_to_client (ch, | ||
994 | GNUNET_NO); | ||
916 | } | 995 | } |
917 | 996 | ||
918 | 997 | ||
919 | /** | 998 | /** |
920 | * Send a message and don't keep any info about it: we won't need to cancel it | 999 | * One of our clients has disconnected, tell the other one that we |
921 | * or resend it. | 1000 | * are finished. Done asynchronously to avoid concurrent modification |
1001 | * issues if this is the same client. | ||
922 | * | 1002 | * |
923 | * @param msg Header of the message to fire away. | 1003 | * @param cls the `struct CadetChannel` where one of the ends is now dead |
924 | * @param ch Channel on which the message should go. | ||
925 | * @param force Is this a forced (undroppable) message? | ||
926 | */ | 1004 | */ |
927 | static void | 1005 | static void |
928 | fire_and_forget (const struct GNUNET_MessageHeader *msg, | 1006 | signal_remote_destroy_cb (void *cls) |
929 | struct CadetChannel *ch, | ||
930 | int force) | ||
931 | { | 1007 | { |
932 | GNUNET_break (NULL == | 1008 | struct CadetChannel *ch = cls; |
933 | GCT_send_prebuilt_message (msg, ch->t, NULL, | 1009 | struct CadetChannelClient *ccc; |
934 | force, NULL, NULL)); | 1010 | |
1011 | /* Find which end is left... */ | ||
1012 | ch->retry_control_task = NULL; | ||
1013 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; | ||
1014 | GSC_handle_remote_channel_destroy (ccc->c, | ||
1015 | ccc->ccn, | ||
1016 | ch); | ||
1017 | channel_destroy (ch); | ||
935 | } | 1018 | } |
936 | 1019 | ||
937 | 1020 | ||
938 | /** | 1021 | /** |
939 | * Notify that a channel create didn't succeed. | 1022 | * Destroy locally created channel. Called by the local client, so no |
1023 | * need to tell the client. | ||
940 | * | 1024 | * |
941 | * @param ch The channel to reject. | 1025 | * @param ch channel to destroy |
1026 | * @param c client that caused the destruction | ||
1027 | * @param ccn client number of the client @a c | ||
942 | */ | 1028 | */ |
943 | static void | 1029 | void |
944 | send_nack (struct CadetChannel *ch) | 1030 | GCCH_channel_local_destroy (struct CadetChannel *ch, |
1031 | struct CadetClient *c, | ||
1032 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
945 | { | 1033 | { |
946 | struct GNUNET_CADET_ChannelManageMessage msg; | ||
947 | |||
948 | msg.header.size = htons (sizeof (msg)); | ||
949 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED); | ||
950 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1034 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
951 | " sending channel NACK for channel %s\n", | 1035 | "%s asks for destruction of %s\n", |
1036 | GSC_2s (c), | ||
952 | GCCH_2s (ch)); | 1037 | GCCH_2s (ch)); |
1038 | GNUNET_assert (NULL != c); | ||
1039 | if ( (NULL != ch->owner) && | ||
1040 | (c == ch->owner->c) && | ||
1041 | (ccn.channel_of_client == ch->owner->ccn.channel_of_client) ) | ||
1042 | { | ||
1043 | free_channel_client (ch->owner); | ||
1044 | ch->owner = NULL; | ||
1045 | } | ||
1046 | else if ( (NULL != ch->dest) && | ||
1047 | (c == ch->dest->c) && | ||
1048 | (ccn.channel_of_client == ch->dest->ccn.channel_of_client) ) | ||
1049 | { | ||
1050 | free_channel_client (ch->dest); | ||
1051 | ch->dest = NULL; | ||
1052 | } | ||
1053 | else | ||
1054 | { | ||
1055 | GNUNET_assert (0); | ||
1056 | } | ||
953 | 1057 | ||
954 | msg.ctn = ch->gid; | 1058 | if (GNUNET_YES == ch->destroy) |
955 | GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); | ||
956 | } | ||
957 | |||
958 | |||
959 | /** | ||
960 | * Destroy all reliable messages queued for a channel, | ||
961 | * during a channel destruction. | ||
962 | * Frees the reliability structure itself. | ||
963 | * | ||
964 | * @param rel Reliability data for a channel. | ||
965 | */ | ||
966 | static void | ||
967 | channel_rel_free_all (struct CadetChannelReliability *rel) | ||
968 | { | ||
969 | struct CadetReliableMessage *copy; | ||
970 | struct CadetReliableMessage *next; | ||
971 | |||
972 | if (NULL == rel) | ||
973 | return; | ||
974 | |||
975 | for (copy = rel->head_recv; NULL != copy; copy = next) | ||
976 | { | 1059 | { |
977 | next = copy->next; | 1060 | /* other end already destroyed, with the local client gone, no need |
978 | GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); | 1061 | to finish transmissions, just destroy immediately. */ |
979 | LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL RECV %p\n", copy); | 1062 | channel_destroy (ch); |
980 | GNUNET_break (NULL == copy->chq); | 1063 | return; |
981 | GNUNET_free (copy); | ||
982 | } | 1064 | } |
983 | for (copy = rel->head_sent; NULL != copy; copy = next) | 1065 | if ( (NULL != ch->head_sent) && |
1066 | ( (NULL != ch->owner) || | ||
1067 | (NULL != ch->dest) ) ) | ||
984 | { | 1068 | { |
985 | next = copy->next; | 1069 | /* Wait for other end to destroy us as well, |
986 | GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); | 1070 | and otherwise allow send queue to be transmitted first */ |
987 | LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL SEND %p\n", copy); | 1071 | ch->destroy = GNUNET_YES; |
988 | if (NULL != copy->chq) | 1072 | return; |
989 | { | ||
990 | if (NULL != copy->chq->tq) | ||
991 | { | ||
992 | GCT_cancel (copy->chq->tq); | ||
993 | /* ch_message_sent will free copy->q */ | ||
994 | } | ||
995 | else | ||
996 | { | ||
997 | GNUNET_free (copy->chq); | ||
998 | GNUNET_break (0); | ||
999 | } | ||
1000 | } | ||
1001 | GNUNET_free (copy); | ||
1002 | } | 1073 | } |
1003 | if (NULL != rel->uniq && NULL != rel->uniq->tq) | 1074 | if ( (GNUNET_YES == ch->is_loopback) && |
1075 | ( (NULL != ch->owner) || | ||
1076 | (NULL != ch->dest) ) ) | ||
1004 | { | 1077 | { |
1005 | GCT_cancel (rel->uniq->tq); | 1078 | if (NULL != ch->retry_control_task) |
1006 | /* ch_message_sent is called freeing uniq */ | 1079 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); |
1080 | ch->retry_control_task | ||
1081 | = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb, | ||
1082 | ch); | ||
1083 | return; | ||
1007 | } | 1084 | } |
1008 | if (NULL != rel->retry_task) | 1085 | if (GNUNET_NO == ch->is_loopback) |
1009 | { | 1086 | { |
1010 | GNUNET_SCHEDULER_cancel (rel->retry_task); | 1087 | /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */ |
1011 | rel->retry_task = NULL; | 1088 | switch (ch->state) |
1089 | { | ||
1090 | case CADET_CHANNEL_NEW: | ||
1091 | /* We gave up on a channel that we created as a client to a remote | ||
1092 | target, but that never went anywhere. Nothing to do here. */ | ||
1093 | break; | ||
1094 | case CADET_CHANNEL_LOOSE: | ||
1095 | GSC_drop_loose_channel (&ch->port, | ||
1096 | ch); | ||
1097 | break; | ||
1098 | default: | ||
1099 | GCT_send_channel_destroy (ch->t, | ||
1100 | ch->ctn); | ||
1101 | } | ||
1012 | } | 1102 | } |
1013 | GNUNET_free (rel); | 1103 | /* Nothing left to do, just finish destruction */ |
1104 | channel_destroy (ch); | ||
1014 | } | 1105 | } |
1015 | 1106 | ||
1016 | 1107 | ||
1017 | /** | 1108 | /** |
1018 | * Mark future messages as ACK'd. | 1109 | * We got an acknowledgement for the creation of the channel |
1019 | * | 1110 | * (the port is open on the other side). Begin transmissions. |
1020 | * @param rel Reliability data. | ||
1021 | * @param msg DataACK message with a bitfield of future ACK'd messages. | ||
1022 | * | 1111 | * |
1023 | * @return How many messages have been freed. | 1112 | * @param ch channel to destroy |
1113 | * @param cti identifier of the connection that delivered the message | ||
1024 | */ | 1114 | */ |
1025 | static unsigned int | 1115 | void |
1026 | channel_rel_free_sent (struct CadetChannelReliability *rel, | 1116 | GCCH_handle_channel_open_ack (struct CadetChannel *ch, |
1027 | const struct GNUNET_CADET_ChannelDataAckMessage *msg) | 1117 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) |
1028 | { | 1118 | { |
1029 | struct CadetReliableMessage *copy; | 1119 | switch (ch->state) |
1030 | struct CadetReliableMessage *next; | ||
1031 | uint64_t bitfield; | ||
1032 | uint64_t mask; | ||
1033 | uint32_t mid; | ||
1034 | uint32_t target; | ||
1035 | unsigned int i; | ||
1036 | unsigned int r; | ||
1037 | |||
1038 | bitfield = msg->futures; | ||
1039 | mid = ntohl (msg->mid); | ||
1040 | LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable %u %lX\n", mid, bitfield); | ||
1041 | LOG (GNUNET_ERROR_TYPE_DEBUG, " rel %p, head %p\n", rel, rel->head_sent); | ||
1042 | for (i = 0, r = 0, copy = rel->head_sent; | ||
1043 | i < 64 && NULL != copy && 0 != bitfield; | ||
1044 | i++) | ||
1045 | { | 1120 | { |
1046 | LOG (GNUNET_ERROR_TYPE_DEBUG, " trying bit %u (mid %u)\n", i, mid + i + 1); | 1121 | case CADET_CHANNEL_NEW: |
1047 | mask = 0x1LL << i; | 1122 | /* this should be impossible */ |
1048 | if (0 == (bitfield & mask)) | 1123 | GNUNET_break (0); |
1049 | continue; | 1124 | break; |
1050 | 1125 | case CADET_CHANNEL_LOOSE: | |
1051 | LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n"); | 1126 | /* This makes no sense. */ |
1052 | /* Bit was set, clear the bit from the bitfield */ | 1127 | GNUNET_break_op (0); |
1053 | bitfield &= ~mask; | 1128 | break; |
1054 | 1129 | case CADET_CHANNEL_OPEN_SENT: | |
1055 | /* The i-th bit was set. Do we have that copy? */ | 1130 | if (NULL == ch->owner) |
1056 | /* Skip copies with mid < target */ | ||
1057 | target = mid + i + 1; | ||
1058 | LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target); | ||
1059 | while (NULL != copy && GC_is_pid_bigger (target, copy->mid)) | ||
1060 | copy = copy->next; | ||
1061 | |||
1062 | /* Did we run out of copies? (previously freed, it's ok) */ | ||
1063 | if (NULL == copy) | ||
1064 | { | 1131 | { |
1065 | LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); | 1132 | /* We're not the owner, wrong direction! */ |
1066 | return r; | 1133 | GNUNET_break_op (0); |
1134 | return; | ||
1067 | } | 1135 | } |
1068 | 1136 | LOG (GNUNET_ERROR_TYPE_DEBUG, | |
1069 | /* Did we overshoot the target? (previously freed, it's ok) */ | 1137 | "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n", |
1070 | if (GC_is_pid_bigger (copy->mid, target)) | 1138 | GCCH_2s (ch)); |
1139 | if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */ | ||
1071 | { | 1140 | { |
1072 | LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid); | 1141 | GNUNET_SCHEDULER_cancel (ch->retry_control_task); |
1073 | i += copy->mid - target - 1; /* MID: 90, t = 85, i += 4 (i++ later) */ | 1142 | ch->retry_control_task = NULL; |
1074 | mask = (0x1LL << (i + 1)) - 1; /* Mask = i-th bit and all before */ | ||
1075 | bitfield &= ~mask; /* Clear all bits up to MID - 1 */ | ||
1076 | continue; | ||
1077 | } | 1143 | } |
1078 | 1144 | ch->state = CADET_CHANNEL_READY; | |
1079 | /* Now copy->mid == target, free it */ | 1145 | /* On first connect, send client as many ACKs as we allow messages |
1080 | next = copy->next; | 1146 | to be buffered! */ |
1081 | GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); | 1147 | for (unsigned int i=0;i<ch->max_pending_messages;i++) |
1082 | r++; | 1148 | send_ack_to_client (ch, |
1083 | copy = next; | 1149 | GNUNET_YES); |
1150 | break; | ||
1151 | case CADET_CHANNEL_READY: | ||
1152 | /* duplicate ACK, maybe we retried the CREATE. Ignore. */ | ||
1153 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1154 | "Received duplicate channel OPEN_ACK for %s\n", | ||
1155 | GCCH_2s (ch)); | ||
1156 | GNUNET_STATISTICS_update (stats, | ||
1157 | "# duplicate CREATE_ACKs", | ||
1158 | 1, | ||
1159 | GNUNET_NO); | ||
1160 | break; | ||
1084 | } | 1161 | } |
1085 | LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n"); | ||
1086 | return r; | ||
1087 | } | 1162 | } |
1088 | 1163 | ||
1089 | 1164 | ||
1090 | /** | 1165 | /** |
1091 | * Destroy a reliable message after it has been acknowledged, either by | 1166 | * Test if element @a e1 comes before element @a e2. |
1092 | * direct mid ACK or bitfield. Updates the appropriate data structures and | ||
1093 | * timers and frees all memory. | ||
1094 | * | 1167 | * |
1095 | * @param copy Message that is no longer needed: remote peer got it. | 1168 | * @param cls closure, to a flag where we indicate duplicate packets |
1096 | * @param update_time Is the timing information relevant? | 1169 | * @param m1 a message of to sort |
1097 | * If this message is ACK in a batch the timing information | 1170 | * @param m2 another message to sort |
1098 | * is skewed by the retransmission, count only for the | 1171 | * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO |
1099 | * retransmitted message. | ||
1100 | * | ||
1101 | * @return #GNUNET_YES if channel was destroyed as a result of the call, | ||
1102 | * #GNUNET_NO otherwise. | ||
1103 | */ | 1172 | */ |
1104 | static int | 1173 | static int |
1105 | rel_message_free (struct CadetReliableMessage *copy, int update_time) | 1174 | is_before (void *cls, |
1175 | struct CadetOutOfOrderMessage *m1, | ||
1176 | struct CadetOutOfOrderMessage *m2) | ||
1106 | { | 1177 | { |
1107 | struct CadetChannelReliability *rel; | 1178 | int *duplicate = cls; |
1108 | struct GNUNET_TIME_Relative time; | 1179 | uint32_t v1 = ntohl (m1->mid.mid); |
1180 | uint32_t v2 = ntohl (m2->mid.mid); | ||
1181 | uint32_t delta; | ||
1109 | 1182 | ||
1110 | rel = copy->rel; | 1183 | delta = v2 - v1; |
1111 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid); | 1184 | if (0 == delta) |
1112 | if (GNUNET_YES == update_time) | 1185 | *duplicate = GNUNET_YES; |
1186 | if (delta > (uint32_t) INT_MAX) | ||
1113 | { | 1187 | { |
1114 | time = GNUNET_TIME_absolute_get_duration (copy->timestamp); | 1188 | /* in overflow range, we can safely assume we wrapped around */ |
1115 | if (0 == rel->expected_delay.rel_value_us) | 1189 | return GNUNET_NO; |
1116 | rel->expected_delay = time; | ||
1117 | else | ||
1118 | { | ||
1119 | rel->expected_delay.rel_value_us *= 7; | ||
1120 | rel->expected_delay.rel_value_us += time.rel_value_us; | ||
1121 | rel->expected_delay.rel_value_us /= 8; | ||
1122 | } | ||
1123 | LOG (GNUNET_ERROR_TYPE_DEBUG, " message time %12s\n", | ||
1124 | GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO)); | ||
1125 | LOG (GNUNET_ERROR_TYPE_DEBUG, " new delay %12s\n", | ||
1126 | GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, | ||
1127 | GNUNET_NO)); | ||
1128 | rel->retry_timer = rel->expected_delay; | ||
1129 | } | 1190 | } |
1130 | else | 1191 | else |
1131 | { | 1192 | { |
1132 | LOG (GNUNET_ERROR_TYPE_DEBUG, "batch free, ignoring timing\n"); | 1193 | /* result is small, thus v2 > v1, thus m1 < m2 */ |
1133 | } | ||
1134 | rel->ch->pending_messages--; | ||
1135 | if (NULL != copy->chq) | ||
1136 | { | ||
1137 | GCT_cancel (copy->chq->tq); | ||
1138 | /* copy->q is set to NULL by ch_message_sent */ | ||
1139 | } | ||
1140 | GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); | ||
1141 | LOG (GNUNET_ERROR_TYPE_DEBUG, " free send copy MID %u at %p\n", | ||
1142 | copy->mid, copy); | ||
1143 | GNUNET_free (copy); | ||
1144 | |||
1145 | if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages) | ||
1146 | { | ||
1147 | GCCH_destroy (rel->ch); | ||
1148 | return GNUNET_YES; | 1194 | return GNUNET_YES; |
1149 | } | 1195 | } |
1150 | return GNUNET_NO; | ||
1151 | } | 1196 | } |
1152 | 1197 | ||
1153 | 1198 | ||
1154 | /** | 1199 | /** |
1155 | * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. | 1200 | * We got payload data for a channel. Pass it on to the client |
1201 | * and send an ACK to the other end (once flow control allows it!) | ||
1156 | * | 1202 | * |
1157 | * @param ch Channel to mark as ready. | 1203 | * @param ch channel that got data |
1158 | * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) | 1204 | * @param cti identifier of the connection that delivered the message |
1205 | * @param msg message that was received | ||
1159 | */ | 1206 | */ |
1160 | static void | 1207 | void |
1161 | channel_confirm (struct CadetChannel *ch, int fwd) | 1208 | GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, |
1209 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1210 | const struct GNUNET_CADET_ChannelAppDataMessage *msg) | ||
1162 | { | 1211 | { |
1163 | struct CadetChannelReliability *rel; | 1212 | struct GNUNET_MQ_Envelope *env; |
1164 | enum CadetChannelState oldstate; | 1213 | struct GNUNET_CADET_LocalData *ld; |
1165 | 1214 | struct CadetChannelClient *ccc; | |
1166 | rel = fwd ? ch->root_rel : ch->dest_rel; | 1215 | size_t payload_size; |
1167 | if (NULL == rel) | 1216 | struct CadetOutOfOrderMessage *com; |
1217 | int duplicate; | ||
1218 | uint32_t mid_min; | ||
1219 | uint32_t mid_max; | ||
1220 | uint32_t mid_msg; | ||
1221 | uint32_t delta; | ||
1222 | |||
1223 | GNUNET_assert (GNUNET_NO == ch->is_loopback); | ||
1224 | if ( (GNUNET_YES == ch->destroy) && | ||
1225 | (NULL == ch->owner) && | ||
1226 | (NULL == ch->dest) ) | ||
1227 | { | ||
1228 | /* This client is gone, but we still have messages to send to | ||
1229 | the other end (which is why @a ch is not yet dead). However, | ||
1230 | we cannot pass messages to our client anymore. */ | ||
1231 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1232 | "Dropping incoming payload on %s as this end is already closed\n", | ||
1233 | GCCH_2s (ch)); | ||
1234 | /* send back DESTROY notification to stop further retransmissions! */ | ||
1235 | GCT_send_channel_destroy (ch->t, | ||
1236 | ch->ctn); | ||
1237 | return; | ||
1238 | } | ||
1239 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | ||
1240 | env = GNUNET_MQ_msg_extra (ld, | ||
1241 | payload_size, | ||
1242 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); | ||
1243 | ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn; | ||
1244 | GNUNET_memcpy (&ld[1], | ||
1245 | &msg[1], | ||
1246 | payload_size); | ||
1247 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; | ||
1248 | if ( (GNUNET_YES == ccc->client_ready) && | ||
1249 | ( (GNUNET_YES == ch->out_of_order) || | ||
1250 | (msg->mid.mid == ch->mid_recv.mid) ) ) | ||
1168 | { | 1251 | { |
1169 | GNUNET_break (GNUNET_NO != ch->destroy); | 1252 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1253 | "Giving %u bytes of payload with MID %u from %s to client %s\n", | ||
1254 | (unsigned int) payload_size, | ||
1255 | ntohl (msg->mid.mid), | ||
1256 | GCCH_2s (ch), | ||
1257 | GSC_2s (ccc->c)); | ||
1258 | ccc->client_ready = GNUNET_NO; | ||
1259 | GSC_send_to_client (ccc->c, | ||
1260 | env); | ||
1261 | ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid)); | ||
1262 | ch->mid_futures >>= 1; | ||
1263 | send_channel_data_ack (ch); | ||
1170 | return; | 1264 | return; |
1171 | } | 1265 | } |
1172 | LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n", | ||
1173 | GC_f2s (fwd), GCCH_2s (ch)); | ||
1174 | oldstate = ch->state; | ||
1175 | ch->state = CADET_CHANNEL_READY; | ||
1176 | 1266 | ||
1177 | if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) | 1267 | if (GNUNET_YES == ch->reliable) |
1178 | { | 1268 | { |
1179 | rel->client_ready = GNUNET_YES; | 1269 | /* check if message ought to be dropped because it is ancient/too distant/duplicate */ |
1180 | rel->expected_delay = rel->retry_timer; | 1270 | mid_min = ntohl (ch->mid_recv.mid); |
1181 | LOG (GNUNET_ERROR_TYPE_DEBUG, " confirm retry timer %s\n", | 1271 | mid_max = mid_min + ch->max_pending_messages; |
1182 | GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO)); | 1272 | mid_msg = ntohl (msg->mid.mid); |
1183 | if (GCT_get_connections_buffer (ch->t) > 0 || GCT_is_loopback (ch->t)) | 1273 | if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) || |
1184 | send_client_ack (ch, fwd); | 1274 | ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) ) |
1185 | |||
1186 | if (NULL != rel->retry_task) | ||
1187 | { | 1275 | { |
1188 | GNUNET_SCHEDULER_cancel (rel->retry_task); | 1276 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1189 | rel->retry_task = NULL; | 1277 | "%s at %u drops ancient or far-future message %u\n", |
1190 | } | 1278 | GCCH_2s (ch), |
1191 | else if (NULL != rel->uniq) | 1279 | (unsigned int) mid_min, |
1192 | { | 1280 | ntohl (msg->mid.mid)); |
1193 | GCT_cancel (rel->uniq->tq); | 1281 | |
1194 | /* ch_message_sent will free and NULL uniq */ | 1282 | GNUNET_STATISTICS_update (stats, |
1283 | "# duplicate DATA (ancient or future)", | ||
1284 | 1, | ||
1285 | GNUNET_NO); | ||
1286 | GNUNET_MQ_discard (env); | ||
1287 | send_channel_data_ack (ch); | ||
1288 | return; | ||
1195 | } | 1289 | } |
1196 | else if (GNUNET_NO == is_loopback (ch)) | 1290 | /* mark bit for future ACKs */ |
1291 | delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */ | ||
1292 | if (delta < 64) | ||
1197 | { | 1293 | { |
1198 | /* We SHOULD have been trying to retransmit this! */ | 1294 | if (0 != (ch->mid_futures & (1LLU << delta))) |
1199 | GNUNET_break (0); | 1295 | { |
1296 | /* Duplicate within the queue, drop also */ | ||
1297 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1298 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | ||
1299 | (unsigned int) payload_size, | ||
1300 | GCCH_2s (ch), | ||
1301 | ntohl (msg->mid.mid)); | ||
1302 | GNUNET_STATISTICS_update (stats, | ||
1303 | "# duplicate DATA", | ||
1304 | 1, | ||
1305 | GNUNET_NO); | ||
1306 | GNUNET_MQ_discard (env); | ||
1307 | send_channel_data_ack (ch); | ||
1308 | return; | ||
1309 | } | ||
1310 | ch->mid_futures |= (1LLU << delta); | ||
1311 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1312 | "Marked bit %llX for mid %u (base: %u); now: %llX\n", | ||
1313 | (1LLU << delta), | ||
1314 | mid_msg, | ||
1315 | mid_min, | ||
1316 | ch->mid_futures); | ||
1200 | } | 1317 | } |
1201 | } | 1318 | } |
1202 | 1319 | else /* ! ch->reliable */ | |
1203 | /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */ | ||
1204 | if (GNUNET_YES == fwd) | ||
1205 | send_ack (ch, GNUNET_NO); | ||
1206 | } | ||
1207 | |||
1208 | |||
1209 | /** | ||
1210 | * Save a copy to retransmit in case it gets lost. | ||
1211 | * | ||
1212 | * Initializes all needed callbacks and timers. | ||
1213 | * | ||
1214 | * @param ch Channel this message goes on. | ||
1215 | * @param msg Message to copy. | ||
1216 | * @param fwd Is this fwd traffic? | ||
1217 | */ | ||
1218 | static struct CadetReliableMessage * | ||
1219 | channel_save_copy (struct CadetChannel *ch, | ||
1220 | const struct GNUNET_MessageHeader *msg, | ||
1221 | int fwd) | ||
1222 | { | ||
1223 | struct CadetChannelReliability *rel; | ||
1224 | struct CadetReliableMessage *copy; | ||
1225 | uint32_t mid; | ||
1226 | uint16_t type; | ||
1227 | uint16_t size; | ||
1228 | |||
1229 | rel = fwd ? ch->root_rel : ch->dest_rel; | ||
1230 | mid = rel->mid_send - 1; | ||
1231 | type = ntohs (msg->type); | ||
1232 | size = ntohs (msg->size); | ||
1233 | |||
1234 | LOG (GNUNET_ERROR_TYPE_DEBUG, "save MID %u %s\n", mid, GC_m2s (type)); | ||
1235 | copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size); | ||
1236 | LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy); | ||
1237 | copy->mid = mid; | ||
1238 | copy->rel = rel; | ||
1239 | copy->type = type; | ||
1240 | GNUNET_memcpy (©[1], msg, size); | ||
1241 | GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy); | ||
1242 | ch->pending_messages++; | ||
1243 | |||
1244 | return copy; | ||
1245 | } | ||
1246 | |||
1247 | |||
1248 | /** | ||
1249 | * Create a new channel. | ||
1250 | * | ||
1251 | * @param t Tunnel this channel is in. | ||
1252 | * @param owner Client that owns the channel, NULL for foreign channels. | ||
1253 | * @param lid_root Local ID for root client. | ||
1254 | * | ||
1255 | * @return A new initialized channel. NULL on error. | ||
1256 | */ | ||
1257 | static struct CadetChannel * | ||
1258 | channel_new (struct CadetTunnel *t, | ||
1259 | struct CadetClient *owner, | ||
1260 | struct GNUNET_CADET_ClientChannelNumber lid_root) | ||
1261 | { | ||
1262 | struct CadetChannel *ch; | ||
1263 | |||
1264 | ch = GNUNET_new (struct CadetChannel); | ||
1265 | ch->root = owner; | ||
1266 | ch->lid_root = lid_root; | ||
1267 | ch->t = t; | ||
1268 | |||
1269 | GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO); | ||
1270 | |||
1271 | if (NULL != owner) | ||
1272 | { | ||
1273 | ch->gid = GCT_get_next_ctn (t); | ||
1274 | GML_channel_add (owner, lid_root, ch); | ||
1275 | } | ||
1276 | GCT_add_channel (t, ch); | ||
1277 | |||
1278 | return ch; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | /** | ||
1283 | * Handle a loopback message: call the appropriate handler for the message type. | ||
1284 | * | ||
1285 | * @param ch Channel this message is on. | ||
1286 | * @param msgh Message header. | ||
1287 | * @param fwd Is this FWD traffic? | ||
1288 | */ | ||
1289 | void | ||
1290 | handle_loopback (struct CadetChannel *ch, | ||
1291 | const struct GNUNET_MessageHeader *msgh, | ||
1292 | int fwd) | ||
1293 | { | ||
1294 | uint16_t type; | ||
1295 | |||
1296 | type = ntohs (msgh->type); | ||
1297 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1298 | "Loopback %s %s message!\n", | ||
1299 | GC_f2s (fwd), GC_m2s (type)); | ||
1300 | |||
1301 | switch (type) | ||
1302 | { | 1320 | { |
1303 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: | 1321 | /* Channel is unreliable, so we do not ACK. But we also cannot |
1304 | /* Don't send hop ACK, wait for client to ACK */ | 1322 | allow buffering everything, so check if we have space... */ |
1305 | LOG (GNUNET_ERROR_TYPE_DEBUG, "SEND loopback %u (%u)\n", | 1323 | if (ccc->num_recv >= ch->max_pending_messages) |
1306 | ntohl (((struct GNUNET_CADET_ChannelAppDataMessage *) msgh)->mid), ntohs (msgh->size)); | 1324 | { |
1307 | GCCH_handle_data (ch, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd); | 1325 | struct CadetOutOfOrderMessage *drop; |
1308 | break; | ||
1309 | |||
1310 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: | ||
1311 | GCCH_handle_data_ack (ch, | ||
1312 | (const struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd); | ||
1313 | break; | ||
1314 | |||
1315 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: | ||
1316 | GCCH_handle_create (ch->t, | ||
1317 | (const struct GNUNET_CADET_ChannelOpenMessage *) msgh); | ||
1318 | break; | ||
1319 | |||
1320 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: | ||
1321 | GCCH_handle_ack (ch, | ||
1322 | (const struct GNUNET_CADET_ChannelManageMessage *) msgh, | ||
1323 | fwd); | ||
1324 | break; | ||
1325 | |||
1326 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED: | ||
1327 | GCCH_handle_nack (ch); | ||
1328 | break; | ||
1329 | |||
1330 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: | ||
1331 | GCCH_handle_destroy (ch, | ||
1332 | (const struct GNUNET_CADET_ChannelManageMessage *) msgh, | ||
1333 | fwd); | ||
1334 | break; | ||
1335 | 1326 | ||
1336 | default: | 1327 | /* Yep, need to drop. Drop the oldest message in |
1337 | GNUNET_break_op (0); | 1328 | the buffer. */ |
1338 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1329 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1339 | "end-to-end message not known (%u)\n", | 1330 | "Queue full due slow client on %s, dropping oldest message\n", |
1340 | ntohs (msgh->type)); | 1331 | GCCH_2s (ch)); |
1332 | GNUNET_STATISTICS_update (stats, | ||
1333 | "# messages dropped due to slow client", | ||
1334 | 1, | ||
1335 | GNUNET_NO); | ||
1336 | drop = ccc->head_recv; | ||
1337 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1338 | ccc->tail_recv, | ||
1339 | drop); | ||
1340 | ccc->num_recv--; | ||
1341 | GNUNET_MQ_discard (drop->env); | ||
1342 | GNUNET_free (drop); | ||
1343 | } | ||
1341 | } | 1344 | } |
1342 | } | ||
1343 | |||
1344 | |||
1345 | |||
1346 | /******************************************************************************/ | ||
1347 | /******************************** API ***********************************/ | ||
1348 | /******************************************************************************/ | ||
1349 | |||
1350 | /** | ||
1351 | * Destroy a channel and free all resources. | ||
1352 | * | ||
1353 | * @param ch Channel to destroy. | ||
1354 | */ | ||
1355 | void | ||
1356 | GCCH_destroy (struct CadetChannel *ch) | ||
1357 | { | ||
1358 | struct CadetClient *c; | ||
1359 | struct CadetTunnel *t; | ||
1360 | 1345 | ||
1361 | if (NULL == ch) | 1346 | /* Insert message into sorted out-of-order queue */ |
1347 | com = GNUNET_new (struct CadetOutOfOrderMessage); | ||
1348 | com->mid = msg->mid; | ||
1349 | com->env = env; | ||
1350 | duplicate = GNUNET_NO; | ||
1351 | GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage, | ||
1352 | is_before, | ||
1353 | &duplicate, | ||
1354 | ccc->head_recv, | ||
1355 | ccc->tail_recv, | ||
1356 | com); | ||
1357 | ccc->num_recv++; | ||
1358 | if (GNUNET_YES == duplicate) | ||
1359 | { | ||
1360 | /* Duplicate within the queue, drop also (this is not covered by | ||
1361 | the case above if "delta" >= 64, which could be the case if | ||
1362 | max_pending_messages is also >= 64 or if our client is unready | ||
1363 | and we are seeing retransmissions of the message our client is | ||
1364 | blocked on. */ | ||
1365 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1366 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | ||
1367 | (unsigned int) payload_size, | ||
1368 | GCCH_2s (ch), | ||
1369 | ntohl (msg->mid.mid)); | ||
1370 | GNUNET_STATISTICS_update (stats, | ||
1371 | "# duplicate DATA", | ||
1372 | 1, | ||
1373 | GNUNET_NO); | ||
1374 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1375 | ccc->tail_recv, | ||
1376 | com); | ||
1377 | ccc->num_recv--; | ||
1378 | GNUNET_MQ_discard (com->env); | ||
1379 | GNUNET_free (com); | ||
1380 | send_channel_data_ack (ch); | ||
1362 | return; | 1381 | return; |
1363 | if (2 == ch->destroy) | ||
1364 | return; /* recursive call */ | ||
1365 | ch->destroy = 2; | ||
1366 | |||
1367 | LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n", | ||
1368 | GCT_2s (ch->t), ch->gid); | ||
1369 | GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); | ||
1370 | |||
1371 | c = ch->root; | ||
1372 | if (NULL != c) | ||
1373 | { | ||
1374 | GML_channel_remove (c, ch->lid_root, ch); | ||
1375 | } | ||
1376 | |||
1377 | c = ch->dest; | ||
1378 | if (NULL != c) | ||
1379 | { | ||
1380 | GML_channel_remove (c, ch->lid_dest, ch); | ||
1381 | } | 1382 | } |
1382 | 1383 | LOG (GNUNET_ERROR_TYPE_DEBUG, | |
1383 | channel_rel_free_all (ch->root_rel); | 1384 | "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n", |
1384 | channel_rel_free_all (ch->dest_rel); | 1385 | (GNUNET_YES == ccc->client_ready) |
1385 | 1386 | ? "out-of-order" | |
1386 | t = ch->t; | 1387 | : "client-not-ready", |
1387 | GCT_remove_channel (t, ch); | 1388 | (unsigned int) payload_size, |
1388 | GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); | 1389 | GCCH_2s (ch), |
1389 | 1390 | ntohl (ccc->ccn.channel_of_client), | |
1390 | GNUNET_free (ch); | 1391 | ccc, |
1391 | GCT_destroy_if_empty (t); | 1392 | ntohl (msg->mid.mid), |
1392 | } | 1393 | ntohl (ch->mid_recv.mid)); |
1393 | 1394 | /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and | |
1394 | 1395 | the sender may already be transmitting the previous one. Needs | |
1395 | /** | 1396 | experimental evaluation to see if/when this ACK helps or |
1396 | * Get the channel's public ID. | 1397 | hurts. (We might even want another option.) */ |
1397 | * | 1398 | send_channel_data_ack (ch); |
1398 | * @param ch Channel. | ||
1399 | * | ||
1400 | * @return ID used to identify the channel with the remote peer. | ||
1401 | */ | ||
1402 | struct GNUNET_CADET_ChannelTunnelNumber | ||
1403 | GCCH_get_id (const struct CadetChannel *ch) | ||
1404 | { | ||
1405 | return ch->gid; | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /** | ||
1410 | * Get the channel tunnel. | ||
1411 | * | ||
1412 | * @param ch Channel to get the tunnel from. | ||
1413 | * | ||
1414 | * @return tunnel of the channel. | ||
1415 | */ | ||
1416 | struct CadetTunnel * | ||
1417 | GCCH_get_tunnel (const struct CadetChannel *ch) | ||
1418 | { | ||
1419 | return ch->t; | ||
1420 | } | ||
1421 | |||
1422 | |||
1423 | /** | ||
1424 | * Get free buffer space towards the client on a specific channel. | ||
1425 | * | ||
1426 | * @param ch Channel. | ||
1427 | * @param fwd Is query about FWD traffic? | ||
1428 | * | ||
1429 | * @return Free buffer space [0 - 64] | ||
1430 | */ | ||
1431 | unsigned int | ||
1432 | GCCH_get_buffer (struct CadetChannel *ch, int fwd) | ||
1433 | { | ||
1434 | struct CadetChannelReliability *rel; | ||
1435 | |||
1436 | rel = fwd ? ch->dest_rel : ch->root_rel; | ||
1437 | LOG (GNUNET_ERROR_TYPE_DEBUG, " get buffer, channel %s\n", GCCH_2s (ch)); | ||
1438 | GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); | ||
1439 | /* If rel is NULL it means that the end is not yet created, | ||
1440 | * most probably is a loopback channel at the point of sending | ||
1441 | * the ChannelCreate to itself. | ||
1442 | */ | ||
1443 | if (NULL == rel) | ||
1444 | { | ||
1445 | LOG (GNUNET_ERROR_TYPE_DEBUG, " rel is NULL: max\n"); | ||
1446 | return 64; | ||
1447 | } | ||
1448 | |||
1449 | LOG (GNUNET_ERROR_TYPE_DEBUG, " n_recv %d\n", rel->n_recv); | ||
1450 | return (64 - rel->n_recv); | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | /** | ||
1455 | * Get flow control status of end point: is client allow to send? | ||
1456 | * | ||
1457 | * @param ch Channel. | ||
1458 | * @param fwd Is query about FWD traffic? (Request root status). | ||
1459 | * | ||
1460 | * @return #GNUNET_YES if client is allowed to send us data. | ||
1461 | */ | ||
1462 | int | ||
1463 | GCCH_get_allowed (struct CadetChannel *ch, int fwd) | ||
1464 | { | ||
1465 | struct CadetChannelReliability *rel; | ||
1466 | |||
1467 | rel = fwd ? ch->root_rel : ch->dest_rel; | ||
1468 | |||
1469 | if (NULL == rel) | ||
1470 | { | ||
1471 | /* Probably shutting down: root/dest NULL'ed to mark disconnection */ | ||
1472 | GNUNET_break (GNUNET_NO != ch->destroy); | ||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | return rel->client_allowed; | ||
1477 | } | 1399 | } |
1478 | 1400 | ||
1479 | 1401 | ||
1480 | /** | 1402 | /** |
1481 | * Is the root client for this channel on this peer? | 1403 | * Function called once the tunnel has sent one of our messages. |
1482 | * | 1404 | * If the message is unreliable, simply frees the `crm`. If the |
1483 | * @param ch Channel. | 1405 | * message was reliable, calculate retransmission time and |
1484 | * @param fwd Is this for fwd traffic? | 1406 | * wait for ACK (or retransmit). |
1485 | * | 1407 | * |
1486 | * @return #GNUNET_YES in case it is. | 1408 | * @param cls the `struct CadetReliableMessage` that was sent |
1409 | * @param cid identifier of the connection within the tunnel, NULL | ||
1410 | * if transmission failed | ||
1487 | */ | 1411 | */ |
1488 | int | 1412 | static void |
1489 | GCCH_is_origin (struct CadetChannel *ch, int fwd) | 1413 | data_sent_cb (void *cls, |
1490 | { | 1414 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); |
1491 | struct CadetClient *c; | ||
1492 | |||
1493 | c = fwd ? ch->root : ch->dest; | ||
1494 | return NULL != c; | ||
1495 | } | ||
1496 | 1415 | ||
1497 | 1416 | ||
1498 | /** | 1417 | /** |
1499 | * Is the destination client for this channel on this peer? | 1418 | * We need to retry a transmission, the last one took too long to |
1500 | * | 1419 | * be acknowledged. |
1501 | * @param ch Channel. | ||
1502 | * @param fwd Is this for fwd traffic? | ||
1503 | * | 1420 | * |
1504 | * @return #GNUNET_YES in case it is. | 1421 | * @param cls the `struct CadetChannel` where we need to retransmit |
1505 | */ | 1422 | */ |
1506 | int | 1423 | static void |
1507 | GCCH_is_terminal (struct CadetChannel *ch, int fwd) | 1424 | retry_transmission (void *cls) |
1508 | { | 1425 | { |
1509 | struct CadetClient *c; | 1426 | struct CadetChannel *ch = cls; |
1427 | struct CadetReliableMessage *crm = ch->head_sent; | ||
1510 | 1428 | ||
1511 | c = fwd ? ch->dest : ch->root; | 1429 | ch->retry_data_task = NULL; |
1512 | return NULL != c; | 1430 | GNUNET_assert (NULL == crm->qe); |
1431 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1432 | "Retrying transmission on %s of message %u\n", | ||
1433 | GCCH_2s (ch), | ||
1434 | (unsigned int) ntohl (crm->data_message->mid.mid)); | ||
1435 | crm->qe = GCT_send (ch->t, | ||
1436 | &crm->data_message->header, | ||
1437 | &data_sent_cb, | ||
1438 | crm); | ||
1439 | GNUNET_assert (NULL == ch->retry_data_task); | ||
1513 | } | 1440 | } |
1514 | 1441 | ||
1515 | 1442 | ||
1516 | /** | 1443 | /** |
1517 | * Send an end-to-end ACK message for the most recent in-sequence payload. | 1444 | * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from |
1445 | * the queue and tell our client that it can send more. | ||
1518 | * | 1446 | * |
1519 | * If channel is not reliable, do nothing. | 1447 | * @param ch the channel that got the PLAINTEXT_DATA_ACK |
1520 | * | 1448 | * @param cti identifier of the connection that delivered the message |
1521 | * @param ch Channel this is about. | 1449 | * @param crm the message that got acknowledged |
1522 | * @param fwd Is for FWD traffic? (ACK dest->owner) | ||
1523 | */ | 1450 | */ |
1524 | void | 1451 | static void |
1525 | GCCH_send_data_ack (struct CadetChannel *ch, int fwd) | 1452 | handle_matching_ack (struct CadetChannel *ch, |
1453 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1454 | struct CadetReliableMessage *crm) | ||
1526 | { | 1455 | { |
1527 | struct GNUNET_CADET_ChannelDataAckMessage msg; | 1456 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, |
1528 | struct CadetChannelReliability *rel; | 1457 | ch->tail_sent, |
1529 | struct CadetReliableMessage *copy; | 1458 | crm); |
1530 | unsigned int delta; | 1459 | ch->pending_messages--; |
1531 | uint64_t mask; | 1460 | GNUNET_assert (ch->pending_messages < ch->max_pending_messages); |
1532 | uint32_t ack; | 1461 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1533 | 1462 | "Received DATA_ACK on %s for message %u (%u ACKs pending)\n", | |
1534 | if (GNUNET_NO == ch->reliable) | 1463 | GCCH_2s (ch), |
1535 | return; | 1464 | (unsigned int) ntohl (crm->data_message->mid.mid), |
1536 | 1465 | ch->pending_messages); | |
1537 | rel = fwd ? ch->dest_rel : ch->root_rel; | 1466 | if (NULL != crm->qe) |
1538 | ack = rel->mid_recv - 1; | 1467 | { |
1539 | 1468 | GCT_send_cancel (crm->qe); | |
1540 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); | 1469 | crm->qe = NULL; |
1541 | msg.header.size = htons (sizeof (msg)); | 1470 | } |
1542 | msg.ctn = ch->gid; | 1471 | if ( (1 == crm->num_transmissions) && |
1543 | msg.mid = htonl (ack); | 1472 | (NULL != cti) ) |
1544 | 1473 | { | |
1545 | msg.futures = 0LL; | 1474 | GCC_ack_observed (cti); |
1546 | for (copy = rel->head_recv; NULL != copy; copy = copy->next) | 1475 | if (0 == memcmp (cti, |
1547 | { | 1476 | &crm->connection_taken, |
1548 | if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA) | 1477 | sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier))) |
1549 | { | 1478 | { |
1550 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Type %s, expected DATA\n", | 1479 | GCC_latency_observed (cti, |
1551 | GC_m2s (copy->type)); | 1480 | GNUNET_TIME_absolute_get_duration (crm->first_transmission_time)); |
1552 | continue; | ||
1553 | } | 1481 | } |
1554 | GNUNET_assert (GC_is_pid_bigger(copy->mid, ack)); | ||
1555 | delta = copy->mid - (ack + 1); | ||
1556 | if (63 < delta) | ||
1557 | break; | ||
1558 | mask = 0x1LL << delta; | ||
1559 | msg.futures |= mask; | ||
1560 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1561 | " setting bit for %u (delta %u) (%lX) -> %lX\n", | ||
1562 | copy->mid, delta, mask, msg.futures); | ||
1563 | } | 1482 | } |
1564 | 1483 | GNUNET_free (crm->data_message); | |
1565 | GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); | 1484 | GNUNET_free (crm); |
1566 | LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); | 1485 | send_ack_to_client (ch, |
1486 | (NULL == ch->owner) | ||
1487 | ? GNUNET_NO | ||
1488 | : GNUNET_YES); | ||
1567 | } | 1489 | } |
1568 | 1490 | ||
1569 | 1491 | ||
1570 | /** | 1492 | /** |
1571 | * Allow a client to send us more data, in case it was choked. | 1493 | * We got an acknowledgement for payload data for a channel. |
1494 | * Possibly resume transmissions. | ||
1572 | * | 1495 | * |
1573 | * @param ch Channel. | 1496 | * @param ch channel that got the ack |
1574 | * @param fwd Is this about FWD traffic? (Root client). | 1497 | * @param cti identifier of the connection that delivered the message |
1498 | * @param ack details about what was received | ||
1575 | */ | 1499 | */ |
1576 | void | 1500 | void |
1577 | GCCH_allow_client (struct CadetChannel *ch, int fwd) | 1501 | GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, |
1502 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
1503 | const struct GNUNET_CADET_ChannelDataAckMessage *ack) | ||
1578 | { | 1504 | { |
1579 | struct CadetChannelReliability *rel; | 1505 | struct CadetReliableMessage *crm; |
1580 | unsigned int buffer; | 1506 | struct CadetReliableMessage *crmn; |
1581 | 1507 | int found; | |
1582 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); | 1508 | uint32_t mid_base; |
1509 | uint64_t mid_mask; | ||
1510 | unsigned int delta; | ||
1583 | 1511 | ||
1584 | if (CADET_CHANNEL_READY != ch->state) | 1512 | GNUNET_break (GNUNET_NO == ch->is_loopback); |
1513 | if (GNUNET_NO == ch->reliable) | ||
1585 | { | 1514 | { |
1586 | LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); | 1515 | /* not expecting ACKs on unreliable channel, odd */ |
1516 | GNUNET_break_op (0); | ||
1587 | return; | 1517 | return; |
1588 | } | 1518 | } |
1589 | 1519 | /* mid_base is the MID of the next message that the | |
1590 | if (GNUNET_YES == ch->reliable) | 1520 | other peer expects (i.e. that is missing!), everything |
1591 | { | 1521 | LOWER (but excluding mid_base itself) was received. */ |
1592 | rel = fwd ? ch->root_rel : ch->dest_rel; | 1522 | mid_base = ntohl (ack->mid.mid); |
1593 | if (NULL == rel) | 1523 | mid_mask = GNUNET_htonll (ack->futures); |
1594 | { | 1524 | found = GNUNET_NO; |
1595 | GNUNET_break (GNUNET_NO != ch->destroy); | 1525 | for (crm = ch->head_sent; |
1596 | return; | 1526 | NULL != crm; |
1597 | } | 1527 | crm = crmn) |
1598 | if (NULL != rel->head_sent) | 1528 | { |
1529 | crmn = crm->next; | ||
1530 | delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base); | ||
1531 | if (delta >= UINT_MAX - ch->max_pending_messages) | ||
1599 | { | 1532 | { |
1600 | if (64 <= rel->mid_send - rel->head_sent->mid) | 1533 | /* overflow, means crm was a bit in the past, so this ACK counts for it. */ |
1601 | { | 1534 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1602 | LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); | 1535 | "Got DATA_ACK with base %u satisfying past message %u on %s\n", |
1603 | return; | 1536 | (unsigned int) mid_base, |
1604 | } | 1537 | ntohl (crm->data_message->mid.mid), |
1605 | else | 1538 | GCCH_2s (ch)); |
1606 | { | 1539 | handle_matching_ack (ch, |
1607 | LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n", | 1540 | cti, |
1608 | rel->head_sent->mid, rel->mid_send); | 1541 | crm); |
1609 | struct CadetReliableMessage *aux; | 1542 | found = GNUNET_YES; |
1610 | for (aux = rel->head_sent; NULL != aux; aux = aux->next) | 1543 | continue; |
1611 | { | ||
1612 | LOG (GNUNET_ERROR_TYPE_DEBUG, " - sent mid %u\n", aux->mid); | ||
1613 | } | ||
1614 | } | ||
1615 | } | 1544 | } |
1616 | else | 1545 | delta--; |
1546 | if (delta >= 64) | ||
1547 | continue; | ||
1548 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1549 | "Testing bit %llX for mid %u (base: %u)\n", | ||
1550 | (1LLU << delta), | ||
1551 | ntohl (crm->data_message->mid.mid), | ||
1552 | mid_base); | ||
1553 | if (0 != (mid_mask & (1LLU << delta))) | ||
1617 | { | 1554 | { |
1618 | LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); | 1555 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1556 | "Got DATA_ACK with mask for %u on %s\n", | ||
1557 | ntohl (crm->data_message->mid.mid), | ||
1558 | GCCH_2s (ch)); | ||
1559 | handle_matching_ack (ch, | ||
1560 | cti, | ||
1561 | crm); | ||
1562 | found = GNUNET_YES; | ||
1619 | } | 1563 | } |
1620 | } | 1564 | } |
1621 | 1565 | if (GNUNET_NO == found) | |
1622 | if (is_loopback (ch)) | ||
1623 | buffer = GCCH_get_buffer (ch, fwd); | ||
1624 | else | ||
1625 | buffer = GCT_get_connections_buffer (ch->t); | ||
1626 | |||
1627 | if (0 == buffer) | ||
1628 | { | 1566 | { |
1629 | LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n"); | 1567 | /* ACK for message we already dropped, might have been a |
1568 | duplicate ACK? Ignore. */ | ||
1569 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1570 | "Duplicate DATA_ACK on %s, ignoring\n", | ||
1571 | GCCH_2s (ch)); | ||
1572 | GNUNET_STATISTICS_update (stats, | ||
1573 | "# duplicate DATA_ACKs", | ||
1574 | 1, | ||
1575 | GNUNET_NO); | ||
1630 | return; | 1576 | return; |
1631 | } | 1577 | } |
1632 | 1578 | if (NULL != ch->retry_data_task) | |
1633 | LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer); | 1579 | { |
1634 | send_client_ack (ch, fwd); | 1580 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); |
1581 | ch->retry_data_task = NULL; | ||
1582 | } | ||
1583 | if ( (NULL != ch->head_sent) && | ||
1584 | (NULL == ch->head_sent->qe) ) | ||
1585 | ch->retry_data_task | ||
1586 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, | ||
1587 | &retry_transmission, | ||
1588 | ch); | ||
1635 | } | 1589 | } |
1636 | 1590 | ||
1637 | 1591 | ||
1638 | /** | 1592 | /** |
1639 | * Log channel info. | 1593 | * Destroy channel, based on the other peer closing the |
1594 | * connection. Also needs to remove this channel from | ||
1595 | * the tunnel. | ||
1640 | * | 1596 | * |
1641 | * @param ch Channel. | 1597 | * @param ch channel to destroy |
1642 | * @param level Debug level to use. | 1598 | * @param cti identifier of the connection that delivered the message, |
1599 | * NULL if we are simulating receiving a destroy due to shutdown | ||
1643 | */ | 1600 | */ |
1644 | void | 1601 | void |
1645 | GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level) | 1602 | GCCH_handle_remote_destroy (struct CadetChannel *ch, |
1603 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti) | ||
1646 | { | 1604 | { |
1647 | int do_log; | 1605 | struct CadetChannelClient *ccc; |
1648 | 1606 | ||
1649 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | 1607 | GNUNET_assert (GNUNET_NO == ch->is_loopback); |
1650 | "cadet-chn", | 1608 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1651 | __FILE__, __FUNCTION__, __LINE__); | 1609 | "Received remote channel DESTROY for %s\n", |
1652 | if (0 == do_log) | 1610 | GCCH_2s (ch)); |
1653 | return; | 1611 | if (GNUNET_YES == ch->destroy) |
1654 | |||
1655 | if (NULL == ch) | ||
1656 | { | 1612 | { |
1657 | LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n"); | 1613 | /* Local client already gone, this is instant-death. */ |
1614 | channel_destroy (ch); | ||
1658 | return; | 1615 | return; |
1659 | } | 1616 | } |
1660 | LOG2 (level, "CHN Channel %s:%X (%p)\n", GCT_2s (ch->t), ch->gid, ch); | 1617 | ccc = (NULL != ch->owner) ? ch->owner : ch->dest; |
1661 | LOG2 (level, "CHN root %p/%p\n", ch->root, ch->root_rel); | 1618 | if ( (NULL != ccc) && |
1662 | if (NULL != ch->root) | 1619 | (NULL != ccc->head_recv) ) |
1663 | { | ||
1664 | LOG2 (level, "CHN cli %s\n", GML_2s (ch->root)); | ||
1665 | LOG2 (level, "CHN ready %s\n", ch->root_rel->client_ready ? "YES" : "NO"); | ||
1666 | LOG2 (level, "CHN id %X\n", ch->lid_root.channel_of_client); | ||
1667 | LOG2 (level, "CHN recv %d\n", ch->root_rel->n_recv); | ||
1668 | LOG2 (level, "CHN MID r: %d, s: %d\n", | ||
1669 | ch->root_rel->mid_recv, ch->root_rel->mid_send); | ||
1670 | } | ||
1671 | LOG2 (level, "CHN dest %p/%p\n", | ||
1672 | ch->dest, ch->dest_rel); | ||
1673 | if (NULL != ch->dest) | ||
1674 | { | 1620 | { |
1675 | LOG2 (level, "CHN cli %s\n", GML_2s (ch->dest)); | 1621 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1676 | LOG2 (level, "CHN ready %s\n", ch->dest_rel->client_ready ? "YES" : "NO"); | 1622 | "Lost end of transmission due to remote shutdown on %s\n", |
1677 | LOG2 (level, "CHN id %X\n", ch->lid_dest); | 1623 | GCCH_2s (ch)); |
1678 | LOG2 (level, "CHN recv %d\n", ch->dest_rel->n_recv); | 1624 | /* FIXME: change API to notify client about truncated transmission! */ |
1679 | LOG2 (level, "CHN MID r: %d, s: %d\n", | ||
1680 | ch->dest_rel->mid_recv, ch->dest_rel->mid_send); | ||
1681 | |||
1682 | } | 1625 | } |
1626 | ch->destroy = GNUNET_YES; | ||
1627 | if (NULL != ccc) | ||
1628 | GSC_handle_remote_channel_destroy (ccc->c, | ||
1629 | ccc->ccn, | ||
1630 | ch); | ||
1631 | channel_destroy (ch); | ||
1683 | } | 1632 | } |
1684 | 1633 | ||
1685 | 1634 | ||
1686 | /** | 1635 | /** |
1687 | * Handle an ACK given by a client. | 1636 | * Test if element @a e1 comes before element @a e2. |
1688 | * | ||
1689 | * Mark client as ready and send him any buffered data we could have for him. | ||
1690 | * | 1637 | * |
1691 | * @param ch Channel. | 1638 | * @param cls closure, to a flag where we indicate duplicate packets |
1692 | * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) | 1639 | * @param crm1 an element of to sort |
1640 | * @param crm2 another element to sort | ||
1641 | * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO | ||
1693 | */ | 1642 | */ |
1694 | void | 1643 | static int |
1695 | GCCH_handle_local_ack (struct CadetChannel *ch, int fwd) | 1644 | cmp_crm_by_next_retry (void *cls, |
1645 | struct CadetReliableMessage *crm1, | ||
1646 | struct CadetReliableMessage *crm2) | ||
1696 | { | 1647 | { |
1697 | struct CadetChannelReliability *rel; | 1648 | if (crm1->next_retry.abs_value_us < |
1698 | struct CadetClient *c; | 1649 | crm2->next_retry.abs_value_us) |
1699 | 1650 | return GNUNET_YES; | |
1700 | rel = fwd ? ch->dest_rel : ch->root_rel; | 1651 | return GNUNET_NO; |
1701 | c = fwd ? ch->dest : ch->root; | ||
1702 | |||
1703 | rel->client_ready = GNUNET_YES; | ||
1704 | send_client_buffered_data (ch, c, fwd); | ||
1705 | |||
1706 | if (GNUNET_YES == ch->destroy && 0 == rel->n_recv) | ||
1707 | { | ||
1708 | send_destroy (ch, GNUNET_YES); | ||
1709 | GCCH_destroy (ch); | ||
1710 | return; | ||
1711 | } | ||
1712 | /* if loopback is marked for destruction, no need to ACK to the other peer, | ||
1713 | * it requested the destruction and is already gone, therefore, else if. | ||
1714 | */ | ||
1715 | else if (is_loopback (ch)) | ||
1716 | { | ||
1717 | unsigned int buffer; | ||
1718 | |||
1719 | buffer = GCCH_get_buffer (ch, fwd); | ||
1720 | if (0 < buffer) | ||
1721 | GCCH_allow_client (ch, fwd); | ||
1722 | |||
1723 | return; | ||
1724 | } | ||
1725 | GCT_send_connection_acks (ch->t); | ||
1726 | } | 1652 | } |
1727 | 1653 | ||
1728 | 1654 | ||
1729 | /** | 1655 | /** |
1730 | * Handle data given by a client. | 1656 | * Function called once the tunnel has sent one of our messages. |
1731 | * | 1657 | * If the message is unreliable, simply frees the `crm`. If the |
1732 | * Check whether the client is allowed to send in this tunnel, save if channel | 1658 | * message was reliable, calculate retransmission time and |
1733 | * is reliable and send an ACK to the client if there is still buffer space | 1659 | * wait for ACK (or retransmit). |
1734 | * in the tunnel. | 1660 | * |
1735 | * | 1661 | * @param cls the `struct CadetReliableMessage` that was sent |
1736 | * @param ch Channel. | 1662 | * @param cid identifier of the connection within the tunnel, NULL |
1737 | * @param c Client which sent the data. | 1663 | * if transmission failed |
1738 | * @param fwd Is this a FWD data? | ||
1739 | * @param message Data message. | ||
1740 | * @param size Size of data. | ||
1741 | * | ||
1742 | * @return #GNUNET_OK if everything goes well, #GNUNET_SYSERR in case of en error. | ||
1743 | */ | 1664 | */ |
1744 | int | 1665 | static void |
1745 | GCCH_handle_local_data (struct CadetChannel *ch, | 1666 | data_sent_cb (void *cls, |
1746 | struct CadetClient *c, | 1667 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) |
1747 | int fwd, | ||
1748 | const struct GNUNET_MessageHeader *message, | ||
1749 | size_t size) | ||
1750 | { | 1668 | { |
1751 | struct CadetChannelReliability *rel; | 1669 | struct CadetReliableMessage *crm = cls; |
1752 | struct GNUNET_CADET_ChannelAppDataMessage *payload; | 1670 | struct CadetChannel *ch = crm->ch; |
1753 | uint16_t p2p_size = sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + size; | 1671 | |
1754 | unsigned char cbuf[p2p_size]; | 1672 | GNUNET_assert (GNUNET_NO == ch->is_loopback); |
1755 | unsigned char buffer; | 1673 | GNUNET_assert (NULL != crm->qe); |
1756 | 1674 | crm->qe = NULL; | |
1757 | /* Is the client in the channel? */ | 1675 | GNUNET_CONTAINER_DLL_remove (ch->head_sent, |
1758 | if ( !( (fwd && | 1676 | ch->tail_sent, |
1759 | ch->root == c) | 1677 | crm); |
1760 | || | 1678 | if (GNUNET_NO == ch->reliable) |
1761 | (!fwd && | ||
1762 | ch->dest == c) ) ) | ||
1763 | { | 1679 | { |
1764 | GNUNET_break_op (0); | 1680 | GNUNET_free (crm->data_message); |
1765 | return GNUNET_SYSERR; | 1681 | GNUNET_free (crm); |
1682 | ch->pending_messages--; | ||
1683 | send_ack_to_client (ch, | ||
1684 | (NULL == ch->owner) | ||
1685 | ? GNUNET_NO | ||
1686 | : GNUNET_YES); | ||
1687 | return; | ||
1766 | } | 1688 | } |
1767 | 1689 | if (NULL == cid) | |
1768 | rel = fwd ? ch->root_rel : ch->dest_rel; | ||
1769 | |||
1770 | if (GNUNET_NO == rel->client_allowed) | ||
1771 | { | 1690 | { |
1772 | GNUNET_break_op (0); | 1691 | /* There was an error sending. */ |
1773 | return GNUNET_SYSERR; | 1692 | crm->num_transmissions = GNUNET_SYSERR; |
1774 | } | 1693 | } |
1775 | 1694 | else if (GNUNET_SYSERR != crm->num_transmissions) | |
1776 | rel->client_allowed = GNUNET_NO; | ||
1777 | |||
1778 | /* Ok, everything is correct, send the message. */ | ||
1779 | payload = (struct GNUNET_CADET_ChannelAppDataMessage *) cbuf; | ||
1780 | payload->mid = htonl (rel->mid_send); | ||
1781 | rel->mid_send++; | ||
1782 | GNUNET_memcpy (&payload[1], message, size); | ||
1783 | payload->header.size = htons (p2p_size); | ||
1784 | payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA); | ||
1785 | payload->ctn = ch->gid; | ||
1786 | LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); | ||
1787 | GCCH_send_prebuilt_message (&payload->header, ch, fwd, NULL); | ||
1788 | |||
1789 | if (is_loopback (ch)) | ||
1790 | buffer = GCCH_get_buffer (ch, fwd); | ||
1791 | else | ||
1792 | buffer = GCT_get_connections_buffer (ch->t); | ||
1793 | |||
1794 | if (0 < buffer) | ||
1795 | GCCH_allow_client (ch, fwd); | ||
1796 | |||
1797 | return GNUNET_OK; | ||
1798 | } | ||
1799 | |||
1800 | |||
1801 | /** | ||
1802 | * Handle a channel destroy requested by a client. | ||
1803 | * | ||
1804 | * TODO: add "reason" field | ||
1805 | * | ||
1806 | * Destroy the channel and the tunnel in case this was the last channel. | ||
1807 | * | ||
1808 | * @param ch Channel. | ||
1809 | * @param c Client that requested the destruction (to avoid notifying him). | ||
1810 | * @param is_root Is the request coming from root? | ||
1811 | */ | ||
1812 | void | ||
1813 | GCCH_handle_local_destroy (struct CadetChannel *ch, | ||
1814 | struct CadetClient *c, | ||
1815 | int is_root) | ||
1816 | { | ||
1817 | ch->destroy = GNUNET_YES; | ||
1818 | /* Cleanup after the tunnel */ | ||
1819 | if (GNUNET_NO == is_root && c == ch->dest) | ||
1820 | { | 1695 | { |
1821 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c)); | 1696 | /* Increment transmission counter, and possibly store @a cid |
1822 | GML_client_delete_channel (c, ch, ch->lid_dest); | 1697 | if this was the first transmission. */ |
1823 | ch->dest = NULL; | 1698 | crm->num_transmissions++; |
1699 | if (1 == crm->num_transmissions) | ||
1700 | { | ||
1701 | crm->first_transmission_time = GNUNET_TIME_absolute_get (); | ||
1702 | crm->connection_taken = *cid; | ||
1703 | GCC_ack_expected (cid); | ||
1704 | } | ||
1824 | } | 1705 | } |
1825 | if (GNUNET_YES == is_root && c == ch->root) | 1706 | if ( (0 == crm->retry_delay.rel_value_us) && |
1707 | (NULL != cid) ) | ||
1826 | { | 1708 | { |
1827 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c)); | 1709 | struct CadetConnection *cc = GCC_lookup (cid); |
1828 | GML_client_delete_channel (c, ch, ch->lid_root); | ||
1829 | ch->root = NULL; | ||
1830 | } | ||
1831 | 1710 | ||
1832 | send_destroy (ch, GNUNET_NO); | 1711 | if (NULL != cc) |
1833 | if (0 == ch->pending_messages) | 1712 | crm->retry_delay = GCC_get_metrics (cc)->aged_latency; |
1834 | GCCH_destroy (ch); | 1713 | else |
1714 | crm->retry_delay = ch->retry_time; | ||
1715 | } | ||
1716 | crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay); | ||
1717 | crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay, | ||
1718 | MIN_RTT_DELAY); | ||
1719 | crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay); | ||
1720 | |||
1721 | GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage, | ||
1722 | cmp_crm_by_next_retry, | ||
1723 | NULL, | ||
1724 | ch->head_sent, | ||
1725 | ch->tail_sent, | ||
1726 | crm); | ||
1727 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1728 | "Message %u sent, next transmission on %s in %s\n", | ||
1729 | (unsigned int) ntohl (crm->data_message->mid.mid), | ||
1730 | GCCH_2s (ch), | ||
1731 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry), | ||
1732 | GNUNET_YES)); | ||
1733 | if (NULL == ch->head_sent->qe) | ||
1734 | { | ||
1735 | if (NULL != ch->retry_data_task) | ||
1736 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
1737 | ch->retry_data_task | ||
1738 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, | ||
1739 | &retry_transmission, | ||
1740 | ch); | ||
1741 | } | ||
1835 | } | 1742 | } |
1836 | 1743 | ||
1837 | 1744 | ||
1838 | /** | 1745 | /** |
1839 | * Handle a channel create requested by a client. | 1746 | * Handle data given by a client. |
1840 | * | ||
1841 | * Create the channel and the tunnel in case this was the first0 channel. | ||
1842 | * | 1747 | * |
1843 | * @param c Client that requested the creation (will be the root). | 1748 | * Check whether the client is allowed to send in this tunnel, save if |
1844 | * @param msg Create Channel message. | 1749 | * channel is reliable and send an ACK to the client if there is still |
1750 | * buffer space in the tunnel. | ||
1845 | * | 1751 | * |
1846 | * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. | 1752 | * @param ch Channel. |
1753 | * @param sender_ccn ccn of the sender | ||
1754 | * @param buf payload to transmit. | ||
1755 | * @param buf_len number of bytes in @a buf | ||
1756 | * @return #GNUNET_OK if everything goes well, | ||
1757 | * #GNUNET_SYSERR in case of an error. | ||
1847 | */ | 1758 | */ |
1848 | int | 1759 | int |
1849 | GCCH_handle_local_create (struct CadetClient *c, | 1760 | GCCH_handle_local_data (struct CadetChannel *ch, |
1850 | struct GNUNET_CADET_LocalChannelCreateMessage *msg) | 1761 | struct GNUNET_CADET_ClientChannelNumber sender_ccn, |
1762 | const char *buf, | ||
1763 | size_t buf_len) | ||
1851 | { | 1764 | { |
1852 | struct CadetChannel *ch; | 1765 | struct CadetReliableMessage *crm; |
1853 | struct CadetTunnel *t; | ||
1854 | struct CadetPeer *peer; | ||
1855 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
1856 | |||
1857 | LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n", | ||
1858 | GNUNET_i2s (&msg->peer), GNUNET_h2s (&msg->port)); | ||
1859 | ccn = msg->ccn; | ||
1860 | |||
1861 | /* Sanity check for duplicate channel IDs */ | ||
1862 | if (NULL != GML_channel_get (c, ccn)) | ||
1863 | { | ||
1864 | GNUNET_break (0); | ||
1865 | return GNUNET_SYSERR; | ||
1866 | } | ||
1867 | 1766 | ||
1868 | peer = GCP_get (&msg->peer, GNUNET_YES); | 1767 | if (ch->pending_messages > ch->max_pending_messages) |
1869 | GCP_add_tunnel (peer); | ||
1870 | t = GCP_get_tunnel (peer); | ||
1871 | |||
1872 | if (GCP_get_short_id (peer) == myid) | ||
1873 | { | ||
1874 | GCT_change_cstate (t, CADET_TUNNEL_READY); | ||
1875 | } | ||
1876 | else | ||
1877 | { | ||
1878 | /* FIXME change to a tunnel API, eliminate ch <-> peer connection */ | ||
1879 | GCP_connect (peer); | ||
1880 | } | ||
1881 | |||
1882 | /* Create channel */ | ||
1883 | ch = channel_new (t, c, ccn); | ||
1884 | if (NULL == ch) | ||
1885 | { | 1768 | { |
1886 | GNUNET_break (0); | 1769 | GNUNET_break (0); |
1887 | return GNUNET_SYSERR; | 1770 | return GNUNET_SYSERR; |
1888 | } | 1771 | } |
1889 | ch->port = msg->port; | 1772 | if (GNUNET_YES == ch->destroy) |
1890 | channel_set_options (ch, ntohl (msg->opt)); | ||
1891 | |||
1892 | /* In unreliable channels, we'll use the DLL to buffer BCK data */ | ||
1893 | ch->root_rel = GNUNET_new (struct CadetChannelReliability); | ||
1894 | ch->root_rel->ch = ch; | ||
1895 | ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME; | ||
1896 | ch->root_rel->expected_delay.rel_value_us = 0; | ||
1897 | |||
1898 | LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GCCH_2s (ch)); | ||
1899 | |||
1900 | send_create (ch); | ||
1901 | |||
1902 | return GNUNET_OK; | ||
1903 | } | ||
1904 | |||
1905 | |||
1906 | /** | ||
1907 | * Handler for cadet network payload traffic. | ||
1908 | * | ||
1909 | * @param ch Channel for the message. | ||
1910 | * @param msg Unencryted data message. | ||
1911 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1912 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1913 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1914 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1915 | */ | ||
1916 | void | ||
1917 | GCCH_handle_data (struct CadetChannel *ch, | ||
1918 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | ||
1919 | int fwd) | ||
1920 | { | ||
1921 | struct CadetChannelReliability *rel; | ||
1922 | struct CadetClient *c; | ||
1923 | struct GNUNET_MessageHeader *payload_msg; | ||
1924 | uint32_t mid; | ||
1925 | uint16_t payload_type; | ||
1926 | uint16_t payload_size; | ||
1927 | |||
1928 | /* If this is a remote (non-loopback) channel, find 'fwd'. */ | ||
1929 | if (GNUNET_SYSERR == fwd) | ||
1930 | { | 1773 | { |
1931 | if (is_loopback (ch)) | 1774 | /* we are going down, drop messages */ |
1932 | { | 1775 | return GNUNET_OK; |
1933 | /* It is a loopback channel after all... */ | ||
1934 | GNUNET_break (0); | ||
1935 | return; | ||
1936 | } | ||
1937 | fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; | ||
1938 | } | 1776 | } |
1777 | ch->pending_messages++; | ||
1939 | 1778 | ||
1940 | /* Initialize FWD/BCK data */ | 1779 | if (GNUNET_YES == ch->is_loopback) |
1941 | c = fwd ? ch->dest : ch->root; | ||
1942 | rel = fwd ? ch->dest_rel : ch->root_rel; | ||
1943 | |||
1944 | if (NULL == c) | ||
1945 | { | 1780 | { |
1946 | GNUNET_break (GNUNET_NO != ch->destroy); | 1781 | struct CadetChannelClient *receiver; |
1947 | return; | 1782 | struct GNUNET_MQ_Envelope *env; |
1948 | } | 1783 | struct GNUNET_CADET_LocalData *ld; |
1784 | int ack_to_owner; | ||
1949 | 1785 | ||
1950 | if (CADET_CHANNEL_READY != ch->state) | 1786 | env = GNUNET_MQ_msg_extra (ld, |
1951 | { | 1787 | buf_len, |
1952 | if (GNUNET_NO == fwd) | 1788 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); |
1789 | if ( (NULL != ch->owner) && | ||
1790 | (sender_ccn.channel_of_client == | ||
1791 | ch->owner->ccn.channel_of_client) ) | ||
1953 | { | 1792 | { |
1954 | /* If we are the root, this means the other peer has sent traffic before | 1793 | receiver = ch->dest; |
1955 | * receiving our ACK. Even if the SYNACK goes missing, no traffic should | 1794 | ack_to_owner = GNUNET_YES; |
1956 | * be sent before the ACK. | ||
1957 | */ | ||
1958 | GNUNET_break_op (0); | ||
1959 | return; | ||
1960 | } | 1795 | } |
1961 | /* If we are the dest, this means that the SYNACK got to the root but | 1796 | else if ( (NULL != ch->dest) && |
1962 | * the ACK went missing. Treat this as an ACK. | 1797 | (sender_ccn.channel_of_client == |
1963 | */ | 1798 | ch->dest->ccn.channel_of_client) ) |
1964 | channel_confirm (ch, GNUNET_NO); | ||
1965 | } | ||
1966 | |||
1967 | payload_msg = (struct GNUNET_MessageHeader *) &msg[1]; | ||
1968 | payload_type = ntohs (payload_msg->type); | ||
1969 | payload_size = ntohs (payload_msg->size); | ||
1970 | |||
1971 | GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO); | ||
1972 | GNUNET_STATISTICS_update (stats, "# bytes received", payload_size, GNUNET_NO); | ||
1973 | |||
1974 | mid = ntohl (msg->mid); | ||
1975 | LOG (GNUNET_ERROR_TYPE_INFO, "<== %s (%s %4u) on chan %s (%p) %s [%5u]\n", | ||
1976 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA), GC_m2s (payload_type), mid, | ||
1977 | GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size)); | ||
1978 | |||
1979 | if ( (GNUNET_NO == ch->reliable) || | ||
1980 | ( (! GC_is_pid_bigger (rel->mid_recv, mid)) && | ||
1981 | GC_is_pid_bigger (rel->mid_recv + 64, mid) ) ) | ||
1982 | { | ||
1983 | if (GNUNET_YES == ch->reliable) | ||
1984 | { | 1799 | { |
1985 | /* Is this the exact next expected messasge? */ | 1800 | receiver = ch->owner; |
1986 | if (mid == rel->mid_recv) | 1801 | ack_to_owner = GNUNET_NO; |
1987 | { | ||
1988 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1989 | "as expected, sending to client\n"); | ||
1990 | send_client_data (ch, msg, fwd); | ||
1991 | } | ||
1992 | else | ||
1993 | { | ||
1994 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1995 | "save for later\n"); | ||
1996 | add_buffered_data (msg, rel); | ||
1997 | } | ||
1998 | } | 1802 | } |
1999 | else | 1803 | else |
2000 | { | 1804 | { |
2001 | /* Tunnel is unreliable: send to clients directly */ | 1805 | GNUNET_break (0); |
2002 | /* FIXME: accept Out Of Order traffic */ | 1806 | return GNUNET_SYSERR; |
2003 | rel->mid_recv = mid + 1; | ||
2004 | send_client_data (ch, msg, fwd); | ||
2005 | } | 1807 | } |
2006 | } | 1808 | GNUNET_assert (NULL != receiver); |
2007 | else | 1809 | ld->ccn = receiver->ccn; |
2008 | { | 1810 | GNUNET_memcpy (&ld[1], |
2009 | GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO); | 1811 | buf, |
2010 | if (GC_is_pid_bigger (rel->mid_recv, mid)) | 1812 | buf_len); |
1813 | if (GNUNET_YES == receiver->client_ready) | ||
2011 | { | 1814 | { |
2012 | GNUNET_break_op (0); | 1815 | ch->pending_messages--; |
2013 | LOG (GNUNET_ERROR_TYPE_WARNING, | 1816 | GSC_send_to_client (receiver->c, |
2014 | "MID %u on channel %s not expected (window: %u - %u). Dropping!\n", | 1817 | env); |
2015 | mid, GCCH_2s (ch), rel->mid_recv, rel->mid_recv + 63); | 1818 | send_ack_to_client (ch, |
1819 | ack_to_owner); | ||
2016 | } | 1820 | } |
2017 | else | 1821 | else |
2018 | { | 1822 | { |
2019 | LOG (GNUNET_ERROR_TYPE_INFO, | 1823 | struct CadetOutOfOrderMessage *oom; |
2020 | "Duplicate MID %u, channel %s (expecting MID %u). Re-sending ACK!\n", | 1824 | |
2021 | mid, GCCH_2s (ch), rel->mid_recv); | 1825 | oom = GNUNET_new (struct CadetOutOfOrderMessage); |
2022 | if (NULL != rel->uniq) | 1826 | oom->env = env; |
2023 | { | 1827 | GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv, |
2024 | LOG (GNUNET_ERROR_TYPE_WARNING, | 1828 | receiver->tail_recv, |
2025 | "We are trying to send an ACK, but don't seem have the " | 1829 | oom); |
2026 | "bandwidth. Have you set enough [ats] QUOTA in your config?\n"); | 1830 | receiver->num_recv++; |
2027 | } | ||
2028 | |||
2029 | } | 1831 | } |
2030 | } | 1832 | return GNUNET_OK; |
2031 | 1833 | } | |
2032 | GCCH_send_data_ack (ch, fwd); | 1834 | |
1835 | /* Everything is correct, send the message. */ | ||
1836 | crm = GNUNET_malloc (sizeof (*crm)); | ||
1837 | crm->ch = ch; | ||
1838 | crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) | ||
1839 | + buf_len); | ||
1840 | crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len); | ||
1841 | crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA); | ||
1842 | ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1); | ||
1843 | crm->data_message->mid = ch->mid_send; | ||
1844 | crm->data_message->ctn = ch->ctn; | ||
1845 | GNUNET_memcpy (&crm->data_message[1], | ||
1846 | buf, | ||
1847 | buf_len); | ||
1848 | GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent, | ||
1849 | ch->tail_sent, | ||
1850 | crm); | ||
1851 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1852 | "Sending message %u from local client to %s with %u bytes\n", | ||
1853 | ntohl (crm->data_message->mid.mid), | ||
1854 | GCCH_2s (ch), | ||
1855 | buf_len); | ||
1856 | if (NULL != ch->retry_data_task) | ||
1857 | { | ||
1858 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | ||
1859 | ch->retry_data_task = NULL; | ||
1860 | } | ||
1861 | crm->qe = GCT_send (ch->t, | ||
1862 | &crm->data_message->header, | ||
1863 | &data_sent_cb, | ||
1864 | crm); | ||
1865 | GNUNET_assert (NULL == ch->retry_data_task); | ||
1866 | return GNUNET_OK; | ||
2033 | } | 1867 | } |
2034 | 1868 | ||
2035 | 1869 | ||
2036 | /** | 1870 | /** |
2037 | * Handler for cadet network traffic end-to-end ACKs. | 1871 | * Handle ACK from client on local channel. Means the client is ready |
1872 | * for more data, see if we have any for it. | ||
2038 | * | 1873 | * |
2039 | * @param ch Channel on which we got this message. | 1874 | * @param ch channel to destroy |
2040 | * @param msg Data message. | 1875 | * @param client_ccn ccn of the client sending the ack |
2041 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
2042 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
2043 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
2044 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
2045 | */ | 1876 | */ |
2046 | void | 1877 | void |
2047 | GCCH_handle_data_ack (struct CadetChannel *ch, | 1878 | GCCH_handle_local_ack (struct CadetChannel *ch, |
2048 | const struct GNUNET_CADET_ChannelDataAckMessage *msg, | 1879 | struct GNUNET_CADET_ClientChannelNumber client_ccn) |
2049 | int fwd) | ||
2050 | { | 1880 | { |
2051 | struct CadetChannelReliability *rel; | 1881 | struct CadetChannelClient *ccc; |
2052 | struct CadetReliableMessage *copy; | 1882 | struct CadetOutOfOrderMessage *com; |
2053 | struct CadetReliableMessage *next; | 1883 | |
2054 | uint32_t ack; | 1884 | if ( (NULL != ch->owner) && |
2055 | int work; | 1885 | (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) ) |
2056 | 1886 | ccc = ch->owner; | |
2057 | /* If this is a remote (non-loopback) channel, find 'fwd'. */ | 1887 | else if ( (NULL != ch->dest) && |
2058 | if (GNUNET_SYSERR == fwd) | 1888 | (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) ) |
2059 | { | 1889 | ccc = ch->dest; |
2060 | if (is_loopback (ch)) | ||
2061 | { | ||
2062 | /* It is a loopback channel after all... */ | ||
2063 | GNUNET_break (0); | ||
2064 | return; | ||
2065 | } | ||
2066 | /* Inverted: if message came 'FWD' is a 'BCK ACK'. */ | ||
2067 | fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES; | ||
2068 | } | ||
2069 | |||
2070 | ack = ntohl (msg->mid); | ||
2071 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2072 | "<== %s (0x%010lX %4u) on chan %s (%p) %s [%5u]\n", | ||
2073 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK), msg->futures, ack, | ||
2074 | GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size)); | ||
2075 | |||
2076 | if (GNUNET_YES == fwd) | ||
2077 | rel = ch->root_rel; | ||
2078 | else | 1890 | else |
2079 | rel = ch->dest_rel; | 1891 | GNUNET_assert (0); |
2080 | 1892 | ccc->client_ready = GNUNET_YES; | |
2081 | if (NULL == rel) | 1893 | com = ccc->head_recv; |
1894 | if (NULL == com) | ||
2082 | { | 1895 | { |
2083 | GNUNET_break (GNUNET_NO != ch->destroy); | 1896 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2084 | return; | 1897 | "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n", |
2085 | } | 1898 | GSC_2s (ccc->c), |
2086 | 1899 | ntohl (client_ccn.channel_of_client), | |
2087 | /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */ | 1900 | GCCH_2s (ch), |
2088 | for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next) | 1901 | ntohl (ccc->ccn.channel_of_client), |
2089 | { | 1902 | ccc); |
2090 | if (GC_is_pid_bigger (copy->mid, ack)) | 1903 | return; /* none pending */ |
2091 | { | 1904 | } |
2092 | LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); | 1905 | if (GNUNET_YES == ch->is_loopback) |
2093 | if (0 < channel_rel_free_sent (rel, msg)) | 1906 | { |
2094 | work = GNUNET_YES; | 1907 | int to_owner; |
2095 | break; | 1908 | |
2096 | } | 1909 | /* Messages are always in-order, just send */ |
2097 | work = GNUNET_YES; | 1910 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
2098 | LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); | 1911 | ccc->tail_recv, |
2099 | next = copy->next; | 1912 | com); |
2100 | if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) | 1913 | ccc->num_recv--; |
2101 | { | 1914 | GSC_send_to_client (ccc->c, |
2102 | LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n"); | 1915 | com->env); |
2103 | return; | 1916 | /* Notify sender that we can receive more */ |
2104 | } | 1917 | if ( (NULL != ch->owner) && |
2105 | } | 1918 | (ccc->ccn.channel_of_client == |
2106 | 1919 | ch->owner->ccn.channel_of_client) ) | |
2107 | /* ACK client if needed and possible */ | ||
2108 | GCCH_allow_client (ch, fwd); | ||
2109 | |||
2110 | /* If some message was free'd, update the retransmission delay */ | ||
2111 | if (GNUNET_YES == work) | ||
2112 | { | ||
2113 | if (NULL != rel->retry_task) | ||
2114 | { | 1920 | { |
2115 | GNUNET_SCHEDULER_cancel (rel->retry_task); | 1921 | to_owner = GNUNET_NO; |
2116 | rel->retry_task = NULL; | ||
2117 | if (NULL != rel->head_sent && NULL == rel->head_sent->chq) | ||
2118 | { | ||
2119 | struct GNUNET_TIME_Absolute new_target; | ||
2120 | struct GNUNET_TIME_Relative delay; | ||
2121 | |||
2122 | delay = GNUNET_TIME_relative_saturating_multiply (rel->retry_timer, | ||
2123 | CADET_RETRANSMIT_MARGIN); | ||
2124 | new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp, | ||
2125 | delay); | ||
2126 | delay = GNUNET_TIME_absolute_get_remaining (new_target); | ||
2127 | rel->retry_task = | ||
2128 | GNUNET_SCHEDULER_add_delayed (delay, | ||
2129 | &channel_retransmit_message, | ||
2130 | rel); | ||
2131 | } | ||
2132 | } | 1922 | } |
2133 | else | 1923 | else |
2134 | { | 1924 | { |
2135 | /* Work was done but no task was pending. | 1925 | GNUNET_assert ( (NULL != ch->dest) && |
2136 | * Task was cancelled by a retransmission that is sitting in the queue. | 1926 | (ccc->ccn.channel_of_client == |
2137 | */ | 1927 | ch->dest->ccn.channel_of_client) ); |
2138 | // FIXME add test to make sure this is the case, probably add return | 1928 | to_owner = GNUNET_YES; |
2139 | // value to GCCH_send_prebuilt_message | ||
2140 | } | 1929 | } |
1930 | send_ack_to_client (ch, | ||
1931 | to_owner); | ||
1932 | GNUNET_free (com); | ||
1933 | return; | ||
2141 | } | 1934 | } |
2142 | } | ||
2143 | 1935 | ||
2144 | 1936 | if ( (com->mid.mid != ch->mid_recv.mid) && | |
2145 | /** | 1937 | (GNUNET_NO == ch->out_of_order) && |
2146 | * Handler for channel create messages. | 1938 | (GNUNET_YES == ch->reliable) ) |
2147 | * | ||
2148 | * Does not have fwd parameter because it's always 'FWD': channel is incoming. | ||
2149 | * | ||
2150 | * @param t Tunnel this channel will be in. | ||
2151 | * @param msg Channel crate message. | ||
2152 | */ | ||
2153 | struct CadetChannel * | ||
2154 | GCCH_handle_create (struct CadetTunnel *t, | ||
2155 | const struct GNUNET_CADET_ChannelOpenMessage *msg) | ||
2156 | { | ||
2157 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
2158 | struct GNUNET_CADET_ChannelTunnelNumber gid; | ||
2159 | struct CadetChannel *ch; | ||
2160 | struct CadetClient *c; | ||
2161 | int new_channel; | ||
2162 | const struct GNUNET_HashCode *port; | ||
2163 | |||
2164 | gid = msg->ctn; | ||
2165 | ch = GCT_get_channel (t, gid); | ||
2166 | if (NULL == ch) | ||
2167 | { | ||
2168 | /* Create channel */ | ||
2169 | ccn.channel_of_client = htonl (0); | ||
2170 | ch = channel_new (t, NULL, ccn); | ||
2171 | ch->gid = gid; | ||
2172 | channel_set_options (ch, ntohl (msg->opt)); | ||
2173 | new_channel = GNUNET_YES; | ||
2174 | } | ||
2175 | else | ||
2176 | { | 1939 | { |
2177 | new_channel = GNUNET_NO; | 1940 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1941 | "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n", | ||
1942 | GSC_2s (ccc->c), | ||
1943 | ntohl (ccc->ccn.channel_of_client), | ||
1944 | ntohl (com->mid.mid), | ||
1945 | ntohl (ch->mid_recv.mid)); | ||
1946 | return; /* missing next one in-order */ | ||
2178 | } | 1947 | } |
2179 | port = &msg->port; | ||
2180 | |||
2181 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2182 | "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n", | ||
2183 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN), ccn, port, | ||
2184 | GCCH_2s (ch), ch, GC_f2s (GNUNET_YES), ntohs (msg->header.size)); | ||
2185 | |||
2186 | if (GNUNET_YES == new_channel || GCT_is_loopback (t)) | ||
2187 | { | ||
2188 | /* Find a destination client */ | ||
2189 | ch->port = *port; | ||
2190 | LOG (GNUNET_ERROR_TYPE_DEBUG, " port %s\n", GNUNET_h2s (port)); | ||
2191 | c = GML_client_get_by_port (port); | ||
2192 | if (NULL == c) | ||
2193 | { | ||
2194 | LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n"); | ||
2195 | if (is_loopback (ch)) | ||
2196 | { | ||
2197 | LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n"); | ||
2198 | send_nack (ch); | ||
2199 | } | ||
2200 | else | ||
2201 | { | ||
2202 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n"); | ||
2203 | send_nack (ch); | ||
2204 | GCCH_destroy (ch); | ||
2205 | } | ||
2206 | return NULL; | ||
2207 | } | ||
2208 | else | ||
2209 | { | ||
2210 | LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c); | ||
2211 | } | ||
2212 | |||
2213 | add_destination (ch, c); | ||
2214 | if (GNUNET_YES == ch->reliable) | ||
2215 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Reliable\n"); | ||
2216 | else | ||
2217 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Not Reliable\n"); | ||
2218 | 1948 | ||
2219 | send_client_create (ch); | 1949 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2220 | ch->state = CADET_CHANNEL_SENT; | 1950 | "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n", |
2221 | } | 1951 | ntohl (com->mid.mid), |
2222 | else | 1952 | GSC_2s (ccc->c), |
2223 | { | 1953 | ntohl (ccc->ccn.channel_of_client), |
2224 | LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n"); | 1954 | GCCH_2s (ch)); |
2225 | if (NULL != ch->dest_rel->retry_task) | ||
2226 | { | ||
2227 | LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n"); | ||
2228 | /* we were waiting to re-send our 'SYNACK', wait no more! */ | ||
2229 | GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task); | ||
2230 | ch->dest_rel->retry_task = NULL; | ||
2231 | } | ||
2232 | else if (NULL != ch->dest_rel->uniq) | ||
2233 | { | ||
2234 | /* we are waiting to for our 'SYNACK' to leave the queue, all done! */ | ||
2235 | return ch; | ||
2236 | } | ||
2237 | } | ||
2238 | send_ack (ch, GNUNET_YES); | ||
2239 | 1955 | ||
2240 | return ch; | 1956 | /* all good, pass next message to client */ |
1957 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1958 | ccc->tail_recv, | ||
1959 | com); | ||
1960 | ccc->num_recv--; | ||
1961 | /* FIXME: if unreliable, this is not aggressive | ||
1962 | enough, as it would be OK to have lost some! */ | ||
1963 | |||
1964 | ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid)); | ||
1965 | ch->mid_futures >>= 1; /* equivalent to division by 2 */ | ||
1966 | ccc->client_ready = GNUNET_NO; | ||
1967 | GSC_send_to_client (ccc->c, | ||
1968 | com->env); | ||
1969 | GNUNET_free (com); | ||
1970 | send_channel_data_ack (ch); | ||
1971 | if (NULL != ccc->head_recv) | ||
1972 | return; | ||
1973 | if (GNUNET_NO == ch->destroy) | ||
1974 | return; | ||
1975 | GCT_send_channel_destroy (ch->t, | ||
1976 | ch->ctn); | ||
1977 | channel_destroy (ch); | ||
2241 | } | 1978 | } |
2242 | 1979 | ||
2243 | 1980 | ||
2244 | /** | 1981 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__) |
2245 | * Handler for channel NACK messages. | ||
2246 | * | ||
2247 | * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. | ||
2248 | * | ||
2249 | * @param ch Channel. | ||
2250 | */ | ||
2251 | void | ||
2252 | GCCH_handle_nack (struct CadetChannel *ch) | ||
2253 | { | ||
2254 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2255 | "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n", | ||
2256 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED), ch->gid, 0, | ||
2257 | GCCH_2s (ch), ch, "---", 0); | ||
2258 | |||
2259 | send_client_nack (ch); | ||
2260 | GCCH_destroy (ch); | ||
2261 | } | ||
2262 | 1982 | ||
2263 | 1983 | ||
2264 | /** | 1984 | /** |
2265 | * Handler for channel ack messages. | 1985 | * Log channel info. |
2266 | * | 1986 | * |
2267 | * @param ch Channel. | 1987 | * @param ch Channel. |
2268 | * @param msg Message. | 1988 | * @param level Debug level to use. |
2269 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
2270 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
2271 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
2272 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
2273 | */ | ||
2274 | void | ||
2275 | GCCH_handle_ack (struct CadetChannel *ch, | ||
2276 | const struct GNUNET_CADET_ChannelManageMessage *msg, | ||
2277 | int fwd) | ||
2278 | { | ||
2279 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2280 | "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n", | ||
2281 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK), ch->gid, 0, | ||
2282 | GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size)); | ||
2283 | |||
2284 | /* If this is a remote (non-loopback) channel, find 'fwd'. */ | ||
2285 | if (GNUNET_SYSERR == fwd) | ||
2286 | { | ||
2287 | if (is_loopback (ch)) | ||
2288 | { | ||
2289 | /* It is a loopback channel after all... */ | ||
2290 | GNUNET_break (0); | ||
2291 | return; | ||
2292 | } | ||
2293 | fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; | ||
2294 | } | ||
2295 | |||
2296 | channel_confirm (ch, !fwd); | ||
2297 | } | ||
2298 | |||
2299 | |||
2300 | /** | ||
2301 | * Handler for channel destroy messages. | ||
2302 | * | ||
2303 | * @param ch Channel to be destroyed of. | ||
2304 | * @param msg Message. | ||
2305 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
2306 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
2307 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
2308 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
2309 | */ | 1989 | */ |
2310 | void | 1990 | void |
2311 | GCCH_handle_destroy (struct CadetChannel *ch, | 1991 | GCCH_debug (struct CadetChannel *ch, |
2312 | const struct GNUNET_CADET_ChannelManageMessage *msg, | 1992 | enum GNUNET_ErrorType level) |
2313 | int fwd) | ||
2314 | { | 1993 | { |
2315 | struct CadetChannelReliability *rel; | 1994 | int do_log; |
2316 | |||
2317 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2318 | "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n", | ||
2319 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY), ch->gid, 0, | ||
2320 | GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size)); | ||
2321 | |||
2322 | /* If this is a remote (non-loopback) channel, find 'fwd'. */ | ||
2323 | if (GNUNET_SYSERR == fwd) | ||
2324 | { | ||
2325 | if (is_loopback (ch)) | ||
2326 | { | ||
2327 | /* It is a loopback channel after all... */ | ||
2328 | GNUNET_break (0); | ||
2329 | return; | ||
2330 | } | ||
2331 | fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; | ||
2332 | } | ||
2333 | 1995 | ||
2334 | GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); | 1996 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), |
2335 | if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) | 1997 | "cadet-chn", |
2336 | { | 1998 | __FILE__, __FUNCTION__, __LINE__); |
2337 | /* Not for us (don't destroy twice a half-open loopback channel) */ | 1999 | if (0 == do_log) |
2338 | return; | 2000 | return; |
2339 | } | ||
2340 | |||
2341 | rel = fwd ? ch->dest_rel : ch->root_rel; | ||
2342 | if (0 == rel->n_recv) | ||
2343 | { | ||
2344 | send_destroy (ch, GNUNET_YES); | ||
2345 | GCCH_destroy (ch); | ||
2346 | } | ||
2347 | else | ||
2348 | { | ||
2349 | ch->destroy = GNUNET_YES; | ||
2350 | } | ||
2351 | } | ||
2352 | |||
2353 | |||
2354 | /** | ||
2355 | * Sends an already built message on a channel. | ||
2356 | * | ||
2357 | * If the channel is on a loopback tunnel, notifies the appropriate destination | ||
2358 | * client locally. | ||
2359 | * | ||
2360 | * On a normal channel passes the message to the tunnel for encryption and | ||
2361 | * sending on a connection. | ||
2362 | * | ||
2363 | * This function DOES NOT save the message for retransmission. | ||
2364 | * | ||
2365 | * @param message Message to send. Function makes a copy of it. | ||
2366 | * @param ch Channel on which this message is transmitted. | ||
2367 | * @param fwd Is this a fwd message? | ||
2368 | * @param existing_copy This is a retransmission, don't save a copy. | ||
2369 | */ | ||
2370 | void | ||
2371 | GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
2372 | struct CadetChannel *ch, int fwd, | ||
2373 | void *existing_copy) | ||
2374 | { | ||
2375 | struct CadetChannelQueue *chq; | ||
2376 | uint32_t data_id; | ||
2377 | uint16_t type; | ||
2378 | uint16_t size; | ||
2379 | char info[32]; | ||
2380 | |||
2381 | type = ntohs (message->type); | ||
2382 | size = ntohs (message->size); | ||
2383 | |||
2384 | data_id = 0; | ||
2385 | switch (type) | ||
2386 | { | ||
2387 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: | ||
2388 | { | ||
2389 | struct GNUNET_CADET_ChannelAppDataMessage *data_msg; | ||
2390 | struct GNUNET_MessageHeader *payload_msg; | ||
2391 | uint16_t payload_type; | ||
2392 | |||
2393 | data_msg = (struct GNUNET_CADET_ChannelAppDataMessage *) message; | ||
2394 | data_id = ntohl (data_msg->mid); | ||
2395 | payload_msg = (struct GNUNET_MessageHeader *) &data_msg[1]; | ||
2396 | payload_type = ntohs (payload_msg->type); | ||
2397 | strncpy (info, GC_m2s (payload_type), 31); | ||
2398 | info[31] = '\0'; | ||
2399 | break; | ||
2400 | } | ||
2401 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: | ||
2402 | { | ||
2403 | struct GNUNET_CADET_ChannelDataAckMessage *ack_msg; | ||
2404 | ack_msg = (struct GNUNET_CADET_ChannelDataAckMessage *) message; | ||
2405 | data_id = ntohl (ack_msg->mid); | ||
2406 | SPRINTF (info, "0x%010lX", | ||
2407 | (unsigned long int) ack_msg->futures); | ||
2408 | break; | ||
2409 | } | ||
2410 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: | ||
2411 | { | ||
2412 | struct GNUNET_CADET_ChannelOpenMessage *cc_msg; | ||
2413 | cc_msg = (struct GNUNET_CADET_ChannelOpenMessage *) message; | ||
2414 | SPRINTF (info, " 0x%08X", ntohl (cc_msg->ctn.cn)); | ||
2415 | break; | ||
2416 | } | ||
2417 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: | ||
2418 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED: | ||
2419 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: | ||
2420 | { | ||
2421 | struct GNUNET_CADET_ChannelManageMessage *m_msg; | ||
2422 | m_msg = (struct GNUNET_CADET_ChannelManageMessage *) message; | ||
2423 | SPRINTF (info, " 0x%08X", ntohl (m_msg->ctn.cn)); | ||
2424 | break; | ||
2425 | } | ||
2426 | default: | ||
2427 | info[0] = '\0'; | ||
2428 | } | ||
2429 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2430 | "==> %s (%12s %4u) on chan %s (%p) %s [%5u]\n", | ||
2431 | GC_m2s (type), info, data_id, | ||
2432 | GCCH_2s (ch), ch, GC_f2s (fwd), size); | ||
2433 | 2001 | ||
2434 | if (GCT_is_loopback (ch->t)) | 2002 | if (NULL == ch) |
2435 | { | 2003 | { |
2436 | handle_loopback (ch, message, fwd); | 2004 | LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n"); |
2437 | return; | 2005 | return; |
2438 | } | 2006 | } |
2439 | 2007 | LOG2 (level, | |
2440 | switch (type) | 2008 | "CHN %s:%X (%p)\n", |
2009 | GCT_2s (ch->t), | ||
2010 | ch->ctn, | ||
2011 | ch); | ||
2012 | if (NULL != ch->owner) | ||
2441 | { | 2013 | { |
2442 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: | 2014 | LOG2 (level, |
2443 | if (GNUNET_YES == ch->reliable) | 2015 | "CHN origin %s ready %s local-id: %u\n", |
2444 | { | 2016 | GSC_2s (ch->owner->c), |
2445 | chq = GNUNET_new (struct CadetChannelQueue); | 2017 | ch->owner->client_ready ? "YES" : "NO", |
2446 | chq->type = type; | 2018 | ntohl (ch->owner->ccn.channel_of_client)); |
2447 | if (NULL == existing_copy) | ||
2448 | chq->copy = channel_save_copy (ch, message, fwd); | ||
2449 | else | ||
2450 | { | ||
2451 | chq->copy = (struct CadetReliableMessage *) existing_copy; | ||
2452 | if (NULL != chq->copy->chq) | ||
2453 | { | ||
2454 | /* Last retransmission was queued but not yet sent! | ||
2455 | * This retransmission was scheduled by a ch_message_sent which | ||
2456 | * followed a very fast RTT, so the tiny delay made the | ||
2457 | * retransmission function to execute before the previous | ||
2458 | * retransmitted message even had a chance to leave the peer. | ||
2459 | * Cancel this message and wait until the pending | ||
2460 | * retransmission leaves the peer and ch_message_sent starts | ||
2461 | * the timer for the next one. | ||
2462 | */ | ||
2463 | GNUNET_free (chq); | ||
2464 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2465 | " exisitng copy not yet transmitted!\n"); | ||
2466 | return; | ||
2467 | } | ||
2468 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2469 | " using existing copy: %p {r:%p q:%p t:%u}\n", | ||
2470 | existing_copy, | ||
2471 | chq->copy->rel, chq->copy->chq, chq->copy->type); | ||
2472 | } | ||
2473 | LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq); | ||
2474 | chq->copy->chq = chq; | ||
2475 | chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL, | ||
2476 | GNUNET_YES, | ||
2477 | &ch_message_sent, chq); | ||
2478 | /* q itself is stored in copy */ | ||
2479 | GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy); | ||
2480 | } | ||
2481 | else | ||
2482 | { | ||
2483 | fire_and_forget (message, ch, GNUNET_NO); | ||
2484 | } | ||
2485 | break; | ||
2486 | |||
2487 | |||
2488 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: | ||
2489 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: | ||
2490 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: | ||
2491 | chq = GNUNET_new (struct CadetChannelQueue); | ||
2492 | chq->type = type; | ||
2493 | chq->rel = fwd ? ch->root_rel : ch->dest_rel; | ||
2494 | if (NULL != chq->rel->uniq) | ||
2495 | { | ||
2496 | if (NULL != chq->rel->uniq->tq) | ||
2497 | { | ||
2498 | GCT_cancel (chq->rel->uniq->tq); | ||
2499 | /* ch_message_sent is called, freeing and NULLing uniq */ | ||
2500 | GNUNET_break (NULL == chq->rel->uniq); | ||
2501 | } | ||
2502 | else | ||
2503 | { | ||
2504 | GNUNET_break (0); | ||
2505 | GNUNET_free (chq->rel->uniq); | ||
2506 | } | ||
2507 | } | ||
2508 | |||
2509 | chq->rel->uniq = chq; | ||
2510 | chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES, | ||
2511 | &ch_message_sent, chq); | ||
2512 | if (NULL == chq->tq) | ||
2513 | { | ||
2514 | GNUNET_break (0); | ||
2515 | chq->rel->uniq = NULL; | ||
2516 | GCT_debug (ch->t, GNUNET_ERROR_TYPE_ERROR); | ||
2517 | GNUNET_free (chq); | ||
2518 | chq = NULL; | ||
2519 | return; | ||
2520 | } | ||
2521 | break; | ||
2522 | |||
2523 | |||
2524 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: | ||
2525 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED: | ||
2526 | fire_and_forget (message, ch, GNUNET_YES); | ||
2527 | break; | ||
2528 | |||
2529 | |||
2530 | default: | ||
2531 | GNUNET_break (0); | ||
2532 | LOG (GNUNET_ERROR_TYPE_WARNING, "type %s unknown!\n", GC_m2s (type)); | ||
2533 | fire_and_forget (message, ch, GNUNET_YES); | ||
2534 | } | 2019 | } |
2020 | if (NULL != ch->dest) | ||
2021 | { | ||
2022 | LOG2 (level, | ||
2023 | "CHN destination %s ready %s local-id: %u\n", | ||
2024 | GSC_2s (ch->dest->c), | ||
2025 | ch->dest->client_ready ? "YES" : "NO", | ||
2026 | ntohl (ch->dest->ccn.channel_of_client)); | ||
2027 | } | ||
2028 | LOG2 (level, | ||
2029 | "CHN Message IDs recv: %d (%LLX), send: %d\n", | ||
2030 | ntohl (ch->mid_recv.mid), | ||
2031 | (unsigned long long) ch->mid_futures, | ||
2032 | ntohl (ch->mid_send.mid)); | ||
2535 | } | 2033 | } |
2536 | 2034 | ||
2537 | 2035 | ||
2538 | /** | ||
2539 | * Get the static string for identification of the channel. | ||
2540 | * | ||
2541 | * @param ch Channel. | ||
2542 | * | ||
2543 | * @return Static string with the channel IDs. | ||
2544 | */ | ||
2545 | const char * | ||
2546 | GCCH_2s (const struct CadetChannel *ch) | ||
2547 | { | ||
2548 | static char buf[64]; | ||
2549 | |||
2550 | if (NULL == ch) | ||
2551 | return "(NULL Channel)"; | ||
2552 | 2036 | ||
2553 | SPRINTF (buf, | 2037 | /* end of gnunet-service-cadet-new_channel.c */ |
2554 | "%s:%s gid:%X (%X / %X)", | ||
2555 | GCT_2s (ch->t), | ||
2556 | GNUNET_h2s (&ch->port), | ||
2557 | ntohl (ch->gid.cn), | ||
2558 | ntohl (ch->lid_root.channel_of_client), | ||
2559 | ntohl (ch->lid_dest.channel_of_client)); | ||
2560 | |||
2561 | return buf; | ||
2562 | } | ||
diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h index 9d4893269..a3ef9a06d 100644 --- a/src/cadet/gnunet-service-cadet_channel.h +++ b/src/cadet/gnunet-service-cadet_channel.h | |||
@@ -1,6 +1,7 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | This file is part of GNUnet. | 3 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 4 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 5 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 6 | 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 | it under the terms of the GNU General Public License as published |
@@ -20,344 +21,242 @@ | |||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * @file cadet/gnunet-service-cadet_channel.h | 23 | * @file cadet/gnunet-service-cadet_channel.h |
23 | * @brief cadet service; dealing with end-to-end channels | 24 | * @brief GNUnet CADET service with encryption |
24 | * @author Bartlomiej Polot | 25 | * @author Bartlomiej Polot |
25 | * | 26 | * @author Christian Grothoff |
26 | * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel) | ||
27 | */ | 27 | */ |
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_CHANNEL_H | 28 | #ifndef GNUNET_SERVICE_CADET_CHANNEL_H |
30 | #define GNUNET_SERVICE_CADET_CHANNEL_H | 29 | #define GNUNET_SERVICE_CADET_CHANNEL_H |
31 | 30 | ||
32 | #ifdef __cplusplus | 31 | #include "gnunet-service-cadet.h" |
33 | extern "C" | 32 | #include "gnunet-service-cadet_peer.h" |
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "platform.h" | ||
41 | #include "gnunet_util_lib.h" | ||
42 | |||
43 | #include "cadet_protocol.h" | 33 | #include "cadet_protocol.h" |
44 | #include "cadet.h" | ||
45 | |||
46 | /** | ||
47 | * Struct containing all information regarding a channel to a remote client. | ||
48 | */ | ||
49 | struct CadetChannel; | ||
50 | |||
51 | |||
52 | #include "gnunet-service-cadet_tunnel.h" | ||
53 | #include "gnunet-service-cadet_local.h" | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Destroy a channel and free all resources. | ||
58 | * | ||
59 | * @param ch Channel to destroy. | ||
60 | */ | ||
61 | void | ||
62 | GCCH_destroy (struct CadetChannel *ch); | ||
63 | 34 | ||
64 | 35 | ||
65 | /** | 36 | /** |
66 | * Get the channel's public ID. | 37 | * A channel is a bidirectional connection between two CADET |
67 | * | 38 | * clients. Communiation can be reliable, unreliable, in-order |
68 | * @param ch Channel. | 39 | * or out-of-order. One client is the "local" client, this |
69 | * | 40 | * one initiated the connection. The other client is the |
70 | * @return ID used to identify the channel with the remote peer. | 41 | * "incoming" client, this one listened on a port to accept |
42 | * the connection from the "local" client. | ||
71 | */ | 43 | */ |
72 | struct GNUNET_CADET_ChannelTunnelNumber | 44 | struct CadetChannel; |
73 | GCCH_get_id (const struct CadetChannel *ch); | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Get the channel tunnel. | ||
78 | * | ||
79 | * @param ch Channel to get the tunnel from. | ||
80 | * | ||
81 | * @return tunnel of the channel. | ||
82 | */ | ||
83 | struct CadetTunnel * | ||
84 | GCCH_get_tunnel (const struct CadetChannel *ch); | ||
85 | 45 | ||
86 | 46 | ||
87 | /** | 47 | /** |
88 | * Get free buffer space towards the client on a specific channel. | 48 | * Get the static string for identification of the channel. |
89 | * | 49 | * |
90 | * @param ch Channel. | 50 | * @param ch Channel. |
91 | * @param fwd Is query about FWD traffic? | ||
92 | * | 51 | * |
93 | * @return Free buffer space [0 - 64] | 52 | * @return Static string with the channel IDs. |
94 | */ | 53 | */ |
95 | unsigned int | 54 | const char * |
96 | GCCH_get_buffer (struct CadetChannel *ch, int fwd); | 55 | GCCH_2s (const struct CadetChannel *ch); |
97 | 56 | ||
98 | 57 | ||
99 | /** | 58 | /** |
100 | * Get flow control status of end point: is client allow to send? | 59 | * Log channel info. |
101 | * | 60 | * |
102 | * @param ch Channel. | 61 | * @param ch Channel. |
103 | * @param fwd Is query about FWD traffic? (Request root status). | 62 | * @param level Debug level to use. |
104 | * | ||
105 | * @return #GNUNET_YES if client is allowed to send us data. | ||
106 | */ | 63 | */ |
107 | int | 64 | void |
108 | GCCH_get_allowed (struct CadetChannel *ch, int fwd); | 65 | GCCH_debug (struct CadetChannel *ch, |
66 | enum GNUNET_ErrorType level); | ||
109 | 67 | ||
110 | 68 | ||
111 | /** | 69 | /** |
112 | * Is the root client for this channel on this peer? | 70 | * Get the channel's public ID. |
113 | * | 71 | * |
114 | * @param ch Channel. | 72 | * @param ch Channel. |
115 | * @param fwd Is this for fwd traffic? | ||
116 | * | 73 | * |
117 | * @return #GNUNET_YES in case it is. | 74 | * @return ID used to identify the channel with the remote peer. |
118 | */ | 75 | */ |
119 | int | 76 | struct GNUNET_CADET_ChannelTunnelNumber |
120 | GCCH_is_origin (struct CadetChannel *ch, int fwd); | 77 | GCCH_get_id (const struct CadetChannel *ch); |
121 | 78 | ||
122 | /** | ||
123 | * Is the destination client for this channel on this peer? | ||
124 | * | ||
125 | * @param ch Channel. | ||
126 | * @param fwd Is this for fwd traffic? | ||
127 | * | ||
128 | * @return #GNUNET_YES in case it is. | ||
129 | */ | ||
130 | int | ||
131 | GCCH_is_terminal (struct CadetChannel *ch, int fwd); | ||
132 | 79 | ||
133 | /** | 80 | /** |
134 | * Send an end-to-end ACK message for the most recent in-sequence payload. | 81 | * Create a new channel. |
135 | * | 82 | * |
136 | * If channel is not reliable, do nothing. | 83 | * @param owner local client owning the channel |
137 | * | 84 | * @param owner_id local chid of this channel at the @a owner |
138 | * @param ch Channel this is about. | 85 | * @param destination peer to which we should build the channel |
139 | * @param fwd Is for FWD traffic? (ACK dest->owner) | 86 | * @param port desired port at @a destination |
87 | * @param options options for the channel | ||
88 | * @return handle to the new channel | ||
140 | */ | 89 | */ |
141 | void | 90 | struct CadetChannel * |
142 | GCCH_send_data_ack (struct CadetChannel *ch, int fwd); | 91 | GCCH_channel_local_new (struct CadetClient *owner, |
92 | struct GNUNET_CADET_ClientChannelNumber owner_id, | ||
93 | struct CadetPeer *destination, | ||
94 | const struct GNUNET_HashCode *port, | ||
95 | uint32_t options); | ||
143 | 96 | ||
144 | /** | ||
145 | * Notify the destination client that a new incoming channel was created. | ||
146 | * | ||
147 | * @param ch Channel that was created. | ||
148 | */ | ||
149 | void | ||
150 | GCCH_send_create (struct CadetChannel *ch); | ||
151 | 97 | ||
152 | /** | 98 | /** |
153 | * Allow a client to send us more data, in case it was choked. | 99 | * A client is bound to the port that we have a channel |
100 | * open to. Send the acknowledgement for the connection | ||
101 | * request and establish the link with the client. | ||
154 | * | 102 | * |
155 | * @param ch Channel. | 103 | * @param ch open incoming channel |
156 | * @param fwd Is this about FWD traffic? (Root client). | 104 | * @param c client listening on the respective port |
157 | */ | 105 | */ |
158 | void | 106 | void |
159 | GCCH_allow_client (struct CadetChannel *ch, int fwd); | 107 | GCCH_bind (struct CadetChannel *ch, |
108 | struct CadetClient *c); | ||
160 | 109 | ||
161 | /** | ||
162 | * Log channel info. | ||
163 | * | ||
164 | * @param ch Channel. | ||
165 | * @param level Debug level to use. | ||
166 | */ | ||
167 | void | ||
168 | GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level); | ||
169 | 110 | ||
170 | /** | 111 | /** |
171 | * Handle an ACK given by a client. | 112 | * Destroy locally created channel. Called by the |
113 | * local client, so no need to tell the client. | ||
172 | * | 114 | * |
173 | * Mark client as ready and send him any buffered data we could have for him. | 115 | * @param ch channel to destroy |
174 | * | 116 | * @param c client that caused the destruction |
175 | * @param ch Channel. | 117 | * @param ccn client number of the client @a c |
176 | * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) | ||
177 | */ | 118 | */ |
178 | void | 119 | void |
179 | GCCH_handle_local_ack (struct CadetChannel *ch, int fwd); | 120 | GCCH_channel_local_destroy (struct CadetChannel *ch, |
121 | struct CadetClient *c, | ||
122 | struct GNUNET_CADET_ClientChannelNumber ccn); | ||
180 | 123 | ||
181 | /** | ||
182 | * Handle data given by a client. | ||
183 | * | ||
184 | * Check whether the client is allowed to send in this tunnel, save if channel | ||
185 | * is reliable and send an ACK to the client if there is still buffer space | ||
186 | * in the tunnel. | ||
187 | * | ||
188 | * @param ch Channel. | ||
189 | * @param c Client which sent the data. | ||
190 | * @param fwd Is this a FWD data? | ||
191 | * @param message Data message. | ||
192 | * @param size Size of data. | ||
193 | * | ||
194 | * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. | ||
195 | */ | ||
196 | int | ||
197 | GCCH_handle_local_data (struct CadetChannel *ch, | ||
198 | struct CadetClient *c, int fwd, | ||
199 | const struct GNUNET_MessageHeader *message, | ||
200 | size_t size); | ||
201 | 124 | ||
202 | /** | 125 | /** |
203 | * Handle a channel destroy requested by a client. | 126 | * Function called once and only once after a channel was bound |
204 | * | 127 | * to its tunnel via #GCT_add_channel() is ready for transmission. |
205 | * Destroy the channel and the tunnel in case this was the last channel. | 128 | * Note that this is only the case for channels that this peer |
206 | * | 129 | * initiates, as for incoming channels we assume that they are |
207 | * @param ch Channel. | 130 | * ready for transmission immediately upon receiving the open |
208 | * @param c Client that requested the destruction (to avoid notifying him). | 131 | * message. Used to bootstrap the #GCT_send() process. |
209 | * @param is_root Is the request coming from root? | 132 | * |
133 | * @param ch the channel for which the tunnel is now ready | ||
210 | */ | 134 | */ |
211 | void | 135 | void |
212 | GCCH_handle_local_destroy (struct CadetChannel *ch, | 136 | GCCH_tunnel_up (struct CadetChannel *ch); |
213 | struct CadetClient *c, | ||
214 | int is_root); | ||
215 | 137 | ||
216 | 138 | ||
217 | /** | 139 | /** |
218 | * Handle a channel create requested by a client. | 140 | * Create a new channel based on a request coming in over the network. |
219 | * | 141 | * |
220 | * Create the channel and the tunnel in case this was the first0 channel. | 142 | * @param t tunnel to the remote peer |
221 | * | 143 | * @param chid identifier of this channel in the tunnel |
222 | * @param c Client that requested the creation (will be the root). | 144 | * @param origin peer to who initiated the channel |
223 | * @param msg Create Channel message. | 145 | * @param port desired local port |
224 | * | 146 | * @param options options for the channel |
225 | * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. | 147 | * @return handle to the new channel |
226 | */ | 148 | */ |
227 | int | 149 | struct CadetChannel * |
228 | GCCH_handle_local_create (struct CadetClient *c, | 150 | GCCH_channel_incoming_new (struct CadetTunnel *t, |
229 | struct GNUNET_CADET_LocalChannelCreateMessage *msg); | 151 | struct GNUNET_CADET_ChannelTunnelNumber chid, |
230 | 152 | const struct GNUNET_HashCode *port, | |
231 | /** | 153 | uint32_t options); |
232 | * Handler for cadet network payload traffic. | ||
233 | * | ||
234 | * @param ch Channel for the message. | ||
235 | * @param msg Unencryted data message. | ||
236 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
237 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
238 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
239 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
240 | */ | ||
241 | void | ||
242 | GCCH_handle_data (struct CadetChannel *ch, | ||
243 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | ||
244 | int fwd); | ||
245 | 154 | ||
246 | 155 | ||
247 | /** | 156 | /** |
248 | * Handler for cadet network traffic end-to-end ACKs. | 157 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for |
158 | * this channel. If the binding was successful, (re)transmit the | ||
159 | * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK. | ||
249 | * | 160 | * |
250 | * @param ch Channel on which we got this message. | 161 | * @param ch channel that got the duplicate open |
251 | * @param msg Data message. | 162 | * @param cti identifier of the connection that delivered the message |
252 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
253 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
254 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
255 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
256 | */ | 163 | */ |
257 | void | 164 | void |
258 | GCCH_handle_data_ack (struct CadetChannel *ch, | 165 | GCCH_handle_duplicate_open (struct CadetChannel *ch, |
259 | const struct GNUNET_CADET_ChannelDataAckMessage *msg, | 166 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); |
260 | int fwd); | ||
261 | 167 | ||
262 | 168 | ||
263 | /** | ||
264 | * Handler for channel create messages. | ||
265 | * | ||
266 | * Does not have fwd parameter because it's always 'FWD': channel is incoming. | ||
267 | * | ||
268 | * @param t Tunnel this channel will be in. | ||
269 | * @param msg Channel crate message. | ||
270 | */ | ||
271 | struct CadetChannel * | ||
272 | GCCH_handle_create (struct CadetTunnel *t, | ||
273 | const struct GNUNET_CADET_ChannelOpenMessage *msg); | ||
274 | |||
275 | 169 | ||
276 | /** | 170 | /** |
277 | * Handler for channel NACK messages. | 171 | * We got payload data for a channel. Pass it on to the client. |
278 | * | 172 | * |
279 | * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. | 173 | * @param ch channel that got data |
280 | * | 174 | * @param cti identifier of the connection that delivered the message |
281 | * @param ch Channel. | 175 | * @param msg message that was received |
282 | */ | 176 | */ |
283 | void | 177 | void |
284 | GCCH_handle_nack (struct CadetChannel *ch); | 178 | GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, |
179 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, | ||
180 | const struct GNUNET_CADET_ChannelAppDataMessage *msg); | ||
285 | 181 | ||
286 | 182 | ||
287 | /** | 183 | /** |
288 | * Handler for channel ack messages. | 184 | * We got an acknowledgement for payload data for a channel. |
185 | * Possibly resume transmissions. | ||
289 | * | 186 | * |
290 | * @param ch Channel this channel is to be created in. | 187 | * @param ch channel that got the ack |
291 | * @param msg Message. | 188 | * @param cti identifier of the connection that delivered the message |
292 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | 189 | * @param ack details about what was received |
293 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
294 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
295 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
296 | */ | 190 | */ |
297 | void | 191 | void |
298 | GCCH_handle_ack (struct CadetChannel *ch, | 192 | GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, |
299 | const struct GNUNET_CADET_ChannelManageMessage *msg, | 193 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, |
300 | int fwd); | 194 | const struct GNUNET_CADET_ChannelDataAckMessage *ack); |
301 | 195 | ||
302 | 196 | ||
303 | /** | 197 | /** |
304 | * Handler for channel destroy messages. | 198 | * We got an acknowledgement for the creation of the channel |
199 | * (the port is open on the other side). Begin transmissions. | ||
305 | * | 200 | * |
306 | * @param ch Channel this channel is to be destroyed of. | 201 | * @param ch channel to destroy |
307 | * @param msg Message. | 202 | * @param cti identifier of the connection that delivered the message, |
308 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | 203 | * NULL if the ACK was inferred because we got payload or are on loopback |
309 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
310 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
311 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
312 | */ | 204 | */ |
313 | void | 205 | void |
314 | GCCH_handle_destroy (struct CadetChannel *ch, | 206 | GCCH_handle_channel_open_ack (struct CadetChannel *ch, |
315 | const struct GNUNET_CADET_ChannelManageMessage *msg, | 207 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); |
316 | int fwd); | ||
317 | 208 | ||
318 | 209 | ||
319 | /** | 210 | /** |
320 | * Sends an already built message on a channel. | 211 | * Destroy channel, based on the other peer closing the |
212 | * connection. Also needs to remove this channel from | ||
213 | * the tunnel. | ||
321 | * | 214 | * |
322 | * If the channel is on a loopback tunnel, notifies the appropriate destination | 215 | * FIXME: need to make it possible to defer destruction until we have |
323 | * client locally. | 216 | * received all messages up to the destroy, and right now the destroy |
217 | * message (and this API) fails to give is the information we need! | ||
324 | * | 218 | * |
325 | * On a normal channel passes the message to the tunnel for encryption and | 219 | * FIXME: also need to know if the other peer got a destroy from |
326 | * sending on a connection. | 220 | * us before! |
327 | * | 221 | * |
328 | * This function DOES NOT save the message for retransmission. | 222 | * @param ch channel to destroy |
329 | * | 223 | * @param cti identifier of the connection that delivered the message, |
330 | * @param message Message to send. Function makes a copy of it. | 224 | * NULL during shutdown |
331 | * @param ch Channel on which this message is transmitted. | ||
332 | * @param fwd Is this a fwd message? | ||
333 | * @param existing_copy This is a retransmission, don't save a copy. | ||
334 | */ | 225 | */ |
335 | void | 226 | void |
336 | GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | 227 | GCCH_handle_remote_destroy (struct CadetChannel *ch, |
337 | struct CadetChannel *ch, int fwd, | 228 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti); |
338 | void *existing_copy); | ||
339 | 229 | ||
340 | 230 | ||
341 | /** | 231 | /** |
342 | * Get the static string for identification of the channel. | 232 | * Handle data given by a client. |
343 | * | 233 | * |
344 | * @param ch Channel.i | 234 | * Check whether the client is allowed to send in this tunnel, save if |
235 | * channel is reliable and send an ACK to the client if there is still | ||
236 | * buffer space in the tunnel. | ||
345 | * | 237 | * |
346 | * @return Static string with the channel IDs. | 238 | * @param ch Channel. |
239 | * @param sender_ccn ccn of the sender | ||
240 | * @param buf payload to transmit. | ||
241 | * @param buf_len number of bytes in @a buf | ||
242 | * @return #GNUNET_OK if everything goes well, | ||
243 | * #GNUNET_SYSERR in case of an error. | ||
347 | */ | 244 | */ |
348 | const char * | 245 | int |
349 | GCCH_2s (const struct CadetChannel *ch); | 246 | GCCH_handle_local_data (struct CadetChannel *ch, |
350 | 247 | struct GNUNET_CADET_ClientChannelNumber sender_ccn, | |
351 | 248 | const char *buf, | |
249 | size_t buf_len); | ||
352 | 250 | ||
353 | 251 | ||
354 | #if 0 /* keep Emacsens' auto-indent happy */ | 252 | /** |
355 | { | 253 | * Handle ACK from client on local channel. |
356 | #endif | 254 | * |
357 | #ifdef __cplusplus | 255 | * @param ch channel to destroy |
358 | } | 256 | * @param client_ccn ccn of the client sending the ack |
359 | #endif | 257 | */ |
258 | void | ||
259 | GCCH_handle_local_ack (struct CadetChannel *ch, | ||
260 | struct GNUNET_CADET_ClientChannelNumber client_ccn); | ||
360 | 261 | ||
361 | /* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */ | ||
362 | #endif | 262 | #endif |
363 | /* end of gnunet-service-cadet_channel.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c index 2d5087f81..7b66f61a2 100644 --- a/src/cadet/gnunet-service-cadet_connection.c +++ b/src/cadet/gnunet-service-cadet_connection.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2001-2015 GNUnet e.V. | 3 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -17,242 +17,126 @@ | |||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | |||
20 | /** | 21 | /** |
21 | * @file cadet/gnunet-service-cadet_connection.c | 22 | * @file cadet/gnunet-service-cadet_connection.c |
22 | * @brief GNUnet CADET service connection handling | 23 | * @brief management of CORE-level end-to-end connections; establishes |
24 | * end-to-end routes and transmits messages along the route | ||
23 | * @author Bartlomiej Polot | 25 | * @author Bartlomiej Polot |
26 | * @author Christian Grothoff | ||
24 | */ | 27 | */ |
25 | #include "platform.h" | 28 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 29 | #include "gnunet-service-cadet_connection.h" |
30 | #include "gnunet-service-cadet_channel.h" | ||
31 | #include "gnunet-service-cadet_paths.h" | ||
32 | #include "gnunet-service-cadet_tunnels.h" | ||
33 | #include "gnunet_cadet_service.h" | ||
27 | #include "gnunet_statistics_service.h" | 34 | #include "gnunet_statistics_service.h" |
28 | #include "cadet_path.h" | ||
29 | #include "cadet_protocol.h" | 35 | #include "cadet_protocol.h" |
30 | #include "cadet.h" | ||
31 | #include "gnunet-service-cadet_connection.h" | ||
32 | #include "gnunet-service-cadet_peer.h" | ||
33 | #include "gnunet-service-cadet_tunnel.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Should we run somewhat expensive checks on our invariants? | ||
38 | */ | ||
39 | #define CHECK_INVARIANTS 0 | ||
40 | |||
41 | |||
42 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__) | ||
43 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__) | ||
44 | |||
45 | |||
46 | #define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\ | ||
47 | GNUNET_TIME_UNIT_MINUTES,\ | ||
48 | 10) | ||
49 | #define AVG_MSGS 32 | ||
50 | |||
51 | |||
52 | /******************************************************************************/ | ||
53 | /******************************** STRUCTS **********************************/ | ||
54 | /******************************************************************************/ | ||
55 | |||
56 | /** | ||
57 | * Handle for messages queued but not yet sent. | ||
58 | */ | ||
59 | struct CadetConnectionQueue | ||
60 | { | ||
61 | 36 | ||
62 | struct CadetConnectionQueue *next; | ||
63 | struct CadetConnectionQueue *prev; | ||
64 | 37 | ||
65 | /** | 38 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__) |
66 | * Peer queue handle, to cancel if necessary. | ||
67 | */ | ||
68 | struct CadetPeerQueue *peer_q; | ||
69 | |||
70 | /** | ||
71 | * Continuation to call once sent. | ||
72 | */ | ||
73 | GCC_sent cont; | ||
74 | |||
75 | /** | ||
76 | * Closure for @e cont. | ||
77 | */ | ||
78 | void *cont_cls; | ||
79 | |||
80 | /** | ||
81 | * Was this a forced message? (Do not account for it) | ||
82 | */ | ||
83 | int forced; | ||
84 | }; | ||
85 | 39 | ||
86 | 40 | ||
87 | /** | 41 | /** |
88 | * Struct to encapsulate all the Flow Control information to a peer to which | 42 | * All the states a connection can be in. |
89 | * we are directly connected (on a core level). | ||
90 | */ | 43 | */ |
91 | struct CadetFlowControl | 44 | enum CadetConnectionState |
92 | { | 45 | { |
93 | /** | 46 | /** |
94 | * Connection this controls. | 47 | * Uninitialized status, we have not yet even gotten the message queue. |
95 | */ | ||
96 | struct CadetConnection *c; | ||
97 | |||
98 | struct CadetConnectionQueue *q_head; | ||
99 | struct CadetConnectionQueue *q_tail; | ||
100 | |||
101 | /** | ||
102 | * How many messages are in the queue on this connection. | ||
103 | */ | ||
104 | unsigned int queue_n; | ||
105 | |||
106 | /** | ||
107 | * How many messages do we accept in the queue. | ||
108 | * If 0, the connection is broken in this direction (next hop disconnected). | ||
109 | */ | ||
110 | unsigned int queue_max; | ||
111 | |||
112 | /** | ||
113 | * ID of the next packet to send. | ||
114 | */ | ||
115 | struct CadetEncryptedMessageIdentifier next_pid; | ||
116 | |||
117 | /** | ||
118 | * ID of the last packet sent towards the peer. | ||
119 | */ | ||
120 | struct CadetEncryptedMessageIdentifier last_pid_sent; | ||
121 | |||
122 | /** | ||
123 | * ID of the last packet received from the peer. | ||
124 | */ | ||
125 | struct CadetEncryptedMessageIdentifier last_pid_recv; | ||
126 | |||
127 | /** | ||
128 | * Bitmap of past 32 messages received: | ||
129 | * - LSB being @c last_pid_recv. | ||
130 | * - MSB being @c last_pid_recv - 31 (mod UINTMAX). | ||
131 | */ | ||
132 | uint32_t recv_bitmap; | ||
133 | |||
134 | /** | ||
135 | * Last ACK sent to the peer (peer is not allowed to send | ||
136 | * messages with PIDs higher than this value). | ||
137 | */ | 48 | */ |
138 | struct CadetEncryptedMessageIdentifier last_ack_sent; | 49 | CADET_CONNECTION_NEW, |
139 | 50 | ||
140 | /** | 51 | /** |
141 | * Last ACK sent towards the origin (for traffic towards leaf node). | 52 | * Connection create message in queue, awaiting transmission by CORE. |
142 | */ | 53 | */ |
143 | struct CadetEncryptedMessageIdentifier last_ack_recv; | 54 | CADET_CONNECTION_SENDING_CREATE, |
144 | 55 | ||
145 | /** | 56 | /** |
146 | * Task to poll the peer in case of a lost ACK causes stall. | 57 | * Connection create message sent, waiting for ACK. |
147 | */ | 58 | */ |
148 | struct GNUNET_SCHEDULER_Task *poll_task; | 59 | CADET_CONNECTION_SENT, |
149 | 60 | ||
150 | /** | 61 | /** |
151 | * How frequently to poll for ACKs. | 62 | * We are an inbound connection, and received a CREATE. Need to |
63 | * send an CREATE_ACK back. | ||
152 | */ | 64 | */ |
153 | struct GNUNET_TIME_Relative poll_time; | 65 | CADET_CONNECTION_CREATE_RECEIVED, |
154 | 66 | ||
155 | /** | 67 | /** |
156 | * Queued poll message, to cancel if not necessary anymore (got ACK). | 68 | * Connection confirmed, ready to carry traffic. |
157 | */ | 69 | */ |
158 | struct CadetConnectionQueue *poll_msg; | 70 | CADET_CONNECTION_READY |
159 | 71 | ||
160 | /** | ||
161 | * Queued poll message, to cancel if not necessary anymore (got ACK). | ||
162 | */ | ||
163 | struct CadetConnectionQueue *ack_msg; | ||
164 | }; | 72 | }; |
165 | 73 | ||
74 | |||
166 | /** | 75 | /** |
167 | * Keep a record of the last messages sent on this connection. | 76 | * Low-level connection to a destination. |
168 | */ | 77 | */ |
169 | struct CadetConnectionPerformance | 78 | struct CadetConnection |
170 | { | 79 | { |
171 | /** | ||
172 | * Circular buffer for storing measurements. | ||
173 | */ | ||
174 | double usecsperbyte[AVG_MSGS]; | ||
175 | 80 | ||
176 | /** | 81 | /** |
177 | * Running average of @c usecsperbyte. | 82 | * ID of the connection. |
178 | */ | ||
179 | double avg; | ||
180 | |||
181 | /** | ||
182 | * How many values of @c usecsperbyte are valid. | ||
183 | */ | ||
184 | uint16_t size; | ||
185 | |||
186 | /** | ||
187 | * Index of the next "free" position in @c usecsperbyte. | ||
188 | */ | 83 | */ |
189 | uint16_t idx; | 84 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; |
190 | }; | ||
191 | |||
192 | 85 | ||
193 | /** | ||
194 | * Struct containing all information regarding a connection to a peer. | ||
195 | */ | ||
196 | struct CadetConnection | ||
197 | { | ||
198 | /** | 86 | /** |
199 | * Tunnel this connection is part of. | 87 | * To which peer does this connection go? |
200 | */ | 88 | */ |
201 | struct CadetTunnel *t; | 89 | struct CadetPeer *destination; |
202 | 90 | ||
203 | /** | 91 | /** |
204 | * Flow control information for traffic fwd. | 92 | * Which tunnel is using this connection? |
205 | */ | 93 | */ |
206 | struct CadetFlowControl fwd_fc; | 94 | struct CadetTConnection *ct; |
207 | 95 | ||
208 | /** | 96 | /** |
209 | * Flow control information for traffic bck. | 97 | * Path we are using to our destination. |
210 | */ | 98 | */ |
211 | struct CadetFlowControl bck_fc; | 99 | struct CadetPeerPath *path; |
212 | 100 | ||
213 | /** | 101 | /** |
214 | * Measure connection performance on the endpoint. | 102 | * Pending message, NULL if we are ready to transmit. |
215 | */ | 103 | */ |
216 | struct CadetConnectionPerformance *perf; | 104 | struct GNUNET_MQ_Envelope *env; |
217 | 105 | ||
218 | /** | 106 | /** |
219 | * ID of the connection. | 107 | * Handle for calling #GCP_request_mq_cancel() once we are finished. |
220 | */ | 108 | */ |
221 | struct GNUNET_CADET_ConnectionTunnelIdentifier id; | 109 | struct GCP_MessageQueueManager *mq_man; |
222 | 110 | ||
223 | /** | 111 | /** |
224 | * Path being used for the tunnel. At the origin of the connection | 112 | * Task for connection maintenance. |
225 | * it's a pointer to the destination's path pool, otherwise just a copy. | ||
226 | */ | 113 | */ |
227 | struct CadetPeerPath *path; | 114 | struct GNUNET_SCHEDULER_Task *task; |
228 | 115 | ||
229 | /** | 116 | /** |
230 | * Task to keep the used paths alive at the owner, | 117 | * Queue entry for keepalive messages. |
231 | * time tunnel out on all the other peers. | ||
232 | */ | 118 | */ |
233 | struct GNUNET_SCHEDULER_Task *fwd_maintenance_task; | 119 | struct CadetTunnelQueueEntry *keepalive_qe; |
234 | 120 | ||
235 | /** | 121 | /** |
236 | * Task to keep the used paths alive at the destination, | 122 | * Function to call once we are ready to transmit. |
237 | * time tunnel out on all the other peers. | ||
238 | */ | 123 | */ |
239 | struct GNUNET_SCHEDULER_Task *bck_maintenance_task; | 124 | GCC_ReadyCallback ready_cb; |
240 | 125 | ||
241 | /** | 126 | /** |
242 | * Queue handle for maintainance traffic. One handle for FWD and BCK since | 127 | * Closure for @e ready_cb. |
243 | * one peer never needs to maintain both directions (no loopback connections). | ||
244 | */ | 128 | */ |
245 | struct CadetPeerQueue *maintenance_q; | 129 | void *ready_cb_cls; |
246 | 130 | ||
247 | /** | 131 | /** |
248 | * Should equal #get_next_hop(), or NULL if that peer disconnected. | 132 | * How long do we wait before we try again with a CREATE message? |
249 | */ | 133 | */ |
250 | struct CadetPeer *next_peer; | 134 | struct GNUNET_TIME_Relative retry_delay; |
251 | 135 | ||
252 | /** | 136 | /** |
253 | * Should equal #get_prev_hop(), or NULL if that peer disconnected. | 137 | * Performance metrics for this connection. |
254 | */ | 138 | */ |
255 | struct CadetPeer *prev_peer; | 139 | struct CadetConnectionMetrics metrics; |
256 | 140 | ||
257 | /** | 141 | /** |
258 | * State of the connection. | 142 | * State of the connection. |
@@ -260,221 +144,36 @@ struct CadetConnection | |||
260 | enum CadetConnectionState state; | 144 | enum CadetConnectionState state; |
261 | 145 | ||
262 | /** | 146 | /** |
263 | * Position of the local peer in the path. | 147 | * Options for the route, control buffering. |
264 | */ | 148 | */ |
265 | unsigned int own_pos; | 149 | enum GNUNET_CADET_ChannelOption options; |
266 | 150 | ||
267 | /** | 151 | /** |
268 | * Pending message count. | 152 | * How many latency observations did we make for this connection? |
269 | */ | 153 | */ |
270 | unsigned int pending_messages; | 154 | unsigned int latency_datapoints; |
271 | 155 | ||
272 | /** | 156 | /** |
273 | * Destroy flag: | 157 | * Offset of our @e destination in @e path. |
274 | * - if 0, connection in use. | ||
275 | * - if 1, destroy on last message. | ||
276 | * - if 2, connection is being destroyed don't re-enter. | ||
277 | */ | 158 | */ |
278 | int destroy; | 159 | unsigned int off; |
279 | 160 | ||
280 | /** | 161 | /** |
281 | * In-connection-map flag. Sometimes, when @e destroy is set but | 162 | * Are we ready to transmit via @e mq_man right now? |
282 | * actual destruction is delayed to enable us to finish processing | ||
283 | * queues (i.e. in the direction that is still working), we remove | ||
284 | * the connection from the map to prevent it from still being | ||
285 | * found (and used) by accident. This flag is set to #GNUNET_YES | ||
286 | * for a connection that is not in the #connections map. Should | ||
287 | * only be #GNUNET_YES if #destroy is also non-zero. | ||
288 | */ | 163 | */ |
289 | int was_removed; | 164 | int mqm_ready; |
290 | 165 | ||
291 | /** | ||
292 | * Counter to do exponential backoff when creating a connection (max 64). | ||
293 | */ | ||
294 | unsigned short create_retry; | ||
295 | |||
296 | /** | ||
297 | * Task to check if connection has duplicates. | ||
298 | */ | ||
299 | struct GNUNET_SCHEDULER_Task *check_duplicates_task; | ||
300 | }; | 166 | }; |
301 | 167 | ||
302 | 168 | ||
303 | /******************************************************************************/ | ||
304 | /******************************* GLOBALS ***********************************/ | ||
305 | /******************************************************************************/ | ||
306 | |||
307 | /** | ||
308 | * Global handle to the statistics service. | ||
309 | */ | ||
310 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
311 | |||
312 | /** | ||
313 | * Local peer own ID (memory efficient handle). | ||
314 | */ | ||
315 | extern GNUNET_PEER_Id myid; | ||
316 | |||
317 | /** | ||
318 | * Local peer own ID (full value). | ||
319 | */ | ||
320 | extern struct GNUNET_PeerIdentity my_full_id; | ||
321 | |||
322 | /** | ||
323 | * Connections known, indexed by cid (CadetConnection). | ||
324 | */ | ||
325 | static struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
326 | |||
327 | /** | ||
328 | * How many connections are we willing to maintain. | ||
329 | * Local connections are always allowed, | ||
330 | * even if there are more connections than max. | ||
331 | */ | ||
332 | static unsigned long long max_connections; | ||
333 | |||
334 | /** | ||
335 | * How many messages *in total* are we willing to queue, divide by number of | ||
336 | * connections to get connection queue size. | ||
337 | */ | ||
338 | static unsigned long long max_msgs_queue; | ||
339 | |||
340 | /** | ||
341 | * How often to send path keepalives. Paths timeout after 4 missed. | ||
342 | */ | ||
343 | static struct GNUNET_TIME_Relative refresh_connection_time; | ||
344 | |||
345 | /** | ||
346 | * How often to send path create / ACKs. | ||
347 | */ | ||
348 | static struct GNUNET_TIME_Relative create_connection_time; | ||
349 | |||
350 | |||
351 | /******************************************************************************/ | ||
352 | /******************************** STATIC ***********************************/ | ||
353 | /******************************************************************************/ | ||
354 | |||
355 | |||
356 | |||
357 | #if 0 // avoid compiler warning for unused static function | ||
358 | static void | ||
359 | fc_debug (struct CadetFlowControl *fc) | ||
360 | { | ||
361 | LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n", | ||
362 | ntohl (fc->last_pid_recv.pid), | ||
363 | ntohl (fc->last_ack_sent.pid)); | ||
364 | LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n", | ||
365 | fc->last_pid_sent, fc->last_ack_recv); | ||
366 | LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n", | ||
367 | fc->queue_n, fc->queue_max); | ||
368 | } | ||
369 | |||
370 | static void | ||
371 | connection_debug (struct CadetConnection *c) | ||
372 | { | ||
373 | if (NULL == c) | ||
374 | { | ||
375 | LOG (GNUNET_ERROR_TYPE_INFO, "DEBUG NULL CONNECTION\n"); | ||
376 | return; | ||
377 | } | ||
378 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n", | ||
379 | peer2s (c->t->peer), GCC_2s (c)); | ||
380 | LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n", | ||
381 | c->state, c->pending_messages); | ||
382 | LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); | ||
383 | fc_debug (&c->fwd_fc); | ||
384 | LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); | ||
385 | fc_debug (&c->bck_fc); | ||
386 | } | ||
387 | #endif | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Schedule next keepalive task, taking in consideration | ||
392 | * the connection state and number of retries. | ||
393 | * | ||
394 | * @param c Connection for which to schedule the next keepalive. | ||
395 | * @param fwd Direction for the next keepalive. | ||
396 | */ | ||
397 | static void | ||
398 | schedule_next_keepalive (struct CadetConnection *c, int fwd); | ||
399 | |||
400 | |||
401 | /** | ||
402 | * Resets the connection timeout task, some other message has done the | ||
403 | * task's job. | ||
404 | * - For the first peer on the direction this means to send | ||
405 | * a keepalive or a path confirmation message (either create or ACK). | ||
406 | * - For all other peers, this means to destroy the connection, | ||
407 | * due to lack of activity. | ||
408 | * Starts the timeout if no timeout was running (connection just created). | ||
409 | * | ||
410 | * @param c Connection whose timeout to reset. | ||
411 | * @param fwd Is this forward? | ||
412 | */ | ||
413 | static void | ||
414 | connection_reset_timeout (struct CadetConnection *c, int fwd); | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Get string description for tunnel state. Reentrant. | ||
419 | * | ||
420 | * @param s Tunnel state. | ||
421 | * | ||
422 | * @return String representation. | ||
423 | */ | ||
424 | static const char * | ||
425 | GCC_state2s (enum CadetConnectionState s) | ||
426 | { | ||
427 | switch (s) | ||
428 | { | ||
429 | case CADET_CONNECTION_NEW: | ||
430 | return "CADET_CONNECTION_NEW"; | ||
431 | case CADET_CONNECTION_SENT: | ||
432 | return "CADET_CONNECTION_SENT"; | ||
433 | case CADET_CONNECTION_ACK: | ||
434 | return "CADET_CONNECTION_ACK"; | ||
435 | case CADET_CONNECTION_READY: | ||
436 | return "CADET_CONNECTION_READY"; | ||
437 | case CADET_CONNECTION_DESTROYED: | ||
438 | return "CADET_CONNECTION_DESTROYED"; | ||
439 | case CADET_CONNECTION_BROKEN: | ||
440 | return "CADET_CONNECTION_BROKEN"; | ||
441 | default: | ||
442 | GNUNET_break (0); | ||
443 | LOG (GNUNET_ERROR_TYPE_ERROR, " conn state %u unknown!\n", s); | ||
444 | return "CADET_CONNECTION_STATE_ERROR"; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | /** | 169 | /** |
450 | * Initialize a Flow Control structure to the initial state. | 170 | * Lookup a connection by its identifier. |
451 | * | 171 | * |
452 | * @param fc Flow Control structure to initialize. | 172 | * @param cid identifier to resolve |
173 | * @return NULL if connection was not found | ||
453 | */ | 174 | */ |
454 | static void | 175 | struct CadetConnection * |
455 | fc_init (struct CadetFlowControl *fc) | 176 | GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) |
456 | { | ||
457 | fc->next_pid.pid = 0; | ||
458 | fc->last_pid_sent.pid = htonl (UINT32_MAX); | ||
459 | fc->last_pid_recv.pid = htonl (UINT32_MAX); | ||
460 | fc->last_ack_sent.pid = (uint32_t) 0; | ||
461 | fc->last_ack_recv.pid = (uint32_t) 0; | ||
462 | fc->poll_task = NULL; | ||
463 | fc->poll_time = GNUNET_TIME_UNIT_SECONDS; | ||
464 | fc->queue_n = 0; | ||
465 | fc->queue_max = (max_msgs_queue / max_connections) + 1; | ||
466 | } | ||
467 | |||
468 | |||
469 | /** | ||
470 | * Find a connection. | ||
471 | * | ||
472 | * @param cid Connection ID. | ||
473 | * | ||
474 | * @return conntection with the given ID @cid or NULL if not found. | ||
475 | */ | ||
476 | static struct CadetConnection * | ||
477 | connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
478 | { | 177 | { |
479 | return GNUNET_CONTAINER_multishortmap_get (connections, | 178 | return GNUNET_CONTAINER_multishortmap_get (connections, |
480 | &cid->connection_of_tunnel); | 179 | &cid->connection_of_tunnel); |
@@ -482,3232 +181,911 @@ connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | |||
482 | 181 | ||
483 | 182 | ||
484 | /** | 183 | /** |
485 | * Change the connection state. Cannot change a connection marked as destroyed. | 184 | * Update the connection state. Also triggers the necessary |
185 | * MQM notifications. | ||
486 | * | 186 | * |
487 | * @param c Connection to change. | 187 | * @param cc connection to update the state for |
488 | * @param state New state to set. | 188 | * @param new_state new state for @a cc |
189 | * @param new_mqm_ready new `mqm_ready` state for @a cc | ||
489 | */ | 190 | */ |
490 | static void | 191 | static void |
491 | connection_change_state (struct CadetConnection* c, | 192 | update_state (struct CadetConnection *cc, |
492 | enum CadetConnectionState state) | 193 | enum CadetConnectionState new_state, |
194 | int new_mqm_ready) | ||
493 | { | 195 | { |
494 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 196 | int old_ready; |
495 | "Connection %s state %s -> %s\n", | 197 | int new_ready; |
496 | GCC_2s (c), GCC_state2s (c->state), GCC_state2s (state)); | ||
497 | if (CADET_CONNECTION_DESTROYED <= c->state) /* Destroyed or broken. */ | ||
498 | { | ||
499 | LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n"); | ||
500 | return; | ||
501 | } | ||
502 | c->state = state; | ||
503 | if (CADET_CONNECTION_READY == state) | ||
504 | c->create_retry = 1; | ||
505 | } | ||
506 | |||
507 | 198 | ||
508 | /** | 199 | if ( (new_state == cc->state) && |
509 | * Mark a connection as "destroyed", to send all pending traffic and freeing | 200 | (new_mqm_ready == cc->mqm_ready) ) |
510 | * all associated resources, without accepting new status changes on it. | 201 | return; /* no change, nothing to do */ |
511 | * | 202 | old_ready = ( (CADET_CONNECTION_READY == cc->state) && |
512 | * @param c Connection to mark as destroyed. | 203 | (GNUNET_YES == cc->mqm_ready) ); |
513 | */ | 204 | new_ready = ( (CADET_CONNECTION_READY == new_state) && |
514 | static void | 205 | (GNUNET_YES == new_mqm_ready) ); |
515 | mark_destroyed (struct CadetConnection *c) | 206 | cc->state = new_state; |
516 | { | 207 | cc->mqm_ready = new_mqm_ready; |
517 | c->destroy = GNUNET_YES; | 208 | if (old_ready != new_ready) |
518 | connection_change_state (c, CADET_CONNECTION_DESTROYED); | 209 | cc->ready_cb (cc->ready_cb_cls, |
210 | new_ready); | ||
519 | } | 211 | } |
520 | 212 | ||
521 | 213 | ||
522 | /** | 214 | /** |
523 | * Function called if a connection has been stalled for a while, | 215 | * Destroy a connection, part of the internal implementation. Called |
524 | * possibly due to a missed ACK. Poll the neighbor about its ACK status. | 216 | * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel(). |
525 | * | ||
526 | * @param cls Closure (poll ctx). | ||
527 | */ | ||
528 | static void | ||
529 | send_poll (void *cls); | ||
530 | |||
531 | |||
532 | /** | ||
533 | * Send an ACK on the connection, informing the predecessor about | ||
534 | * the available buffer space. Should not be called in case the peer | ||
535 | * is origin (no predecessor) in the @c fwd direction. | ||
536 | * | ||
537 | * Note that for fwd ack, the FWD mean forward *traffic* (root->dest), | ||
538 | * the ACK itself goes "back" (dest->root). | ||
539 | * | 217 | * |
540 | * @param c Connection on which to send the ACK. | 218 | * @param cc connection to destroy |
541 | * @param buffer How much space free to advertise? | ||
542 | * @param fwd Is this FWD ACK? (Going dest -> root) | ||
543 | * @param force Don't optimize out. | ||
544 | */ | 219 | */ |
545 | static void | 220 | static void |
546 | send_ack (struct CadetConnection *c, | 221 | GCC_destroy (struct CadetConnection *cc) |
547 | unsigned int buffer, | ||
548 | int fwd, | ||
549 | int force) | ||
550 | { | 222 | { |
551 | static struct CadetEncryptedMessageIdentifier zero; | ||
552 | struct CadetFlowControl *next_fc; | ||
553 | struct CadetFlowControl *prev_fc; | ||
554 | struct GNUNET_CADET_ConnectionEncryptedAckMessage msg; | ||
555 | struct CadetEncryptedMessageIdentifier ack_cemi; | ||
556 | int delta; | ||
557 | |||
558 | GCC_check_connections (); | ||
559 | GNUNET_assert (GNUNET_NO == GCC_is_origin (c, fwd)); | ||
560 | |||
561 | next_fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
562 | prev_fc = fwd ? &c->bck_fc : &c->fwd_fc; | ||
563 | |||
564 | LOG (GNUNET_ERROR_TYPE_DEBUG, "send %s ack on %s\n", | ||
565 | GC_f2s (fwd), GCC_2s (c)); | ||
566 | |||
567 | /* Check if we need to transmit the ACK. */ | ||
568 | delta = ntohl (prev_fc->last_ack_sent.pid) - ntohl (prev_fc->last_pid_recv.pid); | ||
569 | if (3 < delta && buffer < delta && GNUNET_NO == force) | ||
570 | { | ||
571 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, delta > 3\n"); | ||
572 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
573 | " last pid recv: %u, last ack sent: %u\n", | ||
574 | ntohl (prev_fc->last_pid_recv.pid), | ||
575 | ntohl (prev_fc->last_ack_sent.pid)); | ||
576 | GCC_check_connections (); | ||
577 | return; | ||
578 | } | ||
579 | |||
580 | /* Ok, ACK might be necessary, what PID to ACK? */ | ||
581 | ack_cemi.pid = htonl (ntohl (prev_fc->last_pid_recv.pid) + buffer); | ||
582 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 223 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
583 | " ACK %u, last PID %u, last ACK %u, qmax %u, q %u\n", | 224 | "Destroying %s\n", |
584 | ntohl (ack_cemi.pid), | 225 | GCC_2s (cc)); |
585 | ntohl (prev_fc->last_pid_recv.pid), | 226 | if (NULL != cc->mq_man) |
586 | ntohl (prev_fc->last_ack_sent.pid), | ||
587 | next_fc->queue_max, next_fc->queue_n); | ||
588 | if ( (ack_cemi.pid == prev_fc->last_ack_sent.pid) && | ||
589 | (GNUNET_NO == force) ) | ||
590 | { | ||
591 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n"); | ||
592 | GCC_check_connections (); | ||
593 | return; | ||
594 | } | ||
595 | |||
596 | /* Check if message is already in queue */ | ||
597 | if (NULL != prev_fc->ack_msg) | ||
598 | { | ||
599 | if (GC_is_pid_bigger (ntohl (ack_cemi.pid), | ||
600 | ntohl (prev_fc->last_ack_sent.pid))) | ||
601 | { | ||
602 | LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n"); | ||
603 | GCC_cancel (prev_fc->ack_msg); | ||
604 | /* GCC_cancel triggers ack_sent(), which clears fc->ack_msg */ | ||
605 | } | ||
606 | else | ||
607 | { | ||
608 | LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n"); | ||
609 | GCC_check_connections (); | ||
610 | return; | ||
611 | } | ||
612 | } | ||
613 | GNUNET_break (GC_is_pid_bigger (ntohl (ack_cemi.pid), | ||
614 | ntohl (prev_fc->last_ack_sent.pid))); | ||
615 | prev_fc->last_ack_sent = ack_cemi; | ||
616 | |||
617 | /* Build ACK message and send on conn */ | ||
618 | msg.header.size = htons (sizeof (msg)); | ||
619 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK); | ||
620 | msg.cemi_max = ack_cemi; | ||
621 | msg.cid = c->id; | ||
622 | |||
623 | prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header, | ||
624 | UINT16_MAX, | ||
625 | zero, | ||
626 | c, | ||
627 | !fwd, | ||
628 | GNUNET_YES, | ||
629 | NULL, NULL); | ||
630 | GNUNET_assert (NULL != prev_fc->ack_msg); | ||
631 | GCC_check_connections (); | ||
632 | } | ||
633 | |||
634 | |||
635 | /** | ||
636 | * Update performance information if we are a connection's endpoint. | ||
637 | * | ||
638 | * @param c Connection to update. | ||
639 | * @param wait How much time did we wait to send the last message. | ||
640 | * @param size Size of the last message. | ||
641 | */ | ||
642 | static void | ||
643 | update_perf (struct CadetConnection *c, | ||
644 | struct GNUNET_TIME_Relative wait, | ||
645 | uint16_t size) | ||
646 | { | ||
647 | struct CadetConnectionPerformance *p; | ||
648 | double usecsperbyte; | ||
649 | |||
650 | if (NULL == c->perf) | ||
651 | return; /* Only endpoints are interested in timing. */ | ||
652 | |||
653 | p = c->perf; | ||
654 | usecsperbyte = ((double) wait.rel_value_us) / size; | ||
655 | if (p->size == AVG_MSGS) | ||
656 | { | ||
657 | /* Array is full. Substract oldest value, add new one and store. */ | ||
658 | p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS); | ||
659 | p->usecsperbyte[p->idx] = usecsperbyte; | ||
660 | p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS); | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | /* Array not yet full. Add current value to avg and store. */ | ||
665 | p->usecsperbyte[p->idx] = usecsperbyte; | ||
666 | p->avg *= p->size; | ||
667 | p->avg += p->usecsperbyte[p->idx]; | ||
668 | p->size++; | ||
669 | p->avg /= p->size; | ||
670 | } | ||
671 | p->idx = (p->idx + 1) % AVG_MSGS; | ||
672 | } | ||
673 | |||
674 | |||
675 | /** | ||
676 | * Callback called when a connection queued message is sent. | ||
677 | * | ||
678 | * Calculates the average time and connection packet tracking. | ||
679 | * | ||
680 | * @param cls Closure (ConnectionQueue Handle), can be NULL. | ||
681 | * @param c Connection this message was on. | ||
682 | * @param fwd Was this a FWD going message? | ||
683 | * @param sent Was it really sent? (Could have been canceled) | ||
684 | * @param type Type of message sent. | ||
685 | * @param payload_type Type of payload, if applicable. | ||
686 | * @param pid Message ID, or 0 if not applicable (create, destroy, etc). | ||
687 | * @param size Size of the message. | ||
688 | * @param wait Time spent waiting for core (only the time for THIS message) | ||
689 | */ | ||
690 | static void | ||
691 | conn_message_sent (void *cls, | ||
692 | struct CadetConnection *c, | ||
693 | int fwd, | ||
694 | int sent, | ||
695 | uint16_t type, | ||
696 | uint16_t payload_type, | ||
697 | struct CadetEncryptedMessageIdentifier pid, | ||
698 | size_t size, | ||
699 | struct GNUNET_TIME_Relative wait) | ||
700 | { | ||
701 | struct CadetConnectionQueue *q = cls; | ||
702 | struct CadetFlowControl *fc; | ||
703 | int forced; | ||
704 | |||
705 | GCC_check_connections (); | ||
706 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
707 | ">>> %s (%s %4u) on conn %s (%p) %s [%5u] in queue %s\n", | ||
708 | GC_m2s (type), GC_m2s (payload_type), | ||
709 | ntohl (pid.pid), | ||
710 | GCC_2s (c), | ||
711 | c, | ||
712 | GC_f2s (fwd), size, | ||
713 | GNUNET_STRINGS_relative_time_to_string (wait, GNUNET_YES)); | ||
714 | |||
715 | /* If c is NULL, nothing to update. */ | ||
716 | if (NULL == c) | ||
717 | { | ||
718 | if (type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN | ||
719 | && type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY) | ||
720 | { | ||
721 | LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n", | ||
722 | GC_m2s (type)); | ||
723 | } | ||
724 | GCC_check_connections (); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s pid %u\n", | ||
729 | sent ? "" : "not ", GC_f2s (fwd), | ||
730 | GC_m2s (type), GC_m2s (payload_type), | ||
731 | ntohl (pid.pid)); | ||
732 | GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); | ||
733 | |||
734 | /* Update flow control info. */ | ||
735 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
736 | |||
737 | if (NULL != q) | ||
738 | { | 227 | { |
739 | GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q); | 228 | GCP_request_mq_cancel (cc->mq_man, |
740 | forced = q->forced; | 229 | NULL); |
741 | if (NULL != q->cont) | 230 | cc->mq_man = NULL; |
742 | { | ||
743 | LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n"); | ||
744 | q->cont (q->cont_cls, c, q, type, fwd, size); | ||
745 | } | ||
746 | GNUNET_free (q); | ||
747 | } | 231 | } |
748 | else /* CONN_CREATE or CONN_ACK */ | 232 | if (NULL != cc->task) |
749 | { | 233 | { |
750 | GNUNET_assert (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED != type); | 234 | GNUNET_SCHEDULER_cancel (cc->task); |
751 | forced = GNUNET_YES; | 235 | cc->task = NULL; |
752 | } | 236 | } |
753 | 237 | if (NULL != cc->keepalive_qe) | |
754 | LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages); | ||
755 | c->pending_messages--; | ||
756 | if ( (GNUNET_YES == c->destroy) && | ||
757 | (0 == c->pending_messages) ) | ||
758 | { | 238 | { |
759 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 239 | GCT_send_cancel (cc->keepalive_qe); |
760 | "! destroying connection!\n"); | 240 | cc->keepalive_qe = NULL; |
761 | GCC_destroy (c); | ||
762 | GCC_check_connections (); | ||
763 | return; | ||
764 | } | 241 | } |
765 | 242 | GCPP_del_connection (cc->path, | |
766 | /* Send ACK if needed, after accounting for sent ID in fc->queue_n */ | 243 | cc->off, |
767 | switch (type) | 244 | cc); |
768 | { | 245 | for (unsigned int i=0;i<cc->off;i++) |
769 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: | 246 | GCP_remove_connection (GCPP_get_peer_at_offset (cc->path, |
770 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK: | 247 | i), |
771 | c->maintenance_q = NULL; | 248 | cc); |
772 | /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */ | 249 | GNUNET_assert (GNUNET_YES == |
773 | if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd) | 250 | GNUNET_CONTAINER_multishortmap_remove (connections, |
774 | schedule_next_keepalive (c, fwd); | 251 | &GCC_get_id (cc)->connection_of_tunnel, |
775 | break; | 252 | cc)); |
776 | 253 | GNUNET_free (cc); | |
777 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED: | ||
778 | if (GNUNET_YES == sent) | ||
779 | { | ||
780 | fc->last_pid_sent = pid; | ||
781 | if (GC_is_pid_bigger (ntohl (fc->last_pid_sent.pid) + 1, | ||
782 | ntohl (fc->last_ack_recv.pid)) ) | ||
783 | GCC_start_poll (c, fwd); | ||
784 | GCC_send_ack (c, fwd, GNUNET_NO); | ||
785 | connection_reset_timeout (c, fwd); | ||
786 | } | ||
787 | |||
788 | LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n); | ||
789 | if (GNUNET_NO == forced) | ||
790 | { | ||
791 | fc->queue_n--; | ||
792 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
793 | "! accounting pid %u\n", | ||
794 | ntohl (fc->last_pid_sent.pid)); | ||
795 | } | ||
796 | else | ||
797 | { | ||
798 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
799 | "! forced, Q_N not accounting pid %u\n", | ||
800 | ntohl (fc->last_pid_sent.pid)); | ||
801 | } | ||
802 | break; | ||
803 | |||
804 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX: | ||
805 | if (GNUNET_YES == sent) | ||
806 | connection_reset_timeout (c, fwd); | ||
807 | break; | ||
808 | |||
809 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL: | ||
810 | fc->poll_msg = NULL; | ||
811 | if (2 == c->destroy) | ||
812 | { | ||
813 | LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL canceled on shutdown\n"); | ||
814 | return; | ||
815 | } | ||
816 | if (0 == fc->queue_max) | ||
817 | { | ||
818 | LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL cancelled: neighbor disconnected\n"); | ||
819 | return; | ||
820 | } | ||
821 | LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL sent for %s, scheduling new one!\n", | ||
822 | GCC_2s (c)); | ||
823 | GNUNET_assert (NULL == fc->poll_task); | ||
824 | fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time); | ||
825 | fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, | ||
826 | &send_poll, fc); | ||
827 | LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task); | ||
828 | break; | ||
829 | |||
830 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK: | ||
831 | fc->ack_msg = NULL; | ||
832 | break; | ||
833 | |||
834 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: | ||
835 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: | ||
836 | break; | ||
837 | |||
838 | default: | ||
839 | LOG (GNUNET_ERROR_TYPE_ERROR, "%s unknown\n", GC_m2s (type)); | ||
840 | GNUNET_break (0); | ||
841 | break; | ||
842 | } | ||
843 | LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n"); | ||
844 | |||
845 | update_perf (c, wait, size); | ||
846 | GCC_check_connections (); | ||
847 | } | ||
848 | |||
849 | |||
850 | /** | ||
851 | * Get the previous hop in a connection | ||
852 | * | ||
853 | * @param c Connection. | ||
854 | * | ||
855 | * @return Previous peer in the connection. | ||
856 | */ | ||
857 | static struct CadetPeer * | ||
858 | get_prev_hop (const struct CadetConnection *c) | ||
859 | { | ||
860 | GNUNET_PEER_Id id; | ||
861 | |||
862 | if (NULL == c->path) | ||
863 | return NULL; | ||
864 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | " get prev hop %s [%u/%u]\n", | ||
866 | GCC_2s (c), c->own_pos, c->path->length); | ||
867 | if (0 == c->own_pos || c->path->length < 2) | ||
868 | id = c->path->peers[0]; | ||
869 | else | ||
870 | id = c->path->peers[c->own_pos - 1]; | ||
871 | |||
872 | LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", | ||
873 | GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); | ||
874 | |||
875 | return GCP_get_short (id, GNUNET_YES); | ||
876 | } | ||
877 | |||
878 | |||
879 | /** | ||
880 | * Get the next hop in a connection | ||
881 | * | ||
882 | * @param c Connection. | ||
883 | * | ||
884 | * @return Next peer in the connection. | ||
885 | */ | ||
886 | static struct CadetPeer * | ||
887 | get_next_hop (const struct CadetConnection *c) | ||
888 | { | ||
889 | GNUNET_PEER_Id id; | ||
890 | |||
891 | if (NULL == c->path) | ||
892 | return NULL; | ||
893 | |||
894 | LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n", | ||
895 | GCC_2s (c), c->own_pos, c->path->length); | ||
896 | if ((c->path->length - 1) == c->own_pos || c->path->length < 2) | ||
897 | id = c->path->peers[c->path->length - 1]; | ||
898 | else | ||
899 | id = c->path->peers[c->own_pos + 1]; | ||
900 | |||
901 | LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", | ||
902 | GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); | ||
903 | |||
904 | return GCP_get_short (id, GNUNET_YES); | ||
905 | } | 254 | } |
906 | 255 | ||
907 | 256 | ||
908 | /** | ||
909 | * Check that the direct neighbours (previous and next hop) | ||
910 | * are properly associated with this connection. | ||
911 | * | ||
912 | * @param c connection to check | ||
913 | */ | ||
914 | static void | ||
915 | check_neighbours (const struct CadetConnection *c) | ||
916 | { | ||
917 | if (NULL == c->path) | ||
918 | return; /* nothing to check */ | ||
919 | GCP_check_connection (get_next_hop (c), c); | ||
920 | GCP_check_connection (get_prev_hop (c), c); | ||
921 | } | ||
922 | |||
923 | 257 | ||
924 | /** | 258 | /** |
925 | * Helper for #GCC_check_connections(). Calls #check_neighbours(). | 259 | * Destroy a connection, called when the CORE layer is already done |
260 | * (i.e. has received a BROKEN message), but if we still have to | ||
261 | * communicate the destruction of the connection to the tunnel (if one | ||
262 | * exists). | ||
926 | * | 263 | * |
927 | * @param cls NULL | 264 | * @param cc connection to destroy |
928 | * @param key ignored | ||
929 | * @param value the `struct CadetConnection` to check | ||
930 | * @return #GNUNET_OK (continue to iterate) | ||
931 | */ | ||
932 | static int | ||
933 | check_connection (void *cls, | ||
934 | const struct GNUNET_ShortHashCode *key, | ||
935 | void *value) | ||
936 | { | ||
937 | struct CadetConnection *c = value; | ||
938 | |||
939 | check_neighbours (c); | ||
940 | return GNUNET_OK; | ||
941 | } | ||
942 | |||
943 | |||
944 | /** | ||
945 | * Check invariants for all connections using #check_neighbours(). | ||
946 | */ | 265 | */ |
947 | void | 266 | void |
948 | GCC_check_connections () | 267 | GCC_destroy_without_core (struct CadetConnection *cc) |
949 | { | ||
950 | if (0 == CHECK_INVARIANTS) | ||
951 | return; | ||
952 | if (NULL == connections) | ||
953 | return; | ||
954 | GNUNET_CONTAINER_multishortmap_iterate (connections, | ||
955 | &check_connection, | ||
956 | NULL); | ||
957 | } | ||
958 | |||
959 | |||
960 | /** | ||
961 | * Get the hop in a connection. | ||
962 | * | ||
963 | * @param c Connection. | ||
964 | * @param fwd Next in the FWD direction? | ||
965 | * | ||
966 | * @return Next peer in the connection. | ||
967 | */ | ||
968 | static struct CadetPeer * | ||
969 | get_hop (struct CadetConnection *c, int fwd) | ||
970 | { | ||
971 | return (fwd) ? get_next_hop (c) : get_prev_hop (c); | ||
972 | } | ||
973 | |||
974 | |||
975 | /** | ||
976 | * Get a bit mask for a message received out-of-order. | ||
977 | * | ||
978 | * @param last_pid_recv Last PID we received prior to the out-of-order. | ||
979 | * @param ooo_pid PID of the out-of-order message. | ||
980 | */ | ||
981 | static uint32_t | ||
982 | get_recv_bitmask (struct CadetEncryptedMessageIdentifier last_pid_recv, | ||
983 | struct CadetEncryptedMessageIdentifier ooo_pid) | ||
984 | { | ||
985 | // FIXME: should assert that the delta is in range... | ||
986 | return 1 << (ntohl (last_pid_recv.pid) - ntohl (ooo_pid.pid)); | ||
987 | } | ||
988 | |||
989 | |||
990 | /** | ||
991 | * Check is an out-of-order message is ok: | ||
992 | * - at most 31 messages behind. | ||
993 | * - not duplicate. | ||
994 | * | ||
995 | * @param last_pid_recv Last in-order PID received. | ||
996 | */ | ||
997 | static int | ||
998 | is_ooo_ok (struct CadetEncryptedMessageIdentifier last_pid_recv, | ||
999 | struct CadetEncryptedMessageIdentifier ooo_pid, | ||
1000 | uint32_t ooo_bitmap) | ||
1001 | { | ||
1002 | uint32_t mask; | ||
1003 | |||
1004 | if (GC_is_pid_bigger (ntohl (last_pid_recv.pid) - 31, | ||
1005 | ntohl (ooo_pid.pid))) | ||
1006 | return GNUNET_NO; | ||
1007 | |||
1008 | mask = get_recv_bitmask (last_pid_recv, | ||
1009 | ooo_pid); | ||
1010 | if (0 != (ooo_bitmap & mask)) | ||
1011 | return GNUNET_NO; | ||
1012 | |||
1013 | return GNUNET_YES; | ||
1014 | } | ||
1015 | |||
1016 | |||
1017 | /** | ||
1018 | * Is traffic coming from this sender 'FWD' traffic? | ||
1019 | * | ||
1020 | * @param c Connection to check. | ||
1021 | * @param sender Short peer identity of neighbor. | ||
1022 | * | ||
1023 | * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore | ||
1024 | * the traffic is 'FWD'. | ||
1025 | * #GNUNET_NO for BCK. | ||
1026 | * #GNUNET_SYSERR for errors (sender isn't a hop in the connection). | ||
1027 | */ | ||
1028 | static int | ||
1029 | is_fwd (const struct CadetConnection *c, | ||
1030 | const struct CadetPeer *sender) | ||
1031 | { | ||
1032 | GNUNET_PEER_Id id; | ||
1033 | |||
1034 | id = GCP_get_short_id (sender); | ||
1035 | if (GCP_get_short_id (get_prev_hop (c)) == id) | ||
1036 | return GNUNET_YES; | ||
1037 | |||
1038 | if (GCP_get_short_id (get_next_hop (c)) == id) | ||
1039 | return GNUNET_NO; | ||
1040 | |||
1041 | return GNUNET_SYSERR; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | /** | ||
1046 | * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE | ||
1047 | * or a first CONNECTION_ACK directed to us. | ||
1048 | * | ||
1049 | * @param c Connection to confirm. | ||
1050 | * @param fwd Should we send it FWD? (root->dest) | ||
1051 | * (First (~SYNACK) goes BCK, second (~ACK) goes FWD) | ||
1052 | */ | ||
1053 | static void | ||
1054 | send_connection_ack (struct CadetConnection *c, int fwd) | ||
1055 | { | ||
1056 | static struct CadetEncryptedMessageIdentifier zero; | ||
1057 | struct GNUNET_CADET_ConnectionCreateAckMessage msg; | ||
1058 | struct CadetTunnel *t; | ||
1059 | const uint16_t size = sizeof (struct GNUNET_CADET_ConnectionCreateAckMessage); | ||
1060 | const uint16_t type = GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK; | ||
1061 | |||
1062 | GCC_check_connections (); | ||
1063 | t = c->t; | ||
1064 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1065 | "==> %s ({ C %s ACK} 0) on conn %s (%p) %s [%5u]\n", | ||
1066 | GC_m2s (type), GC_f2s (!fwd), GCC_2s (c), c, GC_f2s (fwd), size); | ||
1067 | |||
1068 | msg.header.size = htons (size); | ||
1069 | msg.header.type = htons (type); | ||
1070 | msg.reserved = htonl (0); | ||
1071 | msg.cid = c->id; | ||
1072 | |||
1073 | GNUNET_assert (NULL == c->maintenance_q); | ||
1074 | c->maintenance_q = GCP_send (get_hop (c, fwd), | ||
1075 | &msg.header, | ||
1076 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK, | ||
1077 | zero, | ||
1078 | c, | ||
1079 | fwd, | ||
1080 | &conn_message_sent, NULL); | ||
1081 | LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (conn`ACK)\n", | ||
1082 | c, c->pending_messages); | ||
1083 | c->pending_messages++; | ||
1084 | |||
1085 | if (CADET_TUNNEL_NEW == GCT_get_cstate (t)) | ||
1086 | GCT_change_cstate (t, CADET_TUNNEL_WAITING); | ||
1087 | if (CADET_CONNECTION_READY != c->state) | ||
1088 | connection_change_state (c, CADET_CONNECTION_SENT); | ||
1089 | GCC_check_connections (); | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | /** | ||
1094 | * Send a notification that a connection is broken. | ||
1095 | * | ||
1096 | * @param c Connection that is broken. | ||
1097 | * @param id1 Peer that has disconnected. | ||
1098 | * @param id2 Peer that has disconnected. | ||
1099 | * @param fwd Direction towards which to send it. | ||
1100 | */ | ||
1101 | static void | ||
1102 | send_broken (struct CadetConnection *c, | ||
1103 | const struct GNUNET_PeerIdentity *id1, | ||
1104 | const struct GNUNET_PeerIdentity *id2, | ||
1105 | int fwd) | ||
1106 | { | ||
1107 | static struct CadetEncryptedMessageIdentifier zero; | ||
1108 | struct GNUNET_CADET_ConnectionBrokenMessage msg; | ||
1109 | |||
1110 | GCC_check_connections (); | ||
1111 | msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage)); | ||
1112 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); | ||
1113 | msg.cid = c->id; | ||
1114 | msg.reserved = htonl (0); | ||
1115 | msg.peer1 = *id1; | ||
1116 | msg.peer2 = *id2; | ||
1117 | (void) GCC_send_prebuilt_message (&msg.header, | ||
1118 | UINT16_MAX, | ||
1119 | zero, | ||
1120 | c, | ||
1121 | fwd, | ||
1122 | GNUNET_YES, | ||
1123 | NULL, NULL); | ||
1124 | GCC_check_connections (); | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | /** | ||
1129 | * Send a notification that a connection is broken, when a connection | ||
1130 | * isn't even known to the local peer or soon to be destroyed. | ||
1131 | * | ||
1132 | * @param connection_id Connection ID. | ||
1133 | * @param id1 Peer that has disconnected, probably local peer. | ||
1134 | * @param id2 Peer that has disconnected can be NULL if unknown. | ||
1135 | * @param neighbor Peer to notify (neighbor who sent the connection). | ||
1136 | */ | ||
1137 | static void | ||
1138 | send_broken_unknown (const struct GNUNET_CADET_ConnectionTunnelIdentifier *connection_id, | ||
1139 | const struct GNUNET_PeerIdentity *id1, | ||
1140 | const struct GNUNET_PeerIdentity *id2, | ||
1141 | struct CadetPeer *neighbor) | ||
1142 | { | ||
1143 | static struct CadetEncryptedMessageIdentifier zero; | ||
1144 | struct GNUNET_CADET_ConnectionBrokenMessage msg; | ||
1145 | |||
1146 | GCC_check_connections (); | ||
1147 | LOG (GNUNET_ERROR_TYPE_INFO, "--> BROKEN on unknown connection %s\n", | ||
1148 | GNUNET_sh2s (&connection_id->connection_of_tunnel)); | ||
1149 | |||
1150 | msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage)); | ||
1151 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); | ||
1152 | msg.cid = *connection_id; | ||
1153 | msg.reserved = htonl (0); | ||
1154 | msg.peer1 = *id1; | ||
1155 | if (NULL != id2) | ||
1156 | msg.peer2 = *id2; | ||
1157 | else | ||
1158 | memset (&msg.peer2, 0, sizeof (msg.peer2)); | ||
1159 | GNUNET_assert (NULL != GCP_send (neighbor, | ||
1160 | &msg.header, | ||
1161 | UINT16_MAX, | ||
1162 | zero, | ||
1163 | NULL, | ||
1164 | GNUNET_SYSERR, /* connection, fwd */ | ||
1165 | NULL, NULL)); /* continuation */ | ||
1166 | GCC_check_connections (); | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | /** | ||
1171 | * Send keepalive packets for a connection. | ||
1172 | * | ||
1173 | * @param c Connection to keep alive.. | ||
1174 | * @param fwd Is this a FWD keepalive? (owner -> dest). | ||
1175 | */ | ||
1176 | static void | ||
1177 | send_connection_keepalive (struct CadetConnection *c, int fwd) | ||
1178 | { | 268 | { |
1179 | struct GNUNET_MessageHeader msg; | 269 | if (NULL != cc->ct) |
1180 | struct CadetFlowControl *fc; | ||
1181 | int tunnel_ready; | ||
1182 | |||
1183 | GCC_check_connections (); | ||
1184 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1185 | "keepalive %s for connection %s\n", | ||
1186 | GC_f2s (fwd), GCC_2s (c)); | ||
1187 | |||
1188 | GNUNET_assert (NULL != c->t); | ||
1189 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
1190 | tunnel_ready = GNUNET_YES == GCT_has_queued_traffic (c->t) | ||
1191 | && CADET_TUNNEL_KEY_OK <= GCT_get_estate (c->t); | ||
1192 | if (0 < fc->queue_n || tunnel_ready) | ||
1193 | { | 270 | { |
1194 | LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n"); | 271 | GCT_connection_lost (cc->ct); |
1195 | return; | 272 | cc->ct = NULL; |
1196 | } | 273 | } |
1197 | 274 | GCC_destroy (cc); | |
1198 | GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO); | ||
1199 | |||
1200 | GNUNET_assert (NULL != c->t); | ||
1201 | msg.size = htons (sizeof (msg)); | ||
1202 | msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE); | ||
1203 | |||
1204 | GNUNET_assert (NULL == | ||
1205 | GCT_send_prebuilt_message (&msg, c->t, c, | ||
1206 | GNUNET_NO, NULL, NULL)); | ||
1207 | GCC_check_connections (); | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | /** | ||
1212 | * Send CONNECTION_{CREATE/ACK} packets for a connection. | ||
1213 | * | ||
1214 | * @param c Connection for which to send the message. | ||
1215 | * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK. | ||
1216 | */ | ||
1217 | static void | ||
1218 | connection_recreate (struct CadetConnection *c, int fwd) | ||
1219 | { | ||
1220 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1221 | "sending connection recreate\n"); | ||
1222 | if (fwd) | ||
1223 | GCC_send_create (c); | ||
1224 | else | ||
1225 | send_connection_ack (c, GNUNET_NO); | ||
1226 | } | 275 | } |
1227 | 276 | ||
1228 | 277 | ||
1229 | /** | 278 | /** |
1230 | * Generic connection timer management. | 279 | * Destroy a connection, called if the tunnel association with the |
1231 | * Depending on the role of the peer in the connection will send the | 280 | * connection was already broken, but we still need to notify the CORE |
1232 | * appropriate message (build or keepalive) | 281 | * layer about the breakage. |
1233 | * | 282 | * |
1234 | * @param c Conncetion to maintain. | 283 | * @param cc connection to destroy |
1235 | * @param fwd Is FWD? | ||
1236 | */ | 284 | */ |
1237 | static void | 285 | void |
1238 | connection_maintain (struct CadetConnection *c, int fwd) | 286 | GCC_destroy_without_tunnel (struct CadetConnection *cc) |
1239 | { | 287 | { |
1240 | if (GNUNET_NO != c->destroy) | 288 | cc->ct = NULL; |
289 | if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) && | ||
290 | (NULL != cc->mq_man) ) | ||
1241 | { | 291 | { |
1242 | LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, being destroyed\n"); | 292 | struct GNUNET_MQ_Envelope *env; |
1243 | return; | 293 | struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg; |
1244 | } | ||
1245 | |||
1246 | if (NULL == c->t) | ||
1247 | { | ||
1248 | GNUNET_break (0); | ||
1249 | GCC_debug (c, GNUNET_ERROR_TYPE_ERROR); | ||
1250 | return; | ||
1251 | } | ||
1252 | 294 | ||
1253 | if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (c->t)) | 295 | /* Need to notify next hop that we are down. */ |
1254 | { | 296 | env = GNUNET_MQ_msg (destroy_msg, |
1255 | /* If status is SEARCHING, why is there a connection? Should be WAITING */ | 297 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); |
1256 | GNUNET_break (0); | 298 | destroy_msg->cid = cc->cid; |
1257 | GCT_debug (c->t, GNUNET_ERROR_TYPE_ERROR); | 299 | GCP_request_mq_cancel (cc->mq_man, |
1258 | LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, tunnel SEARCHING\n"); | 300 | env); |
1259 | schedule_next_keepalive (c, fwd); | 301 | cc->mq_man = NULL; |
1260 | return; | ||
1261 | } | ||
1262 | switch (c->state) | ||
1263 | { | ||
1264 | case CADET_CONNECTION_NEW: | ||
1265 | GNUNET_break (0); | ||
1266 | /* fall-through */ | ||
1267 | case CADET_CONNECTION_SENT: | ||
1268 | connection_recreate (c, fwd); | ||
1269 | break; | ||
1270 | case CADET_CONNECTION_READY: | ||
1271 | send_connection_keepalive (c, fwd); | ||
1272 | break; | ||
1273 | default: | ||
1274 | break; | ||
1275 | } | 302 | } |
303 | GCC_destroy (cc); | ||
1276 | } | 304 | } |
1277 | 305 | ||
1278 | 306 | ||
1279 | /** | 307 | /** |
1280 | * Keep the connection alive. | 308 | * Return the tunnel associated with this connection. |
1281 | * | 309 | * |
1282 | * @param c Connection to keep alive. | 310 | * @param cc connection to query |
1283 | * @param fwd Direction. | 311 | * @return corresponding entry in the tunnel's connection list |
1284 | */ | 312 | */ |
1285 | static void | 313 | struct CadetTConnection * |
1286 | connection_keepalive (struct CadetConnection *c, | 314 | GCC_get_ct (struct CadetConnection *cc) |
1287 | int fwd) | ||
1288 | { | 315 | { |
1289 | GCC_check_connections (); | 316 | return cc->ct; |
1290 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1291 | "%s keepalive for %s\n", | ||
1292 | GC_f2s (fwd), GCC_2s (c)); | ||
1293 | |||
1294 | if (fwd) | ||
1295 | c->fwd_maintenance_task = NULL; | ||
1296 | else | ||
1297 | c->bck_maintenance_task = NULL; | ||
1298 | connection_maintain (c, fwd); | ||
1299 | GCC_check_connections (); | ||
1300 | /* Next execution will be scheduled by message_sent or _maintain*/ | ||
1301 | } | 317 | } |
1302 | 318 | ||
1303 | 319 | ||
1304 | /** | 320 | /** |
1305 | * Keep the connection alive in the FWD direction. | 321 | * Obtain performance @a metrics from @a cc. |
1306 | * | 322 | * |
1307 | * @param cls Closure (connection to keepalive). | 323 | * @param cc connection to query |
324 | * @return the metrics | ||
1308 | */ | 325 | */ |
1309 | static void | 326 | const struct CadetConnectionMetrics * |
1310 | connection_fwd_keepalive (void *cls) | 327 | GCC_get_metrics (struct CadetConnection *cc) |
1311 | { | 328 | { |
1312 | struct CadetConnection *c = cls; | 329 | return &cc->metrics; |
1313 | |||
1314 | GCC_check_connections (); | ||
1315 | connection_keepalive (c, | ||
1316 | GNUNET_YES); | ||
1317 | GCC_check_connections (); | ||
1318 | } | 330 | } |
1319 | 331 | ||
1320 | 332 | ||
1321 | /** | 333 | /** |
1322 | * Keep the connection alive in the BCK direction. | 334 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the |
335 | * tunnel to prevent it from timing out. | ||
1323 | * | 336 | * |
1324 | * @param cls Closure (connection to keepalive). | 337 | * @param cls the `struct CadetConnection` to keep alive. |
1325 | */ | 338 | */ |
1326 | static void | 339 | static void |
1327 | connection_bck_keepalive (void *cls) | 340 | send_keepalive (void *cls); |
1328 | { | ||
1329 | struct CadetConnection *c = cls; | ||
1330 | |||
1331 | GCC_check_connections (); | ||
1332 | connection_keepalive (c, | ||
1333 | GNUNET_NO); | ||
1334 | GCC_check_connections (); | ||
1335 | } | ||
1336 | 341 | ||
1337 | 342 | ||
1338 | /** | 343 | /** |
1339 | * Schedule next keepalive task, taking in consideration | 344 | * Keepalive was transmitted. Remember this, and possibly |
1340 | * the connection state and number of retries. | 345 | * schedule the next one. |
1341 | * | 346 | * |
1342 | * If the peer is not the origin, do nothing. | 347 | * @param cls the `struct CadetConnection` to keep alive. |
1343 | * | 348 | * @param cid identifier of the connection within the tunnel, NULL |
1344 | * @param c Connection for which to schedule the next keepalive. | 349 | * if transmission failed |
1345 | * @param fwd Direction for the next keepalive. | ||
1346 | */ | 350 | */ |
1347 | static void | 351 | static void |
1348 | schedule_next_keepalive (struct CadetConnection *c, int fwd) | 352 | keepalive_done (void *cls, |
353 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
1349 | { | 354 | { |
1350 | struct GNUNET_TIME_Relative delay; | 355 | struct CadetConnection *cc = cls; |
1351 | struct GNUNET_SCHEDULER_Task * *task_id; | ||
1352 | GNUNET_SCHEDULER_TaskCallback keepalive_task; | ||
1353 | |||
1354 | GCC_check_connections (); | ||
1355 | if (GNUNET_NO == GCC_is_origin (c, fwd)) | ||
1356 | return; | ||
1357 | |||
1358 | /* Calculate delay to use, depending on the state of the connection */ | ||
1359 | if (CADET_CONNECTION_READY == c->state) | ||
1360 | { | ||
1361 | delay = refresh_connection_time; | ||
1362 | } | ||
1363 | else | ||
1364 | { | ||
1365 | if (1 > c->create_retry) | ||
1366 | c->create_retry = 1; | ||
1367 | delay = GNUNET_TIME_relative_saturating_multiply (create_connection_time, | ||
1368 | c->create_retry); | ||
1369 | if (c->create_retry < 64) // TODO make configurable | ||
1370 | c->create_retry *= 2; | ||
1371 | } | ||
1372 | |||
1373 | /* Select direction-dependent parameters */ | ||
1374 | if (GNUNET_YES == fwd) | ||
1375 | { | ||
1376 | task_id = &c->fwd_maintenance_task; | ||
1377 | keepalive_task = &connection_fwd_keepalive; | ||
1378 | } | ||
1379 | else | ||
1380 | { | ||
1381 | task_id = &c->bck_maintenance_task; | ||
1382 | keepalive_task = &connection_bck_keepalive; | ||
1383 | } | ||
1384 | 356 | ||
1385 | /* Check that no one scheduled it before us */ | 357 | cc->keepalive_qe = NULL; |
1386 | if (NULL != *task_id) | 358 | if ( (GNUNET_YES == cc->mqm_ready) && |
1387 | { | 359 | (NULL == cc->task) ) |
1388 | /* No need for a _break. It can happen for instance when sending a SYNACK | 360 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, |
1389 | * for a duplicate SYN: the first SYNACK scheduled the task. */ | 361 | &send_keepalive, |
1390 | GNUNET_SCHEDULER_cancel (*task_id); | 362 | cc); |
1391 | } | ||
1392 | |||
1393 | /* Schedule the task */ | ||
1394 | *task_id = GNUNET_SCHEDULER_add_delayed (delay, | ||
1395 | keepalive_task, | ||
1396 | c); | ||
1397 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1398 | "next keepalive for %s in in %s\n", | ||
1399 | GCC_2s (c), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); | ||
1400 | GCC_check_connections (); | ||
1401 | } | 363 | } |
1402 | 364 | ||
1403 | 365 | ||
1404 | /** | 366 | /** |
1405 | * Cancel all transmissions that belong to a certain connection. | 367 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the |
368 | * tunnel to prevent it from timing out. | ||
1406 | * | 369 | * |
1407 | * If the connection is scheduled for destruction and no more messages are left, | 370 | * @param cls the `struct CadetConnection` to keep alive. |
1408 | * the connection will be destroyed by the continuation call. | ||
1409 | * | ||
1410 | * @param c Connection which to cancel. Might be destroyed during this call. | ||
1411 | * @param fwd Cancel fwd traffic? | ||
1412 | */ | 371 | */ |
1413 | static void | 372 | static void |
1414 | connection_cancel_queues (struct CadetConnection *c, | 373 | send_keepalive (void *cls) |
1415 | int fwd) | ||
1416 | { | 374 | { |
1417 | struct CadetFlowControl *fc; | 375 | struct CadetConnection *cc = cls; |
376 | struct GNUNET_MessageHeader msg; | ||
1418 | 377 | ||
1419 | GCC_check_connections (); | 378 | cc->task = NULL; |
1420 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 379 | if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t)) |
1421 | "Cancel %s queues for connection %s\n", | ||
1422 | GC_f2s (fwd), GCC_2s (c)); | ||
1423 | if (NULL == c) | ||
1424 | { | 380 | { |
1425 | GNUNET_break (0); | 381 | /* Tunnel not yet ready, wait with keepalives... */ |
382 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
383 | &send_keepalive, | ||
384 | cc); | ||
1426 | return; | 385 | return; |
1427 | } | 386 | } |
1428 | 387 | GNUNET_assert (NULL != cc->ct); | |
1429 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | 388 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); |
1430 | if (NULL != fc->poll_task) | 389 | GNUNET_assert (NULL == cc->keepalive_qe); |
1431 | { | ||
1432 | GNUNET_SCHEDULER_cancel (fc->poll_task); | ||
1433 | fc->poll_task = NULL; | ||
1434 | LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL task for fc %p\n", fc); | ||
1435 | } | ||
1436 | if (NULL != fc->poll_msg) | ||
1437 | { | ||
1438 | GCC_cancel (fc->poll_msg); | ||
1439 | LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL msg for fc %p\n", fc); | ||
1440 | } | ||
1441 | |||
1442 | while (NULL != fc->q_head) | ||
1443 | { | ||
1444 | GCC_cancel (fc->q_head); | ||
1445 | } | ||
1446 | GCC_check_connections (); | ||
1447 | } | ||
1448 | |||
1449 | |||
1450 | /** | ||
1451 | * Function called if a connection has been stalled for a while, | ||
1452 | * possibly due to a missed ACK. Poll the neighbor about its ACK status. | ||
1453 | * | ||
1454 | * @param cls Closure (poll ctx). | ||
1455 | */ | ||
1456 | static void | ||
1457 | send_poll (void *cls) | ||
1458 | { | ||
1459 | static struct CadetEncryptedMessageIdentifier zero; | ||
1460 | struct CadetFlowControl *fc = cls; | ||
1461 | struct GNUNET_CADET_ConnectionHopByHopPollMessage msg; | ||
1462 | struct CadetConnection *c; | ||
1463 | int fwd; | ||
1464 | |||
1465 | fc->poll_task = NULL; | ||
1466 | GCC_check_connections (); | ||
1467 | c = fc->c; | ||
1468 | fwd = fc == &c->fwd_fc; | ||
1469 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Polling connection %s %s\n", | ||
1470 | GCC_2s (c), GC_f2s (fwd)); | ||
1471 | |||
1472 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL); | ||
1473 | msg.header.size = htons (sizeof (msg)); | ||
1474 | msg.cid = c->id; | ||
1475 | msg.cemi = fc->last_pid_sent; | ||
1476 | LOG (GNUNET_ERROR_TYPE_DEBUG, " last pid sent: %u\n", ntohl (fc->last_pid_sent.pid)); | ||
1477 | fc->poll_msg | ||
1478 | = GCC_send_prebuilt_message (&msg.header, | ||
1479 | UINT16_MAX, | ||
1480 | zero, | ||
1481 | c, | ||
1482 | fc == &c->fwd_fc, | ||
1483 | GNUNET_YES, | ||
1484 | NULL, | ||
1485 | NULL); | ||
1486 | GNUNET_assert (NULL != fc->poll_msg); | ||
1487 | GCC_check_connections (); | ||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /** | ||
1492 | * Generic connection timeout implementation. | ||
1493 | * | ||
1494 | * Timeout function due to lack of keepalive/traffic from an endpoint. | ||
1495 | * Destroys connection if called. | ||
1496 | * | ||
1497 | * @param c Connection to destroy. | ||
1498 | * @param fwd Was the timeout from the origin? (FWD timeout) | ||
1499 | */ | ||
1500 | static void | ||
1501 | connection_timeout (struct CadetConnection *c, int fwd) | ||
1502 | { | ||
1503 | GCC_check_connections (); | ||
1504 | |||
1505 | LOG (GNUNET_ERROR_TYPE_INFO, | 390 | LOG (GNUNET_ERROR_TYPE_INFO, |
1506 | "Connection %s %s timed out. Destroying.\n", | 391 | "Sending KEEPALIVE on behalf of %s via %s\n", |
1507 | GCC_2s (c), | 392 | GCC_2s (cc), |
1508 | GC_f2s (fwd)); | 393 | GCT_2s (cc->ct->t)); |
1509 | GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); | 394 | GNUNET_STATISTICS_update (stats, |
1510 | 395 | "# keepalives sent", | |
1511 | if (GCC_is_origin (c, fwd)) /* Loopback? Something is wrong! */ | 396 | 1, |
1512 | { | 397 | GNUNET_NO); |
1513 | GNUNET_break (0); | 398 | msg.size = htons (sizeof (msg)); |
1514 | return; | 399 | msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE); |
1515 | } | ||
1516 | |||
1517 | /* If dest, send "broken" notification. */ | ||
1518 | if (GCC_is_terminal (c, fwd)) | ||
1519 | { | ||
1520 | struct CadetPeer *next_hop; | ||
1521 | |||
1522 | next_hop = fwd ? get_prev_hop (c) : get_next_hop (c); | ||
1523 | send_broken_unknown (&c->id, &my_full_id, NULL, next_hop); | ||
1524 | } | ||
1525 | |||
1526 | GCC_destroy (c); | ||
1527 | GCC_check_connections (); | ||
1528 | } | ||
1529 | |||
1530 | |||
1531 | /** | ||
1532 | * Timeout function due to lack of keepalive/traffic from the owner. | ||
1533 | * Destroys connection if called. | ||
1534 | * | ||
1535 | * @param cls Closure (connection to destroy). | ||
1536 | */ | ||
1537 | static void | ||
1538 | connection_fwd_timeout (void *cls) | ||
1539 | { | ||
1540 | struct CadetConnection *c = cls; | ||
1541 | |||
1542 | c->fwd_maintenance_task = NULL; | ||
1543 | GCC_check_connections (); | ||
1544 | connection_timeout (c, GNUNET_YES); | ||
1545 | GCC_check_connections (); | ||
1546 | } | ||
1547 | |||
1548 | |||
1549 | /** | ||
1550 | * Timeout function due to lack of keepalive/traffic from the destination. | ||
1551 | * Destroys connection if called. | ||
1552 | * | ||
1553 | * @param cls Closure (connection to destroy). | ||
1554 | */ | ||
1555 | static void | ||
1556 | connection_bck_timeout (void *cls) | ||
1557 | { | ||
1558 | struct CadetConnection *c = cls; | ||
1559 | 400 | ||
1560 | c->bck_maintenance_task = NULL; | 401 | cc->keepalive_qe |
1561 | GCC_check_connections (); | 402 | = GCT_send (cc->ct->t, |
1562 | connection_timeout (c, GNUNET_NO); | 403 | &msg, |
1563 | GCC_check_connections (); | 404 | &keepalive_done, |
405 | cc); | ||
1564 | } | 406 | } |
1565 | 407 | ||
1566 | 408 | ||
1567 | /** | 409 | /** |
1568 | * Resets the connection timeout task, some other message has done the | 410 | * We sent a message for which we expect to receive an ACK via |
1569 | * task's job. | 411 | * the connection identified by @a cti. |
1570 | * - For the first peer on the direction this means to send | ||
1571 | * a keepalive or a path confirmation message (either create or ACK). | ||
1572 | * - For all other peers, this means to destroy the connection, | ||
1573 | * due to lack of activity. | ||
1574 | * Starts the timeout if no timeout was running (connection just created). | ||
1575 | * | ||
1576 | * @param c Connection whose timeout to reset. | ||
1577 | * @param fwd Is this forward? | ||
1578 | * | 412 | * |
1579 | * TODO use heap to improve efficiency of scheduler. | 413 | * @param cid connection identifier where we expect an ACK |
1580 | */ | 414 | */ |
1581 | static void | 415 | void |
1582 | connection_reset_timeout (struct CadetConnection *c, int fwd) | 416 | GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) |
1583 | { | 417 | { |
1584 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GC_f2s (fwd)); | 418 | struct CadetConnection *cc; |
1585 | if (GCC_is_origin (c, fwd)) /* Startpoint */ | ||
1586 | { | ||
1587 | schedule_next_keepalive (c, fwd); | ||
1588 | if (NULL != c->maintenance_q) | ||
1589 | { | ||
1590 | GCP_send_cancel (c->maintenance_q); | ||
1591 | c->maintenance_q = NULL; /* Is set to NULL by conn_message_sent anyway */ | ||
1592 | } | ||
1593 | } | ||
1594 | else /* Relay, endpoint. */ | ||
1595 | { | ||
1596 | struct GNUNET_TIME_Relative delay; | ||
1597 | struct GNUNET_SCHEDULER_Task * *ti; | ||
1598 | GNUNET_SCHEDULER_TaskCallback f; | ||
1599 | |||
1600 | ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task; | ||
1601 | 419 | ||
1602 | if (NULL != *ti) | 420 | cc = GCC_lookup (cid); |
1603 | GNUNET_SCHEDULER_cancel (*ti); | 421 | if (NULL == cc) |
1604 | delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 4); | 422 | return; /* whopise, connection alredy down? */ |
1605 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 423 | cc->metrics.num_acked_transmissions++; |
1606 | " timing out in %s\n", | ||
1607 | GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO)); | ||
1608 | f = fwd ? &connection_fwd_timeout : &connection_bck_timeout; | ||
1609 | *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c); | ||
1610 | } | ||
1611 | } | 424 | } |
1612 | 425 | ||
1613 | 426 | ||
1614 | /** | 427 | /** |
1615 | * Iterator to compare each connection's path with the path of a new connection. | 428 | * We observed an ACK for a message that was originally sent via |
429 | * the connection identified by @a cti. | ||
1616 | * | 430 | * |
1617 | * If the connection coincides, the c member of path is set to the connection | 431 | * @param cti connection identifier where we got an ACK for a message |
1618 | * and the destroy flag of the connection is set. | 432 | * that was originally sent via this connection (the ACK |
1619 | * | 433 | * may have gotten back to us via a different connection). |
1620 | * @param cls Closure (new path). | ||
1621 | * @param c Connection in the tunnel to check. | ||
1622 | */ | 434 | */ |
1623 | static void | 435 | void |
1624 | check_path (void *cls, struct CadetConnection *c) | 436 | GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) |
1625 | { | 437 | { |
1626 | struct CadetConnection *new_conn = cls; | 438 | struct CadetConnection *cc; |
1627 | struct CadetPeerPath *path = new_conn->path; | ||
1628 | |||
1629 | LOG (GNUNET_ERROR_TYPE_DEBUG, " checking %s (%p), length %u\n", | ||
1630 | GCC_2s (c), c, c->path->length); | ||
1631 | 439 | ||
1632 | if (c != new_conn | 440 | cc = GCC_lookup (cid); |
1633 | && GNUNET_NO == c->destroy | 441 | if (NULL == cc) |
1634 | && CADET_CONNECTION_BROKEN != c->state | 442 | return; /* whopise, connection alredy down? */ |
1635 | && CADET_CONNECTION_DESTROYED != c->state | 443 | cc->metrics.num_successes++; |
1636 | && path_equivalent (path, c->path)) | ||
1637 | { | ||
1638 | new_conn->destroy = GNUNET_YES; /* Do not mark_destroyed, */ | ||
1639 | new_conn->path->c = c; /* this is only a flag for the Iterator. */ | ||
1640 | LOG (GNUNET_ERROR_TYPE_DEBUG, " MATCH!\n"); | ||
1641 | } | ||
1642 | } | 444 | } |
1643 | 445 | ||
1644 | 446 | ||
1645 | /** | 447 | /** |
1646 | * Finds out if this path is already being used by an existing connection. | 448 | * We observed some the given @a latency on the connection |
1647 | * | 449 | * identified by @a cti. (The same connection was taken |
1648 | * Checks the tunnel towards the destination to see if it contains | 450 | * in both directions.) |
1649 | * any connection with the same path. | ||
1650 | * | 451 | * |
1651 | * If the existing connection is ready, it is kept. | 452 | * @param cid connection identifier where we measured latency |
1652 | * Otherwise if the sender has a smaller ID that ours, we accept it (and | 453 | * @param latency the observed latency |
1653 | * the peer will eventually reject our attempt). | ||
1654 | * | ||
1655 | * @param path Path to check. | ||
1656 | * @return #GNUNET_YES if the tunnel has a connection with the same path, | ||
1657 | * #GNUNET_NO otherwise. | ||
1658 | */ | 454 | */ |
1659 | static int | 455 | void |
1660 | does_connection_exist (struct CadetConnection *conn) | 456 | GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, |
457 | struct GNUNET_TIME_Relative latency) | ||
1661 | { | 458 | { |
1662 | struct CadetPeer *p; | 459 | struct CadetConnection *cc; |
1663 | struct CadetTunnel *t; | 460 | double weight; |
1664 | struct CadetConnection *c; | 461 | double result; |
1665 | |||
1666 | p = GCP_get_short (conn->path->peers[0], GNUNET_NO); | ||
1667 | if (NULL == p) | ||
1668 | return GNUNET_NO; | ||
1669 | t = GCP_get_tunnel (p); | ||
1670 | if (NULL == t) | ||
1671 | return GNUNET_NO; | ||
1672 | |||
1673 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n"); | ||
1674 | 462 | ||
1675 | GCT_iterate_connections (t, &check_path, conn); | 463 | cc = GCC_lookup (cid); |
1676 | 464 | if (NULL == cc) | |
1677 | if (GNUNET_YES == conn->destroy) | 465 | return; /* whopise, connection alredy down? */ |
1678 | { | 466 | GNUNET_STATISTICS_update (stats, |
1679 | c = conn->path->c; | 467 | "# latencies observed", |
1680 | conn->destroy = GNUNET_NO; | 468 | 1, |
1681 | conn->path->c = conn; | 469 | GNUNET_NO); |
1682 | LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn)); | 470 | cc->latency_datapoints++; |
1683 | LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c)); | 471 | if (cc->latency_datapoints >= 7) |
1684 | GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); | 472 | weight = 7.0; |
1685 | if (CADET_CONNECTION_READY == c->state) | ||
1686 | { | ||
1687 | /* The other peer confirmed a live connection with this path, | ||
1688 | * why are they trying to duplicate it? */ | ||
1689 | GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO); | ||
1690 | return GNUNET_YES; | ||
1691 | } | ||
1692 | LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not ready, connection unique\n"); | ||
1693 | return GNUNET_NO; | ||
1694 | } | ||
1695 | else | 473 | else |
1696 | { | 474 | weight = cc->latency_datapoints; |
1697 | LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn)); | 475 | /* Compute weighted average, giving at MOST weight 7 to the |
1698 | return GNUNET_NO; | 476 | existing values, or less if that value is based on fewer than 7 |
1699 | } | 477 | measurements. */ |
478 | result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us; | ||
479 | result /= (weight + 1.0); | ||
480 | cc->metrics.aged_latency.rel_value_us = (uint64_t) result; | ||
1700 | } | 481 | } |
1701 | 482 | ||
1702 | 483 | ||
1703 | /** | 484 | /** |
1704 | * @brief Check if the tunnel this connection belongs to has any other | 485 | * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying |
1705 | * connection with the same path, and destroy one if so. | 486 | * that the end-to-end connection is up. Process it. |
1706 | * | 487 | * |
1707 | * @param cls Closure (connection to check). | 488 | * @param cc the connection that got the ACK. |
1708 | */ | ||
1709 | static void | ||
1710 | check_duplicates (void *cls) | ||
1711 | { | ||
1712 | struct CadetConnection *c = cls; | ||
1713 | |||
1714 | c->check_duplicates_task = NULL; | ||
1715 | if (GNUNET_YES == does_connection_exist (c)) | ||
1716 | { | ||
1717 | GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG); | ||
1718 | send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES)); | ||
1719 | GCC_destroy (c); | ||
1720 | } | ||
1721 | } | ||
1722 | |||
1723 | |||
1724 | /** | ||
1725 | * Wait for enough time to let any dead connections time out and check for | ||
1726 | * any remaining duplicates. | ||
1727 | * | ||
1728 | * @param c Connection that is a potential duplicate. | ||
1729 | */ | ||
1730 | static void | ||
1731 | schedule_check_duplicates (struct CadetConnection *c) | ||
1732 | { | ||
1733 | struct GNUNET_TIME_Relative delay; | ||
1734 | |||
1735 | if (NULL != c->check_duplicates_task) | ||
1736 | return; | ||
1737 | delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 5); | ||
1738 | c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay, | ||
1739 | &check_duplicates, | ||
1740 | c); | ||
1741 | } | ||
1742 | |||
1743 | |||
1744 | /** | ||
1745 | * Add the connection to the list of both neighbors. | ||
1746 | * | ||
1747 | * @param c Connection. | ||
1748 | * | ||
1749 | * @return #GNUNET_OK if everything went fine | ||
1750 | * #GNUNET_SYSERR if the was an error and @c c is malformed. | ||
1751 | */ | ||
1752 | static int | ||
1753 | register_neighbors (struct CadetConnection *c) | ||
1754 | { | ||
1755 | c->next_peer = get_next_hop (c); | ||
1756 | c->prev_peer = get_prev_hop (c); | ||
1757 | GNUNET_assert (c->next_peer != c->prev_peer); | ||
1758 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1759 | "register neighbors for connection %s\n", | ||
1760 | GCC_2s (c)); | ||
1761 | path_debug (c->path); | ||
1762 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1763 | "own pos %u\n", c->own_pos); | ||
1764 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1765 | "putting connection %s to next peer %p\n", | ||
1766 | GCC_2s (c), | ||
1767 | c->next_peer); | ||
1768 | LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", | ||
1769 | c->next_peer, | ||
1770 | GCP_2s (c->next_peer)); | ||
1771 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1772 | "putting connection %s to prev peer %p\n", | ||
1773 | GCC_2s (c), | ||
1774 | c->prev_peer); | ||
1775 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1776 | "prev peer %p %s\n", | ||
1777 | c->prev_peer, | ||
1778 | GCP_2s (c->prev_peer)); | ||
1779 | |||
1780 | if ( (GNUNET_NO == GCP_is_neighbor (c->next_peer)) || | ||
1781 | (GNUNET_NO == GCP_is_neighbor (c->prev_peer)) ) | ||
1782 | { | ||
1783 | if (GCC_is_origin (c, GNUNET_YES)) | ||
1784 | GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO); | ||
1785 | GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO); | ||
1786 | |||
1787 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1788 | " register neighbors failed\n"); | ||
1789 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1790 | " prev: %s, neighbor?: %d\n", | ||
1791 | GCP_2s (c->prev_peer), | ||
1792 | GCP_is_neighbor (c->prev_peer)); | ||
1793 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1794 | " next: %s, neighbor?: %d\n", | ||
1795 | GCP_2s (c->next_peer), | ||
1796 | GCP_is_neighbor (c->next_peer)); | ||
1797 | return GNUNET_SYSERR; | ||
1798 | } | ||
1799 | GCP_add_connection (c->next_peer, c, GNUNET_NO); | ||
1800 | GCP_add_connection (c->prev_peer, c, GNUNET_YES); | ||
1801 | |||
1802 | return GNUNET_OK; | ||
1803 | } | ||
1804 | |||
1805 | |||
1806 | /** | ||
1807 | * Remove the connection from the list of both neighbors. | ||
1808 | * | ||
1809 | * @param c Connection. | ||
1810 | */ | ||
1811 | static void | ||
1812 | unregister_neighbors (struct CadetConnection *c) | ||
1813 | { | ||
1814 | // struct CadetPeer *peer; FIXME dont use next_peer, prev_peer | ||
1815 | /* Either already unregistered or never got registered, it's ok either way. */ | ||
1816 | if (NULL == c->path) | ||
1817 | return; | ||
1818 | if (NULL != c->next_peer) | ||
1819 | { | ||
1820 | GCP_remove_connection (c->next_peer, c); | ||
1821 | c->next_peer = NULL; | ||
1822 | } | ||
1823 | if (NULL != c->prev_peer) | ||
1824 | { | ||
1825 | GCP_remove_connection (c->prev_peer, c); | ||
1826 | c->prev_peer = NULL; | ||
1827 | } | ||
1828 | } | ||
1829 | |||
1830 | |||
1831 | /** | ||
1832 | * Invalidates all paths towards all peers that comprise the connection which | ||
1833 | * rely on the disconnected peer. | ||
1834 | * | ||
1835 | * ~O(n^3) (peers in connection * paths/peer * links/path) | ||
1836 | * | ||
1837 | * @param c Connection whose peers' paths to clean. | ||
1838 | * @param disconnected Peer that disconnected. | ||
1839 | */ | ||
1840 | static void | ||
1841 | invalidate_paths (struct CadetConnection *c, | ||
1842 | struct CadetPeer *disconnected) | ||
1843 | { | ||
1844 | struct CadetPeer *peer; | ||
1845 | unsigned int i; | ||
1846 | |||
1847 | for (i = 0; i < c->path->length; i++) | ||
1848 | { | ||
1849 | peer = GCP_get_short (c->path->peers[i], GNUNET_NO); | ||
1850 | if (NULL != peer) | ||
1851 | GCP_notify_broken_link (peer, &my_full_id, GCP_get_id (disconnected)); | ||
1852 | } | ||
1853 | } | ||
1854 | |||
1855 | |||
1856 | /** | ||
1857 | * Bind the connection to the peer and the tunnel to that peer. | ||
1858 | * | ||
1859 | * If the peer has no tunnel, create one. Update tunnel and connection | ||
1860 | * data structres to reflect new status. | ||
1861 | * | ||
1862 | * @param c Connection. | ||
1863 | * @param peer Peer. | ||
1864 | */ | ||
1865 | static void | ||
1866 | add_to_peer (struct CadetConnection *c, | ||
1867 | struct CadetPeer *peer) | ||
1868 | { | ||
1869 | GCP_add_tunnel (peer); | ||
1870 | c->t = GCP_get_tunnel (peer); | ||
1871 | GCT_add_connection (c->t, c); | ||
1872 | } | ||
1873 | |||
1874 | |||
1875 | /** | ||
1876 | * Log receipt of message on stderr (INFO level). | ||
1877 | * | ||
1878 | * @param message Message received. | ||
1879 | * @param peer Peer who sent the message. | ||
1880 | * @param conn_id Connection ID of the message. | ||
1881 | */ | ||
1882 | static void | ||
1883 | log_message (const struct GNUNET_MessageHeader *message, | ||
1884 | const struct CadetPeer *peer, | ||
1885 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *conn_id) | ||
1886 | { | ||
1887 | uint16_t size; | ||
1888 | uint16_t type; | ||
1889 | char *arrow; | ||
1890 | |||
1891 | size = ntohs (message->size); | ||
1892 | type = ntohs (message->type); | ||
1893 | switch (type) | ||
1894 | { | ||
1895 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: | ||
1896 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK: | ||
1897 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: | ||
1898 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: | ||
1899 | arrow = "=="; | ||
1900 | break; | ||
1901 | default: | ||
1902 | arrow = "--"; | ||
1903 | } | ||
1904 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1905 | "<%s %s on conn %s from %s, %6u bytes\n", | ||
1906 | arrow, | ||
1907 | GC_m2s (type), | ||
1908 | GNUNET_sh2s (&conn_id->connection_of_tunnel), | ||
1909 | GCP_2s(peer), | ||
1910 | (unsigned int) size); | ||
1911 | } | ||
1912 | |||
1913 | /******************************************************************************/ | ||
1914 | /******************************** API ***********************************/ | ||
1915 | /******************************************************************************/ | ||
1916 | |||
1917 | /** | ||
1918 | * Handler for connection creation. | ||
1919 | * | ||
1920 | * @param peer Message sender (neighbor). | ||
1921 | * @param msg Message itself. | ||
1922 | */ | 489 | */ |
1923 | void | 490 | void |
1924 | GCC_handle_create (struct CadetPeer *peer, | 491 | GCC_handle_connection_create_ack (struct CadetConnection *cc) |
1925 | const struct GNUNET_CADET_ConnectionCreateMessage *msg) | ||
1926 | { | 492 | { |
1927 | static struct CadetEncryptedMessageIdentifier zero; | 493 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1928 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid; | 494 | "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n", |
1929 | struct GNUNET_PeerIdentity *id; | 495 | GCC_2s (cc), |
1930 | struct CadetPeerPath *path; | 496 | cc->state, |
1931 | struct CadetPeer *dest_peer; | 497 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); |
1932 | struct CadetPeer *orig_peer; | 498 | if (CADET_CONNECTION_READY == cc->state) |
1933 | struct CadetConnection *c; | 499 | return; /* Duplicate ACK, ignore */ |
1934 | unsigned int own_pos; | 500 | if (NULL != cc->task) |
1935 | uint16_t size; | ||
1936 | |||
1937 | GCC_check_connections (); | ||
1938 | size = ntohs (msg->header.size); | ||
1939 | |||
1940 | /* Calculate hops */ | ||
1941 | size -= sizeof (struct GNUNET_CADET_ConnectionCreateMessage); | ||
1942 | if (0 != size % sizeof (struct GNUNET_PeerIdentity)) | ||
1943 | { | ||
1944 | GNUNET_break_op (0); | ||
1945 | return; | ||
1946 | } | ||
1947 | size /= sizeof (struct GNUNET_PeerIdentity); | ||
1948 | if (1 > size) | ||
1949 | { | ||
1950 | GNUNET_break_op (0); | ||
1951 | return; | ||
1952 | } | ||
1953 | LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); | ||
1954 | |||
1955 | /* Get parameters */ | ||
1956 | cid = &msg->cid; | ||
1957 | log_message (&msg->header, peer, cid); | ||
1958 | id = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1959 | LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id)); | ||
1960 | |||
1961 | /* Create connection */ | ||
1962 | c = connection_get (cid); | ||
1963 | if (NULL == c) | ||
1964 | { | ||
1965 | path = path_build_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1], | ||
1966 | size, myid, &own_pos); | ||
1967 | if (NULL == path) | ||
1968 | { | ||
1969 | /* Path was malformed, probably our own ID was not in it. */ | ||
1970 | GNUNET_STATISTICS_update (stats, "# malformed paths", 1, GNUNET_NO); | ||
1971 | GNUNET_break_op (0); | ||
1972 | return; | ||
1973 | } | ||
1974 | if (0 == own_pos) | ||
1975 | { | ||
1976 | /* We received this request from a neighbor, we cannot be origin */ | ||
1977 | GNUNET_STATISTICS_update (stats, "# fake paths", 1, GNUNET_NO); | ||
1978 | GNUNET_break_op (0); | ||
1979 | path_destroy (path); | ||
1980 | return; | ||
1981 | } | ||
1982 | |||
1983 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); | ||
1984 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n"); | ||
1985 | c = GCC_new (cid, NULL, path, own_pos); | ||
1986 | if (NULL == c) | ||
1987 | { | ||
1988 | if (path->length - 1 == own_pos) | ||
1989 | { | ||
1990 | /* If we are destination, why did the creation fail? */ | ||
1991 | GNUNET_break (0); | ||
1992 | path_destroy (path); | ||
1993 | GCC_check_connections (); | ||
1994 | return; | ||
1995 | } | ||
1996 | send_broken_unknown (cid, &my_full_id, | ||
1997 | GNUNET_PEER_resolve2 (path->peers[own_pos + 1]), | ||
1998 | peer); | ||
1999 | path_destroy (path); | ||
2000 | GCC_check_connections (); | ||
2001 | return; | ||
2002 | } | ||
2003 | GCP_add_path_to_all (path, GNUNET_NO); | ||
2004 | connection_reset_timeout (c, GNUNET_YES); | ||
2005 | } | ||
2006 | else | ||
2007 | { | ||
2008 | path = path_duplicate (c->path); | ||
2009 | } | ||
2010 | if (CADET_CONNECTION_NEW == c->state) | ||
2011 | connection_change_state (c, CADET_CONNECTION_SENT); | ||
2012 | |||
2013 | /* Remember peers */ | ||
2014 | dest_peer = GCP_get (&id[size - 1], GNUNET_YES); | ||
2015 | orig_peer = GCP_get (&id[0], GNUNET_YES); | ||
2016 | |||
2017 | /* Is it a connection to us? */ | ||
2018 | if (c->own_pos == path->length - 1) | ||
2019 | { | ||
2020 | LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); | ||
2021 | GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES); | ||
2022 | |||
2023 | add_to_peer (c, orig_peer); | ||
2024 | if (GNUNET_YES == does_connection_exist (c)) | ||
2025 | { | ||
2026 | /* Peer created a connection equal to one we think exists | ||
2027 | * and is fine. | ||
2028 | * Solution: Keep both and postpone disambiguation. In the meantime | ||
2029 | * the connection will time out or peer will inform us it is broken. | ||
2030 | * | ||
2031 | * Other options: | ||
2032 | * - Use explicit duplicate. | ||
2033 | * - Accept new conn and destroy the old. (interruption in higher level) | ||
2034 | * - Keep the one with higher ID / created by peer with higher ID. */ | ||
2035 | schedule_check_duplicates (c); | ||
2036 | } | ||
2037 | |||
2038 | if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t)) | ||
2039 | GCT_change_cstate (c->t, CADET_TUNNEL_WAITING); | ||
2040 | if (NULL == c->maintenance_q) | ||
2041 | send_connection_ack (c, GNUNET_NO); | ||
2042 | if (CADET_CONNECTION_SENT == c->state) | ||
2043 | connection_change_state (c, CADET_CONNECTION_ACK); | ||
2044 | } | ||
2045 | else | ||
2046 | { | 501 | { |
2047 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); | 502 | GNUNET_SCHEDULER_cancel (cc->task); |
2048 | GCP_add_path (dest_peer, path_duplicate (path), GNUNET_NO); | 503 | cc->task = NULL; |
2049 | GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO); | ||
2050 | (void) GCC_send_prebuilt_message (&msg->header, | ||
2051 | 0, | ||
2052 | zero, | ||
2053 | c, | ||
2054 | GNUNET_YES, GNUNET_YES, | ||
2055 | NULL, NULL); | ||
2056 | } | 504 | } |
2057 | path_destroy (path); | 505 | cc->metrics.age = GNUNET_TIME_absolute_get (); |
2058 | GCC_check_connections (); | 506 | update_state (cc, |
507 | CADET_CONNECTION_READY, | ||
508 | cc->mqm_ready); | ||
509 | if ( (NULL == cc->keepalive_qe) && | ||
510 | (GNUNET_YES == cc->mqm_ready) && | ||
511 | (NULL == cc->task) ) | ||
512 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
513 | &send_keepalive, | ||
514 | cc); | ||
2059 | } | 515 | } |
2060 | 516 | ||
2061 | 517 | ||
2062 | /** | 518 | /** |
2063 | * Handler for connection confirmations. | 519 | * Handle KX message. |
2064 | * | 520 | * |
2065 | * @param peer Message sender (neighbor). | 521 | * @param cc connection that received encrypted message |
2066 | * @param msg Message itself. | 522 | * @param msg the key exchange message |
2067 | */ | 523 | */ |
2068 | void | 524 | void |
2069 | GCC_handle_confirm (struct CadetPeer *peer, | 525 | GCC_handle_kx (struct CadetConnection *cc, |
2070 | const struct GNUNET_CADET_ConnectionCreateAckMessage *msg) | 526 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) |
2071 | { | 527 | { |
2072 | static struct CadetEncryptedMessageIdentifier zero; | 528 | if (CADET_CONNECTION_SENT == cc->state) |
2073 | struct CadetConnection *c; | ||
2074 | enum CadetConnectionState oldstate; | ||
2075 | int fwd; | ||
2076 | |||
2077 | GCC_check_connections (); | ||
2078 | log_message (&msg->header, peer, &msg->cid); | ||
2079 | c = connection_get (&msg->cid); | ||
2080 | if (NULL == c) | ||
2081 | { | ||
2082 | GNUNET_STATISTICS_update (stats, "# control on unknown connection", | ||
2083 | 1, GNUNET_NO); | ||
2084 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2085 | " don't know the connection!\n"); | ||
2086 | send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); | ||
2087 | GCC_check_connections (); | ||
2088 | return; | ||
2089 | } | ||
2090 | if (GNUNET_NO != c->destroy) | ||
2091 | { | 529 | { |
2092 | GNUNET_assert (CADET_CONNECTION_DESTROYED == c->state); | 530 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, |
2093 | GNUNET_STATISTICS_update (stats, "# control on dying connection", | 531 | clearly something is working, so pretend we got an ACK. */ |
2094 | 1, GNUNET_NO); | ||
2095 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 532 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2096 | "connection %s being destroyed, ignoring confirm\n", | 533 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", |
2097 | GCC_2s (c)); | 534 | GCC_2s (cc)); |
2098 | GCC_check_connections (); | 535 | GCC_handle_connection_create_ack (cc); |
2099 | return; | ||
2100 | } | ||
2101 | |||
2102 | oldstate = c->state; | ||
2103 | LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GCP_2s (peer)); | ||
2104 | if (get_next_hop (c) == peer) | ||
2105 | { | ||
2106 | LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n"); | ||
2107 | fwd = GNUNET_NO; | ||
2108 | if (CADET_CONNECTION_SENT == oldstate) | ||
2109 | connection_change_state (c, CADET_CONNECTION_ACK); | ||
2110 | } | ||
2111 | else if (get_prev_hop (c) == peer) | ||
2112 | { | ||
2113 | LOG (GNUNET_ERROR_TYPE_DEBUG, " FINAL ACK\n"); | ||
2114 | fwd = GNUNET_YES; | ||
2115 | connection_change_state (c, CADET_CONNECTION_READY); | ||
2116 | } | ||
2117 | else | ||
2118 | { | ||
2119 | GNUNET_STATISTICS_update (stats, "# control on connection from wrong peer", | ||
2120 | 1, GNUNET_NO); | ||
2121 | GNUNET_break_op (0); | ||
2122 | return; | ||
2123 | } | ||
2124 | |||
2125 | connection_reset_timeout (c, fwd); | ||
2126 | |||
2127 | GNUNET_assert (NULL != c->path); | ||
2128 | GCP_add_path_to_all (c->path, GNUNET_YES); | ||
2129 | |||
2130 | /* Message for us as creator? */ | ||
2131 | if (GNUNET_YES == GCC_is_origin (c, GNUNET_YES)) | ||
2132 | { | ||
2133 | if (GNUNET_NO != fwd) | ||
2134 | { | ||
2135 | GNUNET_break (0); | ||
2136 | return; | ||
2137 | } | ||
2138 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n"); | ||
2139 | |||
2140 | /* If just created, cancel the short timeout and start a long one */ | ||
2141 | if (CADET_CONNECTION_SENT == oldstate) | ||
2142 | { | ||
2143 | c->create_retry = 1; | ||
2144 | connection_reset_timeout (c, GNUNET_YES); | ||
2145 | } | ||
2146 | |||
2147 | /* Change connection state, send ACK */ | ||
2148 | connection_change_state (c, CADET_CONNECTION_READY); | ||
2149 | send_connection_ack (c, GNUNET_YES); | ||
2150 | |||
2151 | /* Change tunnel state, trigger KX */ | ||
2152 | if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t)) | ||
2153 | GCT_change_cstate (c->t, CADET_TUNNEL_READY); | ||
2154 | GCC_check_connections (); | ||
2155 | return; | ||
2156 | } | ||
2157 | |||
2158 | /* Message for us as destination? */ | ||
2159 | if (GCC_is_terminal (c, GNUNET_YES)) | ||
2160 | { | ||
2161 | if (GNUNET_YES != fwd) | ||
2162 | { | ||
2163 | GNUNET_break (0); | ||
2164 | return; | ||
2165 | } | ||
2166 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n"); | ||
2167 | |||
2168 | /* If just created, cancel the short timeout and start a long one */ | ||
2169 | if (CADET_CONNECTION_ACK == oldstate) | ||
2170 | connection_reset_timeout (c, GNUNET_NO); | ||
2171 | |||
2172 | /* Change tunnel state */ | ||
2173 | if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t)) | ||
2174 | GCT_change_cstate (c->t, CADET_TUNNEL_READY); | ||
2175 | GCC_check_connections (); | ||
2176 | } | 536 | } |
2177 | else | 537 | GCT_handle_kx (cc->ct, |
2178 | { | 538 | msg); |
2179 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); | ||
2180 | (void) GCC_send_prebuilt_message (&msg->header, 0, | ||
2181 | zero, | ||
2182 | c, | ||
2183 | fwd, | ||
2184 | GNUNET_YES, NULL, NULL); | ||
2185 | } | ||
2186 | GCC_check_connections (); | ||
2187 | } | 539 | } |
2188 | 540 | ||
2189 | 541 | ||
2190 | /** | 542 | /** |
2191 | * Handler for notifications of broken connections. | 543 | * Handle KX_AUTH message. |
2192 | * | 544 | * |
2193 | * @param peer Message sender (neighbor). | 545 | * @param cc connection that received encrypted message |
2194 | * @param msg Message itself. | 546 | * @param msg the key exchange message |
2195 | */ | 547 | */ |
2196 | void | 548 | void |
2197 | GCC_handle_broken (struct CadetPeer *peer, | 549 | GCC_handle_kx_auth (struct CadetConnection *cc, |
2198 | const struct GNUNET_CADET_ConnectionBrokenMessage *msg) | 550 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg) |
2199 | { | 551 | { |
2200 | static struct CadetEncryptedMessageIdentifier zero; | 552 | if (CADET_CONNECTION_SENT == cc->state) |
2201 | struct CadetConnection *c; | ||
2202 | struct CadetTunnel *t; | ||
2203 | int fwd; | ||
2204 | |||
2205 | GCC_check_connections (); | ||
2206 | log_message (&msg->header, peer, &msg->cid); | ||
2207 | LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer1)); | ||
2208 | LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer2)); | ||
2209 | c = connection_get (&msg->cid); | ||
2210 | if (NULL == c) | ||
2211 | { | ||
2212 | LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n"); | ||
2213 | GNUNET_STATISTICS_update (stats, "# duplicate CONNECTION_BROKEN", | ||
2214 | 1, GNUNET_NO); | ||
2215 | GCC_check_connections (); | ||
2216 | return; | ||
2217 | } | ||
2218 | |||
2219 | t = c->t; | ||
2220 | |||
2221 | fwd = is_fwd (c, peer); | ||
2222 | if (GNUNET_SYSERR == fwd) | ||
2223 | { | ||
2224 | GNUNET_break_op (0); | ||
2225 | GCC_check_connections (); | ||
2226 | return; | ||
2227 | } | ||
2228 | mark_destroyed (c); | ||
2229 | if (GCC_is_terminal (c, fwd)) | ||
2230 | { | ||
2231 | struct CadetPeer *endpoint; | ||
2232 | |||
2233 | if (NULL == t) | ||
2234 | { | ||
2235 | /* A terminal connection should not have 't' set to NULL. */ | ||
2236 | GNUNET_break (0); | ||
2237 | GCC_debug (c, GNUNET_ERROR_TYPE_ERROR); | ||
2238 | return; | ||
2239 | } | ||
2240 | endpoint = GCP_get_short (c->path->peers[c->path->length - 1], GNUNET_YES); | ||
2241 | if (2 < c->path->length) | ||
2242 | path_invalidate (c->path); | ||
2243 | GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2); | ||
2244 | |||
2245 | connection_change_state (c, CADET_CONNECTION_BROKEN); | ||
2246 | GCT_remove_connection (t, c); | ||
2247 | c->t = NULL; | ||
2248 | |||
2249 | GCC_destroy (c); | ||
2250 | } | ||
2251 | else | ||
2252 | { | 553 | { |
2253 | (void) GCC_send_prebuilt_message (&msg->header, 0, | 554 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, |
2254 | zero, c, fwd, | 555 | clearly something is working, so pretend we got an ACK. */ |
2255 | GNUNET_YES, NULL, NULL); | 556 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2256 | connection_cancel_queues (c, !fwd); | 557 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", |
558 | GCC_2s (cc)); | ||
559 | GCC_handle_connection_create_ack (cc); | ||
2257 | } | 560 | } |
2258 | GCC_check_connections (); | 561 | GCT_handle_kx_auth (cc->ct, |
2259 | return; | 562 | msg); |
2260 | } | 563 | } |
2261 | 564 | ||
2262 | 565 | ||
2263 | /** | 566 | /** |
2264 | * Handler for notifications of destroyed connections. | 567 | * Handle encrypted message. |
2265 | * | 568 | * |
2266 | * @param peer Message sender (neighbor). | 569 | * @param cc connection that received encrypted message |
2267 | * @param msg Message itself. | 570 | * @param msg the encrypted message to decrypt |
2268 | */ | 571 | */ |
2269 | void | 572 | void |
2270 | GCC_handle_destroy (struct CadetPeer *peer, | 573 | GCC_handle_encrypted (struct CadetConnection *cc, |
2271 | const struct GNUNET_CADET_ConnectionDestroyMessage *msg) | 574 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) |
2272 | { | 575 | { |
2273 | static struct CadetEncryptedMessageIdentifier zero; | 576 | if (CADET_CONNECTION_SENT == cc->state) |
2274 | struct CadetConnection *c; | ||
2275 | int fwd; | ||
2276 | |||
2277 | GCC_check_connections (); | ||
2278 | log_message (&msg->header, peer, &msg->cid); | ||
2279 | c = connection_get (&msg->cid); | ||
2280 | if (NULL == c) | ||
2281 | { | 577 | { |
2282 | /* Probably already got the message from another path, | 578 | /* We didn't get the CREATE_ACK, but instead got payload. That's fine, |
2283 | * destroyed the tunnel and retransmitted to children. | 579 | clearly something is working, so pretend we got an ACK. */ |
2284 | * Safe to ignore. | ||
2285 | */ | ||
2286 | GNUNET_STATISTICS_update (stats, | ||
2287 | "# control on unknown connection", | ||
2288 | 1, GNUNET_NO); | ||
2289 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 580 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2290 | " connection unknown destroyed: previously destroyed?\n"); | 581 | "Faking connection ACK for %s due to ENCRYPTED payload\n", |
2291 | GCC_check_connections (); | 582 | GCC_2s (cc)); |
2292 | return; | 583 | GCC_handle_connection_create_ack (cc); |
2293 | } | ||
2294 | |||
2295 | fwd = is_fwd (c, peer); | ||
2296 | if (GNUNET_SYSERR == fwd) | ||
2297 | { | ||
2298 | GNUNET_break_op (0); | ||
2299 | GCC_check_connections (); | ||
2300 | return; | ||
2301 | } | ||
2302 | |||
2303 | if (GNUNET_NO == GCC_is_terminal (c, fwd)) | ||
2304 | { | ||
2305 | (void) GCC_send_prebuilt_message (&msg->header, 0, | ||
2306 | zero, c, fwd, | ||
2307 | GNUNET_YES, NULL, NULL); | ||
2308 | } | 584 | } |
2309 | else if (0 == c->pending_messages) | 585 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); |
2310 | { | 586 | GCT_handle_encrypted (cc->ct, |
2311 | LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n"); | 587 | msg); |
2312 | GCC_destroy (c); | ||
2313 | GCC_check_connections (); | ||
2314 | return; | ||
2315 | } | ||
2316 | mark_destroyed (c); | ||
2317 | if (NULL != c->t) | ||
2318 | { | ||
2319 | GCT_remove_connection (c->t, c); | ||
2320 | c->t = NULL; | ||
2321 | } | ||
2322 | GCC_check_connections (); | ||
2323 | return; | ||
2324 | } | 588 | } |
2325 | 589 | ||
2326 | 590 | ||
2327 | /** | 591 | /** |
2328 | * Handler for cadet network traffic hop-by-hop acks. | 592 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the |
593 | * first hop. | ||
2329 | * | 594 | * |
2330 | * @param peer Message sender (neighbor). | 595 | * @param cls the `struct CadetConnection` to initiate |
2331 | * @param msg Message itself. | ||
2332 | */ | 596 | */ |
2333 | void | 597 | static void |
2334 | GCC_handle_ack (struct CadetPeer *peer, | 598 | send_create (void *cls) |
2335 | const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg) | 599 | { |
2336 | { | 600 | struct CadetConnection *cc = cls; |
2337 | struct CadetConnection *c; | 601 | struct GNUNET_CADET_ConnectionCreateMessage *create_msg; |
2338 | struct CadetFlowControl *fc; | 602 | struct GNUNET_PeerIdentity *pids; |
2339 | struct CadetEncryptedMessageIdentifier ack; | 603 | struct GNUNET_MQ_Envelope *env; |
2340 | int fwd; | 604 | unsigned int path_length; |
2341 | 605 | ||
2342 | GCC_check_connections (); | 606 | cc->task = NULL; |
2343 | log_message (&msg->header, peer, &msg->cid); | 607 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); |
2344 | c = connection_get (&msg->cid); | 608 | path_length = GCPP_get_length (cc->path); |
2345 | if (NULL == c) | 609 | env = GNUNET_MQ_msg_extra (create_msg, |
2346 | { | 610 | (1 + path_length) * sizeof (struct GNUNET_PeerIdentity), |
2347 | GNUNET_STATISTICS_update (stats, | 611 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); |
2348 | "# ack on unknown connection", | 612 | create_msg->options = htonl ((uint32_t) cc->options); |
2349 | 1, | 613 | create_msg->cid = cc->cid; |
2350 | GNUNET_NO); | 614 | pids = (struct GNUNET_PeerIdentity *) &create_msg[1]; |
2351 | send_broken_unknown (&msg->cid, | 615 | pids[0] = my_full_id; |
2352 | &my_full_id, | 616 | for (unsigned int i=0;i<path_length;i++) |
2353 | NULL, | 617 | pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path, |
2354 | peer); | 618 | i)); |
2355 | GCC_check_connections (); | 619 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2356 | return; | 620 | "Sending CADET_CONNECTION_CREATE message for %s\n", |
2357 | } | 621 | GCC_2s (cc)); |
2358 | 622 | cc->env = env; | |
2359 | /* Is this a forward or backward ACK? */ | 623 | update_state (cc, |
2360 | if (get_next_hop (c) == peer) | 624 | CADET_CONNECTION_SENT, |
2361 | { | 625 | GNUNET_NO); |
2362 | fc = &c->fwd_fc; | 626 | GCP_send (cc->mq_man, |
2363 | fwd = GNUNET_YES; | 627 | env); |
2364 | } | ||
2365 | else if (get_prev_hop (c) == peer) | ||
2366 | { | ||
2367 | fc = &c->bck_fc; | ||
2368 | fwd = GNUNET_NO; | ||
2369 | } | ||
2370 | else | ||
2371 | { | ||
2372 | GNUNET_break_op (0); | ||
2373 | return; | ||
2374 | } | ||
2375 | |||
2376 | ack = msg->cemi_max; | ||
2377 | LOG (GNUNET_ERROR_TYPE_DEBUG, " %s ACK %u (was %u)\n", | ||
2378 | GC_f2s (fwd), | ||
2379 | ntohl (ack.pid), | ||
2380 | ntohl (fc->last_ack_recv.pid)); | ||
2381 | if (GC_is_pid_bigger (ntohl (ack.pid), | ||
2382 | ntohl (fc->last_ack_recv.pid))) | ||
2383 | fc->last_ack_recv = ack; | ||
2384 | |||
2385 | /* Cancel polling if the ACK is big enough. */ | ||
2386 | if ( (NULL != fc->poll_task) & | ||
2387 | GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid), | ||
2388 | ntohl (fc->last_pid_sent.pid))) | ||
2389 | { | ||
2390 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n"); | ||
2391 | GNUNET_SCHEDULER_cancel (fc->poll_task); | ||
2392 | fc->poll_task = NULL; | ||
2393 | fc->poll_time = GNUNET_TIME_UNIT_SECONDS; | ||
2394 | } | ||
2395 | |||
2396 | GCC_check_connections (); | ||
2397 | } | 628 | } |
2398 | 629 | ||
2399 | 630 | ||
2400 | /** | 631 | /** |
2401 | * Handler for cadet network traffic hop-by-hop data counter polls. | 632 | * Send a CREATE_ACK message towards the origin. |
2402 | * | 633 | * |
2403 | * @param peer Message sender (neighbor). | 634 | * @param cls the `struct CadetConnection` to initiate |
2404 | * @param msg Message itself. | ||
2405 | */ | 635 | */ |
2406 | void | 636 | static void |
2407 | GCC_handle_poll (struct CadetPeer *peer, | 637 | send_create_ack (void *cls) |
2408 | const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg) | ||
2409 | { | 638 | { |
2410 | struct CadetConnection *c; | 639 | struct CadetConnection *cc = cls; |
2411 | struct CadetFlowControl *fc; | 640 | struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg; |
2412 | struct CadetEncryptedMessageIdentifier pid; | 641 | struct GNUNET_MQ_Envelope *env; |
2413 | int fwd; | ||
2414 | |||
2415 | GCC_check_connections (); | ||
2416 | log_message (&msg->header, peer, &msg->cid); | ||
2417 | c = connection_get (&msg->cid); | ||
2418 | if (NULL == c) | ||
2419 | { | ||
2420 | GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1, | ||
2421 | GNUNET_NO); | ||
2422 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2423 | "POLL message on unknown connection %s!\n", | ||
2424 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
2425 | send_broken_unknown (&msg->cid, | ||
2426 | &my_full_id, | ||
2427 | NULL, | ||
2428 | peer); | ||
2429 | GCC_check_connections (); | ||
2430 | return; | ||
2431 | } | ||
2432 | |||
2433 | /* Is this a forward or backward ACK? | ||
2434 | * Note: a poll should never be needed in a loopback case, | ||
2435 | * since there is no possiblility of packet loss there, so | ||
2436 | * this way of discerining FWD/BCK should not be a problem. | ||
2437 | */ | ||
2438 | if (get_next_hop (c) == peer) | ||
2439 | { | ||
2440 | LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); | ||
2441 | fc = &c->fwd_fc; | ||
2442 | } | ||
2443 | else if (get_prev_hop (c) == peer) | ||
2444 | { | ||
2445 | LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); | ||
2446 | fc = &c->bck_fc; | ||
2447 | } | ||
2448 | else | ||
2449 | { | ||
2450 | GNUNET_break_op (0); | ||
2451 | return; | ||
2452 | } | ||
2453 | 642 | ||
2454 | pid = msg->cemi; | 643 | cc->task = NULL; |
644 | GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state); | ||
2455 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 645 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2456 | " PID %u, OLD %u\n", | 646 | "Sending CONNECTION_CREATE_ACK message for %s\n", |
2457 | ntohl (pid.pid), | 647 | GCC_2s (cc)); |
2458 | ntohl (fc->last_pid_recv.pid)); | 648 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); |
2459 | fc->last_pid_recv = pid; | 649 | env = GNUNET_MQ_msg (ack_msg, |
2460 | fwd = fc == &c->bck_fc; | 650 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK); |
2461 | GCC_send_ack (c, fwd, GNUNET_YES); | 651 | ack_msg->cid = cc->cid; |
2462 | GCC_check_connections (); | 652 | cc->env = env; |
653 | update_state (cc, | ||
654 | CADET_CONNECTION_READY, | ||
655 | GNUNET_NO); | ||
656 | GCP_send (cc->mq_man, | ||
657 | env); | ||
2463 | } | 658 | } |
2464 | 659 | ||
2465 | 660 | ||
2466 | /** | 661 | /** |
2467 | * Check the message against internal state and test if it goes FWD or BCK. | 662 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a |
2468 | * | 663 | * connection that we already have. Either our ACK got lost |
2469 | * Updates the PID, state and timeout values for the connection. | 664 | * or something is fishy. Consider retransmitting the ACK. |
2470 | * | ||
2471 | * @param message Message to check. It must belong to an existing connection. | ||
2472 | * @param cid Connection ID (even if @a c is NULL, the ID is still needed). | ||
2473 | * @param c Connection this message should belong. If NULL, check fails. | ||
2474 | * @param sender Neighbor that sent the message. | ||
2475 | * | 665 | * |
2476 | * @return #GNUNET_YES if the message goes FWD. | 666 | * @param cc connection that got the duplicate CREATE |
2477 | * #GNUNET_NO if it goes BCK. | ||
2478 | * #GNUNET_SYSERR if there is an error (unauthorized sender, ...). | ||
2479 | */ | 667 | */ |
2480 | static int | 668 | void |
2481 | check_message (const struct GNUNET_MessageHeader *message, | 669 | GCC_handle_duplicate_create (struct CadetConnection *cc) |
2482 | const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid, | ||
2483 | struct CadetConnection *c, | ||
2484 | struct CadetPeer *sender, | ||
2485 | struct CadetEncryptedMessageIdentifier pid) | ||
2486 | { | 670 | { |
2487 | struct CadetFlowControl *fc; | 671 | if (GNUNET_YES == cc->mqm_ready) |
2488 | struct CadetPeer *hop; | ||
2489 | int fwd; | ||
2490 | uint16_t type; | ||
2491 | |||
2492 | /* Check connection */ | ||
2493 | if (NULL == c) | ||
2494 | { | 672 | { |
2495 | GNUNET_STATISTICS_update (stats, | ||
2496 | "# unknown connection", | ||
2497 | 1, GNUNET_NO); | ||
2498 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 673 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2499 | "%s on unknown connection %s\n", | 674 | "Got duplicate CREATE for %s, scheduling another ACK (%s)\n", |
2500 | GC_m2s (ntohs (message->type)), | 675 | GCC_2s (cc), |
2501 | GNUNET_sh2s (&cid->connection_of_tunnel)); | 676 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); |
2502 | GNUNET_break_op (0); | 677 | /* Revert back to the state of having only received the 'CREATE', |
2503 | send_broken_unknown (cid, | 678 | and immediately proceed to send the CREATE_ACK. */ |
2504 | &my_full_id, | 679 | update_state (cc, |
2505 | NULL, | 680 | CADET_CONNECTION_CREATE_RECEIVED, |
2506 | sender); | 681 | cc->mqm_ready); |
2507 | return GNUNET_SYSERR; | 682 | if (NULL != cc->task) |
2508 | } | 683 | GNUNET_SCHEDULER_cancel (cc->task); |
2509 | 684 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | |
2510 | /* Check if origin is as expected */ | 685 | cc); |
2511 | hop = get_prev_hop (c); | ||
2512 | if (sender == hop) | ||
2513 | { | ||
2514 | fwd = GNUNET_YES; | ||
2515 | } | 686 | } |
2516 | else | 687 | else |
2517 | { | 688 | { |
2518 | hop = get_next_hop (c); | 689 | /* We are currently sending something else back, which |
2519 | GNUNET_break (hop == c->next_peer); | 690 | can only be an ACK or payload, either of which would |
2520 | if (sender == hop) | 691 | do. So actually no need to do anything. */ |
2521 | { | 692 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2522 | fwd = GNUNET_NO; | 693 | "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n", |
2523 | } | 694 | GCC_2s (cc)); |
2524 | else | ||
2525 | { | ||
2526 | /* Unexpected peer sending traffic on a connection. */ | ||
2527 | GNUNET_break_op (0); | ||
2528 | return GNUNET_SYSERR; | ||
2529 | } | ||
2530 | } | ||
2531 | |||
2532 | /* Check PID for payload messages */ | ||
2533 | type = ntohs (message->type); | ||
2534 | if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type) | ||
2535 | { | ||
2536 | fc = fwd ? &c->bck_fc : &c->fwd_fc; | ||
2537 | LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected in interval [%u,%u])\n", | ||
2538 | ntohl (pid.pid), | ||
2539 | ntohl (fc->last_pid_recv.pid) + 1, | ||
2540 | ntohl (fc->last_ack_sent.pid)); | ||
2541 | if (GC_is_pid_bigger (ntohl (pid.pid), | ||
2542 | ntohl (fc->last_ack_sent.pid))) | ||
2543 | { | ||
2544 | GNUNET_STATISTICS_update (stats, | ||
2545 | "# unsolicited message", | ||
2546 | 1, | ||
2547 | GNUNET_NO); | ||
2548 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2549 | "Received PID %u, (prev %u), ACK %u\n", | ||
2550 | pid, fc->last_pid_recv, fc->last_ack_sent); | ||
2551 | return GNUNET_SYSERR; | ||
2552 | } | ||
2553 | if (GC_is_pid_bigger (ntohl (pid.pid), | ||
2554 | ntohl (fc->last_pid_recv.pid))) | ||
2555 | { | ||
2556 | unsigned int delta; | ||
2557 | |||
2558 | delta = ntohl (pid.pid) - ntohl (fc->last_pid_recv.pid); | ||
2559 | fc->last_pid_recv = pid; | ||
2560 | fc->recv_bitmap <<= delta; | ||
2561 | fc->recv_bitmap |= 1; | ||
2562 | } | ||
2563 | else | ||
2564 | { | ||
2565 | GNUNET_STATISTICS_update (stats, | ||
2566 | "# out of order PID", | ||
2567 | 1, | ||
2568 | GNUNET_NO); | ||
2569 | if (GNUNET_NO == is_ooo_ok (fc->last_pid_recv, | ||
2570 | pid, | ||
2571 | fc->recv_bitmap)) | ||
2572 | { | ||
2573 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2574 | "PID %u unexpected (%u+), dropping!\n", | ||
2575 | ntohl (pid.pid), | ||
2576 | ntohl (fc->last_pid_recv.pid) - 31); | ||
2577 | return GNUNET_SYSERR; | ||
2578 | } | ||
2579 | fc->recv_bitmap |= get_recv_bitmask (fc->last_pid_recv, | ||
2580 | pid); | ||
2581 | } | ||
2582 | } | ||
2583 | |||
2584 | /* Count as connection confirmation. */ | ||
2585 | if ( (CADET_CONNECTION_SENT == c->state) || | ||
2586 | (CADET_CONNECTION_ACK == c->state) ) | ||
2587 | { | ||
2588 | connection_change_state (c, CADET_CONNECTION_READY); | ||
2589 | if (NULL != c->t) | ||
2590 | { | ||
2591 | if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t)) | ||
2592 | GCT_change_cstate (c->t, CADET_TUNNEL_READY); | ||
2593 | } | ||
2594 | } | 695 | } |
2595 | connection_reset_timeout (c, fwd); | ||
2596 | |||
2597 | return fwd; | ||
2598 | } | 696 | } |
2599 | 697 | ||
2600 | 698 | ||
2601 | /** | 699 | /** |
2602 | * Handler for key exchange traffic (Axolotl KX). | 700 | * There has been a change in the message queue existence for our |
701 | * peer at the first hop. Adjust accordingly. | ||
2603 | * | 702 | * |
2604 | * @param peer Message sender (neighbor). | 703 | * @param cls the `struct CadetConnection` |
2605 | * @param msg Message itself. | 704 | * @param available #GNUNET_YES if sending is now possible, |
705 | * #GNUNET_NO if sending is no longer possible | ||
706 | * #GNUNET_SYSERR if sending is no longer possible | ||
707 | * and the last envelope was discarded | ||
2606 | */ | 708 | */ |
2607 | void | 709 | static void |
2608 | GCC_handle_kx (struct CadetPeer *peer, | 710 | manage_first_hop_mq (void *cls, |
2609 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | 711 | int available) |
2610 | { | 712 | { |
2611 | static struct CadetEncryptedMessageIdentifier zero; | 713 | struct CadetConnection *cc = cls; |
2612 | const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid; | ||
2613 | struct CadetConnection *c; | ||
2614 | int fwd; | ||
2615 | |||
2616 | GCC_check_connections (); | ||
2617 | cid = &msg->cid; | ||
2618 | log_message (&msg->header, peer, cid); | ||
2619 | |||
2620 | c = connection_get (cid); | ||
2621 | fwd = check_message (&msg->header, | ||
2622 | cid, | ||
2623 | c, | ||
2624 | peer, | ||
2625 | zero); | ||
2626 | |||
2627 | /* If something went wrong, discard message. */ | ||
2628 | if (GNUNET_SYSERR == fwd) | ||
2629 | { | ||
2630 | GNUNET_break_op (0); | ||
2631 | GCC_check_connections (); | ||
2632 | return; | ||
2633 | } | ||
2634 | 714 | ||
2635 | /* Is this message for us? */ | 715 | if (GNUNET_YES != available) |
2636 | if (GCC_is_terminal (c, fwd)) | ||
2637 | { | 716 | { |
2638 | LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); | 717 | /* Connection is down, for now... */ |
2639 | GNUNET_STATISTICS_update (stats, "# received KX", 1, GNUNET_NO); | 718 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2640 | if (NULL == c->t) | 719 | "Core MQ for %s went down\n", |
720 | GCC_2s (cc)); | ||
721 | update_state (cc, | ||
722 | CADET_CONNECTION_NEW, | ||
723 | GNUNET_NO); | ||
724 | cc->retry_delay = GNUNET_TIME_UNIT_ZERO; | ||
725 | if (NULL != cc->task) | ||
2641 | { | 726 | { |
2642 | GNUNET_break (0); | 727 | GNUNET_SCHEDULER_cancel (cc->task); |
2643 | return; | 728 | cc->task = NULL; |
2644 | } | 729 | } |
2645 | GCT_handle_kx (c->t, msg); | ||
2646 | GCC_check_connections (); | ||
2647 | return; | ||
2648 | } | ||
2649 | |||
2650 | /* Message not for us: forward to next hop */ | ||
2651 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); | ||
2652 | GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); | ||
2653 | (void) GCC_send_prebuilt_message (&msg->header, 0, | ||
2654 | zero, c, fwd, | ||
2655 | GNUNET_NO, NULL, NULL); | ||
2656 | GCC_check_connections (); | ||
2657 | } | ||
2658 | |||
2659 | |||
2660 | /** | ||
2661 | * Handler for encrypted cadet network traffic (channel mgmt, data). | ||
2662 | * | ||
2663 | * @param peer Message sender (neighbor). | ||
2664 | * @param msg Message itself. | ||
2665 | */ | ||
2666 | void | ||
2667 | GCC_handle_encrypted (struct CadetPeer *peer, | ||
2668 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
2669 | { | ||
2670 | static struct CadetEncryptedMessageIdentifier zero; | ||
2671 | const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid; | ||
2672 | struct CadetConnection *c; | ||
2673 | struct CadetEncryptedMessageIdentifier pid; | ||
2674 | int fwd; | ||
2675 | |||
2676 | GCC_check_connections (); | ||
2677 | cid = &msg->cid; | ||
2678 | pid = msg->cemi; | ||
2679 | log_message (&msg->header, peer, cid); | ||
2680 | |||
2681 | c = connection_get (cid); | ||
2682 | fwd = check_message (&msg->header, | ||
2683 | cid, | ||
2684 | c, | ||
2685 | peer, | ||
2686 | pid); | ||
2687 | |||
2688 | /* If something went wrong, discard message. */ | ||
2689 | if (GNUNET_SYSERR == fwd) | ||
2690 | { | ||
2691 | GCC_check_connections (); | ||
2692 | return; | 730 | return; |
2693 | } | 731 | } |
2694 | 732 | ||
2695 | /* Is this message for us? */ | 733 | update_state (cc, |
2696 | if (GCC_is_terminal (c, fwd)) | 734 | cc->state, |
2697 | { | 735 | GNUNET_YES); |
2698 | GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO); | 736 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2699 | 737 | "Core MQ for %s became available in state %d\n", | |
2700 | if (NULL == c->t) | 738 | GCC_2s (cc), |
739 | cc->state); | ||
740 | switch (cc->state) | ||
741 | { | ||
742 | case CADET_CONNECTION_NEW: | ||
743 | /* Transmit immediately */ | ||
744 | cc->task = GNUNET_SCHEDULER_add_now (&send_create, | ||
745 | cc); | ||
746 | break; | ||
747 | case CADET_CONNECTION_SENDING_CREATE: | ||
748 | /* Should not be possible to be called in this state. */ | ||
749 | GNUNET_assert (0); | ||
750 | break; | ||
751 | case CADET_CONNECTION_SENT: | ||
752 | /* Retry a bit later... */ | ||
753 | cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay); | ||
754 | cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay, | ||
755 | &send_create, | ||
756 | cc); | ||
757 | break; | ||
758 | case CADET_CONNECTION_CREATE_RECEIVED: | ||
759 | /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */ | ||
760 | cc->metrics.age = GNUNET_TIME_absolute_get (); | ||
761 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | ||
762 | cc); | ||
763 | break; | ||
764 | case CADET_CONNECTION_READY: | ||
765 | if ( (NULL == cc->keepalive_qe) && | ||
766 | (GNUNET_YES == cc->mqm_ready) && | ||
767 | (NULL == cc->task) ) | ||
2701 | { | 768 | { |
2702 | GNUNET_break (GNUNET_NO != c->destroy); | 769 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2703 | return; | 770 | "Scheduling keepalive for %s in %s\n", |
771 | GCC_2s (cc), | ||
772 | GNUNET_STRINGS_relative_time_to_string (keepalive_period, | ||
773 | GNUNET_YES)); | ||
774 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
775 | &send_keepalive, | ||
776 | cc); | ||
2704 | } | 777 | } |
2705 | GCT_handle_encrypted (c->t, msg); | 778 | break; |
2706 | GCC_send_ack (c, fwd, GNUNET_NO); | ||
2707 | GCC_check_connections (); | ||
2708 | return; | ||
2709 | } | 779 | } |
2710 | |||
2711 | /* Message not for us: forward to next hop */ | ||
2712 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); | ||
2713 | GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); | ||
2714 | (void) GCC_send_prebuilt_message (&msg->header, 0, | ||
2715 | zero, c, fwd, | ||
2716 | GNUNET_NO, NULL, NULL); | ||
2717 | GCC_check_connections (); | ||
2718 | } | 780 | } |
2719 | 781 | ||
2720 | 782 | ||
2721 | /** | 783 | /** |
2722 | * Initialize the connections subsystem | 784 | * Create a connection to @a destination via @a path and notify @a cb |
785 | * whenever we are ready for more data. Shared logic independent of | ||
786 | * who is initiating the connection. | ||
2723 | * | 787 | * |
2724 | * @param c Configuration handle. | 788 | * @param destination where to go |
789 | * @param path which path to take (may not be the full path) | ||
790 | * @param off offset of @a destination on @a path | ||
791 | * @param options options for the connection | ||
792 | * @param ct which tunnel uses this connection | ||
793 | * @param init_state initial state for the connection | ||
794 | * @param ready_cb function to call when ready to transmit | ||
795 | * @param ready_cb_cls closure for @a cb | ||
796 | * @return handle to the connection | ||
2725 | */ | 797 | */ |
2726 | void | 798 | static struct CadetConnection * |
2727 | GCC_init (const struct GNUNET_CONFIGURATION_Handle *c) | 799 | connection_create (struct CadetPeer *destination, |
2728 | { | 800 | struct CadetPeerPath *path, |
2729 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); | 801 | unsigned int off, |
2730 | if (GNUNET_OK != | 802 | enum GNUNET_CADET_ChannelOption options, |
2731 | GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE", | 803 | struct CadetTConnection *ct, |
2732 | &max_msgs_queue)) | 804 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, |
2733 | { | 805 | enum CadetConnectionState init_state, |
2734 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | 806 | GCC_ReadyCallback ready_cb, |
2735 | "CADET", "MAX_MSGS_QUEUE", "MISSING"); | 807 | void *ready_cb_cls) |
2736 | GNUNET_SCHEDULER_shutdown (); | 808 | { |
2737 | return; | 809 | struct CadetConnection *cc; |
2738 | } | 810 | struct CadetPeer *first_hop; |
2739 | 811 | ||
2740 | if (GNUNET_OK != | 812 | cc = GNUNET_new (struct CadetConnection); |
2741 | GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS", | 813 | cc->options = options; |
2742 | &max_connections)) | 814 | cc->state = init_state; |
2743 | { | 815 | cc->ct = ct; |
2744 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | 816 | cc->cid = *cid; |
2745 | "CADET", "MAX_CONNECTIONS", "MISSING"); | ||
2746 | GNUNET_SCHEDULER_shutdown (); | ||
2747 | return; | ||
2748 | } | ||
2749 | |||
2750 | if (GNUNET_OK != | ||
2751 | GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME", | ||
2752 | &refresh_connection_time)) | ||
2753 | { | ||
2754 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | ||
2755 | "CADET", "REFRESH_CONNECTION_TIME", "MISSING"); | ||
2756 | GNUNET_SCHEDULER_shutdown (); | ||
2757 | return; | ||
2758 | } | ||
2759 | create_connection_time = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, | ||
2760 | refresh_connection_time); | ||
2761 | connections = GNUNET_CONTAINER_multishortmap_create (1024, | ||
2762 | GNUNET_YES); | ||
2763 | } | ||
2764 | |||
2765 | |||
2766 | /** | ||
2767 | * Destroy each connection on shutdown. | ||
2768 | * | ||
2769 | * @param cls Closure (unused). | ||
2770 | * @param key Current key code (CID, unused). | ||
2771 | * @param value Value in the hash map (`struct CadetConnection`) | ||
2772 | * | ||
2773 | * @return #GNUNET_YES, because we should continue to iterate | ||
2774 | */ | ||
2775 | static int | ||
2776 | shutdown_iterator (void *cls, | ||
2777 | const struct GNUNET_ShortHashCode *key, | ||
2778 | void *value) | ||
2779 | { | ||
2780 | struct CadetConnection *c = value; | ||
2781 | |||
2782 | c->state = CADET_CONNECTION_DESTROYED; | ||
2783 | GCC_destroy (c); | ||
2784 | return GNUNET_YES; | ||
2785 | } | ||
2786 | |||
2787 | |||
2788 | /** | ||
2789 | * Shut down the connections subsystem. | ||
2790 | */ | ||
2791 | void | ||
2792 | GCC_shutdown (void) | ||
2793 | { | ||
2794 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n"); | ||
2795 | GCC_check_connections (); | ||
2796 | GNUNET_CONTAINER_multishortmap_iterate (connections, | ||
2797 | &shutdown_iterator, | ||
2798 | NULL); | ||
2799 | GNUNET_CONTAINER_multishortmap_destroy (connections); | ||
2800 | connections = NULL; | ||
2801 | } | ||
2802 | |||
2803 | |||
2804 | /** | ||
2805 | * Create a connection. | ||
2806 | * | ||
2807 | * @param cid Connection ID (either created locally or imposed remotely). | ||
2808 | * @param t Tunnel this connection belongs to (or NULL for transit connections); | ||
2809 | * @param path Path this connection has to use (copy is made). | ||
2810 | * @param own_pos Own position in the @c path path. | ||
2811 | * | ||
2812 | * @return Newly created connection. | ||
2813 | * NULL in case of error: own id not in path, wrong neighbors, ... | ||
2814 | */ | ||
2815 | struct CadetConnection * | ||
2816 | GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
2817 | struct CadetTunnel *t, | ||
2818 | struct CadetPeerPath *path, | ||
2819 | unsigned int own_pos) | ||
2820 | { | ||
2821 | struct CadetConnection *c; | ||
2822 | struct CadetPeerPath *cpath; | ||
2823 | |||
2824 | GCC_check_connections (); | ||
2825 | cpath = path_duplicate (path); | ||
2826 | GNUNET_assert (NULL != cpath); | ||
2827 | c = GNUNET_new (struct CadetConnection); | ||
2828 | c->id = *cid; | ||
2829 | GNUNET_assert (GNUNET_OK == | 817 | GNUNET_assert (GNUNET_OK == |
2830 | GNUNET_CONTAINER_multishortmap_put (connections, | 818 | GNUNET_CONTAINER_multishortmap_put (connections, |
2831 | &c->id.connection_of_tunnel, | 819 | &GCC_get_id (cc)->connection_of_tunnel, |
2832 | c, | 820 | cc, |
2833 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 821 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
2834 | fc_init (&c->fwd_fc); | 822 | cc->ready_cb = ready_cb; |
2835 | fc_init (&c->bck_fc); | 823 | cc->ready_cb_cls = ready_cb_cls; |
2836 | c->fwd_fc.c = c; | 824 | cc->path = path; |
2837 | c->bck_fc.c = c; | 825 | cc->off = off; |
2838 | |||
2839 | c->t = t; | ||
2840 | GNUNET_assert (own_pos <= cpath->length - 1); | ||
2841 | c->own_pos = own_pos; | ||
2842 | c->path = cpath; | ||
2843 | cpath->c = c; | ||
2844 | if (GNUNET_OK != register_neighbors (c)) | ||
2845 | { | ||
2846 | if (0 == own_pos) | ||
2847 | { | ||
2848 | /* We were the origin of this request, this means we have invalid | ||
2849 | * info about the paths to reach the destination. We must invalidate | ||
2850 | * the *original* path to avoid trying it again in the next minute. | ||
2851 | */ | ||
2852 | if (2 < path->length) | ||
2853 | path_invalidate (path); | ||
2854 | else | ||
2855 | { | ||
2856 | GNUNET_break (0); | ||
2857 | GCT_debug(t, GNUNET_ERROR_TYPE_WARNING); | ||
2858 | } | ||
2859 | c->t = NULL; | ||
2860 | } | ||
2861 | path_destroy (c->path); | ||
2862 | c->path = NULL; | ||
2863 | GCC_destroy (c); | ||
2864 | return NULL; | ||
2865 | } | ||
2866 | LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c)); | ||
2867 | GCC_check_connections (); | ||
2868 | return c; | ||
2869 | } | ||
2870 | |||
2871 | |||
2872 | /** | ||
2873 | * Connection is no longer needed: destroy it. | ||
2874 | * | ||
2875 | * Cancels all pending traffic (including possible DESTROY messages), all | ||
2876 | * maintenance tasks and removes the connection from neighbor peers and tunnel. | ||
2877 | * | ||
2878 | * @param c Connection to destroy. | ||
2879 | */ | ||
2880 | void | ||
2881 | GCC_destroy (struct CadetConnection *c) | ||
2882 | { | ||
2883 | GCC_check_connections (); | ||
2884 | if (NULL == c) | ||
2885 | { | ||
2886 | GNUNET_break (0); | ||
2887 | return; | ||
2888 | } | ||
2889 | |||
2890 | if (2 == c->destroy) /* cancel queues -> GCP_queue_cancel -> q_destroy -> */ | ||
2891 | return; /* -> message_sent -> GCC_destroy. Don't loop. */ | ||
2892 | c->destroy = 2; | ||
2893 | |||
2894 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2895 | "destroying connection %s\n", | ||
2896 | GCC_2s (c)); | ||
2897 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2898 | " fc's f: %p, b: %p\n", | ||
2899 | &c->fwd_fc, &c->bck_fc); | ||
2900 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2901 | " fc tasks f: %u, b: %u\n", | ||
2902 | c->fwd_fc.poll_task, | ||
2903 | c->bck_fc.poll_task); | ||
2904 | |||
2905 | /* Cancel all traffic */ | ||
2906 | if (NULL != c->path) | ||
2907 | { | ||
2908 | connection_cancel_queues (c, GNUNET_YES); | ||
2909 | connection_cancel_queues (c, GNUNET_NO); | ||
2910 | if (NULL != c->maintenance_q) | ||
2911 | { | ||
2912 | GCP_send_cancel (c->maintenance_q); | ||
2913 | c->maintenance_q = NULL; | ||
2914 | } | ||
2915 | } | ||
2916 | unregister_neighbors (c); | ||
2917 | path_destroy (c->path); | ||
2918 | c->path = NULL; | ||
2919 | |||
2920 | /* Delete from tunnel */ | ||
2921 | if (NULL != c->t) | ||
2922 | GCT_remove_connection (c->t, c); | ||
2923 | |||
2924 | if (NULL != c->check_duplicates_task) | ||
2925 | GNUNET_SCHEDULER_cancel (c->check_duplicates_task); | ||
2926 | if (NULL != c->fwd_maintenance_task) | ||
2927 | GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task); | ||
2928 | if (NULL != c->bck_maintenance_task) | ||
2929 | GNUNET_SCHEDULER_cancel (c->bck_maintenance_task); | ||
2930 | |||
2931 | if (GNUNET_NO == c->was_removed) | ||
2932 | { | ||
2933 | GNUNET_break (GNUNET_YES == | ||
2934 | GNUNET_CONTAINER_multishortmap_remove (connections, | ||
2935 | &c->id.connection_of_tunnel, | ||
2936 | c)); | ||
2937 | } | ||
2938 | GNUNET_STATISTICS_update (stats, | ||
2939 | "# connections", | ||
2940 | -1, | ||
2941 | GNUNET_NO); | ||
2942 | GNUNET_free (c); | ||
2943 | GCC_check_connections (); | ||
2944 | } | ||
2945 | |||
2946 | |||
2947 | /** | ||
2948 | * Get the connection ID. | ||
2949 | * | ||
2950 | * @param c Connection to get the ID from. | ||
2951 | * | ||
2952 | * @return ID of the connection. | ||
2953 | */ | ||
2954 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * | ||
2955 | GCC_get_id (const struct CadetConnection *c) | ||
2956 | { | ||
2957 | return &c->id; | ||
2958 | } | ||
2959 | |||
2960 | |||
2961 | /** | ||
2962 | * Get the connection path. | ||
2963 | * | ||
2964 | * @param c Connection to get the path from. | ||
2965 | * | ||
2966 | * @return path used by the connection. | ||
2967 | */ | ||
2968 | const struct CadetPeerPath * | ||
2969 | GCC_get_path (const struct CadetConnection *c) | ||
2970 | { | ||
2971 | if (GNUNET_NO == c->destroy) | ||
2972 | return c->path; | ||
2973 | return NULL; | ||
2974 | } | ||
2975 | |||
2976 | |||
2977 | /** | ||
2978 | * Get the connection state. | ||
2979 | * | ||
2980 | * @param c Connection to get the state from. | ||
2981 | * | ||
2982 | * @return state of the connection. | ||
2983 | */ | ||
2984 | enum CadetConnectionState | ||
2985 | GCC_get_state (const struct CadetConnection *c) | ||
2986 | { | ||
2987 | return c->state; | ||
2988 | } | ||
2989 | |||
2990 | /** | ||
2991 | * Get the connection tunnel. | ||
2992 | * | ||
2993 | * @param c Connection to get the tunnel from. | ||
2994 | * | ||
2995 | * @return tunnel of the connection. | ||
2996 | */ | ||
2997 | struct CadetTunnel * | ||
2998 | GCC_get_tunnel (const struct CadetConnection *c) | ||
2999 | { | ||
3000 | return c->t; | ||
3001 | } | ||
3002 | |||
3003 | |||
3004 | /** | ||
3005 | * Get free buffer space in a connection. | ||
3006 | * | ||
3007 | * @param c Connection. | ||
3008 | * @param fwd Is query about FWD traffic? | ||
3009 | * | ||
3010 | * @return Free buffer space [0 - max_msgs_queue/max_connections] | ||
3011 | */ | ||
3012 | unsigned int | ||
3013 | GCC_get_buffer (struct CadetConnection *c, int fwd) | ||
3014 | { | ||
3015 | struct CadetFlowControl *fc; | ||
3016 | |||
3017 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3018 | |||
3019 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Get %s buffer on %s: %u - %u\n", | ||
3020 | GC_f2s (fwd), GCC_2s (c), fc->queue_max, fc->queue_n); | ||
3021 | GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); | ||
3022 | |||
3023 | return (fc->queue_max - fc->queue_n); | ||
3024 | } | ||
3025 | |||
3026 | |||
3027 | /** | ||
3028 | * Get how many messages have we allowed to send to us from a direction. | ||
3029 | * | ||
3030 | * @param c Connection. | ||
3031 | * @param fwd Are we asking about traffic from FWD (BCK messages)? | ||
3032 | * | ||
3033 | * @return last_ack_sent - last_pid_recv | ||
3034 | */ | ||
3035 | unsigned int | ||
3036 | GCC_get_allowed (struct CadetConnection *c, int fwd) | ||
3037 | { | ||
3038 | struct CadetFlowControl *fc; | ||
3039 | |||
3040 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3041 | if ( (CADET_CONNECTION_READY != c->state) || | ||
3042 | GC_is_pid_bigger (ntohl (fc->last_pid_recv.pid), | ||
3043 | ntohl (fc->last_ack_sent.pid)) ) | ||
3044 | { | ||
3045 | return 0; | ||
3046 | } | ||
3047 | return (ntohl (fc->last_ack_sent.pid) - ntohl (fc->last_pid_recv.pid)); | ||
3048 | } | ||
3049 | |||
3050 | |||
3051 | /** | ||
3052 | * Get messages queued in a connection. | ||
3053 | * | ||
3054 | * @param c Connection. | ||
3055 | * @param fwd Is query about FWD traffic? | ||
3056 | * | ||
3057 | * @return Number of messages queued. | ||
3058 | */ | ||
3059 | unsigned int | ||
3060 | GCC_get_qn (struct CadetConnection *c, int fwd) | ||
3061 | { | ||
3062 | struct CadetFlowControl *fc; | ||
3063 | |||
3064 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3065 | |||
3066 | return fc->queue_n; | ||
3067 | } | ||
3068 | |||
3069 | |||
3070 | /** | ||
3071 | * Get next PID to use. | ||
3072 | * | ||
3073 | * @param c Connection. | ||
3074 | * @param fwd Is query about FWD traffic? | ||
3075 | * @return Next PID to use. | ||
3076 | */ | ||
3077 | struct CadetEncryptedMessageIdentifier | ||
3078 | GCC_get_pid (struct CadetConnection *c, int fwd) | ||
3079 | { | ||
3080 | struct CadetFlowControl *fc; | ||
3081 | struct CadetEncryptedMessageIdentifier pid; | ||
3082 | |||
3083 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3084 | pid = fc->next_pid; | ||
3085 | fc->next_pid.pid = htonl (1 + ntohl (pid.pid)); | ||
3086 | return pid; | ||
3087 | } | ||
3088 | |||
3089 | |||
3090 | /** | ||
3091 | * Allow the connection to advertise a buffer of the given size. | ||
3092 | * | ||
3093 | * The connection will send an @c fwd ACK message (so: in direction !fwd) | ||
3094 | * allowing up to last_pid_recv + buffer. | ||
3095 | * | ||
3096 | * @param c Connection. | ||
3097 | * @param buffer How many more messages the connection can accept. | ||
3098 | * @param fwd Is this about FWD traffic? (The ack will go dest->root). | ||
3099 | */ | ||
3100 | void | ||
3101 | GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd) | ||
3102 | { | ||
3103 | LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n", | ||
3104 | GCC_2s (c), buffer, GC_f2s (fwd)); | ||
3105 | send_ack (c, buffer, fwd, GNUNET_NO); | ||
3106 | } | ||
3107 | |||
3108 | |||
3109 | /** | ||
3110 | * Notify other peers on a connection of a broken link. Mark connections | ||
3111 | * to destroy after all traffic has been sent. | ||
3112 | * | ||
3113 | * @param c Connection on which there has been a disconnection. | ||
3114 | * @param peer Peer that disconnected. | ||
3115 | */ | ||
3116 | void | ||
3117 | GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer) | ||
3118 | { | ||
3119 | struct CadetFlowControl *fc; | ||
3120 | char peer_name[16]; | ||
3121 | int fwd; | ||
3122 | |||
3123 | GCC_check_connections (); | ||
3124 | strncpy (peer_name, GCP_2s (peer), 16); | ||
3125 | peer_name[15] = '\0'; | ||
3126 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 826 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
3127 | "shutting down %s, %s disconnected\n", | 827 | "Creating %s using path %s\n", |
3128 | GCC_2s (c), peer_name); | 828 | GCC_2s (cc), |
3129 | 829 | GCPP_2s (path)); | |
3130 | invalidate_paths (c, peer); | 830 | GCPP_add_connection (path, |
3131 | 831 | off, | |
3132 | fwd = is_fwd (c, peer); | 832 | cc); |
3133 | if (GNUNET_SYSERR == fwd) | 833 | for (unsigned int i=0;i<off;i++) |
3134 | { | 834 | GCP_add_connection (GCPP_get_peer_at_offset (path, |
3135 | GNUNET_break (0); | 835 | i), |
3136 | return; | 836 | cc); |
3137 | } | 837 | |
3138 | if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) || | 838 | first_hop = GCPP_get_peer_at_offset (path, |
3139 | (GNUNET_NO != c->destroy) ) | 839 | 0); |
3140 | { | 840 | cc->mq_man = GCP_request_mq (first_hop, |
3141 | /* Local shutdown, or other peer already down (hence 'c->destroy'); | 841 | &manage_first_hop_mq, |
3142 | so there is no one to notify about this, just clean up. */ | 842 | cc); |
3143 | GCC_destroy (c); | 843 | return cc; |
3144 | GCC_check_connections (); | 844 | } |
3145 | return; | 845 | |
3146 | } | 846 | |
3147 | /* Mark FlowControl towards the peer as unavaliable. */ | 847 | /** |
3148 | fc = fwd ? &c->bck_fc : &c->fwd_fc; | 848 | * Create a connection to @a destination via @a path and |
3149 | fc->queue_max = 0; | 849 | * notify @a cb whenever we are ready for more data. This |
3150 | 850 | * is an inbound tunnel, so we must use the existing @a cid | |
3151 | send_broken (c, &my_full_id, GCP_get_id (peer), fwd); | 851 | * |
3152 | 852 | * @param destination where to go | |
3153 | /* Connection will have at least one pending message | 853 | * @param path which path to take (may not be the full path) |
3154 | * (the one we just scheduled), so delay destruction | 854 | * @param options options for the connection |
3155 | * and remove from map so we don't use accidentally. */ | 855 | * @param ct which tunnel uses this connection |
3156 | mark_destroyed (c); | 856 | * @param ready_cb function to call when ready to transmit |
3157 | GNUNET_assert (GNUNET_NO == c->was_removed); | 857 | * @param ready_cb_cls closure for @a cb |
3158 | c->was_removed = GNUNET_YES; | 858 | * @return handle to the connection, NULL if we already have |
3159 | GNUNET_break (GNUNET_YES == | 859 | * a connection that takes precedence on @a path |
3160 | GNUNET_CONTAINER_multishortmap_remove (connections, | ||
3161 | &c->id.connection_of_tunnel, | ||
3162 | c)); | ||
3163 | /* Cancel queue in the direction that just died. */ | ||
3164 | connection_cancel_queues (c, ! fwd); | ||
3165 | GCC_stop_poll (c, ! fwd); | ||
3166 | unregister_neighbors (c); | ||
3167 | GCC_check_connections (); | ||
3168 | } | ||
3169 | |||
3170 | |||
3171 | /** | ||
3172 | * Is this peer the first one on the connection? | ||
3173 | * | ||
3174 | * @param c Connection. | ||
3175 | * @param fwd Is this about fwd traffic? | ||
3176 | * | ||
3177 | * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. | ||
3178 | */ | 860 | */ |
3179 | int | 861 | struct CadetConnection * |
3180 | GCC_is_origin (struct CadetConnection *c, int fwd) | 862 | GCC_create_inbound (struct CadetPeer *destination, |
3181 | { | 863 | struct CadetPeerPath *path, |
3182 | if (!fwd && c->path->length - 1 == c->own_pos ) | 864 | enum GNUNET_CADET_ChannelOption options, |
3183 | return GNUNET_YES; | 865 | struct CadetTConnection *ct, |
3184 | if (fwd && 0 == c->own_pos) | 866 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, |
3185 | return GNUNET_YES; | 867 | GCC_ReadyCallback ready_cb, |
3186 | return GNUNET_NO; | 868 | void *ready_cb_cls) |
3187 | } | 869 | { |
3188 | 870 | struct CadetConnection *cc; | |
3189 | 871 | unsigned int off; | |
3190 | /** | 872 | |
3191 | * Is this peer the last one on the connection? | 873 | off = GCPP_find_peer (path, |
3192 | * | 874 | destination); |
3193 | * @param c Connection. | 875 | GNUNET_assert (UINT_MAX != off); |
3194 | * @param fwd Is this about fwd traffic? | 876 | cc = GCPP_get_connection (path, |
3195 | * Note that the ROOT is the terminal for BCK traffic! | 877 | destination, |
3196 | * | 878 | off); |
3197 | * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. | 879 | if (NULL != cc) |
3198 | */ | 880 | { |
3199 | int | 881 | int cmp; |
3200 | GCC_is_terminal (struct CadetConnection *c, int fwd) | 882 | |
3201 | { | 883 | cmp = memcmp (cid, |
3202 | return GCC_is_origin (c, ! fwd); | 884 | &cc->cid, |
3203 | } | 885 | sizeof (*cid)); |
3204 | 886 | if (0 == cmp) | |
3205 | 887 | { | |
3206 | /** | 888 | /* Two peers picked the SAME random connection identifier at the |
3207 | * See if we are allowed to send by the next hop in the given direction. | 889 | same time for the same path? Must be malicious. Drop |
3208 | * | 890 | connection (existing and inbound), even if it is the only |
3209 | * @param c Connection. | 891 | one. */ |
3210 | * @param fwd Is this about fwd traffic? | 892 | GNUNET_break_op (0); |
3211 | * | 893 | GCT_connection_lost (cc->ct); |
3212 | * @return #GNUNET_YES in case it's OK to send. | 894 | GCC_destroy_without_tunnel (cc); |
3213 | */ | ||
3214 | int | ||
3215 | GCC_is_sendable (struct CadetConnection *c, int fwd) | ||
3216 | { | ||
3217 | struct CadetFlowControl *fc; | ||
3218 | |||
3219 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3220 | " checking sendability of %s traffic on %s\n", | ||
3221 | GC_f2s (fwd), GCC_2s (c)); | ||
3222 | if (NULL == c) | ||
3223 | { | ||
3224 | GNUNET_break (0); | ||
3225 | return GNUNET_YES; | ||
3226 | } | ||
3227 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3228 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3229 | " last ack recv: %u, last pid sent: %u\n", | ||
3230 | ntohl (fc->last_ack_recv.pid), | ||
3231 | ntohl (fc->last_pid_sent.pid)); | ||
3232 | if (GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid), | ||
3233 | ntohl (fc->last_pid_sent.pid))) | ||
3234 | { | ||
3235 | LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n"); | ||
3236 | return GNUNET_YES; | ||
3237 | } | ||
3238 | LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); | ||
3239 | return GNUNET_NO; | ||
3240 | } | ||
3241 | |||
3242 | |||
3243 | /** | ||
3244 | * Check if this connection is a direct one (never trim a direct connection). | ||
3245 | * | ||
3246 | * @param c Connection. | ||
3247 | * | ||
3248 | * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. | ||
3249 | */ | ||
3250 | int | ||
3251 | GCC_is_direct (struct CadetConnection *c) | ||
3252 | { | ||
3253 | return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO; | ||
3254 | } | ||
3255 | |||
3256 | |||
3257 | /** | ||
3258 | * Sends a completely built message on a connection, properly registering | ||
3259 | * all used resources. | ||
3260 | * | ||
3261 | * @param message Message to send. | ||
3262 | * @param payload_type Type of payload, in case the message is encrypted. | ||
3263 | * 0 for restransmissions (when type is no longer known) | ||
3264 | * UINT16_MAX when not applicable. | ||
3265 | * @param payload_id ID of the payload (PID, ACK, ...). | ||
3266 | * @param c Connection on which this message is transmitted. | ||
3267 | * @param fwd Is this a fwd message? | ||
3268 | * @param force Force the connection to accept the message (buffer overfill). | ||
3269 | * @param cont Continuation called once message is sent. Can be NULL. | ||
3270 | * @param cont_cls Closure for @c cont. | ||
3271 | * | ||
3272 | * @return Handle to cancel the message before it's sent. | ||
3273 | * NULL on error. | ||
3274 | * Invalid on @c cont call. | ||
3275 | */ | ||
3276 | struct CadetConnectionQueue * | ||
3277 | GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
3278 | uint16_t payload_type, | ||
3279 | struct CadetEncryptedMessageIdentifier payload_id, | ||
3280 | struct CadetConnection *c, int fwd, int force, | ||
3281 | GCC_sent cont, void *cont_cls) | ||
3282 | { | ||
3283 | struct CadetFlowControl *fc; | ||
3284 | struct CadetConnectionQueue *q; | ||
3285 | uint16_t size; | ||
3286 | uint16_t type; | ||
3287 | |||
3288 | size = ntohs (message->size); | ||
3289 | type = ntohs (message->type); | ||
3290 | |||
3291 | GCC_check_connections (); | ||
3292 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3293 | if (0 == fc->queue_max) | ||
3294 | { | ||
3295 | GNUNET_break (0); | ||
3296 | return NULL; | ||
3297 | } | ||
3298 | |||
3299 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
3300 | "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n", | ||
3301 | GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c, | ||
3302 | GC_f2s(fwd), size); | ||
3303 | switch (type) | ||
3304 | { | ||
3305 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED: | ||
3306 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u, PIDsnt: %u, ACKrcv: %u\n", | ||
3307 | fc, | ||
3308 | fc->queue_n, | ||
3309 | ntohl (fc->last_pid_sent.pid), | ||
3310 | ntohl (fc->last_ack_recv.pid)); | ||
3311 | if (GNUNET_NO == force) | ||
3312 | { | ||
3313 | fc->queue_n++; | ||
3314 | } | ||
3315 | break; | ||
3316 | |||
3317 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX: | ||
3318 | /* nothing to do here */ | ||
3319 | break; | ||
3320 | |||
3321 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: | ||
3322 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK: | ||
3323 | /* Should've only be used for restransmissions. */ | ||
3324 | GNUNET_break (0 == payload_type); | ||
3325 | break; | ||
3326 | |||
3327 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK: | ||
3328 | case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL: | ||
3329 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: | ||
3330 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: | ||
3331 | GNUNET_assert (GNUNET_YES == force); | ||
3332 | break; | ||
3333 | |||
3334 | default: | ||
3335 | GNUNET_break (0); | ||
3336 | return NULL; | 895 | return NULL; |
3337 | } | 896 | } |
3338 | 897 | if (0 < cmp) | |
3339 | if (fc->queue_n > fc->queue_max && GNUNET_NO == force) | ||
3340 | { | ||
3341 | GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)", | ||
3342 | 1, GNUNET_NO); | ||
3343 | GNUNET_break (0); | ||
3344 | LOG (GNUNET_ERROR_TYPE_DEBUG, "queue full: %u/%u\n", | ||
3345 | fc->queue_n, fc->queue_max); | ||
3346 | if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type) | ||
3347 | { | 898 | { |
3348 | fc->queue_n--; | 899 | /* drop existing */ |
900 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
901 | "Got two connections on %s, dropping my existing %s\n", | ||
902 | GCPP_2s (path), | ||
903 | GCC_2s (cc)); | ||
904 | GCT_connection_lost (cc->ct); | ||
905 | GCC_destroy_without_tunnel (cc); | ||
3349 | } | 906 | } |
3350 | return NULL; /* Drop this message */ | 907 | else |
3351 | } | ||
3352 | |||
3353 | LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %s %u\n", | ||
3354 | GCC_2s (c), c->pending_messages); | ||
3355 | c->pending_messages++; | ||
3356 | |||
3357 | q = GNUNET_new (struct CadetConnectionQueue); | ||
3358 | q->cont = cont; | ||
3359 | q->cont_cls = cont_cls; | ||
3360 | q->forced = force; | ||
3361 | GNUNET_CONTAINER_DLL_insert (fc->q_head, fc->q_tail, q); | ||
3362 | q->peer_q = GCP_send (get_hop (c, fwd), | ||
3363 | message, | ||
3364 | payload_type, | ||
3365 | payload_id, | ||
3366 | c, | ||
3367 | fwd, | ||
3368 | &conn_message_sent, q); | ||
3369 | if (NULL == q->peer_q) | ||
3370 | { | ||
3371 | LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c)); | ||
3372 | GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q); | ||
3373 | GNUNET_free (q); | ||
3374 | GCC_check_connections (); | ||
3375 | return NULL; | ||
3376 | } | ||
3377 | GCC_check_connections (); | ||
3378 | return q; | ||
3379 | } | ||
3380 | |||
3381 | |||
3382 | /** | ||
3383 | * Cancel a previously sent message while it's in the queue. | ||
3384 | * | ||
3385 | * ONLY can be called before the continuation given to the send function | ||
3386 | * is called. Once the continuation is called, the message is no longer in the | ||
3387 | * queue. | ||
3388 | * | ||
3389 | * @param q Handle to the queue. | ||
3390 | */ | ||
3391 | void | ||
3392 | GCC_cancel (struct CadetConnectionQueue *q) | ||
3393 | { | ||
3394 | LOG (GNUNET_ERROR_TYPE_DEBUG, "! GCC cancel message\n"); | ||
3395 | |||
3396 | /* send_cancel calls message_sent, which calls q->cont and frees q */ | ||
3397 | GCP_send_cancel (q->peer_q); | ||
3398 | GCC_check_connections (); | ||
3399 | } | ||
3400 | |||
3401 | |||
3402 | /** | ||
3403 | * Sends a CREATE CONNECTION message for a path to a peer. | ||
3404 | * Changes the connection and tunnel states if necessary. | ||
3405 | * | ||
3406 | * @param c Connection to create. | ||
3407 | */ | ||
3408 | void | ||
3409 | GCC_send_create (struct CadetConnection *c) | ||
3410 | { | ||
3411 | static struct CadetEncryptedMessageIdentifier zero; | ||
3412 | enum CadetTunnelCState state; | ||
3413 | size_t size; | ||
3414 | |||
3415 | GCC_check_connections (); | ||
3416 | size = sizeof (struct GNUNET_CADET_ConnectionCreateMessage); | ||
3417 | size += c->path->length * sizeof (struct GNUNET_PeerIdentity); | ||
3418 | { | ||
3419 | /* Allocate message on the stack */ | ||
3420 | unsigned char cbuf[size]; | ||
3421 | struct GNUNET_CADET_ConnectionCreateMessage *msg; | ||
3422 | struct GNUNET_PeerIdentity *peers; | ||
3423 | |||
3424 | |||
3425 | msg = (struct GNUNET_CADET_ConnectionCreateMessage *) cbuf; | ||
3426 | msg->header.size = htons (size); | ||
3427 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); | ||
3428 | msg->options = htonl (0); | ||
3429 | msg->cid = *GCC_get_id (c); | ||
3430 | peers = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
3431 | for (int i = 0; i < c->path->length; i++) | ||
3432 | { | 908 | { |
3433 | GNUNET_PEER_resolve (c->path->peers[i], peers++); | 909 | /* keep existing */ |
910 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
911 | "Got two connections on %s, keeping my existing %s\n", | ||
912 | GCPP_2s (path), | ||
913 | GCC_2s (cc)); | ||
914 | return NULL; | ||
3434 | } | 915 | } |
3435 | GNUNET_assert (NULL == c->maintenance_q); | ||
3436 | c->maintenance_q = GCP_send (get_next_hop (c), | ||
3437 | &msg->header, | ||
3438 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, | ||
3439 | zero, | ||
3440 | c, GNUNET_YES, | ||
3441 | &conn_message_sent, NULL); | ||
3442 | } | 916 | } |
3443 | 917 | ||
3444 | LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n", | 918 | return connection_create (destination, |
3445 | GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "", | 919 | path, |
3446 | GCC_2s (c), c, size); | 920 | off, |
3447 | LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n", | 921 | options, |
3448 | c, c->pending_messages); | 922 | ct, |
3449 | c->pending_messages++; | 923 | cid, |
3450 | 924 | CADET_CONNECTION_CREATE_RECEIVED, | |
3451 | state = GCT_get_cstate (c->t); | 925 | ready_cb, |
3452 | if (CADET_TUNNEL_SEARCHING == state || CADET_TUNNEL_NEW == state) | 926 | ready_cb_cls); |
3453 | GCT_change_cstate (c->t, CADET_TUNNEL_WAITING); | ||
3454 | if (CADET_CONNECTION_NEW == c->state) | ||
3455 | connection_change_state (c, CADET_CONNECTION_SENT); | ||
3456 | GCC_check_connections (); | ||
3457 | } | 927 | } |
3458 | 928 | ||
3459 | 929 | ||
3460 | /** | 930 | /** |
3461 | * Send an ACK on the appropriate connection/channel, depending on | 931 | * Create a connection to @a destination via @a path and |
3462 | * the direction and the position of the peer. | 932 | * notify @a cb whenever we are ready for more data. |
3463 | * | 933 | * |
3464 | * @param c Which connection to send the hop-by-hop ACK. | 934 | * @param destination where to go |
3465 | * @param fwd Is this a fwd ACK? (will go dest->root). | 935 | * @param path which path to take (may not be the full path) |
3466 | * @param force Send the ACK even if suboptimal (e.g. requested by POLL). | 936 | * @param off offset of @a destination on @a path |
937 | * @param options options for the connection | ||
938 | * @param ct tunnel that uses the connection | ||
939 | * @param ready_cb function to call when ready to transmit | ||
940 | * @param ready_cb_cls closure for @a cb | ||
941 | * @return handle to the connection | ||
3467 | */ | 942 | */ |
3468 | void | 943 | struct CadetConnection * |
3469 | GCC_send_ack (struct CadetConnection *c, int fwd, int force) | 944 | GCC_create (struct CadetPeer *destination, |
945 | struct CadetPeerPath *path, | ||
946 | unsigned int off, | ||
947 | enum GNUNET_CADET_ChannelOption options, | ||
948 | struct CadetTConnection *ct, | ||
949 | GCC_ReadyCallback ready_cb, | ||
950 | void *ready_cb_cls) | ||
3470 | { | 951 | { |
3471 | unsigned int buffer; | 952 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; |
3472 | |||
3473 | GCC_check_connections (); | ||
3474 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GCC send %s ACK on %s\n", | ||
3475 | GC_f2s (fwd), GCC_2s (c)); | ||
3476 | |||
3477 | if (NULL == c) | ||
3478 | { | ||
3479 | GNUNET_break (0); | ||
3480 | return; | ||
3481 | } | ||
3482 | 953 | ||
3483 | if (GNUNET_NO != c->destroy) | 954 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, |
3484 | { | 955 | &cid, |
3485 | LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n"); | 956 | sizeof (cid)); |
3486 | GCC_check_connections (); | 957 | return connection_create (destination, |
3487 | return; | 958 | path, |
3488 | } | 959 | off, |
3489 | 960 | options, | |
3490 | /* Get available buffer space */ | 961 | ct, |
3491 | if (GCC_is_terminal (c, fwd)) | 962 | &cid, |
3492 | { | 963 | CADET_CONNECTION_NEW, |
3493 | LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n"); | 964 | ready_cb, |
3494 | buffer = GCT_get_channels_buffer (c->t); | 965 | ready_cb_cls); |
3495 | } | ||
3496 | else | ||
3497 | { | ||
3498 | LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n"); | ||
3499 | buffer = GCC_get_buffer (c, fwd); | ||
3500 | } | ||
3501 | LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer); | ||
3502 | if (0 == buffer && GNUNET_NO == force) | ||
3503 | { | ||
3504 | GCC_check_connections (); | ||
3505 | return; | ||
3506 | } | ||
3507 | |||
3508 | /* Send available buffer space */ | ||
3509 | if (GNUNET_YES == GCC_is_origin (c, fwd)) | ||
3510 | { | ||
3511 | GNUNET_assert (NULL != c->t); | ||
3512 | LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n"); | ||
3513 | GCT_unchoke_channels (c->t); | ||
3514 | } | ||
3515 | else | ||
3516 | { | ||
3517 | LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n"); | ||
3518 | send_ack (c, buffer, fwd, force); | ||
3519 | } | ||
3520 | GCC_check_connections (); | ||
3521 | } | 966 | } |
3522 | 967 | ||
3523 | 968 | ||
3524 | /** | 969 | /** |
3525 | * Send a message to all peers in this connection that the connection | 970 | * Transmit message @a msg via connection @a cc. Must only be called |
3526 | * is no longer valid. | 971 | * (once) after the connection has signalled that it is ready via the |
972 | * `ready_cb`. Clients can also use #GCC_is_ready() to check if the | ||
973 | * connection is right now ready for transmission. | ||
3527 | * | 974 | * |
3528 | * If some peer should not receive the message, it should be zero'ed out | 975 | * @param cc connection identification |
3529 | * before calling this function. | 976 | * @param env envelope with message to transmit; must NOT |
3530 | * | 977 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it |
3531 | * @param c The connection whose peers to notify. | ||
3532 | */ | 978 | */ |
3533 | void | 979 | void |
3534 | GCC_send_destroy (struct CadetConnection *c) | 980 | GCC_transmit (struct CadetConnection *cc, |
981 | struct GNUNET_MQ_Envelope *env) | ||
3535 | { | 982 | { |
3536 | static struct CadetEncryptedMessageIdentifier zero; | ||
3537 | struct GNUNET_CADET_ConnectionDestroyMessage msg; | ||
3538 | |||
3539 | if (GNUNET_YES == c->destroy) | ||
3540 | return; | ||
3541 | GCC_check_connections (); | ||
3542 | msg.header.size = htons (sizeof (msg)); | ||
3543 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); | ||
3544 | msg.cid = c->id; | ||
3545 | msg.reserved = htonl (0); | ||
3546 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 983 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
3547 | " sending connection destroy for connection %s\n", | 984 | "Scheduling message for transmission on %s\n", |
3548 | GCC_2s (c)); | 985 | GCC_2s (cc)); |
3549 | 986 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | |
3550 | if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES)) | 987 | GNUNET_assert (CADET_CONNECTION_READY == cc->state); |
3551 | (void) GCC_send_prebuilt_message (&msg.header, | 988 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); |
3552 | UINT16_MAX, | 989 | cc->mqm_ready = GNUNET_NO; |
3553 | zero, | 990 | if (NULL != cc->task) |
3554 | c, | 991 | { |
3555 | GNUNET_YES, GNUNET_YES, NULL, NULL); | 992 | GNUNET_SCHEDULER_cancel (cc->task); |
3556 | if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO)) | 993 | cc->task = NULL; |
3557 | (void) GCC_send_prebuilt_message (&msg.header, | 994 | } |
3558 | UINT16_MAX, | 995 | GCP_send (cc->mq_man, |
3559 | zero, | 996 | env); |
3560 | c, | ||
3561 | GNUNET_NO, GNUNET_YES, NULL, NULL); | ||
3562 | mark_destroyed (c); | ||
3563 | GCC_check_connections (); | ||
3564 | } | 997 | } |
3565 | 998 | ||
3566 | 999 | ||
3567 | /** | 1000 | /** |
3568 | * @brief Start a polling timer for the connection. | 1001 | * Obtain the path used by this connection. |
3569 | * | ||
3570 | * When a neighbor does not accept more traffic on the connection it could be | ||
3571 | * caused by a simple congestion or by a lost ACK. Polling enables to check | ||
3572 | * for the lastest ACK status for a connection. | ||
3573 | * | 1002 | * |
3574 | * @param c Connection. | 1003 | * @param cc connection |
3575 | * @param fwd Should we poll in the FWD direction? | 1004 | * @return path to @a cc |
3576 | */ | 1005 | */ |
3577 | void | 1006 | struct CadetPeerPath * |
3578 | GCC_start_poll (struct CadetConnection *c, int fwd) | 1007 | GCC_get_path (struct CadetConnection *cc) |
3579 | { | 1008 | { |
3580 | struct CadetFlowControl *fc; | 1009 | return cc->path; |
3581 | |||
3582 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3583 | LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL %s requested\n", | ||
3584 | GC_f2s (fwd)); | ||
3585 | if (NULL != fc->poll_task || NULL != fc->poll_msg) | ||
3586 | { | ||
3587 | LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL already in progress (t: %p, m: %p)\n", | ||
3588 | fc->poll_task, fc->poll_msg); | ||
3589 | return; | ||
3590 | } | ||
3591 | if (0 == fc->queue_max) | ||
3592 | { | ||
3593 | /* Should not be needed, traffic should've been cancelled. */ | ||
3594 | GNUNET_break (0); | ||
3595 | LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL not possible, peer disconnected\n"); | ||
3596 | return; | ||
3597 | } | ||
3598 | LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n"); | ||
3599 | fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, &send_poll, fc); | ||
3600 | } | 1010 | } |
3601 | 1011 | ||
3602 | 1012 | ||
3603 | /** | 1013 | /** |
3604 | * @brief Stop polling a connection for ACKs. | 1014 | * Obtain unique ID for the connection. |
3605 | * | 1015 | * |
3606 | * Once we have enough ACKs for future traffic, polls are no longer necessary. | 1016 | * @param cc connection. |
3607 | * | 1017 | * @return unique number of the connection |
3608 | * @param c Connection. | ||
3609 | * @param fwd Should we stop the poll in the FWD direction? | ||
3610 | */ | 1018 | */ |
3611 | void | 1019 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * |
3612 | GCC_stop_poll (struct CadetConnection *c, int fwd) | 1020 | GCC_get_id (struct CadetConnection *cc) |
3613 | { | 1021 | { |
3614 | struct CadetFlowControl *fc; | 1022 | return &cc->cid; |
3615 | |||
3616 | fc = fwd ? &c->fwd_fc : &c->bck_fc; | ||
3617 | if (NULL != fc->poll_task) | ||
3618 | { | ||
3619 | GNUNET_SCHEDULER_cancel (fc->poll_task); | ||
3620 | fc->poll_task = NULL; | ||
3621 | } | ||
3622 | if (NULL != fc->poll_msg) | ||
3623 | { | ||
3624 | GCC_cancel (fc->poll_msg); | ||
3625 | fc->poll_msg = NULL; | ||
3626 | } | ||
3627 | } | 1023 | } |
3628 | 1024 | ||
3629 | 1025 | ||
3630 | /** | 1026 | /** |
3631 | * Get a (static) string for a connection. | 1027 | * Get a (static) string for a connection. |
3632 | * | 1028 | * |
3633 | * @param c Connection. | 1029 | * @param cc Connection. |
3634 | */ | 1030 | */ |
3635 | const char * | 1031 | const char * |
3636 | GCC_2s (const struct CadetConnection *c) | 1032 | GCC_2s (const struct CadetConnection *cc) |
3637 | { | 1033 | { |
3638 | if (NULL == c) | 1034 | static char buf[128]; |
3639 | return "NULL"; | ||
3640 | 1035 | ||
3641 | if (NULL != c->t) | 1036 | if (NULL == cc) |
3642 | { | 1037 | return "Connection(NULL)"; |
3643 | static char buf[128]; | ||
3644 | 1038 | ||
3645 | SPRINTF (buf, "%s (->%s)", | 1039 | if (NULL != cc->ct) |
3646 | GNUNET_sh2s (&GCC_get_id (c)->connection_of_tunnel), | 1040 | { |
3647 | GCT_2s (c->t)); | 1041 | GNUNET_snprintf (buf, |
1042 | sizeof (buf), | ||
1043 | "Connection %s (%s)", | ||
1044 | GNUNET_sh2s (&cc->cid.connection_of_tunnel), | ||
1045 | GCT_2s (cc->ct->t)); | ||
3648 | return buf; | 1046 | return buf; |
3649 | } | 1047 | } |
3650 | return GNUNET_sh2s (&c->id.connection_of_tunnel); | 1048 | GNUNET_snprintf (buf, |
1049 | sizeof (buf), | ||
1050 | "Connection %s", | ||
1051 | GNUNET_sh2s (&cc->cid.connection_of_tunnel)); | ||
1052 | return buf; | ||
3651 | } | 1053 | } |
3652 | 1054 | ||
3653 | 1055 | ||
1056 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__) | ||
1057 | |||
1058 | |||
3654 | /** | 1059 | /** |
3655 | * Log all possible info about the connection state. | 1060 | * Log connection info. |
3656 | * | 1061 | * |
3657 | * @param c Connection to debug. | 1062 | * @param cc connection |
3658 | * @param level Debug level to use. | 1063 | * @param level Debug level to use. |
3659 | */ | 1064 | */ |
3660 | void | 1065 | void |
3661 | GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level) | 1066 | GCC_debug (struct CadetConnection *cc, |
1067 | enum GNUNET_ErrorType level) | ||
3662 | { | 1068 | { |
3663 | int do_log; | 1069 | int do_log; |
3664 | char *s; | ||
3665 | 1070 | ||
3666 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | 1071 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), |
3667 | "cadet-con", | 1072 | "cadet-con", |
3668 | __FILE__, __FUNCTION__, __LINE__); | 1073 | __FILE__, __FUNCTION__, __LINE__); |
3669 | if (0 == do_log) | 1074 | if (0 == do_log) |
3670 | return; | 1075 | return; |
3671 | 1076 | if (NULL == cc) | |
3672 | if (NULL == c) | ||
3673 | { | 1077 | { |
3674 | LOG2 (level, "CCC DEBUG NULL CONNECTION\n"); | 1078 | LOG2 (level, |
1079 | "Connection (NULL)\n"); | ||
3675 | return; | 1080 | return; |
3676 | } | 1081 | } |
3677 | 1082 | LOG2 (level, | |
3678 | LOG2 (level, "CCC DEBUG CONNECTION %s\n", GCC_2s (c)); | 1083 | "%s to %s via path %s in state %d is %s\n", |
3679 | s = path_2s (c->path); | 1084 | GCC_2s (cc), |
3680 | LOG2 (level, "CCC path %s, own pos: %u\n", s, c->own_pos); | 1085 | GCP_2s (cc->destination), |
3681 | GNUNET_free (s); | 1086 | GCPP_2s (cc->path), |
3682 | LOG2 (level, "CCC state: %s, destroy: %u\n", | 1087 | cc->state, |
3683 | GCC_state2s (c->state), c->destroy); | 1088 | (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy"); |
3684 | LOG2 (level, "CCC pending messages: %u\n", c->pending_messages); | ||
3685 | if (NULL != c->perf) | ||
3686 | LOG2 (level, "CCC us/byte: %f\n", c->perf->avg); | ||
3687 | |||
3688 | LOG2 (level, "CCC FWD flow control:\n"); | ||
3689 | LOG2 (level, "CCC queue: %u/%u\n", c->fwd_fc.queue_n, c->fwd_fc.queue_max); | ||
3690 | LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n", | ||
3691 | ntohl (c->fwd_fc.last_pid_sent.pid), | ||
3692 | ntohl (c->fwd_fc.last_pid_recv.pid)); | ||
3693 | LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n", | ||
3694 | ntohl (c->fwd_fc.last_ack_sent.pid), | ||
3695 | ntohl (c->fwd_fc.last_ack_recv.pid)); | ||
3696 | LOG2 (level, "CCC recv PID bitmap: %X\n", c->fwd_fc.recv_bitmap); | ||
3697 | LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n", | ||
3698 | c->fwd_fc.poll_task, c->fwd_fc.poll_msg, c->fwd_fc.ack_msg); | ||
3699 | |||
3700 | LOG2 (level, "CCC BCK flow control:\n"); | ||
3701 | LOG2 (level, "CCC queue: %u/%u\n", c->bck_fc.queue_n, c->bck_fc.queue_max); | ||
3702 | LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n", | ||
3703 | ntohl (c->bck_fc.last_pid_sent.pid), | ||
3704 | ntohl (c->bck_fc.last_pid_recv.pid)); | ||
3705 | LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n", | ||
3706 | ntohl (c->bck_fc.last_ack_sent.pid), | ||
3707 | ntohl (c->bck_fc.last_ack_recv.pid)); | ||
3708 | LOG2 (level, "CCC recv PID bitmap: %X\n", c->bck_fc.recv_bitmap); | ||
3709 | LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n", | ||
3710 | c->bck_fc.poll_task, c->bck_fc.poll_msg, c->bck_fc.ack_msg); | ||
3711 | |||
3712 | LOG2 (level, "CCC DEBUG CONNECTION END\n"); | ||
3713 | } | 1089 | } |
1090 | |||
1091 | /* end of gnunet-service-cadet-new_connection.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h index 307cb42c2..fdb184366 100644 --- a/src/cadet/gnunet-service-cadet_connection.h +++ b/src/cadet/gnunet-service-cadet_connection.h | |||
@@ -1,6 +1,7 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | This file is part of GNUnet. | 3 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 4 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 5 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 6 | 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 | it under the terms of the GNU General Public License as published |
@@ -20,557 +21,319 @@ | |||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * @file cadet/gnunet-service-cadet_connection.h | 23 | * @file cadet/gnunet-service-cadet_connection.h |
23 | * @brief cadet service; dealing with connections | 24 | * @brief A connection is a live end-to-end messaging mechanism |
25 | * where the peers are identified by a path and know how | ||
26 | * to forward along the route using a connection identifier | ||
27 | * for routing the data. | ||
24 | * @author Bartlomiej Polot | 28 | * @author Bartlomiej Polot |
25 | * | 29 | * @author Christian Grothoff |
26 | * All functions in this file use the prefix GCC (GNUnet Cadet Connection) | ||
27 | */ | 30 | */ |
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_CONNECTION_H | 31 | #ifndef GNUNET_SERVICE_CADET_CONNECTION_H |
30 | #define GNUNET_SERVICE_CADET_CONNECTION_H | 32 | #define GNUNET_SERVICE_CADET_CONNECTION_H |
31 | 33 | ||
32 | #ifdef __cplusplus | ||
33 | extern "C" | ||
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "gnunet_util_lib.h" | 34 | #include "gnunet_util_lib.h" |
41 | 35 | #include "gnunet-service-cadet.h" | |
42 | |||
43 | /** | ||
44 | * All the states a connection can be in. | ||
45 | */ | ||
46 | enum CadetConnectionState | ||
47 | { | ||
48 | /** | ||
49 | * Uninitialized status, should never appear in operation. | ||
50 | */ | ||
51 | CADET_CONNECTION_NEW, | ||
52 | |||
53 | /** | ||
54 | * Connection create message sent, waiting for ACK. | ||
55 | */ | ||
56 | CADET_CONNECTION_SENT, | ||
57 | |||
58 | /** | ||
59 | * Connection ACK sent, waiting for ACK. | ||
60 | */ | ||
61 | CADET_CONNECTION_ACK, | ||
62 | |||
63 | /** | ||
64 | * Connection confirmed, ready to carry traffic. | ||
65 | */ | ||
66 | CADET_CONNECTION_READY, | ||
67 | |||
68 | /** | ||
69 | * Connection to be destroyed, just waiting to empty queues. | ||
70 | */ | ||
71 | CADET_CONNECTION_DESTROYED, | ||
72 | |||
73 | /** | ||
74 | * Connection to be destroyed because of a distant peer, same as DESTROYED. | ||
75 | */ | ||
76 | CADET_CONNECTION_BROKEN, | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Struct containing all information regarding a connection to a peer. | ||
82 | */ | ||
83 | struct CadetConnection; | ||
84 | |||
85 | /** | ||
86 | * Handle for messages queued but not yet sent. | ||
87 | */ | ||
88 | struct CadetConnectionQueue; | ||
89 | |||
90 | #include "cadet_path.h" | ||
91 | #include "gnunet-service-cadet_channel.h" | ||
92 | #include "gnunet-service-cadet_peer.h" | 36 | #include "gnunet-service-cadet_peer.h" |
37 | #include "cadet_protocol.h" | ||
93 | 38 | ||
94 | 39 | ||
95 | /** | 40 | /** |
96 | * Check invariants for all connections using #check_neighbours(). | 41 | * Function called to notify tunnel about change in our readyness. |
97 | */ | ||
98 | void | ||
99 | GCC_check_connections (void); | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Callback called when a queued message is sent. | ||
104 | * | 42 | * |
105 | * @param cls Closure. | 43 | * @param cls closure |
106 | * @param c Connection this message was on. | 44 | * @param is_ready #GNUNET_YES if the connection is now ready for transmission, |
107 | * @param type Type of message sent. | 45 | * #GNUNET_NO if the connection is no longer ready for transmission |
108 | * @param fwd Was this a FWD going message? | ||
109 | * @param size Size of the message. | ||
110 | */ | 46 | */ |
111 | typedef void | 47 | typedef void |
112 | (*GCC_sent) (void *cls, | 48 | (*GCC_ReadyCallback)(void *cls, |
113 | struct CadetConnection *c, | 49 | int is_ready); |
114 | struct CadetConnectionQueue *q, | ||
115 | uint16_t type, | ||
116 | int fwd, | ||
117 | size_t size); | ||
118 | 50 | ||
119 | 51 | ||
120 | /** | 52 | /** |
121 | * Handler for connection creation. | 53 | * Destroy a connection, called when the CORE layer is already done |
54 | * (i.e. has received a BROKEN message), but if we still have to | ||
55 | * communicate the destruction of the connection to the tunnel (if one | ||
56 | * exists). | ||
122 | * | 57 | * |
123 | * @param peer Message sender (neighbor). | 58 | * @param cc connection to destroy |
124 | * @param msg Message itself. | ||
125 | */ | 59 | */ |
126 | void | 60 | void |
127 | GCC_handle_create (struct CadetPeer *peer, | 61 | GCC_destroy_without_core (struct CadetConnection *cc); |
128 | const struct GNUNET_CADET_ConnectionCreateMessage *msg); | ||
129 | 62 | ||
130 | 63 | ||
131 | /** | 64 | /** |
132 | * Handler for connection confirmations. | 65 | * Destroy a connection, called if the tunnel association with the |
66 | * connection was already broken, but we still need to notify the CORE | ||
67 | * layer about the breakage. | ||
133 | * | 68 | * |
134 | * @param peer Message sender (neighbor). | 69 | * @param cc connection to destroy |
135 | * @param msg Message itself. | ||
136 | */ | 70 | */ |
137 | void | 71 | void |
138 | GCC_handle_confirm (struct CadetPeer *peer, | 72 | GCC_destroy_without_tunnel (struct CadetConnection *cc); |
139 | const struct GNUNET_CADET_ConnectionCreateAckMessage *msg); | ||
140 | 73 | ||
141 | 74 | ||
142 | /** | 75 | /** |
143 | * Handler for notifications of broken connections. | 76 | * Lookup a connection by its identifier. |
144 | * | 77 | * |
145 | * @param peer Message sender (neighbor). | 78 | * @param cid identifier to resolve |
146 | * @param msg Message itself. | 79 | * @return NULL if connection was not found |
147 | */ | 80 | */ |
148 | void | 81 | struct CadetConnection * |
149 | GCC_handle_broken (struct CadetPeer *peer, | 82 | GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); |
150 | const struct GNUNET_CADET_ConnectionBrokenMessage *msg); | ||
151 | 83 | ||
152 | /** | ||
153 | * Handler for notifications of destroyed connections. | ||
154 | * | ||
155 | * @param peer Message sender (neighbor). | ||
156 | * @param msg Message itself. | ||
157 | */ | ||
158 | void | ||
159 | GCC_handle_destroy (struct CadetPeer *peer, | ||
160 | const struct GNUNET_CADET_ConnectionDestroyMessage *msg); | ||
161 | 84 | ||
162 | /** | 85 | /** |
163 | * Handler for cadet network traffic hop-by-hop acks. | 86 | * Create a connection to @a destination via @a path and |
87 | * notify @a cb whenever we are ready for more data. | ||
164 | * | 88 | * |
165 | * @param peer Message sender (neighbor). | 89 | * @param destination where to go |
166 | * @param msg Message itself. | 90 | * @param path which path to take (may not be the full path) |
91 | * @param off offset of @a destination on @a path | ||
92 | * @param options options for the connection | ||
93 | * @param ct which tunnel uses this connection | ||
94 | * @param ready_cb function to call when ready to transmit | ||
95 | * @param ready_cb_cls closure for @a cb | ||
96 | * @return handle to the connection | ||
167 | */ | 97 | */ |
168 | void | 98 | struct CadetConnection * |
169 | GCC_handle_ack (struct CadetPeer *peer, | 99 | GCC_create (struct CadetPeer *destination, |
170 | const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg); | 100 | struct CadetPeerPath *path, |
101 | unsigned int off, | ||
102 | enum GNUNET_CADET_ChannelOption options, | ||
103 | struct CadetTConnection *ct, | ||
104 | GCC_ReadyCallback ready_cb, | ||
105 | void *ready_cb_cls); | ||
171 | 106 | ||
172 | /** | ||
173 | * Handler for cadet network traffic hop-by-hop data counter polls. | ||
174 | * | ||
175 | * @param peer Message sender (neighbor). | ||
176 | * @param msg Message itself. | ||
177 | */ | ||
178 | void | ||
179 | GCC_handle_poll (struct CadetPeer *peer, | ||
180 | const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg); | ||
181 | 107 | ||
182 | /** | 108 | /** |
183 | * Handler for key exchange traffic (Axolotl KX). | 109 | * Create a connection to @a destination via @a path and |
110 | * notify @a cb whenever we are ready for more data. This | ||
111 | * is an inbound tunnel, so we must use the existing @a cid | ||
184 | * | 112 | * |
185 | * @param peer Message sender (neighbor). | 113 | * @param destination where to go |
186 | * @param msg Message itself. | 114 | * @param path which path to take (may not be the full path) |
115 | * @param options options for the connection | ||
116 | * @param ct which tunnel uses this connection | ||
117 | * @param ready_cb function to call when ready to transmit | ||
118 | * @param ready_cb_cls closure for @a cb | ||
119 | * @return handle to the connection, NULL if we already have | ||
120 | * a connection that takes precedence on @a path | ||
187 | */ | 121 | */ |
188 | void | 122 | struct CadetConnection * |
189 | GCC_handle_kx (struct CadetPeer *peer, | 123 | GCC_create_inbound (struct CadetPeer *destination, |
190 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); | 124 | struct CadetPeerPath *path, |
125 | enum GNUNET_CADET_ChannelOption options, | ||
126 | struct CadetTConnection *ct, | ||
127 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
128 | GCC_ReadyCallback ready_cb, | ||
129 | void *ready_cb_cls); | ||
130 | |||
191 | 131 | ||
192 | /** | 132 | /** |
193 | * Handler for encrypted cadet network traffic (channel mgmt, data). | 133 | * Transmit message @a msg via connection @a cc. Must only be called |
134 | * (once) after the connection has signalled that it is ready via the | ||
135 | * `ready_cb`. Clients can also use #GCC_is_ready() to check if the | ||
136 | * connection is right now ready for transmission. | ||
194 | * | 137 | * |
195 | * @param peer Message sender (neighbor). | 138 | * @param cc connection identification |
196 | * @param msg Message itself. | 139 | * @param env envelope with message to transmit; |
140 | * the #GNUNET_MQ_notify_send() must not have yet been used | ||
141 | * for the envelope. Also, the message better match the | ||
142 | * connection identifier of this connection... | ||
197 | */ | 143 | */ |
198 | void | 144 | void |
199 | GCC_handle_encrypted (struct CadetPeer *peer, | 145 | GCC_transmit (struct CadetConnection *cc, |
200 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg); | 146 | struct GNUNET_MQ_Envelope *env); |
201 | 147 | ||
202 | /** | ||
203 | * Core handler for axolotl key exchange traffic. | ||
204 | * | ||
205 | * @param cls Closure (unused). | ||
206 | * @param message Message received. | ||
207 | * @param peer Neighbor who sent the message. | ||
208 | * | ||
209 | * @return GNUNET_OK, to keep the connection open. | ||
210 | */ | ||
211 | int | ||
212 | GCC_handle_ax_kx (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
213 | const struct GNUNET_MessageHeader *message); | ||
214 | 148 | ||
215 | /** | 149 | /** |
216 | * Core handler for axolotl encrypted cadet network traffic. | 150 | * A CREATE_ACK was received for this connection, process it. |
217 | * | 151 | * |
218 | * @param cls Closure (unused). | 152 | * @param cc the connection that got the ACK. |
219 | * @param message Message received. | ||
220 | * @param peer Neighbor who sent the message. | ||
221 | * | ||
222 | * @return GNUNET_OK, to keep the connection open. | ||
223 | */ | 153 | */ |
224 | int | 154 | void |
225 | GCC_handle_ax (void *cls, const struct GNUNET_PeerIdentity *peer, | 155 | GCC_handle_connection_create_ack (struct CadetConnection *cc); |
226 | struct GNUNET_MessageHeader *message); | ||
227 | 156 | ||
228 | /** | ||
229 | * Core handler for cadet keepalives. | ||
230 | * | ||
231 | * @param cls closure | ||
232 | * @param message message | ||
233 | * @param peer peer identity this notification is about | ||
234 | * @return GNUNET_OK to keep the connection open, | ||
235 | * GNUNET_SYSERR to close it (signal serious error) | ||
236 | * | ||
237 | * TODO: Check who we got this from, to validate route. | ||
238 | */ | ||
239 | int | ||
240 | GCC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
241 | const struct GNUNET_MessageHeader *message); | ||
242 | 157 | ||
243 | /** | 158 | /** |
244 | * Send an ACK on the appropriate connection/channel, depending on | 159 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a |
245 | * the direction and the position of the peer. | 160 | * connection that we already have. Either our ACK got lost |
161 | * or something is fishy. Consider retransmitting the ACK. | ||
246 | * | 162 | * |
247 | * @param c Which connection to send the hop-by-hop ACK. | 163 | * @param cc connection that got the duplicate CREATE |
248 | * @param fwd Is this a fwd ACK? (will go dest->root). | ||
249 | * @param force Send the ACK even if suboptimal (e.g. requested by POLL). | ||
250 | */ | 164 | */ |
251 | void | 165 | void |
252 | GCC_send_ack (struct CadetConnection *c, int fwd, int force); | 166 | GCC_handle_duplicate_create (struct CadetConnection *cc); |
253 | 167 | ||
254 | /** | ||
255 | * Initialize the connections subsystem | ||
256 | * | ||
257 | * @param c Configuration handle. | ||
258 | */ | ||
259 | void | ||
260 | GCC_init (const struct GNUNET_CONFIGURATION_Handle *c); | ||
261 | 168 | ||
262 | /** | 169 | /** |
263 | * Shut down the connections subsystem. | 170 | * Handle KX message. |
171 | * | ||
172 | * @param cc connection that received encrypted message | ||
173 | * @param msg the key exchange message | ||
264 | */ | 174 | */ |
265 | void | 175 | void |
266 | GCC_shutdown (void); | 176 | GCC_handle_kx (struct CadetConnection *cc, |
177 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); | ||
267 | 178 | ||
268 | /** | ||
269 | * Create a connection. | ||
270 | * | ||
271 | * @param cid Connection ID (either created locally or imposed remotely). | ||
272 | * @param t Tunnel this connection belongs to (or NULL for transit connections); | ||
273 | * @param path Path this connection has to use (copy is made). | ||
274 | * @param own_pos Own position in the @c path path. | ||
275 | * | ||
276 | * @return Newly created connection. | ||
277 | * NULL in case of error: own id not in path, wrong neighbors, ... | ||
278 | */ | ||
279 | struct CadetConnection * | ||
280 | GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
281 | struct CadetTunnel *t, | ||
282 | struct CadetPeerPath *path, | ||
283 | unsigned int own_pos); | ||
284 | 179 | ||
285 | /** | 180 | /** |
286 | * Connection is no longer needed: destroy it. | 181 | * Handle KX_AUTH message. |
287 | * | ||
288 | * Cancels all pending traffic (including possible DESTROY messages), all | ||
289 | * maintenance tasks and removes the connection from neighbor peers and tunnel. | ||
290 | * | 182 | * |
291 | * @param c Connection to destroy. | 183 | * @param cc connection that received encrypted message |
184 | * @param msg the key exchange message | ||
292 | */ | 185 | */ |
293 | void | 186 | void |
294 | GCC_destroy (struct CadetConnection *c); | 187 | GCC_handle_kx_auth (struct CadetConnection *cc, |
295 | 188 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg); | |
296 | /** | ||
297 | * Get the connection ID. | ||
298 | * | ||
299 | * @param c Connection to get the ID from. | ||
300 | * | ||
301 | * @return ID of the connection. | ||
302 | */ | ||
303 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * | ||
304 | GCC_get_id (const struct CadetConnection *c); | ||
305 | 189 | ||
306 | 190 | ||
307 | /** | 191 | /** |
308 | * Get the connection path. | 192 | * Performance metrics for a connection. |
309 | * | ||
310 | * @param c Connection to get the path from. | ||
311 | * | ||
312 | * @return path used by the connection. | ||
313 | */ | 193 | */ |
314 | const struct CadetPeerPath * | 194 | struct CadetConnectionMetrics |
315 | GCC_get_path (const struct CadetConnection *c); | 195 | { |
316 | 196 | ||
317 | /** | 197 | /** |
318 | * Get the connection state. | 198 | * Our current best estimate of the latency, based on a weighted |
319 | * | 199 | * average of at least @a latency_datapoints values. |
320 | * @param c Connection to get the state from. | 200 | */ |
321 | * | 201 | struct GNUNET_TIME_Relative aged_latency; |
322 | * @return state of the connection. | ||
323 | */ | ||
324 | enum CadetConnectionState | ||
325 | GCC_get_state (const struct CadetConnection *c); | ||
326 | 202 | ||
327 | /** | 203 | /** |
328 | * Get the connection tunnel. | 204 | * When was this connection first established? (by us sending or |
329 | * | 205 | * receiving the CREATE_ACK for the first time) |
330 | * @param c Connection to get the tunnel from. | 206 | */ |
331 | * | 207 | struct GNUNET_TIME_Absolute age; |
332 | * @return tunnel of the connection. | ||
333 | */ | ||
334 | struct CadetTunnel * | ||
335 | GCC_get_tunnel (const struct CadetConnection *c); | ||
336 | 208 | ||
337 | /** | 209 | /** |
338 | * Get free buffer space in a connection. | 210 | * When was this connection last used? (by us sending or |
339 | * | 211 | * receiving a PAYLOAD message on it) |
340 | * @param c Connection. | 212 | */ |
341 | * @param fwd Is query about FWD traffic? | 213 | struct GNUNET_TIME_Absolute last_use; |
342 | * | ||
343 | * @return Free buffer space [0 - max_msgs_queue/max_connections] | ||
344 | */ | ||
345 | unsigned int | ||
346 | GCC_get_buffer (struct CadetConnection *c, int fwd); | ||
347 | 214 | ||
348 | /** | 215 | /** |
349 | * Get how many messages have we allowed to send to us from a direction. | 216 | * How many packets that ought to generate an ACK did we send via |
350 | * | 217 | * this connection? |
351 | * @param c Connection. | 218 | */ |
352 | * @param fwd Are we asking about traffic from FWD (BCK messages)? | 219 | unsigned long long num_acked_transmissions; |
353 | * | ||
354 | * @return last_ack_sent - last_pid_recv | ||
355 | */ | ||
356 | unsigned int | ||
357 | GCC_get_allowed (struct CadetConnection *c, int fwd); | ||
358 | 220 | ||
359 | /** | 221 | /** |
360 | * Get messages queued in a connection. | 222 | * Number of packets that were sent via this connection did actually |
361 | * | 223 | * receive an ACK? (Note: ACKs may be transmitted and lost via |
362 | * @param c Connection. | 224 | * other connections, so this value should only be interpreted |
363 | * @param fwd Is query about FWD traffic? | 225 | * relative to @e num_acked_transmissions and in relation to other |
364 | * | 226 | * connections.) |
365 | * @return Number of messages queued. | 227 | */ |
366 | */ | 228 | unsigned long long num_successes; |
367 | unsigned int | ||
368 | GCC_get_qn (struct CadetConnection *c, int fwd); | ||
369 | 229 | ||
370 | /** | 230 | }; |
371 | * Get next PID to use. | ||
372 | * | ||
373 | * @param c Connection. | ||
374 | * @param fwd Is query about FWD traffic? | ||
375 | * @return Next PID to use. | ||
376 | */ | ||
377 | struct CadetEncryptedMessageIdentifier | ||
378 | GCC_get_pid (struct CadetConnection *c, int fwd); | ||
379 | 231 | ||
380 | /** | ||
381 | * Allow the connection to advertise a buffer of the given size. | ||
382 | * | ||
383 | * The connection will send an @c fwd ACK message (so: in direction !fwd) | ||
384 | * allowing up to last_pid_recv + buffer. | ||
385 | * | ||
386 | * @param c Connection. | ||
387 | * @param buffer How many more messages the connection can accept. | ||
388 | * @param fwd Is this about FWD traffic? (The ack will go dest->root). | ||
389 | */ | ||
390 | void | ||
391 | GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd); | ||
392 | 232 | ||
393 | /** | 233 | /** |
394 | * Send FWD keepalive packets for a connection. | 234 | * Obtain performance @a metrics from @a cc. |
395 | * | 235 | * |
396 | * @param cls Closure (connection for which to send the keepalive). | 236 | * @param cc connection to query |
397 | * @param tc Notification context. | 237 | * @return the metrics |
398 | */ | 238 | */ |
399 | void | 239 | const struct CadetConnectionMetrics * |
400 | GCC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 240 | GCC_get_metrics (struct CadetConnection *cc); |
241 | |||
401 | 242 | ||
402 | /** | 243 | /** |
403 | * Send BCK keepalive packets for a connection. | 244 | * Handle encrypted message. |
404 | * | 245 | * |
405 | * @param cls Closure (connection for which to send the keepalive). | 246 | * @param cc connection that received encrypted message |
406 | * @param tc Notification context. | 247 | * @param msg the encrypted message to decrypt |
407 | */ | 248 | */ |
408 | void | 249 | void |
409 | GCC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 250 | GCC_handle_encrypted (struct CadetConnection *cc, |
251 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg); | ||
410 | 252 | ||
411 | 253 | ||
412 | /** | 254 | /** |
413 | * Notify other peers on a connection of a broken link. Mark connections | 255 | * We sent a message for which we expect to receive an ACK via |
414 | * to destroy after all traffic has been sent. | 256 | * the connection identified by @a cti. |
415 | * | 257 | * |
416 | * @param c Connection on which there has been a disconnection. | 258 | * @param cid connection identifier where we expect an ACK |
417 | * @param peer Peer that disconnected. | ||
418 | */ | 259 | */ |
419 | void | 260 | void |
420 | GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer); | 261 | GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); |
421 | 262 | ||
422 | /** | ||
423 | * Is this peer the first one on the connection? | ||
424 | * | ||
425 | * @param c Connection. | ||
426 | * @param fwd Is this about fwd traffic? | ||
427 | * | ||
428 | * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. | ||
429 | */ | ||
430 | int | ||
431 | GCC_is_origin (struct CadetConnection *c, int fwd); | ||
432 | 263 | ||
433 | /** | 264 | /** |
434 | * Is this peer the last one on the connection? | 265 | * We observed an ACK for a message that was originally sent via |
435 | * | 266 | * the connection identified by @a cti. |
436 | * @param c Connection. | ||
437 | * @param fwd Is this about fwd traffic? | ||
438 | * Note that the ROOT is the terminal for BCK traffic! | ||
439 | * | 267 | * |
440 | * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. | 268 | * @param cid connection identifier where we got an ACK for a message |
269 | * that was originally sent via this connection (the ACK | ||
270 | * may have gotten back to us via a different connection). | ||
441 | */ | 271 | */ |
442 | int | 272 | void |
443 | GCC_is_terminal (struct CadetConnection *c, int fwd); | 273 | GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); |
444 | |||
445 | /** | ||
446 | * See if we are allowed to send by the next hop in the given direction. | ||
447 | * | ||
448 | * @param c Connection. | ||
449 | * @param fwd Is this about fwd traffic? | ||
450 | * | ||
451 | * @return #GNUNET_YES in case it's OK to send. | ||
452 | */ | ||
453 | int | ||
454 | GCC_is_sendable (struct CadetConnection *c, int fwd); | ||
455 | 274 | ||
456 | /** | ||
457 | * Check if this connection is a direct one (never trim a direct connection). | ||
458 | * | ||
459 | * @param c Connection. | ||
460 | * | ||
461 | * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. | ||
462 | */ | ||
463 | int | ||
464 | GCC_is_direct (struct CadetConnection *c); | ||
465 | 275 | ||
466 | /** | 276 | /** |
467 | * Cancel a previously sent message while it's in the queue. | 277 | * We observed some the given @a latency on the connection |
278 | * identified by @a cti. (The same connection was taken | ||
279 | * in both directions.) | ||
468 | * | 280 | * |
469 | * ONLY can be called before the continuation given to the send function | 281 | * @param cti connection identifier where we measured latency |
470 | * is called. Once the continuation is called, the message is no longer in the | 282 | * @param latency the observed latency |
471 | * queue. | ||
472 | * | ||
473 | * @param q Handle to the queue. | ||
474 | */ | 283 | */ |
475 | void | 284 | void |
476 | GCC_cancel (struct CadetConnectionQueue *q); | 285 | GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, |
286 | struct GNUNET_TIME_Relative latency); | ||
477 | 287 | ||
478 | /** | ||
479 | * Sends an already built message on a connection, properly registering | ||
480 | * all used resources. | ||
481 | * | ||
482 | * @param message Message to send. | ||
483 | * @param payload_type Type of payload, in case the message is encrypted. | ||
484 | * 0 for restransmissions (when type is no longer known) | ||
485 | * UINT16_MAX when not applicable. | ||
486 | * @param payload_id ID of the payload (PID, ACK, ...). | ||
487 | * @param c Connection on which this message is transmitted. | ||
488 | * @param fwd Is this a fwd message? | ||
489 | * @param force Force the connection to accept the message (buffer overfill). | ||
490 | * @param cont Continuation called once message is sent. Can be NULL. | ||
491 | * @param cont_cls Closure for @c cont. | ||
492 | * | ||
493 | * @return Handle to cancel the message before it's sent. | ||
494 | * NULL on error. | ||
495 | * Invalid on @c cont call. | ||
496 | */ | ||
497 | struct CadetConnectionQueue * | ||
498 | GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
499 | uint16_t payload_type, | ||
500 | struct CadetEncryptedMessageIdentifier payload_id, | ||
501 | struct CadetConnection *c, int fwd, int force, | ||
502 | GCC_sent cont, void *cont_cls); | ||
503 | 288 | ||
504 | /** | 289 | /** |
505 | * Sends a CREATE CONNECTION message for a path to a peer. | 290 | * Return the tunnel associated with this connection. |
506 | * Changes the connection and tunnel states if necessary. | ||
507 | * | 291 | * |
508 | * @param connection Connection to create. | 292 | * @param cc connection to query |
293 | * @return corresponding entry in the tunnel's connection list | ||
509 | */ | 294 | */ |
510 | void | 295 | struct CadetTConnection * |
511 | GCC_send_create (struct CadetConnection *connection); | 296 | GCC_get_ct (struct CadetConnection *cc); |
512 | 297 | ||
513 | /** | ||
514 | * Send a message to all peers in this connection that the connection | ||
515 | * is no longer valid. | ||
516 | * | ||
517 | * If some peer should not receive the message, it should be zero'ed out | ||
518 | * before calling this function. | ||
519 | * | ||
520 | * @param c The connection whose peers to notify. | ||
521 | */ | ||
522 | void | ||
523 | GCC_send_destroy (struct CadetConnection *c); | ||
524 | 298 | ||
525 | /** | 299 | /** |
526 | * @brief Start a polling timer for the connection. | 300 | * Obtain the path used by this connection. |
527 | * | 301 | * |
528 | * When a neighbor does not accept more traffic on the connection it could be | 302 | * @param cc connection |
529 | * caused by a simple congestion or by a lost ACK. Polling enables to check | 303 | * @return path to @a cc |
530 | * for the lastest ACK status for a connection. | ||
531 | * | ||
532 | * @param c Connection. | ||
533 | * @param fwd Should we poll in the FWD direction? | ||
534 | */ | 304 | */ |
535 | void | 305 | struct CadetPeerPath * |
536 | GCC_start_poll (struct CadetConnection *c, int fwd); | 306 | GCC_get_path (struct CadetConnection *cc); |
537 | 307 | ||
538 | 308 | ||
539 | /** | 309 | /** |
540 | * @brief Stop polling a connection for ACKs. | 310 | * Obtain unique ID for the connection. |
541 | * | ||
542 | * Once we have enough ACKs for future traffic, polls are no longer necessary. | ||
543 | * | 311 | * |
544 | * @param c Connection. | 312 | * @param cc connection. |
545 | * @param fwd Should we stop the poll in the FWD direction? | 313 | * @return unique number of the connection |
546 | */ | 314 | */ |
547 | void | 315 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * |
548 | GCC_stop_poll (struct CadetConnection *c, int fwd); | 316 | GCC_get_id (struct CadetConnection *cc); |
317 | |||
549 | 318 | ||
550 | /** | 319 | /** |
551 | * Get a (static) string for a connection. | 320 | * Get a (static) string for a connection. |
552 | * | 321 | * |
553 | * @param c Connection. | 322 | * @param cc Connection. |
554 | */ | 323 | */ |
555 | const char * | 324 | const char * |
556 | GCC_2s (const struct CadetConnection *c); | 325 | GCC_2s (const struct CadetConnection *cc); |
326 | |||
557 | 327 | ||
558 | /** | 328 | /** |
559 | * Log all possible info about the connection state. | 329 | * Log connection info. |
560 | * | 330 | * |
561 | * @param c Connection to debug. | 331 | * @param cc connection |
562 | * @param level Debug level to use. | 332 | * @param level Debug level to use. |
563 | */ | 333 | */ |
564 | void | 334 | void |
565 | GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level); | 335 | GCC_debug (struct CadetConnection *cc, |
336 | enum GNUNET_ErrorType level); | ||
566 | 337 | ||
567 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
568 | { | ||
569 | #endif | ||
570 | #ifdef __cplusplus | ||
571 | } | ||
572 | #endif | ||
573 | 338 | ||
574 | /* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */ | ||
575 | #endif | 339 | #endif |
576 | /* end of gnunet-service-cadet_connection.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_core.c b/src/cadet/gnunet-service-cadet_core.c index 3768c36a5..ae03b4f35 100644 --- a/src/cadet/gnunet-service-cadet-new_core.c +++ b/src/cadet/gnunet-service-cadet_core.c | |||
@@ -30,11 +30,11 @@ | |||
30 | * - Optimization: given BROKEN messages, destroy paths (?) | 30 | * - Optimization: given BROKEN messages, destroy paths (?) |
31 | */ | 31 | */ |
32 | #include "platform.h" | 32 | #include "platform.h" |
33 | #include "gnunet-service-cadet-new_core.h" | 33 | #include "gnunet-service-cadet_core.h" |
34 | #include "gnunet-service-cadet-new_paths.h" | 34 | #include "gnunet-service-cadet_paths.h" |
35 | #include "gnunet-service-cadet-new_peer.h" | 35 | #include "gnunet-service-cadet_peer.h" |
36 | #include "gnunet-service-cadet-new_connection.h" | 36 | #include "gnunet-service-cadet_connection.h" |
37 | #include "gnunet-service-cadet-new_tunnels.h" | 37 | #include "gnunet-service-cadet_tunnels.h" |
38 | #include "gnunet_core_service.h" | 38 | #include "gnunet_core_service.h" |
39 | #include "gnunet_statistics_service.h" | 39 | #include "gnunet_statistics_service.h" |
40 | #include "cadet_protocol.h" | 40 | #include "cadet_protocol.h" |
diff --git a/src/cadet/gnunet-service-cadet-new_core.h b/src/cadet/gnunet-service-cadet_core.h index 65b0a6ba5..65b0a6ba5 100644 --- a/src/cadet/gnunet-service-cadet-new_core.h +++ b/src/cadet/gnunet-service-cadet_core.h | |||
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c index 22673b167..f00c0caf3 100644 --- a/src/cadet/gnunet-service-cadet_dht.c +++ b/src/cadet/gnunet-service-cadet_dht.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 3 | Copyright (C) 2013, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -17,25 +17,41 @@ | |||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | 20 | /** | |
21 | * @file cadet/gnunet-service-cadet_dht.c | ||
22 | * @brief Information we track per peer. | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
21 | 26 | ||
22 | #include "platform.h" | 27 | #include "platform.h" |
23 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
24 | |||
25 | #include "gnunet_dht_service.h" | 29 | #include "gnunet_dht_service.h" |
26 | #include "gnunet_statistics_service.h" | 30 | #include "gnunet_statistics_service.h" |
27 | 31 | #include "gnunet-service-cadet.h" | |
28 | #include "cadet_path.h" | ||
29 | #include "gnunet-service-cadet_dht.h" | 32 | #include "gnunet-service-cadet_dht.h" |
30 | #include "gnunet-service-cadet_peer.h" | ||
31 | #include "gnunet-service-cadet_hello.h" | 33 | #include "gnunet-service-cadet_hello.h" |
34 | #include "gnunet-service-cadet_peer.h" | ||
35 | #include "gnunet-service-cadet_paths.h" | ||
32 | 36 | ||
33 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) | 37 | /** |
38 | * How long do we wait before first announcing our presence to the DHT. | ||
39 | * Used to wait for our HELLO to be available. Note that we also get | ||
40 | * notifications when our HELLO is ready, so this is just the maximum | ||
41 | * we wait for the first notification. | ||
42 | */ | ||
43 | #define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) | ||
34 | 44 | ||
45 | /** | ||
46 | * How long do we wait after we get an updated HELLO before publishing? | ||
47 | * Allows for the HELLO to be updated again quickly, for example in | ||
48 | * case multiple addresses changed and we got a partial update. | ||
49 | */ | ||
50 | #define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100) | ||
51 | |||
52 | |||
53 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) | ||
35 | 54 | ||
36 | /******************************************************************************/ | ||
37 | /******************************** STRUCTS **********************************/ | ||
38 | /******************************************************************************/ | ||
39 | 55 | ||
40 | /** | 56 | /** |
41 | * Handle for DHT searches. | 57 | * Handle for DHT searches. |
@@ -47,42 +63,9 @@ struct GCD_search_handle | |||
47 | */ | 63 | */ |
48 | struct GNUNET_DHT_GetHandle *dhtget; | 64 | struct GNUNET_DHT_GetHandle *dhtget; |
49 | 65 | ||
50 | /** | ||
51 | * Provided callback to call when a path is found. | ||
52 | */ | ||
53 | GCD_search_callback callback; | ||
54 | |||
55 | /** | ||
56 | * Provided closure. | ||
57 | */ | ||
58 | void *cls; | ||
59 | |||
60 | /** | ||
61 | * Peer ID searched for | ||
62 | */ | ||
63 | GNUNET_PEER_Id peer_id; | ||
64 | }; | 66 | }; |
65 | 67 | ||
66 | 68 | ||
67 | /******************************************************************************/ | ||
68 | /******************************* GLOBALS ***********************************/ | ||
69 | /******************************************************************************/ | ||
70 | |||
71 | /** | ||
72 | * Global handle to the statistics service. | ||
73 | */ | ||
74 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
75 | |||
76 | /** | ||
77 | * Own ID (short value). | ||
78 | */ | ||
79 | extern GNUNET_PEER_Id myid; | ||
80 | |||
81 | /** | ||
82 | * Own ID (full value). | ||
83 | */ | ||
84 | extern struct GNUNET_PeerIdentity my_full_id; | ||
85 | |||
86 | /** | 69 | /** |
87 | * Handle to use DHT. | 70 | * Handle to use DHT. |
88 | */ | 71 | */ |
@@ -94,69 +77,20 @@ static struct GNUNET_DHT_Handle *dht_handle; | |||
94 | static struct GNUNET_TIME_Relative id_announce_time; | 77 | static struct GNUNET_TIME_Relative id_announce_time; |
95 | 78 | ||
96 | /** | 79 | /** |
97 | * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put. | 80 | * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put(). |
98 | */ | 81 | */ |
99 | static unsigned long long dht_replication_level; | 82 | static unsigned long long dht_replication_level; |
100 | 83 | ||
101 | /** | 84 | /** |
102 | * Task to periodically announce itself in the network. | 85 | * Task to periodically announce itself in the network. |
103 | */ | 86 | */ |
104 | static struct GNUNET_SCHEDULER_Task * announce_id_task; | 87 | static struct GNUNET_SCHEDULER_Task *announce_id_task; |
105 | 88 | ||
106 | /** | 89 | /** |
107 | * Delay for the next ID announce. | 90 | * Delay for the next ID announce. |
108 | */ | 91 | */ |
109 | static struct GNUNET_TIME_Relative announce_delay; | 92 | static struct GNUNET_TIME_Relative announce_delay; |
110 | 93 | ||
111 | /** | ||
112 | * GET requests to stop on shutdown. | ||
113 | */ | ||
114 | static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests; | ||
115 | |||
116 | /******************************************************************************/ | ||
117 | /******************************** STATIC ***********************************/ | ||
118 | /******************************************************************************/ | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Build a PeerPath from the paths returned from the DHT, reversing the paths | ||
123 | * to obtain a local peer -> destination path and interning the peer ids. | ||
124 | * | ||
125 | * @return Newly allocated and created path | ||
126 | * | ||
127 | * FIXME refactor and use build_path_from_peer_ids | ||
128 | */ | ||
129 | static struct CadetPeerPath * | ||
130 | path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, | ||
131 | unsigned int get_path_length, | ||
132 | const struct GNUNET_PeerIdentity *put_path, | ||
133 | unsigned int put_path_length) | ||
134 | { | ||
135 | size_t size = get_path_length + put_path_length + 1; | ||
136 | struct GNUNET_PeerIdentity peers[size]; | ||
137 | const struct GNUNET_PeerIdentity *peer; | ||
138 | struct CadetPeerPath *p; | ||
139 | unsigned int own_pos; | ||
140 | int i; | ||
141 | |||
142 | peers[0] = my_full_id; | ||
143 | LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length); | ||
144 | for (i = 0 ; i < get_path_length; i++) | ||
145 | { | ||
146 | peer = &get_path[get_path_length - i - 1]; | ||
147 | LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer)); | ||
148 | peers[i + 1] = *peer; | ||
149 | } | ||
150 | for (i = 0 ; i < put_path_length; i++) | ||
151 | { | ||
152 | peer = &put_path[put_path_length - i - 1]; | ||
153 | LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer)); | ||
154 | peers[i + get_path_length + 1] = *peer; | ||
155 | } | ||
156 | p = path_build_from_peer_ids (peers, size, myid, &own_pos); | ||
157 | return p; | ||
158 | } | ||
159 | |||
160 | 94 | ||
161 | /** | 95 | /** |
162 | * Function to process paths received for a new peer addition. The recorded | 96 | * Function to process paths received for a new peer addition. The recorded |
@@ -176,42 +110,34 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, | |||
176 | */ | 110 | */ |
177 | static void | 111 | static void |
178 | dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, | 112 | dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, |
179 | const struct GNUNET_HashCode * key, | 113 | const struct GNUNET_HashCode *key, |
180 | const struct GNUNET_PeerIdentity *get_path, | 114 | const struct GNUNET_PeerIdentity *get_path, |
181 | unsigned int get_path_length, | 115 | unsigned int get_path_length, |
182 | const struct GNUNET_PeerIdentity *put_path, | 116 | const struct GNUNET_PeerIdentity *put_path, |
183 | unsigned int put_path_length, enum GNUNET_BLOCK_Type type, | 117 | unsigned int put_path_length, |
184 | size_t size, const void *data) | 118 | enum GNUNET_BLOCK_Type type, |
119 | size_t size, | ||
120 | const void *data) | ||
185 | { | 121 | { |
186 | struct GCD_search_handle *h = cls; | 122 | const struct GNUNET_HELLO_Message *hello = data; |
187 | struct GNUNET_HELLO_Message *hello; | ||
188 | struct CadetPeerPath *p; | ||
189 | struct CadetPeer *peer; | 123 | struct CadetPeer *peer; |
190 | char *s; | ||
191 | 124 | ||
192 | p = path_build_from_dht (get_path, get_path_length, | 125 | GCPP_try_path_from_dht (get_path, |
193 | put_path, put_path_length); | 126 | get_path_length, |
194 | if (NULL == p) | 127 | put_path, |
128 | put_path_length); | ||
129 | if ( (size >= sizeof (struct GNUNET_HELLO_Message)) && | ||
130 | (ntohs (hello->header.size) == size) && | ||
131 | (size == GNUNET_HELLO_size (hello)) ) | ||
195 | { | 132 | { |
196 | GNUNET_break_op (0); | 133 | peer = GCP_get (&put_path[0], |
197 | return; | 134 | GNUNET_YES); |
135 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
136 | "Got HELLO for %s\n", | ||
137 | GCP_2s (peer)); | ||
138 | GCP_set_hello (peer, | ||
139 | hello); | ||
198 | } | 140 | } |
199 | |||
200 | s = path_2s (p); | ||
201 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
202 | "Got path from DHT: %s\n", | ||
203 | s); | ||
204 | GNUNET_free_non_null (s); | ||
205 | |||
206 | peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES); | ||
207 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
208 | "Got HELLO for %s\n", | ||
209 | GCP_2s (peer)); | ||
210 | h->callback (h->cls, p); | ||
211 | path_destroy (p); | ||
212 | hello = (struct GNUNET_HELLO_Message *) data; | ||
213 | GCP_set_hello (peer, hello); | ||
214 | GCP_try_connect (peer); | ||
215 | } | 141 | } |
216 | 142 | ||
217 | 143 | ||
@@ -229,19 +155,10 @@ announce_id (void *cls) | |||
229 | struct GNUNET_TIME_Absolute expiration; | 155 | struct GNUNET_TIME_Absolute expiration; |
230 | struct GNUNET_TIME_Relative next_put; | 156 | struct GNUNET_TIME_Relative next_put; |
231 | 157 | ||
232 | announce_id_task = NULL; | ||
233 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n"); | ||
234 | hello = GCH_get_mine (); | 158 | hello = GCH_get_mine (); |
235 | size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0; | 159 | size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0; |
236 | if ( (NULL == hello) || (0 == size) ) | 160 | if (0 == size) |
237 | { | 161 | { |
238 | /* Peerinfo gave us no hello yet, try again soon. */ | ||
239 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
240 | " no hello, waiting!\n"); | ||
241 | GNUNET_STATISTICS_update (stats, | ||
242 | "# DHT announce skipped (no hello)", | ||
243 | 1, | ||
244 | GNUNET_NO); | ||
245 | expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), | 162 | expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), |
246 | announce_delay); | 163 | announce_delay); |
247 | announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay); | 164 | announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay); |
@@ -252,71 +169,64 @@ announce_id (void *cls) | |||
252 | announce_delay = GNUNET_TIME_UNIT_SECONDS; | 169 | announce_delay = GNUNET_TIME_UNIT_SECONDS; |
253 | } | 170 | } |
254 | 171 | ||
255 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
256 | "Hello %p size: %u\n", | ||
257 | hello, | ||
258 | size); | ||
259 | if (NULL != hello) | ||
260 | { | ||
261 | GNUNET_STATISTICS_update (stats, | ||
262 | "# DHT announce", | ||
263 | 1, GNUNET_NO); | ||
264 | memset (&phash, | ||
265 | 0, | ||
266 | sizeof (phash)); | ||
267 | GNUNET_memcpy (&phash, | ||
268 | &my_full_id, | ||
269 | sizeof (my_full_id)); | ||
270 | GNUNET_DHT_put (dht_handle, /* DHT handle */ | ||
271 | &phash, /* Key to use */ | ||
272 | dht_replication_level, /* Replication level */ | ||
273 | GNUNET_DHT_RO_RECORD_ROUTE | ||
274 | | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ | ||
275 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ | ||
276 | size, /* Size of the data */ | ||
277 | (const char *) hello, /* Data itself */ | ||
278 | expiration, /* Data expiration */ | ||
279 | NULL, /* Continuation */ | ||
280 | NULL); /* Continuation closure */ | ||
281 | } | ||
282 | /* Call again in id_announce_time, unless HELLO expires first, | 172 | /* Call again in id_announce_time, unless HELLO expires first, |
283 | * but wait at least 1s. */ | 173 | * but wait at least 1s. */ |
284 | next_put = GNUNET_TIME_absolute_get_remaining (expiration); | 174 | next_put |
285 | next_put = GNUNET_TIME_relative_min (next_put, | 175 | = GNUNET_TIME_absolute_get_remaining (expiration); |
286 | id_announce_time); | 176 | next_put |
287 | next_put = GNUNET_TIME_relative_max (next_put, | 177 | = GNUNET_TIME_relative_min (next_put, |
288 | GNUNET_TIME_UNIT_SECONDS); | 178 | id_announce_time); |
289 | announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put, | 179 | next_put |
290 | &announce_id, | 180 | = GNUNET_TIME_relative_max (next_put, |
291 | cls); | 181 | GNUNET_TIME_UNIT_SECONDS); |
182 | announce_id_task | ||
183 | = GNUNET_SCHEDULER_add_delayed (next_put, | ||
184 | &announce_id, | ||
185 | cls); | ||
186 | GNUNET_STATISTICS_update (stats, | ||
187 | "# DHT announce", | ||
188 | 1, | ||
189 | GNUNET_NO); | ||
190 | memset (&phash, | ||
191 | 0, | ||
192 | sizeof (phash)); | ||
193 | GNUNET_memcpy (&phash, | ||
194 | &my_full_id, | ||
195 | sizeof (my_full_id)); | ||
196 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
197 | "Announcing my HELLO (%u bytes) in the DHT\n", | ||
198 | size); | ||
199 | GNUNET_DHT_put (dht_handle, /* DHT handle */ | ||
200 | &phash, /* Key to use */ | ||
201 | dht_replication_level, /* Replication level */ | ||
202 | GNUNET_DHT_RO_RECORD_ROUTE | ||
203 | | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ | ||
204 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ | ||
205 | size, /* Size of the data */ | ||
206 | (const char *) hello, /* Data itself */ | ||
207 | expiration, /* Data expiration */ | ||
208 | NULL, /* Continuation */ | ||
209 | NULL); /* Continuation closure */ | ||
292 | } | 210 | } |
293 | 211 | ||
212 | |||
294 | /** | 213 | /** |
295 | * Iterator over hash map entries and stop GET requests before disconnecting | 214 | * Function called by the HELLO subsystem whenever OUR hello |
296 | * from the DHT. | 215 | * changes. Re-triggers the DHT PUT immediately. |
297 | * | ||
298 | * @param cls Closure (unused) | ||
299 | * @param key Current peer ID. | ||
300 | * @param value Value in the hash map (GCD_search_handle). | ||
301 | * | ||
302 | * @return #GNUNET_YES, we should continue to iterate, | ||
303 | */ | 216 | */ |
304 | int | 217 | void |
305 | stop_get (void *cls, | 218 | GCD_hello_update () |
306 | uint32_t key, | ||
307 | void *value) | ||
308 | { | 219 | { |
309 | struct GCD_search_handle *h = value; | 220 | if (NULL == announce_id_task) |
310 | 221 | return; /* too early */ | |
311 | GCD_search_stop (h); | 222 | GNUNET_SCHEDULER_cancel (announce_id_task); |
312 | return GNUNET_YES; | 223 | announce_id_task |
224 | = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY, | ||
225 | &announce_id, | ||
226 | NULL); | ||
313 | } | 227 | } |
314 | 228 | ||
315 | 229 | ||
316 | /******************************************************************************/ | ||
317 | /******************************** API ***********************************/ | ||
318 | /******************************************************************************/ | ||
319 | |||
320 | /** | 230 | /** |
321 | * Initialize the DHT subsystem. | 231 | * Initialize the DHT subsystem. |
322 | * | 232 | * |
@@ -325,36 +235,40 @@ stop_get (void *cls, | |||
325 | void | 235 | void |
326 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c) | 236 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c) |
327 | { | 237 | { |
328 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); | ||
329 | if (GNUNET_OK != | 238 | if (GNUNET_OK != |
330 | GNUNET_CONFIGURATION_get_value_number (c, "CADET", | 239 | GNUNET_CONFIGURATION_get_value_number (c, |
240 | "CADET", | ||
331 | "DHT_REPLICATION_LEVEL", | 241 | "DHT_REPLICATION_LEVEL", |
332 | &dht_replication_level)) | 242 | &dht_replication_level)) |
333 | { | 243 | { |
334 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET", | 244 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, |
335 | "DHT_REPLICATION_LEVEL", "USING DEFAULT"); | 245 | "CADET", |
246 | "DHT_REPLICATION_LEVEL", | ||
247 | "USING DEFAULT"); | ||
336 | dht_replication_level = 3; | 248 | dht_replication_level = 3; |
337 | } | 249 | } |
338 | 250 | ||
339 | if (GNUNET_OK != | 251 | if (GNUNET_OK != |
340 | GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME", | 252 | GNUNET_CONFIGURATION_get_value_time (c, |
253 | "CADET", | ||
254 | "ID_ANNOUNCE_TIME", | ||
341 | &id_announce_time)) | 255 | &id_announce_time)) |
342 | { | 256 | { |
343 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET", | 257 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, |
344 | "ID_ANNOUNCE_TIME", "MISSING"); | 258 | "CADET", |
259 | "ID_ANNOUNCE_TIME", | ||
260 | "MISSING"); | ||
345 | GNUNET_SCHEDULER_shutdown (); | 261 | GNUNET_SCHEDULER_shutdown (); |
346 | return; | 262 | return; |
347 | } | 263 | } |
348 | 264 | ||
349 | dht_handle = GNUNET_DHT_connect (c, 64); | 265 | dht_handle = GNUNET_DHT_connect (c, |
350 | if (NULL == dht_handle) | 266 | 64); |
351 | { | 267 | GNUNET_break (NULL != dht_handle); |
352 | GNUNET_break (0); | ||
353 | } | ||
354 | |||
355 | announce_delay = GNUNET_TIME_UNIT_SECONDS; | 268 | announce_delay = GNUNET_TIME_UNIT_SECONDS; |
356 | announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); | 269 | announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY, |
357 | get_requests = GNUNET_CONTAINER_multihashmap32_create (32); | 270 | &announce_id, |
271 | NULL); | ||
358 | } | 272 | } |
359 | 273 | ||
360 | 274 | ||
@@ -364,10 +278,7 @@ GCD_init (const struct GNUNET_CONFIGURATION_Handle *c) | |||
364 | void | 278 | void |
365 | GCD_shutdown (void) | 279 | GCD_shutdown (void) |
366 | { | 280 | { |
367 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n"); | 281 | if (NULL != dht_handle) |
368 | GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL); | ||
369 | GNUNET_CONTAINER_multihashmap32_destroy (get_requests); | ||
370 | if (dht_handle != NULL) | ||
371 | { | 282 | { |
372 | GNUNET_DHT_disconnect (dht_handle); | 283 | GNUNET_DHT_disconnect (dht_handle); |
373 | dht_handle = NULL; | 284 | dht_handle = NULL; |
@@ -379,22 +290,31 @@ GCD_shutdown (void) | |||
379 | } | 290 | } |
380 | } | 291 | } |
381 | 292 | ||
293 | |||
294 | /** | ||
295 | * Search DHT for paths to @a peeR_id | ||
296 | * | ||
297 | * @param peer_id peer to search for | ||
298 | * @return handle to abort search | ||
299 | */ | ||
382 | struct GCD_search_handle * | 300 | struct GCD_search_handle * |
383 | GCD_search (const struct GNUNET_PeerIdentity *peer_id, | 301 | GCD_search (const struct GNUNET_PeerIdentity *peer_id) |
384 | GCD_search_callback callback, void *cls) | ||
385 | { | 302 | { |
386 | struct GNUNET_HashCode phash; | 303 | struct GNUNET_HashCode phash; |
387 | struct GCD_search_handle *h; | 304 | struct GCD_search_handle *h; |
388 | 305 | ||
389 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n", | 306 | GNUNET_STATISTICS_update (stats, |
390 | GNUNET_i2s (peer_id)); | 307 | "# DHT search", |
391 | GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO); | 308 | 1, |
392 | memset (&phash, 0, sizeof (phash)); | 309 | GNUNET_NO); |
393 | GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id)); | 310 | memset (&phash, |
311 | 0, | ||
312 | sizeof (phash)); | ||
313 | GNUNET_memcpy (&phash, | ||
314 | peer_id, | ||
315 | sizeof (*peer_id)); | ||
316 | |||
394 | h = GNUNET_new (struct GCD_search_handle); | 317 | h = GNUNET_new (struct GCD_search_handle); |
395 | h->peer_id = GNUNET_PEER_intern (peer_id); | ||
396 | h->callback = callback; | ||
397 | h->cls = cls; | ||
398 | h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ | 318 | h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ |
399 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ | 319 | GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ |
400 | &phash, /* key to search */ | 320 | &phash, /* key to search */ |
@@ -405,20 +325,27 @@ GCD_search (const struct GNUNET_PeerIdentity *peer_id, | |||
405 | 0, /* xquery bits */ | 325 | 0, /* xquery bits */ |
406 | &dht_get_id_handler, | 326 | &dht_get_id_handler, |
407 | h); | 327 | h); |
408 | GNUNET_CONTAINER_multihashmap32_put (get_requests, | 328 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
409 | h->peer_id, | 329 | "Starting DHT GET for peer %s (%p)\n", |
410 | h, | 330 | GNUNET_i2s (peer_id), |
411 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | 331 | h); |
412 | return h; | 332 | return h; |
413 | } | 333 | } |
414 | 334 | ||
415 | 335 | ||
336 | /** | ||
337 | * Stop DHT search started with #GCD_search(). | ||
338 | * | ||
339 | * @param h handle to search to stop | ||
340 | */ | ||
416 | void | 341 | void |
417 | GCD_search_stop (struct GCD_search_handle *h) | 342 | GCD_search_stop (struct GCD_search_handle *h) |
418 | { | 343 | { |
419 | GNUNET_break (GNUNET_OK == | 344 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
420 | GNUNET_CONTAINER_multihashmap32_remove (get_requests, | 345 | "Stopping DHT GET %p\n", |
421 | h->peer_id, h)); | 346 | h); |
422 | GNUNET_DHT_get_stop (h->dhtget); | 347 | GNUNET_DHT_get_stop (h->dhtget); |
423 | GNUNET_free (h); | 348 | GNUNET_free (h); |
424 | } | 349 | } |
350 | |||
351 | /* end of gnunet-service-cadet_dht.c */ | ||
diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h index b70dfe975..5d7ab29a0 100644 --- a/src/cadet/gnunet-service-cadet_dht.h +++ b/src/cadet/gnunet-service-cadet_dht.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 3 | Copyright (C) 2013, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -22,10 +22,10 @@ | |||
22 | * @file cadet/gnunet-service-cadet_dht.h | 22 | * @file cadet/gnunet-service-cadet_dht.h |
23 | * @brief cadet service; dealing with DHT requests and results | 23 | * @brief cadet service; dealing with DHT requests and results |
24 | * @author Bartlomiej Polot | 24 | * @author Bartlomiej Polot |
25 | * @author Christian Grothoff | ||
25 | * | 26 | * |
26 | * All functions in this file should use the prefix GMD (Gnunet Cadet Dht) | 27 | * All functions in this file should use the prefix GCD (Gnunet Cadet Dht) |
27 | */ | 28 | */ |
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_DHT_H | 29 | #ifndef GNUNET_SERVICE_CADET_DHT_H |
30 | #define GNUNET_SERVICE_CADET_DHT_H | 30 | #define GNUNET_SERVICE_CADET_DHT_H |
31 | 31 | ||
@@ -40,23 +40,11 @@ extern "C" | |||
40 | #include "platform.h" | 40 | #include "platform.h" |
41 | #include "gnunet_util_lib.h" | 41 | #include "gnunet_util_lib.h" |
42 | 42 | ||
43 | struct GCD_search_handle; | ||
44 | |||
45 | |||
46 | /** | 43 | /** |
47 | * Callback called on each path found over the DHT. | 44 | * Handle for DHT search operation. |
48 | * | ||
49 | * @param cls Closure. | ||
50 | * @param path An unchecked, unoptimized path to the target node. | ||
51 | * After callback will no longer be valid! | ||
52 | */ | 45 | */ |
53 | typedef void | 46 | struct GCD_search_handle; |
54 | (*GCD_search_callback) (void *cls, | ||
55 | const struct CadetPeerPath *path); | ||
56 | 47 | ||
57 | /******************************************************************************/ | ||
58 | /******************************** API ***********************************/ | ||
59 | /******************************************************************************/ | ||
60 | 48 | ||
61 | /** | 49 | /** |
62 | * Initialize the DHT subsystem. | 50 | * Initialize the DHT subsystem. |
@@ -66,6 +54,7 @@ typedef void | |||
66 | void | 54 | void |
67 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c); | 55 | GCD_init (const struct GNUNET_CONFIGURATION_Handle *c); |
68 | 56 | ||
57 | |||
69 | /** | 58 | /** |
70 | * Shut down the DHT subsystem. | 59 | * Shut down the DHT subsystem. |
71 | */ | 60 | */ |
@@ -73,14 +62,32 @@ void | |||
73 | GCD_shutdown (void); | 62 | GCD_shutdown (void); |
74 | 63 | ||
75 | 64 | ||
65 | /** | ||
66 | * Function called by the HELLO subsystem whenever OUR hello | ||
67 | * changes. Re-triggers the DHT PUT immediately. | ||
68 | */ | ||
69 | void | ||
70 | GCD_hello_update (void); | ||
71 | |||
72 | /** | ||
73 | * Search DHT for paths to @a peeR_id | ||
74 | * | ||
75 | * @param peer_id peer to search for | ||
76 | * @return handle to abort search | ||
77 | */ | ||
76 | struct GCD_search_handle * | 78 | struct GCD_search_handle * |
77 | GCD_search (const struct GNUNET_PeerIdentity *peer_id, | 79 | GCD_search (const struct GNUNET_PeerIdentity *peer_id); |
78 | GCD_search_callback callback, void *cls); | ||
79 | 80 | ||
80 | 81 | ||
82 | /** | ||
83 | * Stop DHT search started with #GCD_search(). | ||
84 | * | ||
85 | * @param h handle to search to stop | ||
86 | */ | ||
81 | void | 87 | void |
82 | GCD_search_stop (struct GCD_search_handle *h); | 88 | GCD_search_stop (struct GCD_search_handle *h); |
83 | 89 | ||
90 | |||
84 | #if 0 /* keep Emacsens' auto-indent happy */ | 91 | #if 0 /* keep Emacsens' auto-indent happy */ |
85 | { | 92 | { |
86 | #endif | 93 | #endif |
@@ -88,6 +95,6 @@ GCD_search_stop (struct GCD_search_handle *h); | |||
88 | } | 95 | } |
89 | #endif | 96 | #endif |
90 | 97 | ||
91 | /* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ | 98 | /* ifndef GNUNET_CADET_SERVICE_DHT_H */ |
92 | #endif | 99 | #endif |
93 | /* end of gnunet-cadet-service_LOCAL.h */ | 100 | /* end of gnunet-service-cadet_dht.h */ |
diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c index 3c63f3551..6d85de39f 100644 --- a/src/cadet/gnunet-service-cadet_hello.c +++ b/src/cadet/gnunet-service-cadet_hello.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2014 GNUnet e.V. | 3 | Copyright (C) 2014, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -17,58 +17,33 @@ | |||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | 20 | /** | |
21 | * @file cadet/gnunet-service-cadet_hello.c | ||
22 | * @brief spread knowledge about how to contact other peers from PEERINFO | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - is most of this necessary/helpful? | ||
28 | * - should we not simply restrict this to OUR hello? | ||
29 | */ | ||
21 | #include "platform.h" | 30 | #include "platform.h" |
22 | #include "gnunet_util_lib.h" | 31 | #include "gnunet_util_lib.h" |
23 | 32 | ||
24 | #include "gnunet_statistics_service.h" | 33 | #include "gnunet_statistics_service.h" |
25 | #include "gnunet_peerinfo_service.h" | 34 | #include "gnunet_peerinfo_service.h" |
26 | |||
27 | #include "cadet_protocol.h" | 35 | #include "cadet_protocol.h" |
28 | #include "cadet_path.h" | 36 | #include "gnunet-service-cadet.h" |
29 | 37 | #include "gnunet-service-cadet_dht.h" | |
30 | #include "gnunet-service-cadet_hello.h" | 38 | #include "gnunet-service-cadet_hello.h" |
31 | #include "gnunet-service-cadet_peer.h" | 39 | #include "gnunet-service-cadet_peer.h" |
32 | 40 | ||
33 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) | 41 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) |
34 | 42 | ||
35 | |||
36 | /******************************************************************************/ | ||
37 | /******************************** STRUCTS **********************************/ | ||
38 | /******************************************************************************/ | ||
39 | |||
40 | |||
41 | |||
42 | /******************************************************************************/ | ||
43 | /******************************* GLOBALS ***********************************/ | ||
44 | /******************************************************************************/ | ||
45 | |||
46 | /** | ||
47 | * Global handle to the statistics service. | ||
48 | */ | ||
49 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
50 | |||
51 | /** | ||
52 | * Local peer own ID (memory efficient handle). | ||
53 | */ | ||
54 | extern GNUNET_PEER_Id myid; | ||
55 | |||
56 | /** | ||
57 | * Local peer own ID (full value). | ||
58 | */ | ||
59 | extern struct GNUNET_PeerIdentity my_full_id; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Don't try to recover tunnels if shutting down. | ||
64 | */ | ||
65 | extern int shutting_down; | ||
66 | |||
67 | |||
68 | /** | 43 | /** |
69 | * Hello message of local peer. | 44 | * Hello message of local peer. |
70 | */ | 45 | */ |
71 | const struct GNUNET_HELLO_Message *mine; | 46 | static struct GNUNET_HELLO_Message *mine; |
72 | 47 | ||
73 | /** | 48 | /** |
74 | * Handle to peerinfo service. | 49 | * Handle to peerinfo service. |
@@ -78,13 +53,9 @@ static struct GNUNET_PEERINFO_Handle *peerinfo; | |||
78 | /** | 53 | /** |
79 | * Iterator context. | 54 | * Iterator context. |
80 | */ | 55 | */ |
81 | struct GNUNET_PEERINFO_NotifyContext* nc; | 56 | static struct GNUNET_PEERINFO_NotifyContext *nc; |
82 | 57 | ||
83 | 58 | ||
84 | /******************************************************************************/ | ||
85 | /******************************** STATIC ***********************************/ | ||
86 | /******************************************************************************/ | ||
87 | |||
88 | /** | 59 | /** |
89 | * Process each hello message received from peerinfo. | 60 | * Process each hello message received from peerinfo. |
90 | * | 61 | * |
@@ -94,31 +65,37 @@ struct GNUNET_PEERINFO_NotifyContext* nc; | |||
94 | * @param err_msg Error message. | 65 | * @param err_msg Error message. |
95 | */ | 66 | */ |
96 | static void | 67 | static void |
97 | got_hello (void *cls, const struct GNUNET_PeerIdentity *id, | 68 | got_hello (void *cls, |
69 | const struct GNUNET_PeerIdentity *id, | ||
98 | const struct GNUNET_HELLO_Message *hello, | 70 | const struct GNUNET_HELLO_Message *hello, |
99 | const char *err_msg) | 71 | const char *err_msg) |
100 | { | 72 | { |
101 | struct CadetPeer *peer; | 73 | struct CadetPeer *peer; |
102 | 74 | ||
103 | if (NULL == id || NULL == hello) | 75 | if ( (NULL == id) || |
76 | (NULL == hello) ) | ||
77 | return; | ||
78 | if (0 == memcmp (id, | ||
79 | &my_full_id, | ||
80 | sizeof (struct GNUNET_PeerIdentity))) | ||
104 | { | 81 | { |
105 | LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello); | 82 | GNUNET_free_non_null (mine); |
83 | mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header); | ||
84 | GCD_hello_update (); | ||
106 | return; | 85 | return; |
107 | } | 86 | } |
108 | LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n", | ||
109 | GNUNET_i2s (id), GNUNET_HELLO_size (hello), | ||
110 | GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello))); | ||
111 | peer = GCP_get (id, GNUNET_YES); | ||
112 | GCP_set_hello (peer, hello); | ||
113 | |||
114 | if (GCP_get_short_id (peer) == myid) | ||
115 | mine = GCP_get_hello (peer); | ||
116 | } | ||
117 | 87 | ||
88 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
89 | "Hello for %s (%d bytes), expires on %s\n", | ||
90 | GNUNET_i2s (id), | ||
91 | GNUNET_HELLO_size (hello), | ||
92 | GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello))); | ||
93 | peer = GCP_get (id, | ||
94 | GNUNET_YES); | ||
95 | GCP_set_hello (peer, | ||
96 | hello); | ||
97 | } | ||
118 | 98 | ||
119 | /******************************************************************************/ | ||
120 | /******************************** API ***********************************/ | ||
121 | /******************************************************************************/ | ||
122 | 99 | ||
123 | /** | 100 | /** |
124 | * Initialize the hello subsystem. | 101 | * Initialize the hello subsystem. |
@@ -128,10 +105,12 @@ got_hello (void *cls, const struct GNUNET_PeerIdentity *id, | |||
128 | void | 105 | void |
129 | GCH_init (const struct GNUNET_CONFIGURATION_Handle *c) | 106 | GCH_init (const struct GNUNET_CONFIGURATION_Handle *c) |
130 | { | 107 | { |
131 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); | ||
132 | GNUNET_assert (NULL == nc); | 108 | GNUNET_assert (NULL == nc); |
133 | peerinfo = GNUNET_PEERINFO_connect (c); | 109 | peerinfo = GNUNET_PEERINFO_connect (c); |
134 | nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL); | 110 | nc = GNUNET_PEERINFO_notify (c, |
111 | GNUNET_NO, | ||
112 | &got_hello, | ||
113 | NULL); | ||
135 | } | 114 | } |
136 | 115 | ||
137 | 116 | ||
@@ -141,7 +120,6 @@ GCH_init (const struct GNUNET_CONFIGURATION_Handle *c) | |||
141 | void | 120 | void |
142 | GCH_shutdown () | 121 | GCH_shutdown () |
143 | { | 122 | { |
144 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down channels\n"); | ||
145 | if (NULL != nc) | 123 | if (NULL != nc) |
146 | { | 124 | { |
147 | GNUNET_PEERINFO_notify_cancel (nc); | 125 | GNUNET_PEERINFO_notify_cancel (nc); |
@@ -152,6 +130,11 @@ GCH_shutdown () | |||
152 | GNUNET_PEERINFO_disconnect (peerinfo); | 130 | GNUNET_PEERINFO_disconnect (peerinfo); |
153 | peerinfo = NULL; | 131 | peerinfo = NULL; |
154 | } | 132 | } |
133 | if (NULL != mine) | ||
134 | { | ||
135 | GNUNET_free (mine); | ||
136 | mine = NULL; | ||
137 | } | ||
155 | } | 138 | } |
156 | 139 | ||
157 | 140 | ||
@@ -166,35 +149,4 @@ GCH_get_mine (void) | |||
166 | return mine; | 149 | return mine; |
167 | } | 150 | } |
168 | 151 | ||
169 | 152 | /* end of gnunet-service-cadet-new_hello.c */ | |
170 | /** | ||
171 | * Get another peer's hello message. | ||
172 | * | ||
173 | * @param id ID of the peer whose hello message is requested. | ||
174 | * | ||
175 | * @return Hello message, if any (NULL possible). | ||
176 | */ | ||
177 | const struct GNUNET_HELLO_Message * | ||
178 | GCH_get (const struct GNUNET_PeerIdentity *id) | ||
179 | { | ||
180 | struct CadetPeer *p; | ||
181 | |||
182 | p = GCP_get (id, GNUNET_NO); | ||
183 | if (NULL == p) | ||
184 | return NULL; | ||
185 | return GCP_get_hello (p); | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Convert a hello message to a string. | ||
191 | * | ||
192 | * @param h Hello message. | ||
193 | */ | ||
194 | char * | ||
195 | GCH_2s (const struct GNUNET_HELLO_Message *h) | ||
196 | { | ||
197 | return "hello (TODO)"; | ||
198 | } | ||
199 | |||
200 | |||
diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h index 34121e1e0..4291ae985 100644 --- a/src/cadet/gnunet-service-cadet_hello.h +++ b/src/cadet/gnunet-service-cadet_hello.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2014 GNUnet e.V. | 3 | Copyright (C) 2014, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -22,8 +22,9 @@ | |||
22 | * @file cadet/gnunet-service-cadet_hello.h | 22 | * @file cadet/gnunet-service-cadet_hello.h |
23 | * @brief cadet service; dealing with hello messages | 23 | * @brief cadet service; dealing with hello messages |
24 | * @author Bartlomiej Polot | 24 | * @author Bartlomiej Polot |
25 | * @author Christian Grothoff | ||
25 | * | 26 | * |
26 | * All functions in this file should use the prefix GMH (Gnunet Cadet Hello) | 27 | * All functions in this file should use the prefix GCH (Gnunet Cadet Hello) |
27 | */ | 28 | */ |
28 | 29 | ||
29 | #ifndef GNUNET_SERVICE_CADET_HELLO_H | 30 | #ifndef GNUNET_SERVICE_CADET_HELLO_H |
diff --git a/src/cadet/gnunet-service-cadet_local.c b/src/cadet/gnunet-service-cadet_local.c deleted file mode 100644 index dea6681df..000000000 --- a/src/cadet/gnunet-service-cadet_local.c +++ /dev/null | |||
@@ -1,1553 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | |||
22 | #include "platform.h" | ||
23 | #include "gnunet_util_lib.h" | ||
24 | |||
25 | #include "gnunet_statistics_service.h" | ||
26 | |||
27 | #include "cadet.h" | ||
28 | #include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */ | ||
29 | |||
30 | #include "gnunet-service-cadet_local.h" | ||
31 | #include "gnunet-service-cadet_channel.h" | ||
32 | |||
33 | /* INFO DEBUG */ | ||
34 | #include "gnunet-service-cadet_tunnel.h" | ||
35 | #include "gnunet-service-cadet_peer.h" | ||
36 | |||
37 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__) | ||
38 | |||
39 | /******************************************************************************/ | ||
40 | /******************************** STRUCTS **********************************/ | ||
41 | /******************************************************************************/ | ||
42 | |||
43 | /** | ||
44 | * Struct containing information about a client of the service | ||
45 | * | ||
46 | * TODO: add a list of 'waiting' ports | ||
47 | */ | ||
48 | struct CadetClient | ||
49 | { | ||
50 | /** | ||
51 | * Linked list next | ||
52 | */ | ||
53 | struct CadetClient *next; | ||
54 | |||
55 | /** | ||
56 | * Linked list prev | ||
57 | */ | ||
58 | struct CadetClient *prev; | ||
59 | |||
60 | /** | ||
61 | * Tunnels that belong to this client, indexed by local id | ||
62 | */ | ||
63 | struct GNUNET_CONTAINER_MultiHashMap32 *own_channels; | ||
64 | |||
65 | /** | ||
66 | * Tunnels this client has accepted, indexed by incoming local id | ||
67 | */ | ||
68 | struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels; | ||
69 | |||
70 | /** | ||
71 | * Channel ID for the next incoming channel. | ||
72 | */ | ||
73 | struct GNUNET_CADET_ClientChannelNumber next_ccn; | ||
74 | |||
75 | /** | ||
76 | * Handle to communicate with the client | ||
77 | */ | ||
78 | struct GNUNET_SERVER_Client *handle; | ||
79 | |||
80 | /** | ||
81 | * Ports that this client has declared interest in. | ||
82 | * Indexed by port, contains *Client. | ||
83 | */ | ||
84 | struct GNUNET_CONTAINER_MultiHashMap *ports; | ||
85 | |||
86 | /** | ||
87 | * Whether the client is active or shutting down (don't send confirmations | ||
88 | * to a client that is shutting down. | ||
89 | */ | ||
90 | int shutting_down; | ||
91 | |||
92 | /** | ||
93 | * ID of the client, mainly for debug messages | ||
94 | */ | ||
95 | unsigned int id; | ||
96 | }; | ||
97 | |||
98 | /******************************************************************************/ | ||
99 | /******************************* GLOBALS ***********************************/ | ||
100 | /******************************************************************************/ | ||
101 | |||
102 | /** | ||
103 | * Global handle to the statistics service. | ||
104 | */ | ||
105 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
106 | |||
107 | /** | ||
108 | * Handle to server lib. | ||
109 | */ | ||
110 | static struct GNUNET_SERVER_Handle *server_handle; | ||
111 | |||
112 | /** | ||
113 | * DLL with all the clients, head. | ||
114 | */ | ||
115 | static struct CadetClient *clients_head; | ||
116 | |||
117 | /** | ||
118 | * DLL with all the clients, tail. | ||
119 | */ | ||
120 | static struct CadetClient *clients_tail; | ||
121 | |||
122 | /** | ||
123 | * Next ID to assign to a client. | ||
124 | */ | ||
125 | unsigned int next_client_id; | ||
126 | |||
127 | /** | ||
128 | * All ports clients of this peer have opened. | ||
129 | */ | ||
130 | static struct GNUNET_CONTAINER_MultiHashMap *ports; | ||
131 | |||
132 | /** | ||
133 | * Notification context, to send messages to local clients. | ||
134 | */ | ||
135 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
136 | |||
137 | |||
138 | /******************************************************************************/ | ||
139 | /******************************** STATIC ***********************************/ | ||
140 | /******************************************************************************/ | ||
141 | |||
142 | /** | ||
143 | * Remove client's ports from the global hashmap on disconnect. | ||
144 | * | ||
145 | * @param cls Closure (unused). | ||
146 | * @param key Port. | ||
147 | * @param value Client structure. | ||
148 | * | ||
149 | * @return #GNUNET_OK, keep iterating. | ||
150 | */ | ||
151 | static int | ||
152 | client_release_ports (void *cls, | ||
153 | const struct GNUNET_HashCode *key, | ||
154 | void *value) | ||
155 | { | ||
156 | int res; | ||
157 | |||
158 | res = GNUNET_CONTAINER_multihashmap_remove (ports, key, value); | ||
159 | if (GNUNET_YES != res) | ||
160 | { | ||
161 | GNUNET_break (0); | ||
162 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
163 | "Port %s by client %p was not registered.\n", | ||
164 | GNUNET_h2s (key), value); | ||
165 | } | ||
166 | return GNUNET_OK; | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Iterator for deleting each channel whose client endpoint disconnected. | ||
172 | * | ||
173 | * @param cls Closure (client that has disconnected). | ||
174 | * @param key The local channel id (used to access the hashmap). | ||
175 | * @param value The value stored at the key (channel to destroy). | ||
176 | * | ||
177 | * @return #GNUNET_OK, keep iterating. | ||
178 | */ | ||
179 | static int | ||
180 | channel_destroy_iterator (void *cls, | ||
181 | uint32_t key, | ||
182 | void *value) | ||
183 | { | ||
184 | struct CadetChannel *ch = value; | ||
185 | struct CadetClient *c = cls; | ||
186 | |||
187 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
188 | " Channel %s destroy, due to client %s shutdown.\n", | ||
189 | GCCH_2s (ch), GML_2s (c)); | ||
190 | |||
191 | GCCH_handle_local_destroy (ch, | ||
192 | c, | ||
193 | key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
194 | return GNUNET_OK; | ||
195 | } | ||
196 | |||
197 | |||
198 | /** | ||
199 | * Unregister data and free memory for a client. | ||
200 | * | ||
201 | * @param c Client to destroy. No longer valid after call. | ||
202 | */ | ||
203 | static void | ||
204 | client_destroy (struct CadetClient *c) | ||
205 | { | ||
206 | LOG (GNUNET_ERROR_TYPE_DEBUG, " client destroy: %p/%u\n", c, c->id); | ||
207 | GNUNET_SERVER_client_drop (c->handle); | ||
208 | c->shutting_down = GNUNET_YES; | ||
209 | |||
210 | if (NULL != c->own_channels) | ||
211 | { | ||
212 | GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels, | ||
213 | &channel_destroy_iterator, c); | ||
214 | GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels); | ||
215 | } | ||
216 | if (NULL != c->incoming_channels) | ||
217 | { | ||
218 | GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels, | ||
219 | &channel_destroy_iterator, c); | ||
220 | GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels); | ||
221 | } | ||
222 | if (NULL != c->ports) | ||
223 | { | ||
224 | GNUNET_CONTAINER_multihashmap_iterate (c->ports, | ||
225 | &client_release_ports, c); | ||
226 | GNUNET_CONTAINER_multihashmap_destroy (c->ports); | ||
227 | } | ||
228 | |||
229 | GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c); | ||
230 | GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO); | ||
231 | GNUNET_SERVER_client_set_user_context (c->handle, NULL); | ||
232 | GNUNET_free (c); | ||
233 | } | ||
234 | |||
235 | |||
236 | /** | ||
237 | * Create a client record, register data and initialize memory. | ||
238 | * | ||
239 | * @param client Client's handle. | ||
240 | */ | ||
241 | static struct CadetClient * | ||
242 | client_new (struct GNUNET_SERVER_Client *client) | ||
243 | { | ||
244 | struct CadetClient *c; | ||
245 | |||
246 | GNUNET_SERVER_client_keep (client); | ||
247 | GNUNET_SERVER_notification_context_add (nc, client); | ||
248 | |||
249 | c = GNUNET_new (struct CadetClient); | ||
250 | c->handle = client; | ||
251 | c->id = next_client_id++; /* overflow not important: just for debug */ | ||
252 | |||
253 | c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32); | ||
254 | c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32); | ||
255 | |||
256 | GNUNET_SERVER_client_set_user_context (client, c); | ||
257 | GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c); | ||
258 | GNUNET_STATISTICS_update (stats, "# clients", +1, GNUNET_NO); | ||
259 | |||
260 | LOG (GNUNET_ERROR_TYPE_DEBUG, " client created: %p/%u\n", c, c->id); | ||
261 | |||
262 | return c; | ||
263 | } | ||
264 | |||
265 | |||
266 | /******************************************************************************/ | ||
267 | /******************************** HANDLES ***********************************/ | ||
268 | /******************************************************************************/ | ||
269 | |||
270 | /** | ||
271 | * Handler for client connection. | ||
272 | * | ||
273 | * @param cls Closure (unused). | ||
274 | * @param client Client handler. | ||
275 | */ | ||
276 | static void | ||
277 | handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client) | ||
278 | { | ||
279 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); | ||
280 | if (NULL == client) | ||
281 | return; | ||
282 | |||
283 | (void) client_new (client); | ||
284 | } | ||
285 | |||
286 | |||
287 | /** | ||
288 | * Handler for client disconnection | ||
289 | * | ||
290 | * @param cls closure | ||
291 | * @param client identification of the client; NULL | ||
292 | * for the last call when the server is destroyed | ||
293 | */ | ||
294 | static void | ||
295 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
296 | { | ||
297 | struct CadetClient *c; | ||
298 | |||
299 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected: %p\n", client); | ||
300 | |||
301 | c = GML_client_get (client); | ||
302 | if (NULL != c) | ||
303 | { | ||
304 | LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n", | ||
305 | c->id, c); | ||
306 | client_destroy (c); | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | LOG (GNUNET_ERROR_TYPE_DEBUG, " disconnecting client's context NULL\n"); | ||
311 | } | ||
312 | return; | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * Handler for port open requests. | ||
318 | * | ||
319 | * @param cls Closure. | ||
320 | * @param client Identification of the client. | ||
321 | * @param message The actual message. | ||
322 | */ | ||
323 | static void | ||
324 | handle_port_open (void *cls, struct GNUNET_SERVER_Client *client, | ||
325 | const struct GNUNET_MessageHeader *message) | ||
326 | { | ||
327 | struct CadetClient *c; | ||
328 | struct GNUNET_CADET_PortMessage *pmsg; | ||
329 | |||
330 | LOG (GNUNET_ERROR_TYPE_DEBUG, "open port requested\n"); | ||
331 | |||
332 | /* Sanity check for client registration */ | ||
333 | if (NULL == (c = GML_client_get (client))) | ||
334 | { | ||
335 | GNUNET_break (0); | ||
336 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
337 | return; | ||
338 | } | ||
339 | LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); | ||
340 | |||
341 | /* Message size sanity check */ | ||
342 | if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size)) | ||
343 | { | ||
344 | GNUNET_break (0); | ||
345 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | pmsg = (struct GNUNET_CADET_PortMessage *) message; | ||
350 | if (NULL == c->ports) | ||
351 | { | ||
352 | c->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO); | ||
353 | } | ||
354 | /* store in client's hashmap */ | ||
355 | if (GNUNET_OK != | ||
356 | GNUNET_CONTAINER_multihashmap_put (c->ports, &pmsg->port, c, | ||
357 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
358 | { | ||
359 | GNUNET_break (0); | ||
360 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
361 | return; | ||
362 | } | ||
363 | /* store in global hashmap */ | ||
364 | /* FIXME only allow one client to have the port open, | ||
365 | * have a backup hashmap with waiting clients */ | ||
366 | GNUNET_CONTAINER_multihashmap_put (ports, &pmsg->port, c, | ||
367 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
368 | |||
369 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Handler for port close requests. | ||
375 | * | ||
376 | * @param cls Closure. | ||
377 | * @param client Identification of the client. | ||
378 | * @param message The actual message. | ||
379 | */ | ||
380 | static void | ||
381 | handle_port_close (void *cls, struct GNUNET_SERVER_Client *client, | ||
382 | const struct GNUNET_MessageHeader *message) | ||
383 | { | ||
384 | struct CadetClient *c; | ||
385 | struct GNUNET_CADET_PortMessage *pmsg; | ||
386 | int removed; | ||
387 | |||
388 | LOG (GNUNET_ERROR_TYPE_DEBUG, "close port requested\n"); | ||
389 | |||
390 | /* Sanity check for client registration */ | ||
391 | if (NULL == (c = GML_client_get (client))) | ||
392 | { | ||
393 | GNUNET_break (0); | ||
394 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
395 | return; | ||
396 | } | ||
397 | LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); | ||
398 | |||
399 | /* Message size sanity check */ | ||
400 | if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size)) | ||
401 | { | ||
402 | GNUNET_break (0); | ||
403 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
404 | return; | ||
405 | } | ||
406 | |||
407 | pmsg = (struct GNUNET_CADET_PortMessage *) message; | ||
408 | removed = GNUNET_CONTAINER_multihashmap_remove (c->ports, &pmsg->port, c); | ||
409 | GNUNET_break_op (GNUNET_YES == removed); | ||
410 | removed = GNUNET_CONTAINER_multihashmap_remove (ports, &pmsg->port, c); | ||
411 | GNUNET_break_op (GNUNET_YES == removed); | ||
412 | |||
413 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
414 | } | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Handler for requests of new channels. | ||
419 | * | ||
420 | * @param cls Closure. | ||
421 | * @param client Identification of the client. | ||
422 | * @param message The actual message. | ||
423 | */ | ||
424 | static void | ||
425 | handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, | ||
426 | const struct GNUNET_MessageHeader *message) | ||
427 | { | ||
428 | struct CadetClient *c; | ||
429 | |||
430 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
431 | LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n"); | ||
432 | |||
433 | /* Sanity check for client registration */ | ||
434 | if (NULL == (c = GML_client_get (client))) | ||
435 | { | ||
436 | GNUNET_break (0); | ||
437 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
438 | return; | ||
439 | } | ||
440 | LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); | ||
441 | |||
442 | /* Message size sanity check */ | ||
443 | if (sizeof (struct GNUNET_CADET_LocalChannelCreateMessage) | ||
444 | != ntohs (message->size)) | ||
445 | { | ||
446 | GNUNET_break (0); | ||
447 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
448 | return; | ||
449 | } | ||
450 | |||
451 | if (GNUNET_OK != | ||
452 | GCCH_handle_local_create (c, | ||
453 | (struct GNUNET_CADET_LocalChannelCreateMessage *) | ||
454 | message)) | ||
455 | { | ||
456 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
457 | return; | ||
458 | } | ||
459 | |||
460 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
461 | } | ||
462 | |||
463 | |||
464 | /** | ||
465 | * Handler for requests of deleting tunnels | ||
466 | * | ||
467 | * @param cls closure | ||
468 | * @param client identification of the client | ||
469 | * @param message the actual message | ||
470 | */ | ||
471 | static void | ||
472 | handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, | ||
473 | const struct GNUNET_MessageHeader *message) | ||
474 | { | ||
475 | const struct GNUNET_CADET_LocalChannelDestroyMessage *msg; | ||
476 | struct CadetClient *c; | ||
477 | struct CadetChannel *ch; | ||
478 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
479 | |||
480 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n"); | ||
481 | |||
482 | /* Sanity check for client registration */ | ||
483 | if (NULL == (c = GML_client_get (client))) | ||
484 | { | ||
485 | GNUNET_break (0); | ||
486 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
487 | return; | ||
488 | } | ||
489 | LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); | ||
490 | |||
491 | /* Message sanity check */ | ||
492 | if (sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage) | ||
493 | != ntohs (message->size)) | ||
494 | { | ||
495 | GNUNET_break (0); | ||
496 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
497 | return; | ||
498 | } | ||
499 | |||
500 | msg = (const struct GNUNET_CADET_LocalChannelDestroyMessage *) message; | ||
501 | |||
502 | /* Retrieve tunnel */ | ||
503 | ccn = msg->ccn; | ||
504 | ch = GML_channel_get (c, ccn); | ||
505 | |||
506 | LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n", | ||
507 | c->id, ccn); | ||
508 | |||
509 | if (NULL == ch) | ||
510 | { | ||
511 | LOG (GNUNET_ERROR_TYPE_WARNING, " channel %X not found\n", ccn); | ||
512 | GNUNET_STATISTICS_update (stats, | ||
513 | "# client destroy messages on unknown channel", | ||
514 | 1, GNUNET_NO); | ||
515 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | GCCH_handle_local_destroy (ch, | ||
520 | c, | ||
521 | ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
522 | |||
523 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
524 | } | ||
525 | |||
526 | |||
527 | /** | ||
528 | * Handler for client traffic | ||
529 | * | ||
530 | * @param cls closure | ||
531 | * @param client identification of the client | ||
532 | * @param message the actual message | ||
533 | */ | ||
534 | static void | ||
535 | handle_data (void *cls, struct GNUNET_SERVER_Client *client, | ||
536 | const struct GNUNET_MessageHeader *message) | ||
537 | { | ||
538 | const struct GNUNET_MessageHeader *payload; | ||
539 | struct GNUNET_CADET_LocalData *msg; | ||
540 | struct CadetClient *c; | ||
541 | struct CadetChannel *ch; | ||
542 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
543 | size_t message_size; | ||
544 | size_t payload_size; | ||
545 | size_t payload_claimed_size; | ||
546 | int fwd; | ||
547 | |||
548 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
549 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
550 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client\n"); | ||
551 | |||
552 | /* Sanity check for client registration */ | ||
553 | if (NULL == (c = GML_client_get (client))) | ||
554 | { | ||
555 | GNUNET_break (0); | ||
556 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
557 | return; | ||
558 | } | ||
559 | |||
560 | /* Sanity check for message size */ | ||
561 | message_size = ntohs (message->size); | ||
562 | if (sizeof (struct GNUNET_CADET_LocalData) | ||
563 | + sizeof (struct GNUNET_MessageHeader) > message_size | ||
564 | || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < message_size) | ||
565 | { | ||
566 | GNUNET_break (0); | ||
567 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | /* Sanity check for payload size */ | ||
572 | payload_size = message_size - sizeof (struct GNUNET_CADET_LocalData); | ||
573 | msg = (struct GNUNET_CADET_LocalData *) message; | ||
574 | payload = (struct GNUNET_MessageHeader *) &msg[1]; | ||
575 | payload_claimed_size = ntohs (payload->size); | ||
576 | if (sizeof (struct GNUNET_MessageHeader) > payload_claimed_size | ||
577 | || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size | ||
578 | || payload_claimed_size > payload_size) | ||
579 | { | ||
580 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
581 | "client claims to send %u bytes in %u payload\n", | ||
582 | payload_claimed_size, payload_size); | ||
583 | GNUNET_break (0); | ||
584 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | ccn = msg->ccn; | ||
589 | LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes (%u payload) by client %u\n", | ||
590 | payload_size, payload_claimed_size, c->id); | ||
591 | |||
592 | /* Channel exists? */ | ||
593 | fwd = ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; | ||
594 | ch = GML_channel_get (c, ccn); | ||
595 | if (NULL == ch) | ||
596 | { | ||
597 | GNUNET_STATISTICS_update (stats, | ||
598 | "# client data messages on unknown channel", | ||
599 | 1, GNUNET_NO); | ||
600 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
601 | return; | ||
602 | } | ||
603 | |||
604 | if (GNUNET_OK != GCCH_handle_local_data (ch, c, fwd, payload, payload_size)) | ||
605 | { | ||
606 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n"); | ||
611 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
612 | |||
613 | return; | ||
614 | } | ||
615 | |||
616 | |||
617 | /** | ||
618 | * Handler for client's ACKs for payload traffic. | ||
619 | * | ||
620 | * @param cls Closure (unused). | ||
621 | * @param client Identification of the client. | ||
622 | * @param message The actual message. | ||
623 | */ | ||
624 | static void | ||
625 | handle_ack (void *cls, struct GNUNET_SERVER_Client *client, | ||
626 | const struct GNUNET_MessageHeader *message) | ||
627 | { | ||
628 | struct GNUNET_CADET_LocalAck *msg; | ||
629 | struct CadetChannel *ch; | ||
630 | struct CadetClient *c; | ||
631 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
632 | int fwd; | ||
633 | |||
634 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
635 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n"); | ||
636 | |||
637 | /* Sanity check for client registration */ | ||
638 | if (NULL == (c = GML_client_get (client))) | ||
639 | { | ||
640 | GNUNET_break (0); | ||
641 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
642 | return; | ||
643 | } | ||
644 | LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); | ||
645 | |||
646 | msg = (struct GNUNET_CADET_LocalAck *) message; | ||
647 | |||
648 | /* Channel exists? */ | ||
649 | ccn = msg->ccn; | ||
650 | LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", | ||
651 | ntohl (ccn.channel_of_client)); | ||
652 | ch = GML_channel_get (c, ccn); | ||
653 | LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch); | ||
654 | if (NULL == ch) | ||
655 | { | ||
656 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
657 | "Channel %X unknown.\n", | ||
658 | ntohl (ccn.channel_of_client)); | ||
659 | LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id); | ||
660 | GNUNET_STATISTICS_update (stats, | ||
661 | "# client ack messages on unknown channel", | ||
662 | 1, GNUNET_NO); | ||
663 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
664 | return; | ||
665 | } | ||
666 | |||
667 | /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ | ||
668 | /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ | ||
669 | fwd = ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; | ||
670 | |||
671 | GCCH_handle_local_ack (ch, fwd); | ||
672 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
673 | } | ||
674 | |||
675 | |||
676 | /** | ||
677 | * Iterator over all peers to send a monitoring client info about each peer. | ||
678 | * | ||
679 | * @param cls Closure (). | ||
680 | * @param peer Peer ID (tunnel remote peer). | ||
681 | * @param value Peer info. | ||
682 | * | ||
683 | * @return #GNUNET_YES, to keep iterating. | ||
684 | */ | ||
685 | static int | ||
686 | get_all_peers_iterator (void *cls, | ||
687 | const struct GNUNET_PeerIdentity * peer, | ||
688 | void *value) | ||
689 | { | ||
690 | struct GNUNET_SERVER_Client *client = cls; | ||
691 | struct CadetPeer *p = value; | ||
692 | struct GNUNET_CADET_LocalInfoPeer msg; | ||
693 | |||
694 | msg.header.size = htons (sizeof (msg)); | ||
695 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
696 | msg.destination = *peer; | ||
697 | msg.paths = htons (GCP_count_paths (p)); | ||
698 | msg.tunnel = htons (NULL != GCP_get_tunnel (p)); | ||
699 | |||
700 | LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n", | ||
701 | GNUNET_i2s (peer)); | ||
702 | |||
703 | GNUNET_SERVER_notification_context_unicast (nc, client, | ||
704 | &msg.header, GNUNET_NO); | ||
705 | return GNUNET_YES; | ||
706 | } | ||
707 | |||
708 | |||
709 | /** | ||
710 | * Iterator over all peers to dump info for each peer. | ||
711 | * | ||
712 | * @param cls Closure (unused). | ||
713 | * @param peer Peer ID (tunnel remote peer). | ||
714 | * @param value Peer info. | ||
715 | * | ||
716 | * @return #GNUNET_YES, to keep iterating. | ||
717 | */ | ||
718 | static int | ||
719 | show_peer_iterator (void *cls, | ||
720 | const struct GNUNET_PeerIdentity * peer, | ||
721 | void *value) | ||
722 | { | ||
723 | struct CadetPeer *p = value; | ||
724 | struct CadetTunnel *t; | ||
725 | |||
726 | t = GCP_get_tunnel (p); | ||
727 | if (NULL != t) | ||
728 | GCT_debug (t, GNUNET_ERROR_TYPE_ERROR); | ||
729 | |||
730 | LOG (GNUNET_ERROR_TYPE_ERROR, "\n"); | ||
731 | |||
732 | return GNUNET_YES; | ||
733 | } | ||
734 | |||
735 | |||
736 | /** | ||
737 | * Iterator over all paths of a peer to build an InfoPeer message. | ||
738 | * | ||
739 | * Message contains blocks of peers, first not included. | ||
740 | * | ||
741 | * @param cls Closure (message to build). | ||
742 | * @param peer Peer this path is towards. | ||
743 | * @param path Path itself | ||
744 | * @return #GNUNET_YES if should keep iterating. | ||
745 | * #GNUNET_NO otherwise. | ||
746 | */ | ||
747 | static int | ||
748 | path_info_iterator (void *cls, | ||
749 | struct CadetPeer *peer, | ||
750 | struct CadetPeerPath *path) | ||
751 | { | ||
752 | struct GNUNET_CADET_LocalInfoPeer *resp = cls; | ||
753 | struct GNUNET_PeerIdentity *id; | ||
754 | uint16_t msg_size; | ||
755 | uint16_t path_size; | ||
756 | unsigned int i; | ||
757 | |||
758 | msg_size = ntohs (resp->header.size); | ||
759 | path_size = sizeof (struct GNUNET_PeerIdentity) * (path->length - 1); | ||
760 | |||
761 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Info Path %u\n", path->length); | ||
762 | if (msg_size + path_size > UINT16_MAX) | ||
763 | { | ||
764 | LOG (GNUNET_ERROR_TYPE_WARNING, "path too long for info message\n"); | ||
765 | return GNUNET_NO; | ||
766 | } | ||
767 | |||
768 | i = msg_size - sizeof (struct GNUNET_CADET_LocalInfoPeer); | ||
769 | i = i / sizeof (struct GNUNET_PeerIdentity); | ||
770 | |||
771 | /* Set id to the address of the first free peer slot. */ | ||
772 | id = (struct GNUNET_PeerIdentity *) &resp[1]; | ||
773 | id = &id[i]; | ||
774 | |||
775 | /* Don't copy first peers. | ||
776 | * First peer is always the local one. | ||
777 | * Last peer is always the destination (leave as 0, EOL). | ||
778 | */ | ||
779 | for (i = 0; i < path->length - 1; i++) | ||
780 | { | ||
781 | GNUNET_PEER_resolve (path->peers[i + 1], &id[i]); | ||
782 | LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&id[i])); | ||
783 | } | ||
784 | |||
785 | resp->header.size = htons (msg_size + path_size); | ||
786 | |||
787 | return GNUNET_YES; | ||
788 | } | ||
789 | |||
790 | |||
791 | /** | ||
792 | * Handler for client's INFO PEERS request. | ||
793 | * | ||
794 | * @param cls Closure (unused). | ||
795 | * @param client Identification of the client. | ||
796 | * @param message The actual message. | ||
797 | */ | ||
798 | static void | ||
799 | handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client, | ||
800 | const struct GNUNET_MessageHeader *message) | ||
801 | { | ||
802 | struct CadetClient *c; | ||
803 | struct GNUNET_MessageHeader reply; | ||
804 | |||
805 | /* Sanity check for client registration */ | ||
806 | if (NULL == (c = GML_client_get (client))) | ||
807 | { | ||
808 | GNUNET_break (0); | ||
809 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
810 | return; | ||
811 | } | ||
812 | |||
813 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
814 | "Received get peers request from client %u (%p)\n", | ||
815 | c->id, client); | ||
816 | |||
817 | GCP_iterate_all (get_all_peers_iterator, client); | ||
818 | reply.size = htons (sizeof (reply)); | ||
819 | reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
820 | GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); | ||
821 | |||
822 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
823 | "Get peers request from client %u completed\n", c->id); | ||
824 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
825 | } | ||
826 | |||
827 | |||
828 | /** | ||
829 | * Handler for client's SHOW_PEER request. | ||
830 | * | ||
831 | * @param cls Closure (unused). | ||
832 | * @param client Identification of the client. | ||
833 | * @param message The actual message. | ||
834 | */ | ||
835 | void | ||
836 | handle_show_peer (void *cls, struct GNUNET_SERVER_Client *client, | ||
837 | const struct GNUNET_MessageHeader *message) | ||
838 | { | ||
839 | const struct GNUNET_CADET_LocalInfo *msg; | ||
840 | struct GNUNET_CADET_LocalInfoPeer *resp; | ||
841 | struct CadetPeer *p; | ||
842 | struct CadetClient *c; | ||
843 | unsigned char cbuf[64 * 1024]; | ||
844 | |||
845 | /* Sanity check for client registration */ | ||
846 | if (NULL == (c = GML_client_get (client))) | ||
847 | { | ||
848 | GNUNET_break (0); | ||
849 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
850 | return; | ||
851 | } | ||
852 | |||
853 | msg = (struct GNUNET_CADET_LocalInfo *) message; | ||
854 | resp = (struct GNUNET_CADET_LocalInfoPeer *) cbuf; | ||
855 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
856 | "Received peer info request from client %u for peer %s\n", | ||
857 | c->id, GNUNET_i2s_full (&msg->peer)); | ||
858 | |||
859 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); | ||
860 | resp->header.size = htons (sizeof (struct GNUNET_CADET_LocalInfoPeer)); | ||
861 | resp->destination = msg->peer; | ||
862 | p = GCP_get (&msg->peer, GNUNET_NO); | ||
863 | if (NULL == p) | ||
864 | { | ||
865 | /* We don't know the peer */ | ||
866 | |||
867 | LOG (GNUNET_ERROR_TYPE_INFO, "Peer %s unknown\n", | ||
868 | GNUNET_i2s_full (&msg->peer)); | ||
869 | resp->paths = htons (0); | ||
870 | resp->tunnel = htons (NULL != GCP_get_tunnel (p)); | ||
871 | |||
872 | GNUNET_SERVER_notification_context_unicast (nc, client, | ||
873 | &resp->header, | ||
874 | GNUNET_NO); | ||
875 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
876 | return; | ||
877 | } | ||
878 | |||
879 | resp->paths = htons (GCP_count_paths (p)); | ||
880 | resp->tunnel = htons (NULL != GCP_get_tunnel (p)); | ||
881 | GCP_iterate_paths (p, &path_info_iterator, resp); | ||
882 | |||
883 | GNUNET_SERVER_notification_context_unicast (nc, c->handle, | ||
884 | &resp->header, GNUNET_NO); | ||
885 | |||
886 | LOG (GNUNET_ERROR_TYPE_INFO, "Show peer from client %u completed.\n", c->id); | ||
887 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
888 | } | ||
889 | |||
890 | |||
891 | /** | ||
892 | * Iterator over all tunnels to send a monitoring client info about each tunnel. | ||
893 | * | ||
894 | * @param cls Closure (). | ||
895 | * @param peer Peer ID (tunnel remote peer). | ||
896 | * @param value Tunnel info. | ||
897 | * | ||
898 | * @return #GNUNET_YES, to keep iterating. | ||
899 | */ | ||
900 | static int | ||
901 | get_all_tunnels_iterator (void *cls, | ||
902 | const struct GNUNET_PeerIdentity * peer, | ||
903 | void *value) | ||
904 | { | ||
905 | struct GNUNET_SERVER_Client *client = cls; | ||
906 | struct CadetTunnel *t = value; | ||
907 | struct GNUNET_CADET_LocalInfoTunnel msg; | ||
908 | |||
909 | msg.header.size = htons (sizeof (msg)); | ||
910 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
911 | msg.destination = *peer; | ||
912 | msg.channels = htonl (GCT_count_channels (t)); | ||
913 | msg.connections = htonl (GCT_count_any_connections (t)); | ||
914 | msg.cstate = htons ((uint16_t) GCT_get_cstate (t)); | ||
915 | msg.estate = htons ((uint16_t) GCT_get_estate (t)); | ||
916 | |||
917 | LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n", | ||
918 | GNUNET_i2s (peer)); | ||
919 | |||
920 | GNUNET_SERVER_notification_context_unicast (nc, client, | ||
921 | &msg.header, GNUNET_NO); | ||
922 | return GNUNET_YES; | ||
923 | } | ||
924 | |||
925 | |||
926 | /** | ||
927 | * Handler for client's INFO TUNNELS request. | ||
928 | * | ||
929 | * @param cls Closure (unused). | ||
930 | * @param client Identification of the client. | ||
931 | * @param message The actual message. | ||
932 | */ | ||
933 | static void | ||
934 | handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client, | ||
935 | const struct GNUNET_MessageHeader *message) | ||
936 | { | ||
937 | struct CadetClient *c; | ||
938 | struct GNUNET_MessageHeader reply; | ||
939 | |||
940 | /* Sanity check for client registration */ | ||
941 | if (NULL == (c = GML_client_get (client))) | ||
942 | { | ||
943 | GNUNET_break (0); | ||
944 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
945 | return; | ||
946 | } | ||
947 | |||
948 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
949 | "Received get tunnels request from client %u (%p)\n", | ||
950 | c->id, client); | ||
951 | |||
952 | GCT_iterate_all (get_all_tunnels_iterator, client); | ||
953 | reply.size = htons (sizeof (reply)); | ||
954 | reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
955 | GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); | ||
956 | |||
957 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
958 | "Get tunnels request from client %u completed\n", c->id); | ||
959 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
960 | } | ||
961 | |||
962 | |||
963 | static void | ||
964 | iter_connection (void *cls, struct CadetConnection *c) | ||
965 | { | ||
966 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
967 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h; | ||
968 | |||
969 | h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
970 | h[msg->connections] = *(GCC_get_id (c)); | ||
971 | msg->connections++; | ||
972 | } | ||
973 | |||
974 | static void | ||
975 | iter_channel (void *cls, struct CadetChannel *ch) | ||
976 | { | ||
977 | struct GNUNET_CADET_LocalInfoTunnel *msg = cls; | ||
978 | struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
979 | struct GNUNET_CADET_ChannelTunnelNumber *chn = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections]; | ||
980 | |||
981 | chn[msg->channels] = GCCH_get_id (ch); | ||
982 | msg->channels++; | ||
983 | } | ||
984 | |||
985 | |||
986 | /** | ||
987 | * Handler for client's SHOW_TUNNEL request. | ||
988 | * | ||
989 | * @param cls Closure (unused). | ||
990 | * @param client Identification of the client. | ||
991 | * @param message The actual message. | ||
992 | */ | ||
993 | void | ||
994 | handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client, | ||
995 | const struct GNUNET_MessageHeader *message) | ||
996 | { | ||
997 | const struct GNUNET_CADET_LocalInfo *msg; | ||
998 | struct GNUNET_CADET_LocalInfoTunnel *resp; | ||
999 | struct CadetClient *c; | ||
1000 | struct CadetTunnel *t; | ||
1001 | unsigned int ch_n; | ||
1002 | unsigned int c_n; | ||
1003 | size_t size; | ||
1004 | |||
1005 | /* Sanity check for client registration */ | ||
1006 | if (NULL == (c = GML_client_get (client))) | ||
1007 | { | ||
1008 | GNUNET_break (0); | ||
1009 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1010 | return; | ||
1011 | } | ||
1012 | |||
1013 | msg = (struct GNUNET_CADET_LocalInfo *) message; | ||
1014 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1015 | "Received tunnel info request from client %u for tunnel %s\n", | ||
1016 | c->id, GNUNET_i2s_full(&msg->peer)); | ||
1017 | |||
1018 | t = GCP_get_tunnel (GCP_get (&msg->peer, GNUNET_NO)); | ||
1019 | if (NULL == t) | ||
1020 | { | ||
1021 | /* We don't know the tunnel */ | ||
1022 | struct GNUNET_CADET_LocalInfoTunnel warn; | ||
1023 | |||
1024 | LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n", | ||
1025 | GNUNET_i2s_full(&msg->peer), sizeof (warn)); | ||
1026 | warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1027 | warn.header.size = htons (sizeof (warn)); | ||
1028 | warn.destination = msg->peer; | ||
1029 | warn.channels = htonl (0); | ||
1030 | warn.connections = htonl (0); | ||
1031 | warn.cstate = htons (0); | ||
1032 | warn.estate = htons (0); | ||
1033 | |||
1034 | GNUNET_SERVER_notification_context_unicast (nc, client, | ||
1035 | &warn.header, | ||
1036 | GNUNET_NO); | ||
1037 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1038 | return; | ||
1039 | } | ||
1040 | |||
1041 | /* Initialize context */ | ||
1042 | ch_n = GCT_count_channels (t); | ||
1043 | c_n = GCT_count_any_connections (t); | ||
1044 | |||
1045 | size = sizeof (struct GNUNET_CADET_LocalInfoTunnel); | ||
1046 | size += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier); | ||
1047 | size += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber); | ||
1048 | |||
1049 | resp = GNUNET_malloc (size); | ||
1050 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1051 | resp->header.size = htons (size); | ||
1052 | resp->destination = msg->peer; | ||
1053 | /* Do not interleave with iterators, iter_channel needs conn in HBO */ | ||
1054 | GCT_iterate_connections (t, &iter_connection, resp); | ||
1055 | GCT_iterate_channels (t, &iter_channel, resp); | ||
1056 | resp->connections = htonl (resp->connections); | ||
1057 | resp->channels = htonl (resp->channels); | ||
1058 | /* Do not interleave end */ | ||
1059 | resp->cstate = htons (GCT_get_cstate (t)); | ||
1060 | resp->estate = htons (GCT_get_estate (t)); | ||
1061 | GNUNET_SERVER_notification_context_unicast (nc, c->handle, | ||
1062 | &resp->header, GNUNET_NO); | ||
1063 | GNUNET_free (resp); | ||
1064 | |||
1065 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1066 | "Show tunnel request from client %u completed. %u conn, %u ch\n", | ||
1067 | c->id, c_n, ch_n); | ||
1068 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1069 | } | ||
1070 | |||
1071 | |||
1072 | /** | ||
1073 | * Handler for client's INFO_DUMP request. | ||
1074 | * | ||
1075 | * @param cls Closure (unused). | ||
1076 | * @param client Identification of the client. | ||
1077 | * @param message The actual message. | ||
1078 | */ | ||
1079 | void | ||
1080 | handle_info_dump (void *cls, struct GNUNET_SERVER_Client *client, | ||
1081 | const struct GNUNET_MessageHeader *message) | ||
1082 | { | ||
1083 | struct CadetClient *c; | ||
1084 | |||
1085 | /* Sanity check for client registration */ | ||
1086 | if (NULL == (c = GML_client_get (client))) | ||
1087 | { | ||
1088 | GNUNET_break (0); | ||
1089 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1090 | return; | ||
1091 | } | ||
1092 | |||
1093 | LOG (GNUNET_ERROR_TYPE_INFO, "Received dump info request from client %u\n", | ||
1094 | c->id); | ||
1095 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1096 | "*************************** DUMP START ***************************\n"); | ||
1097 | |||
1098 | for (c = clients_head; NULL != c; c = c->next) | ||
1099 | { | ||
1100 | LOG (GNUNET_ERROR_TYPE_ERROR, "Client %u (%p), handle: %p\n", | ||
1101 | c->id, c, c->handle); | ||
1102 | if (NULL != c->ports) | ||
1103 | LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u ports registered\n", | ||
1104 | GNUNET_CONTAINER_multihashmap_size (c->ports)); | ||
1105 | else | ||
1106 | LOG (GNUNET_ERROR_TYPE_ERROR, "\t no ports registered\n"); | ||
1107 | LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u own channles\n", | ||
1108 | GNUNET_CONTAINER_multihashmap32_size (c->own_channels)); | ||
1109 | LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u incoming channles\n", | ||
1110 | GNUNET_CONTAINER_multihashmap32_size (c->incoming_channels)); | ||
1111 | } | ||
1112 | LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n"); | ||
1113 | GCP_iterate_all (&show_peer_iterator, NULL); | ||
1114 | |||
1115 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1116 | "**************************** DUMP END ****************************\n"); | ||
1117 | |||
1118 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | /** | ||
1123 | * Functions to handle messages from clients | ||
1124 | */ | ||
1125 | static struct GNUNET_SERVER_MessageHandler client_handlers[] = { | ||
1126 | {&handle_port_open, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN, | ||
1127 | sizeof (struct GNUNET_CADET_PortMessage)}, | ||
1128 | {&handle_port_close, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE, | ||
1129 | sizeof (struct GNUNET_CADET_PortMessage)}, | ||
1130 | {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE, | ||
1131 | sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)}, | ||
1132 | {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY, | ||
1133 | sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)}, | ||
1134 | {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0}, | ||
1135 | {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, | ||
1136 | sizeof (struct GNUNET_CADET_LocalAck)}, | ||
1137 | {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, | ||
1138 | sizeof (struct GNUNET_MessageHeader)}, | ||
1139 | {&handle_show_peer, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, | ||
1140 | sizeof (struct GNUNET_CADET_LocalInfo)}, | ||
1141 | {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, | ||
1142 | sizeof (struct GNUNET_MessageHeader)}, | ||
1143 | {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, | ||
1144 | sizeof (struct GNUNET_CADET_LocalInfo)}, | ||
1145 | {&handle_info_dump, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP, | ||
1146 | sizeof (struct GNUNET_MessageHeader)}, | ||
1147 | {NULL, NULL, 0, 0} | ||
1148 | }; | ||
1149 | |||
1150 | |||
1151 | |||
1152 | /******************************************************************************/ | ||
1153 | /******************************** API ***********************************/ | ||
1154 | /******************************************************************************/ | ||
1155 | |||
1156 | /** | ||
1157 | * Initialize server subsystem. | ||
1158 | * | ||
1159 | * @param handle Server handle. | ||
1160 | */ | ||
1161 | void | ||
1162 | GML_init (struct GNUNET_SERVER_Handle *handle) | ||
1163 | { | ||
1164 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); | ||
1165 | server_handle = handle; | ||
1166 | GNUNET_SERVER_suspend (server_handle); | ||
1167 | ports = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO); | ||
1168 | } | ||
1169 | |||
1170 | |||
1171 | /** | ||
1172 | * Install server (service) handlers and start listening to clients. | ||
1173 | */ | ||
1174 | void | ||
1175 | GML_start (void) | ||
1176 | { | ||
1177 | GNUNET_SERVER_add_handlers (server_handle, client_handlers); | ||
1178 | GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL); | ||
1179 | GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect, | ||
1180 | NULL); | ||
1181 | nc = GNUNET_SERVER_notification_context_create (server_handle, 1); | ||
1182 | |||
1183 | clients_head = NULL; | ||
1184 | clients_tail = NULL; | ||
1185 | next_client_id = 0; | ||
1186 | GNUNET_SERVER_resume (server_handle); | ||
1187 | } | ||
1188 | |||
1189 | |||
1190 | /** | ||
1191 | * Shutdown server. | ||
1192 | */ | ||
1193 | void | ||
1194 | GML_shutdown (void) | ||
1195 | { | ||
1196 | struct CadetClient *c; | ||
1197 | |||
1198 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down local\n"); | ||
1199 | |||
1200 | for (c = clients_head; NULL != clients_head; c = clients_head) | ||
1201 | client_destroy (c); | ||
1202 | |||
1203 | if (nc != NULL) | ||
1204 | { | ||
1205 | GNUNET_SERVER_notification_context_destroy (nc); | ||
1206 | nc = NULL; | ||
1207 | } | ||
1208 | |||
1209 | } | ||
1210 | |||
1211 | |||
1212 | /** | ||
1213 | * Get a channel from a client. | ||
1214 | * | ||
1215 | * @param c Client to check. | ||
1216 | * @param ccn Channel ID, must be local (> 0x800...). | ||
1217 | * | ||
1218 | * @return non-NULL if channel exists in the clients lists | ||
1219 | */ | ||
1220 | struct CadetChannel * | ||
1221 | GML_channel_get (struct CadetClient *c, | ||
1222 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1223 | { | ||
1224 | struct GNUNET_CONTAINER_MultiHashMap32 *map; | ||
1225 | |||
1226 | if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1227 | map = c->own_channels; | ||
1228 | else | ||
1229 | map = c->incoming_channels; | ||
1230 | |||
1231 | if (NULL == map) | ||
1232 | { | ||
1233 | GNUNET_break (0); | ||
1234 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1235 | "Client %s does no t have a valid map for CCN %X\n", | ||
1236 | GML_2s (c), ccn); | ||
1237 | return NULL; | ||
1238 | } | ||
1239 | return GNUNET_CONTAINER_multihashmap32_get (map, | ||
1240 | ccn.channel_of_client); | ||
1241 | } | ||
1242 | |||
1243 | |||
1244 | /** | ||
1245 | * Add a channel to a client | ||
1246 | * | ||
1247 | * @param client Client. | ||
1248 | * @param ccn Channel ID. | ||
1249 | * @param ch Channel. | ||
1250 | */ | ||
1251 | void | ||
1252 | GML_channel_add (struct CadetClient *client, | ||
1253 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
1254 | struct CadetChannel *ch) | ||
1255 | { | ||
1256 | if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1257 | GNUNET_CONTAINER_multihashmap32_put (client->own_channels, | ||
1258 | ccn.channel_of_client, | ||
1259 | ch, | ||
1260 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1261 | else | ||
1262 | GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, | ||
1263 | ccn.channel_of_client, | ||
1264 | ch, | ||
1265 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | /** | ||
1270 | * Remove a channel from a client. | ||
1271 | * | ||
1272 | * @param client Client. | ||
1273 | * @param ccn Channel ID. | ||
1274 | * @param ch Channel. | ||
1275 | */ | ||
1276 | void | ||
1277 | GML_channel_remove (struct CadetClient *client, | ||
1278 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
1279 | struct CadetChannel *ch) | ||
1280 | { | ||
1281 | if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1282 | GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, | ||
1283 | ccn.channel_of_client, | ||
1284 | ch); | ||
1285 | else | ||
1286 | GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, | ||
1287 | ccn.channel_of_client, | ||
1288 | ch); | ||
1289 | } | ||
1290 | |||
1291 | |||
1292 | /** | ||
1293 | * Get the tunnel's next free local channel ID. | ||
1294 | * | ||
1295 | * @param c Client. | ||
1296 | * | ||
1297 | * @return LID of a channel free to use. | ||
1298 | */ | ||
1299 | struct GNUNET_CADET_ClientChannelNumber | ||
1300 | GML_get_next_ccn (struct CadetClient *c) | ||
1301 | { | ||
1302 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
1303 | |||
1304 | while (NULL != GML_channel_get (c, | ||
1305 | c->next_ccn)) | ||
1306 | { | ||
1307 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1308 | "Channel %u exists...\n", | ||
1309 | c->next_ccn); | ||
1310 | c->next_ccn.channel_of_client | ||
1311 | = htonl (1 + (ntohl (c->next_ccn.channel_of_client))); | ||
1312 | if (ntohl (c->next_ccn.channel_of_client) >= | ||
1313 | GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1314 | c->next_ccn.channel_of_client = htonl (0); | ||
1315 | } | ||
1316 | ccn = c->next_ccn; | ||
1317 | c->next_ccn.channel_of_client | ||
1318 | = htonl (1 + (ntohl (c->next_ccn.channel_of_client))); | ||
1319 | |||
1320 | return ccn; | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * Check if client has registered with the service and has not disconnected | ||
1326 | * | ||
1327 | * @param client the client to check | ||
1328 | * | ||
1329 | * @return non-NULL if client exists in the global DLL | ||
1330 | */ | ||
1331 | struct CadetClient * | ||
1332 | GML_client_get (struct GNUNET_SERVER_Client *client) | ||
1333 | { | ||
1334 | if (NULL == client) | ||
1335 | return NULL; | ||
1336 | return GNUNET_SERVER_client_get_user_context (client, | ||
1337 | struct CadetClient); | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | /** | ||
1342 | * Find a client that has opened a port | ||
1343 | * | ||
1344 | * @param port Port to check. | ||
1345 | * | ||
1346 | * @return non-NULL if a client has the port. | ||
1347 | */ | ||
1348 | struct CadetClient * | ||
1349 | GML_client_get_by_port (const struct GNUNET_HashCode *port) | ||
1350 | { | ||
1351 | return GNUNET_CONTAINER_multihashmap_get (ports, port); | ||
1352 | } | ||
1353 | |||
1354 | |||
1355 | /** | ||
1356 | * Deletes a channel from a client (either owner or destination). | ||
1357 | * | ||
1358 | * @param c Client whose tunnel to delete. | ||
1359 | * @param ch Channel which should be deleted. | ||
1360 | * @param id Channel ID. | ||
1361 | */ | ||
1362 | void | ||
1363 | GML_client_delete_channel (struct CadetClient *c, | ||
1364 | struct CadetChannel *ch, | ||
1365 | struct GNUNET_CADET_ClientChannelNumber id) | ||
1366 | { | ||
1367 | int res; | ||
1368 | |||
1369 | if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1370 | { | ||
1371 | res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, | ||
1372 | id.channel_of_client, | ||
1373 | ch); | ||
1374 | if (GNUNET_YES != res) | ||
1375 | LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n"); | ||
1376 | } | ||
1377 | else | ||
1378 | { | ||
1379 | res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, | ||
1380 | id.channel_of_client, | ||
1381 | ch); | ||
1382 | if (GNUNET_YES != res) | ||
1383 | LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n"); | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1387 | /** | ||
1388 | * Build a local ACK message and send it to a local client, if needed. | ||
1389 | * | ||
1390 | * If the client was already allowed to send data, do nothing. | ||
1391 | * | ||
1392 | * @param c Client to whom send the ACK. | ||
1393 | * @param ccn Channel ID to use | ||
1394 | */ | ||
1395 | void | ||
1396 | GML_send_ack (struct CadetClient *c, | ||
1397 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1398 | { | ||
1399 | struct GNUNET_CADET_LocalAck msg; | ||
1400 | |||
1401 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1402 | "send local %s ack on %X towards %p\n", | ||
1403 | ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | ||
1404 | ? "FWD" : "BCK", | ||
1405 | ntohl (ccn.channel_of_client), | ||
1406 | c); | ||
1407 | |||
1408 | msg.header.size = htons (sizeof (msg)); | ||
1409 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); | ||
1410 | msg.ccn = ccn; | ||
1411 | GNUNET_SERVER_notification_context_unicast (nc, | ||
1412 | c->handle, | ||
1413 | &msg.header, | ||
1414 | GNUNET_NO); | ||
1415 | |||
1416 | } | ||
1417 | |||
1418 | |||
1419 | |||
1420 | /** | ||
1421 | * Notify the client that a new incoming channel was created. | ||
1422 | * | ||
1423 | * @param c Client to notify. | ||
1424 | * @param ccn Channel ID. | ||
1425 | * @param port Channel's destination port. | ||
1426 | * @param opt Options (bit array). | ||
1427 | * @param peer Origin peer. | ||
1428 | */ | ||
1429 | void | ||
1430 | GML_send_channel_create (struct CadetClient *c, | ||
1431 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
1432 | const struct GNUNET_HashCode *port, | ||
1433 | uint32_t opt, | ||
1434 | const struct GNUNET_PeerIdentity *peer) | ||
1435 | { | ||
1436 | struct GNUNET_CADET_LocalChannelCreateMessage msg; | ||
1437 | |||
1438 | msg.header.size = htons (sizeof (msg)); | ||
1439 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE); | ||
1440 | msg.ccn = ccn; | ||
1441 | msg.port = *port; | ||
1442 | msg.opt = htonl (opt); | ||
1443 | msg.peer = *peer; | ||
1444 | GNUNET_SERVER_notification_context_unicast (nc, c->handle, | ||
1445 | &msg.header, GNUNET_NO); | ||
1446 | } | ||
1447 | |||
1448 | |||
1449 | /** | ||
1450 | * Build a local channel NACK message and send it to a local client. | ||
1451 | * | ||
1452 | * @param c Client to whom send the NACK. | ||
1453 | * @param ccn Channel ID to use | ||
1454 | */ | ||
1455 | void | ||
1456 | GML_send_channel_nack (struct CadetClient *c, | ||
1457 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1458 | { | ||
1459 | struct GNUNET_CADET_LocalAck msg; | ||
1460 | |||
1461 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1462 | "send local nack on %X towards %p\n", | ||
1463 | ntohl (ccn.channel_of_client), | ||
1464 | c); | ||
1465 | |||
1466 | msg.header.size = htons (sizeof (msg)); | ||
1467 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED); | ||
1468 | msg.ccn = ccn; | ||
1469 | GNUNET_SERVER_notification_context_unicast (nc, | ||
1470 | c->handle, | ||
1471 | &msg.header, | ||
1472 | GNUNET_NO); | ||
1473 | |||
1474 | } | ||
1475 | |||
1476 | /** | ||
1477 | * Notify a client that a channel is no longer valid. | ||
1478 | * | ||
1479 | * @param c Client. | ||
1480 | * @param ccn ID of the channel that is destroyed. | ||
1481 | */ | ||
1482 | void | ||
1483 | GML_send_channel_destroy (struct CadetClient *c, | ||
1484 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1485 | { | ||
1486 | struct GNUNET_CADET_LocalChannelDestroyMessage msg; | ||
1487 | |||
1488 | if (NULL == c) | ||
1489 | { | ||
1490 | GNUNET_break (0); | ||
1491 | return; | ||
1492 | } | ||
1493 | if (GNUNET_YES == c->shutting_down) | ||
1494 | return; | ||
1495 | msg.header.size = htons (sizeof (msg)); | ||
1496 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); | ||
1497 | msg.ccn = ccn; | ||
1498 | GNUNET_SERVER_notification_context_unicast (nc, c->handle, | ||
1499 | &msg.header, GNUNET_NO); | ||
1500 | } | ||
1501 | |||
1502 | |||
1503 | /** | ||
1504 | * Modify the cadet message ID from global to local and send to client. | ||
1505 | * | ||
1506 | * @param c Client to send to. | ||
1507 | * @param msg Message to modify and send. | ||
1508 | * @param ccn Channel ID to use (c can be both owner and client). | ||
1509 | */ | ||
1510 | void | ||
1511 | GML_send_data (struct CadetClient *c, | ||
1512 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | ||
1513 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
1514 | { | ||
1515 | struct GNUNET_CADET_LocalData *copy; | ||
1516 | uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_ChannelAppDataMessage); | ||
1517 | char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)]; | ||
1518 | |||
1519 | if (size < sizeof (struct GNUNET_MessageHeader)) | ||
1520 | { | ||
1521 | GNUNET_break_op (0); | ||
1522 | return; | ||
1523 | } | ||
1524 | if (NULL == c) | ||
1525 | { | ||
1526 | GNUNET_break (0); | ||
1527 | return; | ||
1528 | } | ||
1529 | copy = (struct GNUNET_CADET_LocalData *) cbuf; | ||
1530 | GNUNET_memcpy (©[1], &msg[1], size); | ||
1531 | copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size); | ||
1532 | copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); | ||
1533 | copy->ccn = ccn; | ||
1534 | GNUNET_SERVER_notification_context_unicast (nc, c->handle, | ||
1535 | ©->header, GNUNET_NO); | ||
1536 | } | ||
1537 | |||
1538 | |||
1539 | /** | ||
1540 | * Get the static string to represent a client. | ||
1541 | * | ||
1542 | * @param c Client. | ||
1543 | * | ||
1544 | * @return Static string for the client. | ||
1545 | */ | ||
1546 | const char * | ||
1547 | GML_2s (const struct CadetClient *c) | ||
1548 | { | ||
1549 | static char buf[32]; | ||
1550 | |||
1551 | SPRINTF (buf, "%u", c->id); | ||
1552 | return buf; | ||
1553 | } | ||
diff --git a/src/cadet/gnunet-service-cadet_local.h b/src/cadet/gnunet-service-cadet_local.h deleted file mode 100644 index 113c2f489..000000000 --- a/src/cadet/gnunet-service-cadet_local.h +++ /dev/null | |||
@@ -1,234 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet_local.h | ||
23 | * @brief cadet service; dealing with local clients | ||
24 | * @author Bartlomiej Polot | ||
25 | * | ||
26 | * All functions in this file should use the prefix GML (Gnunet Cadet Local) | ||
27 | */ | ||
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_LOCAL_H | ||
30 | #define GNUNET_SERVICE_CADET_LOCAL_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" | ||
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "platform.h" | ||
41 | #include "gnunet_util_lib.h" | ||
42 | |||
43 | /** | ||
44 | * Struct containing information about a client of the service | ||
45 | */ | ||
46 | struct CadetClient; | ||
47 | |||
48 | #include "gnunet-service-cadet_channel.h" | ||
49 | |||
50 | /******************************************************************************/ | ||
51 | /******************************** API ***********************************/ | ||
52 | /******************************************************************************/ | ||
53 | |||
54 | /** | ||
55 | * Initialize server subsystem. | ||
56 | * | ||
57 | * @param handle Server handle. | ||
58 | */ | ||
59 | void | ||
60 | GML_init (struct GNUNET_SERVER_Handle *handle); | ||
61 | |||
62 | /** | ||
63 | * Install server (service) handlers and start listening to clients. | ||
64 | */ | ||
65 | void | ||
66 | GML_start (void); | ||
67 | |||
68 | /** | ||
69 | * Shutdown server. | ||
70 | */ | ||
71 | void | ||
72 | GML_shutdown (void); | ||
73 | |||
74 | /** | ||
75 | * Get a channel from a client. | ||
76 | * | ||
77 | * @param c Client to check. | ||
78 | * @param ccn Channel ID, must be local (> 0x800...). | ||
79 | * | ||
80 | * @return non-NULL if channel exists in the clients lists | ||
81 | */ | ||
82 | struct CadetChannel * | ||
83 | GML_channel_get (struct CadetClient *c, | ||
84 | struct GNUNET_CADET_ClientChannelNumber ccn); | ||
85 | |||
86 | /** | ||
87 | * Add a channel to a client | ||
88 | * | ||
89 | * @param client Client. | ||
90 | * @param ccn Channel ID. | ||
91 | * @param ch Channel. | ||
92 | */ | ||
93 | void | ||
94 | GML_channel_add (struct CadetClient *client, | ||
95 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
96 | struct CadetChannel *ch); | ||
97 | |||
98 | /** | ||
99 | * Remove a channel from a client | ||
100 | * | ||
101 | * @param client Client. | ||
102 | * @param ccn Channel ID. | ||
103 | * @param ch Channel. | ||
104 | */ | ||
105 | void | ||
106 | GML_channel_remove (struct CadetClient *client, | ||
107 | struct GNUNET_CADET_ClientChannelNumber ccn, | ||
108 | struct CadetChannel *ch); | ||
109 | |||
110 | /** | ||
111 | * Get the tunnel's next free local channel ID. | ||
112 | * | ||
113 | * @param c Client. | ||
114 | * | ||
115 | * @return LID of a channel free to use. | ||
116 | */ | ||
117 | struct GNUNET_CADET_ClientChannelNumber | ||
118 | GML_get_next_ccn (struct CadetClient *c); | ||
119 | |||
120 | /** | ||
121 | * Check if client has registered with the service and has not disconnected | ||
122 | * | ||
123 | * @param client the client to check | ||
124 | * | ||
125 | * @return non-NULL if client exists in the global DLL | ||
126 | */ | ||
127 | struct CadetClient * | ||
128 | GML_client_get (struct GNUNET_SERVER_Client *client); | ||
129 | |||
130 | /** | ||
131 | * Find a client that has opened a port | ||
132 | * | ||
133 | * @param port Port to check. | ||
134 | * | ||
135 | * @return non-NULL if a client has the port. | ||
136 | */ | ||
137 | struct CadetClient * | ||
138 | GML_client_get_by_port (const struct GNUNET_HashCode *port); | ||
139 | |||
140 | /** | ||
141 | * Deletes a tunnel from a client (either owner or destination). | ||
142 | * | ||
143 | * @param c Client whose tunnel to delete. | ||
144 | * @param ch Channel which should be deleted. | ||
145 | * @param id Channel ID. | ||
146 | */ | ||
147 | void | ||
148 | GML_client_delete_channel (struct CadetClient *c, | ||
149 | struct CadetChannel *ch, | ||
150 | struct GNUNET_CADET_ClientChannelNumber id); | ||
151 | |||
152 | /** | ||
153 | * Build a local ACK message and send it to a local client, if needed. | ||
154 | * | ||
155 | * If the client was already allowed to send data, do nothing. | ||
156 | * | ||
157 | * @param c Client to whom send the ACK. | ||
158 | * @param id Channel ID to use | ||
159 | */ | ||
160 | void | ||
161 | GML_send_ack (struct CadetClient *c, | ||
162 | struct GNUNET_CADET_ClientChannelNumber id); | ||
163 | |||
164 | /** | ||
165 | * Notify the appropriate client that a new incoming channel was created. | ||
166 | * | ||
167 | * @param c Client to notify. | ||
168 | * @param id Channel ID. | ||
169 | * @param port Channel's destination port. | ||
170 | * @param opt Options (bit array). | ||
171 | * @param peer Origin peer. | ||
172 | */ | ||
173 | void | ||
174 | GML_send_channel_create (struct CadetClient *c, | ||
175 | struct GNUNET_CADET_ClientChannelNumber id, | ||
176 | const struct GNUNET_HashCode *port, | ||
177 | uint32_t opt, | ||
178 | const struct GNUNET_PeerIdentity *peer); | ||
179 | |||
180 | /** | ||
181 | * Build a local channel NACK message and send it to a local client. | ||
182 | * | ||
183 | * @param c Client to whom send the NACK. | ||
184 | * @param id Channel ID to use | ||
185 | */ | ||
186 | void | ||
187 | GML_send_channel_nack (struct CadetClient *c, | ||
188 | struct GNUNET_CADET_ClientChannelNumber id); | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Notify a client that a channel is no longer valid. | ||
193 | * | ||
194 | * @param c Client. | ||
195 | * @param id ID of the channel that is destroyed. | ||
196 | */ | ||
197 | void | ||
198 | GML_send_channel_destroy (struct CadetClient *c, | ||
199 | struct GNUNET_CADET_ClientChannelNumber id); | ||
200 | |||
201 | |||
202 | /** | ||
203 | * Modify the cadet message ID from global to local and send to client. | ||
204 | * | ||
205 | * @param c Client to send to. | ||
206 | * @param msg Message to modify and send. | ||
207 | * @param id Channel ID to use (c can be both owner and client). | ||
208 | */ | ||
209 | void | ||
210 | GML_send_data (struct CadetClient *c, | ||
211 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | ||
212 | struct GNUNET_CADET_ClientChannelNumber id); | ||
213 | |||
214 | /** | ||
215 | * Get the static string to represent a client. | ||
216 | * | ||
217 | * @param c Client. | ||
218 | * | ||
219 | * @return Static string for the client. | ||
220 | */ | ||
221 | const char * | ||
222 | GML_2s (const struct CadetClient *c); | ||
223 | |||
224 | |||
225 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
226 | { | ||
227 | #endif | ||
228 | #ifdef __cplusplus | ||
229 | } | ||
230 | #endif | ||
231 | |||
232 | /* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ | ||
233 | #endif | ||
234 | /* end of gnunet-cadet-service_LOCAL.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet_paths.c index c6121a133..13752643c 100644 --- a/src/cadet/gnunet-service-cadet-new_paths.c +++ b/src/cadet/gnunet-service-cadet_paths.c | |||
@@ -18,16 +18,16 @@ | |||
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | /** | 20 | /** |
21 | * @file cadet/gnunet-service-cadet-new_paths.c | 21 | * @file cadet/gnunet-service-cadet_paths.c |
22 | * @brief Information we track per path. | 22 | * @brief Information we track per path. |
23 | * @author Bartlomiej Polot | 23 | * @author Bartlomiej Polot |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet-service-cadet-new_connection.h" | 27 | #include "gnunet-service-cadet_connection.h" |
28 | #include "gnunet-service-cadet-new_tunnels.h" | 28 | #include "gnunet-service-cadet_tunnels.h" |
29 | #include "gnunet-service-cadet-new_peer.h" | 29 | #include "gnunet-service-cadet_peer.h" |
30 | #include "gnunet-service-cadet-new_paths.h" | 30 | #include "gnunet-service-cadet_paths.h" |
31 | 31 | ||
32 | 32 | ||
33 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__) | 33 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__) |
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet_paths.h index 7310d75e6..6b7bef640 100644 --- a/src/cadet/gnunet-service-cadet-new_paths.h +++ b/src/cadet/gnunet-service-cadet_paths.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define GNUNET_SERVICE_CADET_PATHS_H | 29 | #define GNUNET_SERVICE_CADET_PATHS_H |
30 | 30 | ||
31 | #include "gnunet_util_lib.h" | 31 | #include "gnunet_util_lib.h" |
32 | #include "gnunet-service-cadet-new.h" | 32 | #include "gnunet-service-cadet.h" |
33 | 33 | ||
34 | /** | 34 | /** |
35 | * Create a peer path based on the result of a DHT lookup. If we | 35 | * Create a peer path based on the result of a DHT lookup. If we |
diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c index fa3f2be80..71c7c67d0 100644 --- a/src/cadet/gnunet-service-cadet_peer.c +++ b/src/cadet/gnunet-service-cadet_peer.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2013, 2015 GNUnet e.V. | 3 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -17,2193 +17,1461 @@ | |||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | |||
20 | /** | 21 | /** |
21 | * @file cadet/gnunet-service-cadet_peer.c | 22 | * @file cadet/gnunet-service-cadet_peer.c |
22 | * @brief GNUnet CADET service connection handling | 23 | * @brief Information we track per peer. |
23 | * @author Bartlomiej Polot | 24 | * @author Bartlomiej Polot |
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * TODO: | ||
28 | * - optimize stopping/restarting DHT search to situations | ||
29 | * where we actually need it (i.e. not if we have a direct connection, | ||
30 | * or if we already have plenty of good short ones, or maybe even | ||
31 | * to take a break if we have some connections and have searched a lot (?)) | ||
24 | */ | 32 | */ |
25 | #include "platform.h" | 33 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 34 | #include "gnunet_util_lib.h" |
35 | #include "gnunet_hello_lib.h" | ||
27 | #include "gnunet_signatures.h" | 36 | #include "gnunet_signatures.h" |
28 | #include "gnunet_transport_service.h" | 37 | #include "gnunet_transport_service.h" |
29 | #include "gnunet_ats_service.h" | 38 | #include "gnunet_ats_service.h" |
30 | #include "gnunet_core_service.h" | 39 | #include "gnunet_core_service.h" |
31 | #include "gnunet_statistics_service.h" | 40 | #include "gnunet_statistics_service.h" |
32 | #include "cadet_protocol.h" | 41 | #include "cadet_protocol.h" |
33 | #include "gnunet-service-cadet_peer.h" | ||
34 | #include "gnunet-service-cadet_dht.h" | ||
35 | #include "gnunet-service-cadet_connection.h" | 42 | #include "gnunet-service-cadet_connection.h" |
36 | #include "gnunet-service-cadet_tunnel.h" | 43 | #include "gnunet-service-cadet_dht.h" |
37 | #include "cadet_path.h" | 44 | #include "gnunet-service-cadet_peer.h" |
45 | #include "gnunet-service-cadet_paths.h" | ||
46 | #include "gnunet-service-cadet_tunnels.h" | ||
38 | 47 | ||
39 | #define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__) | ||
40 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-p2p",__VA_ARGS__) | ||
41 | 48 | ||
49 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__) | ||
42 | 50 | ||
43 | /******************************************************************************/ | ||
44 | /******************************** STRUCTS **********************************/ | ||
45 | /******************************************************************************/ | ||
46 | 51 | ||
47 | /** | 52 | /** |
48 | * Information about a queued message on the peer level. | 53 | * How long do we wait until tearing down an idle peer? |
49 | */ | 54 | */ |
50 | struct CadetPeerQueue { | 55 | #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) |
51 | |||
52 | struct CadetPeerQueue *next; | ||
53 | struct CadetPeerQueue *prev; | ||
54 | |||
55 | /** | ||
56 | * Envelope to cancel message before MQ sends it. | ||
57 | */ | ||
58 | struct GNUNET_MQ_Envelope *env; | ||
59 | |||
60 | /** | ||
61 | * Peer (neighbor) this message is being sent to. | ||
62 | */ | ||
63 | struct CadetPeer *peer; | ||
64 | |||
65 | /** | ||
66 | * Continuation to call to notify higher layers about message sent. | ||
67 | */ | ||
68 | GCP_sent cont; | ||
69 | |||
70 | /** | ||
71 | * Closure for @a cont. | ||
72 | */ | ||
73 | void *cont_cls; | ||
74 | |||
75 | /** | ||
76 | * Task to asynchronously run the drop continuation. | ||
77 | */ | ||
78 | struct GNUNET_SCHEDULER_Task *drop_task; | ||
79 | |||
80 | /** | ||
81 | * Time when message was queued for sending. | ||
82 | */ | ||
83 | struct GNUNET_TIME_Absolute queue_timestamp; | ||
84 | |||
85 | /** | ||
86 | * #GNUNET_YES if message was management traffic (POLL, ACK, ...). | ||
87 | */ | ||
88 | int management_traffic; | ||
89 | |||
90 | /** | ||
91 | * Message type. | ||
92 | */ | ||
93 | uint16_t type; | ||
94 | |||
95 | /** | ||
96 | * Message size. | ||
97 | */ | ||
98 | uint16_t size; | ||
99 | |||
100 | /** | ||
101 | * Type of the message's payload, if it was encrypted data. | ||
102 | */ | ||
103 | uint16_t payload_type; | ||
104 | |||
105 | /** | ||
106 | * ID of the payload (PID, ACK #, ...). | ||
107 | */ | ||
108 | struct CadetEncryptedMessageIdentifier payload_id; | ||
109 | |||
110 | /** | ||
111 | * Connection this message was sent on. | ||
112 | */ | ||
113 | struct CadetConnection *c; | ||
114 | |||
115 | /** | ||
116 | * Direction in @a c this message was send on (#GNUNET_YES = FWD). | ||
117 | */ | ||
118 | int c_fwd; | ||
119 | }; | ||
120 | |||
121 | 56 | ||
122 | /** | 57 | /** |
123 | * Struct containing all information regarding a given peer | 58 | * How long do we keep paths around if we no longer care about the peer? |
124 | */ | 59 | */ |
125 | struct CadetPeer | 60 | #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) |
126 | { | ||
127 | /** | ||
128 | * ID of the peer | ||
129 | */ | ||
130 | GNUNET_PEER_Id id; | ||
131 | |||
132 | struct CadetPeerQueue *q_head; | ||
133 | struct CadetPeerQueue *q_tail; | ||
134 | |||
135 | /** | ||
136 | * Last time we heard from this peer | ||
137 | */ | ||
138 | struct GNUNET_TIME_Absolute last_contact; | ||
139 | |||
140 | /** | ||
141 | * Paths to reach the peer, ordered by ascending hop count | ||
142 | */ | ||
143 | struct CadetPeerPath *path_head; | ||
144 | |||
145 | /** | ||
146 | * Paths to reach the peer, ordered by ascending hop count | ||
147 | */ | ||
148 | struct CadetPeerPath *path_tail; | ||
149 | |||
150 | /** | ||
151 | * Handle to stop the DHT search for paths to this peer | ||
152 | */ | ||
153 | struct GCD_search_handle *search_h; | ||
154 | |||
155 | /** | ||
156 | * Handle to stop the DHT search for paths to this peer | ||
157 | */ | ||
158 | struct GNUNET_SCHEDULER_Task *search_delayed; | ||
159 | |||
160 | /** | ||
161 | * Tunnel to this peer, if any. | ||
162 | */ | ||
163 | struct CadetTunnel *tunnel; | ||
164 | |||
165 | /** | ||
166 | * Connections that go through this peer; indexed by tid. | ||
167 | */ | ||
168 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
169 | |||
170 | /** | ||
171 | * Handle for core transmissions. | ||
172 | */ | ||
173 | struct GNUNET_MQ_Handle *core_mq; | ||
174 | |||
175 | /** | ||
176 | * How many messages are in the queue to this peer. | ||
177 | */ | ||
178 | unsigned int queue_n; | ||
179 | |||
180 | /** | ||
181 | * Hello message. | ||
182 | */ | ||
183 | struct GNUNET_HELLO_Message* hello; | ||
184 | |||
185 | /** | ||
186 | * Handle to us offering the HELLO to the transport. | ||
187 | */ | ||
188 | struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer; | ||
189 | |||
190 | /** | ||
191 | * Handle to our ATS request asking ATS to suggest an address | ||
192 | * to TRANSPORT for this peer (to establish a direct link). | ||
193 | */ | ||
194 | struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion; | ||
195 | 61 | ||
196 | }; | ||
197 | |||
198 | |||
199 | /******************************************************************************/ | ||
200 | /******************************* GLOBALS ***********************************/ | ||
201 | /******************************************************************************/ | ||
202 | |||
203 | /** | ||
204 | * Global handle to the statistics service. | ||
205 | */ | ||
206 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
207 | 62 | ||
208 | /** | ||
209 | * Local peer own ID (full value). | ||
210 | */ | ||
211 | extern struct GNUNET_PeerIdentity my_full_id; | ||
212 | 63 | ||
213 | /** | ||
214 | * Local peer own ID (short) | ||
215 | */ | ||
216 | extern GNUNET_PEER_Id myid; | ||
217 | 64 | ||
218 | /** | 65 | /** |
219 | * Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`. | 66 | * Data structure used to track whom we have to notify about changes |
67 | * to our message queue. | ||
220 | */ | 68 | */ |
221 | static struct GNUNET_CONTAINER_MultiPeerMap *peers; | 69 | struct GCP_MessageQueueManager |
222 | 70 | { | |
223 | /** | ||
224 | * How many peers do we want to remember? | ||
225 | */ | ||
226 | static unsigned long long max_peers; | ||
227 | 71 | ||
228 | /** | 72 | /** |
229 | * Percentage of messages that will be dropped (for test purposes only). | 73 | * Kept in a DLL. |
230 | */ | 74 | */ |
231 | static unsigned long long drop_percent; | 75 | struct GCP_MessageQueueManager *next; |
232 | 76 | ||
233 | /** | 77 | /** |
234 | * Handle to communicate with CORE. | 78 | * Kept in a DLL. |
235 | */ | 79 | */ |
236 | static struct GNUNET_CORE_Handle *core_handle; | 80 | struct GCP_MessageQueueManager *prev; |
237 | 81 | ||
238 | /** | 82 | /** |
239 | * Our configuration; | 83 | * Function to call with updated message queue object. |
240 | */ | 84 | */ |
241 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 85 | GCP_MessageQueueNotificationCallback cb; |
242 | 86 | ||
243 | /** | 87 | /** |
244 | * Handle to communicate with ATS. | 88 | * Closure for @e cb. |
245 | */ | 89 | */ |
246 | static struct GNUNET_ATS_ConnectivityHandle *ats_ch; | 90 | void *cb_cls; |
247 | 91 | ||
248 | /** | 92 | /** |
249 | * Shutdown falg. | 93 | * The peer this is for. |
250 | */ | 94 | */ |
251 | static int in_shutdown; | 95 | struct CadetPeer *cp; |
252 | 96 | ||
97 | /** | ||
98 | * Envelope this manager would like to transmit once it is its turn. | ||
99 | */ | ||
100 | struct GNUNET_MQ_Envelope *env; | ||
253 | 101 | ||
254 | /******************************************************************************/ | 102 | }; |
255 | /***************************** CORE HELPERS *********************************/ | ||
256 | /******************************************************************************/ | ||
257 | 103 | ||
258 | 104 | ||
259 | /** | 105 | /** |
260 | * Iterator to notify all connections of a broken link. Mark connections | 106 | * Struct containing all information regarding a given peer |
261 | * to destroy after all traffic has been sent. | ||
262 | * | ||
263 | * @param cls Closure (disconnected peer). | ||
264 | * @param key Current key code (peer id). | ||
265 | * @param value Value in the hash map (connection). | ||
266 | * | ||
267 | * @return #GNUNET_YES to continue to iterate. | ||
268 | */ | 107 | */ |
269 | static int | 108 | struct CadetPeer |
270 | notify_broken (void *cls, | ||
271 | const struct GNUNET_ShortHashCode *key, | ||
272 | void *value) | ||
273 | { | 109 | { |
274 | struct CadetPeer *peer = cls; | 110 | /** |
275 | struct CadetConnection *c = value; | 111 | * ID of the peer |
112 | */ | ||
113 | struct GNUNET_PeerIdentity pid; | ||
114 | |||
115 | /** | ||
116 | * Last time we heard from this peer (currently not used!) | ||
117 | */ | ||
118 | struct GNUNET_TIME_Absolute last_contactXXX; | ||
119 | |||
120 | /** | ||
121 | * Array of DLLs of paths traversing the peer, organized by the | ||
122 | * offset of the peer on the larger path. | ||
123 | */ | ||
124 | struct CadetPeerPathEntry **path_heads; | ||
125 | |||
126 | /** | ||
127 | * Array of DLL of paths traversing the peer, organized by the | ||
128 | * offset of the peer on the larger path. | ||
129 | */ | ||
130 | struct CadetPeerPathEntry **path_tails; | ||
131 | |||
132 | /** | ||
133 | * Notifications to call when @e core_mq changes. | ||
134 | */ | ||
135 | struct GCP_MessageQueueManager *mqm_head; | ||
136 | |||
137 | /** | ||
138 | * Notifications to call when @e core_mq changes. | ||
139 | */ | ||
140 | struct GCP_MessageQueueManager *mqm_tail; | ||
141 | |||
142 | /** | ||
143 | * Pointer to first "ready" entry in @e mqm_head. | ||
144 | */ | ||
145 | struct GCP_MessageQueueManager *mqm_ready_ptr; | ||
146 | |||
147 | /** | ||
148 | * MIN-heap of paths owned by this peer (they also end at this | ||
149 | * peer). Ordered by desirability. | ||
150 | */ | ||
151 | struct GNUNET_CONTAINER_Heap *path_heap; | ||
152 | |||
153 | /** | ||
154 | * Handle to stop the DHT search for paths to this peer | ||
155 | */ | ||
156 | struct GCD_search_handle *search_h; | ||
157 | |||
158 | /** | ||
159 | * Task to clean up @e path_heap asynchronously. | ||
160 | */ | ||
161 | struct GNUNET_SCHEDULER_Task *heap_cleanup_task; | ||
162 | |||
163 | /** | ||
164 | * Task to destroy this entry. | ||
165 | */ | ||
166 | struct GNUNET_SCHEDULER_Task *destroy_task; | ||
167 | |||
168 | /** | ||
169 | * Tunnel to this peer, if any. | ||
170 | */ | ||
171 | struct CadetTunnel *t; | ||
172 | |||
173 | /** | ||
174 | * Connections that go through this peer; indexed by tid. | ||
175 | */ | ||
176 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
177 | |||
178 | /** | ||
179 | * Handle for core transmissions. | ||
180 | */ | ||
181 | struct GNUNET_MQ_Handle *core_mq; | ||
182 | |||
183 | /** | ||
184 | * Hello message of the peer. | ||
185 | */ | ||
186 | struct GNUNET_HELLO_Message *hello; | ||
187 | |||
188 | /** | ||
189 | * Handle to us offering the HELLO to the transport. | ||
190 | */ | ||
191 | struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer; | ||
192 | |||
193 | /** | ||
194 | * Handle to our ATS request asking ATS to suggest an address | ||
195 | * to TRANSPORT for this peer (to establish a direct link). | ||
196 | */ | ||
197 | struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion; | ||
198 | |||
199 | /** | ||
200 | * How many messages are in the queue to this peer. | ||
201 | */ | ||
202 | unsigned int queue_n; | ||
203 | |||
204 | /** | ||
205 | * How many paths do we have to this peer (in all @e path_heads DLLs combined). | ||
206 | */ | ||
207 | unsigned int num_paths; | ||
208 | |||
209 | /** | ||
210 | * Sum over all of the offsets of all of the paths in the @a path_heads DLLs. | ||
211 | * Used to speed-up @GCP_get_desirability_of_path() calculation. | ||
212 | */ | ||
213 | unsigned int off_sum; | ||
214 | |||
215 | /** | ||
216 | * Number of message queue managers of this peer that have a message in waiting. | ||
217 | * | ||
218 | * Used to quickly see if we need to bother scanning the @e msm_head DLL. | ||
219 | * TODO: could be replaced by another DLL that would then allow us to avoid | ||
220 | * the O(n)-scan of the DLL for ready entries! | ||
221 | */ | ||
222 | unsigned int mqm_ready_counter; | ||
223 | |||
224 | /** | ||
225 | * Current length of the @e path_heads and @path_tails arrays. | ||
226 | * The arrays should be grown as needed. | ||
227 | */ | ||
228 | unsigned int path_dll_length; | ||
276 | 229 | ||
277 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 230 | }; |
278 | "Notifying %s due to %s disconnect\n", | ||
279 | GCC_2s (c), GCP_2s (peer)); | ||
280 | GCC_neighbor_disconnected (c, peer); | ||
281 | return GNUNET_YES; | ||
282 | } | ||
283 | 231 | ||
284 | 232 | ||
285 | /** | 233 | /** |
286 | * Remove the direct path to the peer. | 234 | * Get the static string for a peer ID. |
287 | * | ||
288 | * @param peer Peer to remove the direct path from. | ||
289 | */ | ||
290 | static struct CadetPeerPath * | ||
291 | pop_direct_path (struct CadetPeer *peer) | ||
292 | { | ||
293 | struct CadetPeerPath *iter; | ||
294 | |||
295 | for (iter = peer->path_head; NULL != iter; iter = iter->next) | ||
296 | { | ||
297 | if (2 >= iter->length) | ||
298 | { | ||
299 | GNUNET_CONTAINER_DLL_remove (peer->path_head, | ||
300 | peer->path_tail, | ||
301 | iter); | ||
302 | return iter; | ||
303 | } | ||
304 | } | ||
305 | return NULL; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * Call the continuation after a message has been sent or dropped. | ||
310 | * | ||
311 | * This funcion removes the message from the queue. | ||
312 | * | 235 | * |
313 | * @param q Queue handle. | 236 | * @param cp Peer. |
314 | * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped. | 237 | * @return Static string for it's ID. |
315 | */ | 238 | */ |
316 | static void | 239 | const char * |
317 | call_peer_cont (struct CadetPeerQueue *q, int sent); | 240 | GCP_2s (const struct CadetPeer *cp) |
241 | { | ||
242 | static char buf[32]; | ||
243 | |||
244 | GNUNET_snprintf (buf, | ||
245 | sizeof (buf), | ||
246 | "P(%s)", | ||
247 | GNUNET_i2s (&cp->pid)); | ||
248 | return buf; | ||
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Calculate how desirable a path is for @a cp if @a cp | ||
254 | * is at offset @a off. | ||
255 | * | ||
256 | * The 'desirability_table.c' program can be used to compute a list of | ||
257 | * sample outputs for different scenarios. Basically, we score paths | ||
258 | * lower if there are many alternatives, and higher if they are | ||
259 | * shorter than average, and very high if they are much shorter than | ||
260 | * average and without many alternatives. | ||
261 | * | ||
262 | * @param cp a peer reachable via a path | ||
263 | * @param off offset of @a cp in the path | ||
264 | * @return score how useful a path is to reach @a cp, | ||
265 | * positive scores mean path is more desirable | ||
266 | */ | ||
267 | double | ||
268 | GCP_get_desirability_of_path (struct CadetPeer *cp, | ||
269 | unsigned int off) | ||
270 | { | ||
271 | unsigned int num_alts = cp->num_paths; | ||
272 | unsigned int off_sum; | ||
273 | double avg_sum; | ||
274 | double path_delta; | ||
275 | double weight_alts; | ||
276 | |||
277 | GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */ | ||
278 | GNUNET_assert (0 != cp->path_dll_length); | ||
279 | |||
280 | /* We maintain 'off_sum' in 'peer' and thereby | ||
281 | avoid the SLOW recalculation each time. Kept here | ||
282 | just to document what is going on. */ | ||
283 | #if SLOW | ||
284 | off_sum = 0; | ||
285 | for (unsigned int j=0;j<cp->path_dll_length;j++) | ||
286 | for (struct CadetPeerPathEntry *pe = cp->path_heads[j]; | ||
287 | NULL != pe; | ||
288 | pe = pe->next) | ||
289 | off_sum += j; | ||
290 | GNUNET_assert (off_sum == cp->off_sum); | ||
291 | #else | ||
292 | off_sum = cp->off_sum; | ||
293 | #endif | ||
294 | avg_sum = off_sum * 1.0 / cp->path_dll_length; | ||
295 | path_delta = off - avg_sum; | ||
296 | /* path_delta positiv: path off of peer above average (bad path for peer), | ||
297 | path_delta negativ: path off of peer below average (good path for peer) */ | ||
298 | if (path_delta <= - 1.0) | ||
299 | weight_alts = - num_alts / path_delta; /* discount alternative paths */ | ||
300 | else if (path_delta >= 1.0) | ||
301 | weight_alts = num_alts * path_delta; /* overcount alternative paths */ | ||
302 | else | ||
303 | weight_alts = num_alts; /* count alternative paths normally */ | ||
318 | 304 | ||
319 | 305 | ||
320 | /******************************************************************************/ | 306 | /* off+1: long paths are generally harder to find and thus count |
321 | /***************************** CORE CALLBACKS *********************************/ | 307 | a bit more as they get longer. However, above-average paths |
322 | /******************************************************************************/ | 308 | still need to count less, hence the squaring of that factor. */ |
309 | return (off + 1.0) / (weight_alts * weight_alts); | ||
310 | } | ||
323 | 311 | ||
324 | 312 | ||
325 | /** | 313 | /** |
326 | * Method called whenever a given peer connects. | 314 | * This peer is no longer be needed, clean it up now. |
327 | * | 315 | * |
328 | * @param cls Core closure (unused). | 316 | * @param cls peer to clean up |
329 | * @param peer Peer identity this notification is about | ||
330 | * @param mq Message Queue to this peer. | ||
331 | * | ||
332 | * @return Internal closure for handlers (CadetPeer struct). | ||
333 | */ | 317 | */ |
334 | static void * | 318 | static void |
335 | core_connect_handler (void *cls, | 319 | destroy_peer (void *cls) |
336 | const struct GNUNET_PeerIdentity *peer, | 320 | { |
337 | struct GNUNET_MQ_Handle *mq) | 321 | struct CadetPeer *cp = cls; |
338 | { | 322 | |
339 | struct CadetPeer *neighbor; | 323 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
340 | struct CadetPeerPath *path; | 324 | "Destroying state about peer %s\n", |
341 | char own_id[16]; | 325 | GCP_2s (cp)); |
342 | 326 | cp->destroy_task = NULL; | |
343 | GCC_check_connections (); | 327 | GNUNET_assert (NULL == cp->t); |
344 | GNUNET_snprintf (own_id, | 328 | GNUNET_assert (NULL == cp->core_mq); |
345 | sizeof (own_id), | 329 | GNUNET_assert (0 == cp->num_paths); |
346 | "%s", | 330 | for (unsigned int i=0;i<cp->path_dll_length;i++) |
347 | GNUNET_i2s (&my_full_id)); | 331 | GNUNET_assert (NULL == cp->path_heads[i]); |
348 | 332 | GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)); | |
349 | /* Save a path to the neighbor */ | 333 | GNUNET_assert (GNUNET_YES == |
350 | neighbor = GCP_get (peer, GNUNET_YES); | 334 | GNUNET_CONTAINER_multipeermap_remove (peers, |
351 | if (myid == neighbor->id) | 335 | &cp->pid, |
352 | { | 336 | cp)); |
353 | LOG (GNUNET_ERROR_TYPE_INFO, | 337 | GNUNET_free_non_null (cp->path_heads); |
354 | "CONNECTED %s (self)\n", | 338 | GNUNET_free_non_null (cp->path_tails); |
355 | own_id); | 339 | cp->path_dll_length = 0; |
356 | path = path_new (1); | 340 | if (NULL != cp->search_h) |
357 | } | 341 | { |
358 | else | 342 | GCD_search_stop (cp->search_h); |
359 | { | 343 | cp->search_h = NULL; |
360 | LOG (GNUNET_ERROR_TYPE_INFO, | 344 | } |
361 | "CONNECTED %s <= %s\n", | 345 | /* FIXME: clean up search_delayedXXX! */ |
362 | own_id, | ||
363 | GNUNET_i2s (peer)); | ||
364 | path = path_new (2); | ||
365 | path->peers[1] = neighbor->id; | ||
366 | GNUNET_PEER_change_rc (neighbor->id, 1); | ||
367 | GNUNET_assert (NULL == neighbor->core_mq); | ||
368 | neighbor->core_mq = mq; | ||
369 | } | ||
370 | path->peers[0] = myid; | ||
371 | GNUNET_PEER_change_rc (myid, 1); | ||
372 | GCP_add_path (neighbor, path, GNUNET_YES); | ||
373 | |||
374 | /* Create the connections hashmap */ | ||
375 | GNUNET_assert (NULL == neighbor->connections); | ||
376 | neighbor->connections = GNUNET_CONTAINER_multishortmap_create (16, | ||
377 | GNUNET_YES); | ||
378 | GNUNET_STATISTICS_update (stats, | ||
379 | "# peers", | ||
380 | 1, | ||
381 | GNUNET_NO); | ||
382 | |||
383 | if ( (NULL != GCP_get_tunnel (neighbor)) && | ||
384 | (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) ) | ||
385 | { | ||
386 | GCP_connect (neighbor); | ||
387 | } | ||
388 | GCC_check_connections (); | ||
389 | 346 | ||
390 | return neighbor; | 347 | if (NULL != cp->hello_offer) |
348 | { | ||
349 | GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer); | ||
350 | cp->hello_offer = NULL; | ||
351 | } | ||
352 | if (NULL != cp->connectivity_suggestion) | ||
353 | { | ||
354 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
355 | cp->connectivity_suggestion = NULL; | ||
356 | } | ||
357 | GNUNET_CONTAINER_multishortmap_destroy (cp->connections); | ||
358 | if (NULL != cp->path_heap) | ||
359 | { | ||
360 | GNUNET_CONTAINER_heap_destroy (cp->path_heap); | ||
361 | cp->path_heap = NULL; | ||
362 | } | ||
363 | if (NULL != cp->heap_cleanup_task) | ||
364 | { | ||
365 | GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task); | ||
366 | cp->heap_cleanup_task = NULL; | ||
367 | } | ||
368 | GNUNET_free_non_null (cp->hello); | ||
369 | /* Peer should not be freed if paths exist; if there are no paths, | ||
370 | there ought to be no connections, and without connections, no | ||
371 | notifications. Thus we can assert that mqm_head is empty at this | ||
372 | point. */ | ||
373 | GNUNET_assert (NULL == cp->mqm_head); | ||
374 | GNUNET_assert (NULL == cp->mqm_ready_ptr); | ||
375 | GNUNET_free (cp); | ||
391 | } | 376 | } |
392 | 377 | ||
393 | 378 | ||
394 | /** | 379 | /** |
395 | * Method called whenever a peer disconnects. | 380 | * This peer is now on more "active" duty, activate processes related to it. |
396 | * | 381 | * |
397 | * @param cls Core closure (unused). | 382 | * @param cp the more-active peer |
398 | * @param peer Peer identity this notification is about. | ||
399 | * @param internal_cls Internal closure (CadetPeer struct). | ||
400 | */ | 383 | */ |
401 | static void | 384 | static void |
402 | core_disconnect_handler (void *cls, | 385 | consider_peer_activate (struct CadetPeer *cp) |
403 | const struct GNUNET_PeerIdentity *peer, | ||
404 | void *internal_cls) | ||
405 | { | 386 | { |
406 | struct CadetPeer *p = internal_cls; | 387 | uint32_t strength; |
407 | struct CadetPeerPath *direct_path; | 388 | |
408 | char own_id[16]; | 389 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
409 | 390 | "Updating peer %s activation state (%u connections)%s%s\n", | |
410 | GCC_check_connections (); | 391 | GCP_2s (cp), |
411 | strncpy (own_id, GNUNET_i2s (&my_full_id), 16); | 392 | GNUNET_CONTAINER_multishortmap_size (cp->connections), |
412 | own_id[15] = '\0'; | 393 | (NULL == cp->t) ? "" : " with tunnel", |
413 | if (myid == p->id) | 394 | (NULL == cp->core_mq) ? "" : " with CORE link"); |
414 | { | 395 | if (NULL != cp->destroy_task) |
415 | LOG (GNUNET_ERROR_TYPE_INFO, | 396 | { |
416 | "DISCONNECTED %s (self)\n", | 397 | /* It's active, do not destory! */ |
417 | own_id); | 398 | GNUNET_SCHEDULER_cancel (cp->destroy_task); |
418 | } | 399 | cp->destroy_task = NULL; |
419 | else | 400 | } |
401 | if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) && | ||
402 | (NULL == cp->t) ) | ||
403 | { | ||
404 | /* We're just on a path or directly connected; don't bother too much */ | ||
405 | if (NULL != cp->connectivity_suggestion) | ||
420 | { | 406 | { |
421 | LOG (GNUNET_ERROR_TYPE_INFO, | 407 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); |
422 | "DISCONNECTED %s <= %s\n", | 408 | cp->connectivity_suggestion = NULL; |
423 | own_id, GNUNET_i2s (peer)); | ||
424 | p->core_mq = NULL; | ||
425 | } | 409 | } |
426 | direct_path = pop_direct_path (p); | 410 | if (NULL != cp->search_h) |
427 | if (NULL != p->connections) | ||
428 | { | 411 | { |
429 | GNUNET_CONTAINER_multishortmap_iterate (p->connections, | 412 | GCD_search_stop (cp->search_h); |
430 | ¬ify_broken, | 413 | cp->search_h = NULL; |
431 | p); | ||
432 | GNUNET_CONTAINER_multishortmap_destroy (p->connections); | ||
433 | p->connections = NULL; | ||
434 | } | 414 | } |
435 | GNUNET_STATISTICS_update (stats, | 415 | return; |
436 | "# peers", | 416 | } |
437 | -1, | 417 | if (NULL == cp->core_mq) |
438 | GNUNET_NO); | 418 | { |
439 | path_destroy (direct_path); | 419 | /* Lacks direct connection, try to create one by querying the DHT */ |
440 | GCC_check_connections (); | 420 | if ( (NULL == cp->search_h) && |
441 | } | 421 | (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) ) |
442 | 422 | cp->search_h | |
443 | 423 | = GCD_search (&cp->pid); | |
444 | /******************************************************************************/ | 424 | } |
445 | /******************************************************************************/ | 425 | else |
446 | /******************************************************************************/ | 426 | { |
447 | /******************************************************************************/ | 427 | /* Have direct connection, stop DHT search if active */ |
448 | /******************************************************************************/ | 428 | if (NULL != cp->search_h) |
449 | |||
450 | /** | ||
451 | * Check if the create_connection message has the appropriate size. | ||
452 | * | ||
453 | * @param cls Closure (unused). | ||
454 | * @param msg Message to check. | ||
455 | * | ||
456 | * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. | ||
457 | */ | ||
458 | static int | ||
459 | check_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg) | ||
460 | { | ||
461 | uint16_t size; | ||
462 | |||
463 | size = ntohs (msg->header.size); | ||
464 | if (size < sizeof (*msg)) | ||
465 | { | 429 | { |
466 | GNUNET_break_op (0); | 430 | GCD_search_stop (cp->search_h); |
467 | return GNUNET_NO; | 431 | cp->search_h = NULL; |
468 | } | 432 | } |
469 | return GNUNET_YES; | 433 | } |
470 | } | ||
471 | |||
472 | /** | ||
473 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE | ||
474 | * | ||
475 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
476 | * @param msg Message itself. | ||
477 | */ | ||
478 | static void | ||
479 | handle_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg) | ||
480 | { | ||
481 | struct CadetPeer *peer = cls; | ||
482 | GCC_handle_create (peer, msg); | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK | ||
488 | * | ||
489 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
490 | * @param msg Message itself. | ||
491 | */ | ||
492 | static void | ||
493 | handle_confirm (void *cls, const struct GNUNET_CADET_ConnectionCreateAckMessage *msg) | ||
494 | { | ||
495 | struct CadetPeer *peer = cls; | ||
496 | GCC_handle_confirm (peer, msg); | ||
497 | } | ||
498 | |||
499 | 434 | ||
500 | /** | 435 | /* If we have a tunnel, our urge for connections is much bigger */ |
501 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN | 436 | strength = (NULL != cp->t) ? 32 : 1; |
502 | * | 437 | if (NULL != cp->connectivity_suggestion) |
503 | * @param cls Closure (CadetPeer for neighbor that sent the message). | 438 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); |
504 | * @param msg Message itself. | 439 | cp->connectivity_suggestion |
505 | */ | 440 | = GNUNET_ATS_connectivity_suggest (ats_ch, |
506 | static void | 441 | &cp->pid, |
507 | handle_broken (void *cls, const struct GNUNET_CADET_ConnectionBrokenMessage *msg) | 442 | strength); |
508 | { | ||
509 | struct CadetPeer *peer = cls; | ||
510 | GCC_handle_broken (peer, msg); | ||
511 | } | 443 | } |
512 | 444 | ||
513 | 445 | ||
514 | /** | 446 | /** |
515 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY | 447 | * This peer may no longer be needed, consider cleaning it up. |
516 | * | 448 | * |
517 | * @param cls Closure (CadetPeer for neighbor that sent the message). | 449 | * @param cp peer to clean up |
518 | * @param msg Message itself. | ||
519 | */ | 450 | */ |
520 | static void | 451 | static void |
521 | handle_destroy (void *cls, const struct GNUNET_CADET_ConnectionDestroyMessage *msg) | 452 | consider_peer_destroy (struct CadetPeer *cp); |
522 | { | ||
523 | struct CadetPeer *peer = cls; | ||
524 | GCC_handle_destroy (peer, msg); | ||
525 | } | ||
526 | 453 | ||
527 | 454 | ||
528 | /** | 455 | /** |
529 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK | 456 | * We really no longere care about a peer, stop hogging memory with paths to it. |
457 | * Afterwards, see if there is more to be cleaned up about this peer. | ||
530 | * | 458 | * |
531 | * @param cls Closure (CadetPeer for neighbor that sent the message). | 459 | * @param cls a `struct CadetPeer`. |
532 | * @param msg Message itself. | ||
533 | */ | 460 | */ |
534 | static void | 461 | static void |
535 | handle_ack (void *cls, const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg) | 462 | drop_paths (void *cls) |
536 | { | 463 | { |
537 | struct CadetPeer *peer = cls; | 464 | struct CadetPeer *cp = cls; |
538 | GCC_handle_ack (peer, msg); | 465 | struct CadetPeerPath *path; |
539 | } | ||
540 | 466 | ||
541 | 467 | cp->destroy_task = NULL; | |
542 | /** | 468 | while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap))) |
543 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL | 469 | GCPP_release (path); |
544 | * | 470 | consider_peer_destroy (cp); |
545 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
546 | * @param msg Message itself. | ||
547 | */ | ||
548 | static void | ||
549 | handle_poll (void *cls, const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg) | ||
550 | { | ||
551 | struct CadetPeer *peer = cls; | ||
552 | GCC_handle_poll (peer, msg); | ||
553 | } | 471 | } |
554 | 472 | ||
555 | 473 | ||
556 | /** | 474 | /** |
557 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX | 475 | * This peer may no longer be needed, consider cleaning it up. |
558 | * | 476 | * |
559 | * @param cls Closure (CadetPeer for neighbor that sent the message). | 477 | * @param cp peer to clean up |
560 | * @param msg Message itself. | ||
561 | */ | 478 | */ |
562 | static void | 479 | static void |
563 | handle_kx (void *cls, const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | 480 | consider_peer_destroy (struct CadetPeer *cp) |
564 | { | ||
565 | struct CadetPeer *peer = cls; | ||
566 | GCC_handle_kx (peer, msg); | ||
567 | } | ||
568 | |||
569 | |||
570 | /** | ||
571 | * Check if the encrypted message has the appropriate size. | ||
572 | * | ||
573 | * @param cls Closure (unused). | ||
574 | * @param msg Message to check. | ||
575 | * | ||
576 | * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. | ||
577 | */ | ||
578 | static int | ||
579 | check_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
580 | { | 481 | { |
581 | uint16_t size; | 482 | struct GNUNET_TIME_Relative exp; |
582 | uint16_t minimum_size; | ||
583 | |||
584 | size = ntohs (msg->header.size); | ||
585 | minimum_size = sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) | ||
586 | + sizeof (struct GNUNET_MessageHeader); | ||
587 | |||
588 | if (size < minimum_size) | ||
589 | { | ||
590 | GNUNET_break_op (0); | ||
591 | return GNUNET_NO; | ||
592 | } | ||
593 | return GNUNET_YES; | ||
594 | } | ||
595 | 483 | ||
596 | /** | 484 | if (NULL != cp->destroy_task) |
597 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED. | 485 | { |
598 | * | 486 | GNUNET_SCHEDULER_cancel (cp->destroy_task); |
599 | * @param cls Closure (CadetPeer for neighbor that sent the message). | 487 | cp->destroy_task = NULL; |
600 | * @param msg Message itself. | 488 | } |
601 | */ | 489 | if (NULL != cp->t) |
602 | static void | 490 | return; /* still relevant! */ |
603 | handle_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | 491 | if (NULL != cp->core_mq) |
604 | { | 492 | return; /* still relevant! */ |
605 | struct CadetPeer *peer = cls; | 493 | if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections)) |
606 | GCC_handle_encrypted (peer, msg); | 494 | return; /* still relevant! */ |
607 | } | 495 | if ( (NULL != cp->path_heap) && |
608 | 496 | (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) ) | |
609 | 497 | { | |
610 | /** | 498 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT, |
611 | * To be called on core init/fail. | 499 | &drop_paths, |
612 | * | 500 | cp); |
613 | * @param cls Closure (config) | 501 | return; |
614 | * @param identity The public identity of this peer. | 502 | } |
615 | */ | 503 | if (0 != cp->num_paths) |
616 | static void | 504 | return; /* still relevant! */ |
617 | core_init_notify (void *cls, | 505 | if (NULL != cp->hello) |
618 | const struct GNUNET_PeerIdentity *identity); | 506 | { |
619 | 507 | /* relevant only until HELLO expires */ | |
620 | 508 | exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello)); | |
621 | static void | 509 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp, |
622 | connect_to_core (const struct GNUNET_CONFIGURATION_Handle *c) | 510 | &destroy_peer, |
623 | { | 511 | cp); |
624 | struct GNUNET_MQ_MessageHandler core_handlers[] = { | 512 | return; |
625 | GNUNET_MQ_hd_var_size (create, | 513 | } |
626 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, | 514 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT, |
627 | struct GNUNET_CADET_ConnectionCreateMessage, | 515 | &destroy_peer, |
628 | NULL), | 516 | cp); |
629 | GNUNET_MQ_hd_fixed_size (confirm, | ||
630 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK, | ||
631 | struct GNUNET_CADET_ConnectionCreateAckMessage, | ||
632 | NULL), | ||
633 | GNUNET_MQ_hd_fixed_size (broken, | ||
634 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, | ||
635 | struct GNUNET_CADET_ConnectionBrokenMessage, | ||
636 | NULL), | ||
637 | GNUNET_MQ_hd_fixed_size (destroy, | ||
638 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, | ||
639 | struct GNUNET_CADET_ConnectionDestroyMessage, | ||
640 | NULL), | ||
641 | GNUNET_MQ_hd_fixed_size (ack, | ||
642 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK, | ||
643 | struct GNUNET_CADET_ConnectionEncryptedAckMessage, | ||
644 | NULL), | ||
645 | GNUNET_MQ_hd_fixed_size (poll, | ||
646 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL, | ||
647 | struct GNUNET_CADET_ConnectionHopByHopPollMessage, | ||
648 | NULL), | ||
649 | GNUNET_MQ_hd_fixed_size (kx, | ||
650 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX, | ||
651 | struct GNUNET_CADET_TunnelKeyExchangeMessage, | ||
652 | NULL), | ||
653 | GNUNET_MQ_hd_var_size (encrypted, | ||
654 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED, | ||
655 | struct GNUNET_CADET_TunnelEncryptedMessage, | ||
656 | NULL), | ||
657 | GNUNET_MQ_handler_end () | ||
658 | }; | ||
659 | core_handle = GNUNET_CORE_connect (c, NULL, | ||
660 | &core_init_notify, | ||
661 | &core_connect_handler, | ||
662 | &core_disconnect_handler, | ||
663 | core_handlers); | ||
664 | } | ||
665 | |||
666 | /******************************************************************************/ | ||
667 | /******************************************************************************/ | ||
668 | /******************************************************************************/ | ||
669 | /******************************************************************************/ | ||
670 | /******************************************************************************/ | ||
671 | |||
672 | /** | ||
673 | * To be called on core init/fail. | ||
674 | * | ||
675 | * @param cls Closure (config) | ||
676 | * @param identity The public identity of this peer. | ||
677 | */ | ||
678 | static void | ||
679 | core_init_notify (void *cls, | ||
680 | const struct GNUNET_PeerIdentity *core_identity) | ||
681 | { | ||
682 | const struct GNUNET_CONFIGURATION_Handle *c = cls; | ||
683 | |||
684 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); | ||
685 | if (0 != memcmp (core_identity, &my_full_id, sizeof (my_full_id))) | ||
686 | { | ||
687 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); | ||
688 | LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (core_identity)); | ||
689 | LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id)); | ||
690 | GNUNET_CORE_disconnect (core_handle); | ||
691 | connect_to_core (c); | ||
692 | return; | ||
693 | } | ||
694 | GML_start (); | ||
695 | } | 517 | } |
696 | 518 | ||
697 | 519 | ||
698 | /******************************************************************************/ | ||
699 | /******************************** STATIC ***********************************/ | ||
700 | /******************************************************************************/ | ||
701 | |||
702 | |||
703 | /** | 520 | /** |
704 | * Get priority for a queued message. | 521 | * Set the message queue to @a mq for peer @a cp and notify watchers. |
705 | * | ||
706 | * @param q Queued message | ||
707 | * | ||
708 | * @return CORE priority to use. | ||
709 | * | 522 | * |
710 | * FIXME make static | 523 | * @param cp peer to modify |
711 | * FIXME use when sending | 524 | * @param mq message queue to set (can be NULL) |
712 | */ | 525 | */ |
713 | enum GNUNET_CORE_Priority | 526 | void |
714 | get_priority (struct CadetPeerQueue *q) | 527 | GCP_set_mq (struct CadetPeer *cp, |
715 | { | 528 | struct GNUNET_MQ_Handle *mq) |
716 | enum GNUNET_CORE_Priority low; | 529 | { |
717 | enum GNUNET_CORE_Priority high; | 530 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
718 | 531 | "Message queue for peer %s is now %p\n", | |
719 | if (NULL == q) | 532 | GCP_2s (cp), |
720 | { | 533 | mq); |
721 | GNUNET_break (0); | 534 | cp->core_mq = mq; |
722 | return GNUNET_CORE_PRIO_BACKGROUND; | 535 | for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next; |
723 | } | 536 | NULL != mqm; |
724 | 537 | mqm = next) | |
725 | /* Relayed traffic has lower priority, our own traffic has higher */ | 538 | { |
726 | if (NULL == q->c || GNUNET_NO == GCC_is_origin (q->c, q->c_fwd)) | 539 | /* Save next pointer in case mqm gets freed by the callback */ |
540 | next = mqm->next; | ||
541 | if (NULL == mq) | ||
727 | { | 542 | { |
728 | low = GNUNET_CORE_PRIO_BEST_EFFORT; | 543 | if (NULL != mqm->env) |
729 | high = GNUNET_CORE_PRIO_URGENT; | 544 | { |
545 | GNUNET_MQ_discard (mqm->env); | ||
546 | mqm->env = NULL; | ||
547 | mqm->cb (mqm->cb_cls, | ||
548 | GNUNET_SYSERR); | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | mqm->cb (mqm->cb_cls, | ||
553 | GNUNET_NO); | ||
554 | } | ||
730 | } | 555 | } |
731 | else | 556 | else |
732 | { | 557 | { |
733 | low = GNUNET_CORE_PRIO_URGENT; | 558 | GNUNET_assert (NULL == mqm->env); |
734 | high = GNUNET_CORE_PRIO_CRITICAL_CONTROL; | 559 | mqm->cb (mqm->cb_cls, |
560 | GNUNET_YES); | ||
735 | } | 561 | } |
562 | } | ||
563 | if ( (NULL != mq) || | ||
564 | (NULL != cp->t) ) | ||
565 | consider_peer_activate (cp); | ||
566 | else | ||
567 | consider_peer_destroy (cp); | ||
736 | 568 | ||
737 | /* Bulky payload has lower priority, control traffic has higher. */ | 569 | if ( (NULL != mq) && |
738 | if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == q->type) | 570 | (NULL != cp->t) ) |
739 | return low; | 571 | { |
740 | return high; | 572 | /* have a new, direct path to the target, notify tunnel */ |
741 | } | 573 | struct CadetPeerPath *path; |
742 | |||
743 | |||
744 | /** | ||
745 | * Cancel all messages queued to CORE MQ towards this peer. | ||
746 | * | ||
747 | * @param peer Peer towards which to cancel all messages. | ||
748 | */ | ||
749 | static void | ||
750 | cancel_queued_messages (struct CadetPeer *peer) | ||
751 | { | ||
752 | while (NULL != peer->q_head) | ||
753 | { | ||
754 | struct CadetPeerQueue *q; | ||
755 | |||
756 | q = peer->q_head; | ||
757 | call_peer_cont (q, GNUNET_NO); | ||
758 | GNUNET_free (q); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | |||
763 | /** | ||
764 | * Destroy the peer_info and free any allocated resources linked to it | ||
765 | * | ||
766 | * @param peer The peer_info to destroy. | ||
767 | * @return #GNUNET_OK on success | ||
768 | */ | ||
769 | static int | ||
770 | peer_destroy (struct CadetPeer *peer) | ||
771 | { | ||
772 | struct GNUNET_PeerIdentity id; | ||
773 | struct CadetPeerPath *p; | ||
774 | struct CadetPeerPath *nextp; | ||
775 | |||
776 | GNUNET_PEER_resolve (peer->id, &id); | ||
777 | GNUNET_PEER_change_rc (peer->id, -1); | ||
778 | |||
779 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
780 | "destroying peer %s\n", | ||
781 | GNUNET_i2s (&id)); | ||
782 | |||
783 | if (GNUNET_YES != | ||
784 | GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) | ||
785 | { | ||
786 | GNUNET_break (0); | ||
787 | LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n"); | ||
788 | } | ||
789 | GCP_stop_search (peer); | ||
790 | p = peer->path_head; | ||
791 | while (NULL != p) | ||
792 | { | ||
793 | nextp = p->next; | ||
794 | GNUNET_CONTAINER_DLL_remove (peer->path_head, | ||
795 | peer->path_tail, | ||
796 | p); | ||
797 | path_destroy (p); | ||
798 | p = nextp; | ||
799 | } | ||
800 | if (NULL != peer->tunnel) | ||
801 | GCT_destroy_empty (peer->tunnel); | ||
802 | if (NULL != peer->connections) | ||
803 | { | ||
804 | GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (peer->connections)); | ||
805 | GNUNET_CONTAINER_multishortmap_destroy (peer->connections); | ||
806 | peer->connections = NULL; | ||
807 | } | ||
808 | if (NULL != peer->hello_offer) | ||
809 | { | ||
810 | GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer); | ||
811 | peer->hello_offer = NULL; | ||
812 | } | ||
813 | if (NULL != peer->connectivity_suggestion) | ||
814 | { | ||
815 | GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion); | ||
816 | peer->connectivity_suggestion = NULL; | ||
817 | } | ||
818 | cancel_queued_messages (peer); | ||
819 | 574 | ||
820 | GNUNET_free_non_null (peer->hello); | 575 | path = GCPP_get_path_from_route (1, |
821 | GNUNET_free (peer); | 576 | &cp->pid); |
822 | return GNUNET_OK; | 577 | GCT_consider_path (cp->t, |
578 | path, | ||
579 | 0); | ||
580 | } | ||
823 | } | 581 | } |
824 | 582 | ||
825 | 583 | ||
826 | /** | 584 | /** |
827 | * Iterator over peer hash map entries to destroy the peer during in_shutdown. | 585 | * Debug function should NEVER return true in production code, useful to |
586 | * simulate losses for testcases. | ||
828 | * | 587 | * |
829 | * @param cls closure | 588 | * @return #GNUNET_YES or #GNUNET_NO with the decision to drop. |
830 | * @param key current key code | ||
831 | * @param value value in the hash map | ||
832 | * @return #GNUNET_YES if we should continue to iterate, | ||
833 | * #GNUNET_NO if not. | ||
834 | */ | 589 | */ |
835 | static int | 590 | static int |
836 | shutdown_peer (void *cls, | 591 | should_I_drop (void) |
837 | const struct GNUNET_PeerIdentity *key, | ||
838 | void *value) | ||
839 | { | 592 | { |
840 | struct CadetPeer *p = value; | 593 | if (0 == drop_percent) |
841 | struct CadetTunnel *t = p->tunnel; | 594 | return GNUNET_NO; |
842 | 595 | if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | |
843 | LOG (GNUNET_ERROR_TYPE_DEBUG, " shutting down %s\n", GCP_2s (p)); | 596 | 101) < drop_percent) |
844 | if (NULL != t) | ||
845 | GCT_destroy (t); | ||
846 | p->tunnel = NULL; | ||
847 | peer_destroy (p); | ||
848 | return GNUNET_YES; | 597 | return GNUNET_YES; |
598 | return GNUNET_NO; | ||
849 | } | 599 | } |
850 | 600 | ||
851 | 601 | ||
852 | /** | 602 | /** |
853 | * Check if peer is searching for a path (either active or delayed search). | 603 | * Function called when CORE took one of the messages from |
854 | * | 604 | * a message queue manager and transmitted it. |
855 | * @param peer Peer to check | ||
856 | * @return #GNUNET_YES if there is a search active. | ||
857 | * #GNUNET_NO otherwise. | ||
858 | */ | ||
859 | static int | ||
860 | is_searching (const struct CadetPeer *peer) | ||
861 | { | ||
862 | return ( (NULL == peer->search_h) && | ||
863 | (NULL == peer->search_delayed) ) ? | ||
864 | GNUNET_NO : GNUNET_YES; | ||
865 | } | ||
866 | |||
867 | |||
868 | /** | ||
869 | * @brief Start a search for a peer. | ||
870 | * | 605 | * |
871 | * @param cls Closure (Peer to search for). | 606 | * @param cls the `struct CadetPeeer` where we made progress |
872 | */ | 607 | */ |
873 | static void | 608 | static void |
874 | delayed_search (void *cls) | 609 | mqm_send_done (void *cls); |
875 | { | ||
876 | struct CadetPeer *peer = cls; | ||
877 | |||
878 | peer->search_delayed = NULL; | ||
879 | GCC_check_connections (); | ||
880 | GCP_start_search (peer); | ||
881 | GCC_check_connections (); | ||
882 | } | ||
883 | 610 | ||
884 | 611 | ||
885 | /** | 612 | /** |
886 | * Returns if peer is used (has a tunnel or is neighbor). | 613 | * Transmit current envelope from this @a mqm. |
887 | * | 614 | * |
888 | * @param peer Peer to check. | 615 | * @param mqm mqm to transmit message for now |
889 | * @return #GNUNET_YES if peer is in use. | ||
890 | */ | 616 | */ |
891 | static int | 617 | static void |
892 | peer_is_used (struct CadetPeer *peer) | 618 | mqm_execute (struct GCP_MessageQueueManager *mqm) |
893 | { | ||
894 | struct CadetPeerPath *p; | ||
895 | |||
896 | if (NULL != peer->tunnel) | ||
897 | return GNUNET_YES; | ||
898 | |||
899 | for (p = peer->path_head; NULL != p; p = p->next) | ||
900 | { | ||
901 | if (p->length < 3) | ||
902 | return GNUNET_YES; | ||
903 | } | ||
904 | return GNUNET_NO; | ||
905 | } | ||
906 | |||
907 | |||
908 | /** | ||
909 | * Iterator over all the peers to get the oldest timestamp. | ||
910 | * | ||
911 | * @param cls Closure (unsued). | ||
912 | * @param key ID of the peer. | ||
913 | * @param value Peer_Info of the peer. | ||
914 | */ | ||
915 | static int | ||
916 | peer_get_oldest (void *cls, | ||
917 | const struct GNUNET_PeerIdentity *key, | ||
918 | void *value) | ||
919 | { | 619 | { |
920 | struct CadetPeer *p = value; | 620 | struct CadetPeer *cp = mqm->cp; |
921 | struct GNUNET_TIME_Absolute *abs = cls; | ||
922 | |||
923 | /* Don't count active peers */ | ||
924 | if (GNUNET_YES == peer_is_used (p)) | ||
925 | return GNUNET_YES; | ||
926 | 621 | ||
927 | if (abs->abs_value_us < p->last_contact.abs_value_us) | 622 | /* Move ready pointer to the next entry that might be ready. */ |
928 | abs->abs_value_us = p->last_contact.abs_value_us; | 623 | if ( (mqm == cp->mqm_ready_ptr) && |
929 | 624 | (NULL != mqm->next) ) | |
930 | return GNUNET_YES; | 625 | cp->mqm_ready_ptr = mqm->next; |
626 | /* Move entry to the end of the DLL, to be fair. */ | ||
627 | if (mqm != cp->mqm_tail) | ||
628 | { | ||
629 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
630 | cp->mqm_tail, | ||
631 | mqm); | ||
632 | GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head, | ||
633 | cp->mqm_tail, | ||
634 | mqm); | ||
635 | } | ||
636 | cp->mqm_ready_counter--; | ||
637 | if (GNUNET_YES == should_I_drop ()) | ||
638 | { | ||
639 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
640 | "DROPPING message to peer %s from MQM %p\n", | ||
641 | GCP_2s (cp), | ||
642 | mqm); | ||
643 | GNUNET_MQ_discard (mqm->env); | ||
644 | mqm->env = NULL; | ||
645 | mqm_send_done (cp); | ||
646 | } | ||
647 | else | ||
648 | { | ||
649 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
650 | "Sending to peer %s from MQM %p\n", | ||
651 | GCP_2s (cp), | ||
652 | mqm); | ||
653 | GNUNET_MQ_send (cp->core_mq, | ||
654 | mqm->env); | ||
655 | mqm->env = NULL; | ||
656 | } | ||
657 | mqm->cb (mqm->cb_cls, | ||
658 | GNUNET_YES); | ||
931 | } | 659 | } |
932 | 660 | ||
933 | 661 | ||
934 | /** | 662 | /** |
935 | * Iterator over all the peers to remove the oldest entry. | 663 | * Find the next ready message in the queue (starting |
664 | * the search from the `cp->mqm_ready_ptr`) and if possible | ||
665 | * execute the transmission. | ||
936 | * | 666 | * |
937 | * @param cls Closure (unsued). | 667 | * @param cp peer to try to send the next ready message to |
938 | * @param key ID of the peer. | ||
939 | * @param value Peer_Info of the peer. | ||
940 | */ | ||
941 | static int | ||
942 | peer_timeout (void *cls, | ||
943 | const struct GNUNET_PeerIdentity *key, | ||
944 | void *value) | ||
945 | { | ||
946 | struct CadetPeer *p = value; | ||
947 | struct GNUNET_TIME_Absolute *abs = cls; | ||
948 | |||
949 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
950 | "peer %s timeout\n", GNUNET_i2s (key)); | ||
951 | |||
952 | if (p->last_contact.abs_value_us == abs->abs_value_us && | ||
953 | GNUNET_NO == peer_is_used (p)) | ||
954 | { | ||
955 | peer_destroy (p); | ||
956 | return GNUNET_NO; | ||
957 | } | ||
958 | return GNUNET_YES; | ||
959 | } | ||
960 | |||
961 | |||
962 | /** | ||
963 | * Delete oldest unused peer. | ||
964 | */ | 668 | */ |
965 | static void | 669 | static void |
966 | peer_delete_oldest (void) | 670 | send_next_ready (struct CadetPeer *cp) |
967 | { | 671 | { |
968 | struct GNUNET_TIME_Absolute abs; | 672 | struct GCP_MessageQueueManager *mqm; |
969 | |||
970 | abs = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
971 | |||
972 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
973 | &peer_get_oldest, | ||
974 | &abs); | ||
975 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
976 | &peer_timeout, | ||
977 | &abs); | ||
978 | } | ||
979 | |||
980 | 673 | ||
981 | /** | 674 | if (0 == cp->mqm_ready_counter) |
982 | * Choose the best (yet unused) path towards a peer, | 675 | return; |
983 | * considering the tunnel properties. | 676 | while ( (NULL != (mqm = cp->mqm_ready_ptr)) && |
984 | * | 677 | (NULL == mqm->env) ) |
985 | * @param peer The destination peer. | 678 | cp->mqm_ready_ptr = mqm->next; |
986 | * @return Best current known path towards the peer, if any. | 679 | if (NULL == mqm) |
987 | */ | 680 | return; /* nothing to do */ |
988 | static struct CadetPeerPath * | 681 | mqm_execute (mqm); |
989 | peer_get_best_path (const struct CadetPeer *peer) | ||
990 | { | ||
991 | struct CadetPeerPath *best_p; | ||
992 | struct CadetPeerPath *p; | ||
993 | unsigned int best_cost; | ||
994 | unsigned int cost; | ||
995 | |||
996 | best_cost = UINT_MAX; | ||
997 | best_p = NULL; | ||
998 | for (p = peer->path_head; NULL != p; p = p->next) | ||
999 | { | ||
1000 | if (GNUNET_NO == path_is_valid (p)) | ||
1001 | continue; /* Don't use invalid paths. */ | ||
1002 | if (GNUNET_YES == GCT_is_path_used (peer->tunnel, p)) | ||
1003 | continue; /* If path is already in use, skip it. */ | ||
1004 | |||
1005 | if ((cost = GCT_get_path_cost (peer->tunnel, p)) < best_cost) | ||
1006 | { | ||
1007 | best_cost = cost; | ||
1008 | best_p = p; | ||
1009 | } | ||
1010 | } | ||
1011 | return best_p; | ||
1012 | } | 682 | } |
1013 | 683 | ||
1014 | 684 | ||
1015 | /** | 685 | /** |
1016 | * Function to process paths received for a new peer addition. The recorded | 686 | * Function called when CORE took one of the messages from |
1017 | * paths form the initial tunnel, which can be optimized later. | 687 | * a message queue manager and transmitted it. |
1018 | * Called on each result obtained for the DHT search. | ||
1019 | * | 688 | * |
1020 | * @param cls Closure (peer towards a path has been found). | 689 | * @param cls the `struct CadetPeeer` where we made progress |
1021 | * @param path Path created from the DHT query. Will be freed afterwards. | ||
1022 | */ | 690 | */ |
1023 | static void | 691 | static void |
1024 | search_handler (void *cls, const struct CadetPeerPath *path) | 692 | mqm_send_done (void *cls) |
1025 | { | 693 | { |
1026 | struct CadetPeer *peer = cls; | 694 | struct CadetPeer *cp = cls; |
1027 | unsigned int connection_count; | ||
1028 | |||
1029 | GCC_check_connections (); | ||
1030 | GCP_add_path_to_all (path, GNUNET_NO); | ||
1031 | |||
1032 | /* Count connections */ | ||
1033 | connection_count = GCT_count_connections (peer->tunnel); | ||
1034 | 695 | ||
1035 | /* If we already have our minimum (or more) connections, it's enough */ | 696 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1036 | if (CONNECTIONS_PER_TUNNEL <= connection_count) | 697 | "Sending to peer %s completed\n", |
1037 | { | 698 | GCP_2s (cp)); |
1038 | GCC_check_connections (); | 699 | send_next_ready (cp); |
1039 | return; | ||
1040 | } | ||
1041 | |||
1042 | if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel)) | ||
1043 | { | ||
1044 | LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n"); | ||
1045 | GCP_connect (peer); | ||
1046 | } | ||
1047 | GCC_check_connections (); | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
1052 | * Test if a message type is connection management traffic | ||
1053 | * or regular payload traffic. | ||
1054 | * | ||
1055 | * @param type Message type. | ||
1056 | * | ||
1057 | * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise. | ||
1058 | */ | ||
1059 | static int | ||
1060 | is_connection_management (uint16_t type) | ||
1061 | { | ||
1062 | return type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK || | ||
1063 | type == GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL; | ||
1064 | } | 700 | } |
1065 | 701 | ||
1066 | 702 | ||
1067 | /** | 703 | /** |
1068 | * Debug function should NEVER return true in production code, useful to | 704 | * Send the message in @a env to @a cp. |
1069 | * simulate losses for testcases. | ||
1070 | * | 705 | * |
1071 | * @return #GNUNET_YES or #GNUNET_NO with the decision to drop. | 706 | * @param mqm the message queue manager to use for transmission |
707 | * @param env envelope with the message to send; must NOT | ||
708 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
1072 | */ | 709 | */ |
1073 | static int | 710 | void |
1074 | should_I_drop (void) | 711 | GCP_send (struct GCP_MessageQueueManager *mqm, |
712 | struct GNUNET_MQ_Envelope *env) | ||
1075 | { | 713 | { |
1076 | if (0 == drop_percent) | 714 | struct CadetPeer *cp = mqm->cp; |
1077 | return GNUNET_NO; | ||
1078 | 715 | ||
1079 | if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent) | 716 | GNUNET_assert (NULL != env); |
1080 | return GNUNET_YES; | 717 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1081 | 718 | "Queueing message to peer %s in MQM %p\n", | |
1082 | return GNUNET_NO; | 719 | GCP_2s (cp), |
720 | mqm); | ||
721 | GNUNET_assert (NULL != cp->core_mq); | ||
722 | GNUNET_assert (NULL == mqm->env); | ||
723 | GNUNET_MQ_notify_sent (env, | ||
724 | &mqm_send_done, | ||
725 | cp); | ||
726 | mqm->env = env; | ||
727 | cp->mqm_ready_counter++; | ||
728 | if (mqm != cp->mqm_ready_ptr) | ||
729 | cp->mqm_ready_ptr = cp->mqm_head; | ||
730 | if (1 == cp->mqm_ready_counter) | ||
731 | cp->mqm_ready_ptr = mqm; | ||
732 | if (0 != GNUNET_MQ_get_length (cp->core_mq)) | ||
733 | return; | ||
734 | send_next_ready (cp); | ||
1083 | } | 735 | } |
1084 | 736 | ||
1085 | 737 | ||
1086 | /******************************************************************************/ | ||
1087 | /******************************** API ***********************************/ | ||
1088 | /******************************************************************************/ | ||
1089 | |||
1090 | /** | 738 | /** |
1091 | * Call the continuation after a message has been sent or dropped. | 739 | * Function called to destroy a peer now. |
1092 | * | 740 | * |
1093 | * This funcion removes the message from the queue. | 741 | * @param cls NULL |
1094 | * | 742 | * @param pid identity of the peer (unused) |
1095 | * @param q Queue handle. | 743 | * @param value the `struct CadetPeer` to clean up |
1096 | * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped. | 744 | * @return #GNUNET_OK (continue to iterate) |
1097 | */ | 745 | */ |
1098 | static void | 746 | static int |
1099 | call_peer_cont (struct CadetPeerQueue *q, int sent) | 747 | destroy_iterator_cb (void *cls, |
1100 | { | 748 | const struct GNUNET_PeerIdentity *pid, |
1101 | LOG (GNUNET_ERROR_TYPE_DEBUG, " core mq just sent %s\n", GC_m2s (q->type)); | 749 | void *value) |
1102 | if (NULL != q->cont) | ||
1103 | { | ||
1104 | struct GNUNET_TIME_Relative wait_time; | ||
1105 | |||
1106 | wait_time = GNUNET_TIME_absolute_get_duration (q->queue_timestamp); | ||
1107 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1108 | " calling callback on %s after %s\n", | ||
1109 | GCC_2s (q->c), | ||
1110 | GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO)); | ||
1111 | q->cont (q->cont_cls, | ||
1112 | q->c, q->c_fwd, sent, | ||
1113 | q->type, | ||
1114 | q->payload_type, | ||
1115 | q->payload_id, | ||
1116 | q->size, wait_time); | ||
1117 | q->cont = NULL; | ||
1118 | } | ||
1119 | GNUNET_CONTAINER_DLL_remove (q->peer->q_head, q->peer->q_tail, q); | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | /** | ||
1124 | * Function called by MQ when a message is sent to CORE. | ||
1125 | * | ||
1126 | * @param cls Closure (queue handle). | ||
1127 | */ | ||
1128 | static void | ||
1129 | mq_sent (void *cls) | ||
1130 | { | 750 | { |
1131 | struct CadetPeerQueue *q = cls; | 751 | struct CadetPeer *cp = value; |
1132 | 752 | ||
1133 | if (GNUNET_NO == q->management_traffic) | 753 | if (NULL != cp->destroy_task) |
1134 | { | 754 | { |
1135 | q->peer->queue_n--; | 755 | GNUNET_SCHEDULER_cancel (cp->destroy_task); |
1136 | } | 756 | cp->destroy_task = NULL; |
1137 | call_peer_cont (q, GNUNET_YES); | 757 | } |
1138 | GNUNET_free (q); | 758 | destroy_peer (cp); |
759 | return GNUNET_OK; | ||
1139 | } | 760 | } |
1140 | 761 | ||
1141 | 762 | ||
1142 | /** | 763 | /** |
1143 | * Finish the drop operation. | 764 | * Clean up all entries about all peers. |
1144 | * | 765 | * Must only be called after all tunnels, CORE-connections and |
1145 | * @param cls queue entry to finish drop for | 766 | * connections are down. |
1146 | */ | 767 | */ |
1147 | static void | 768 | void |
1148 | drop_cb (void *cls) | 769 | GCP_destroy_all_peers () |
1149 | { | 770 | { |
1150 | struct CadetPeerQueue *q = cls; | 771 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1151 | 772 | "Destroying all peers now\n"); | |
1152 | GNUNET_MQ_discard (q->env); | 773 | GNUNET_CONTAINER_multipeermap_iterate (peers, |
1153 | call_peer_cont (q, GNUNET_YES); | 774 | &destroy_iterator_cb, |
1154 | GNUNET_free (q); | 775 | NULL); |
1155 | } | 776 | } |
1156 | 777 | ||
1157 | 778 | ||
1158 | /** | 779 | /** |
1159 | * @brief Send a message to another peer (using CORE). | 780 | * Drop all paths owned by this peer, and do not |
781 | * allow new ones to be added: We are shutting down. | ||
1160 | * | 782 | * |
1161 | * @param peer Peer towards which to queue the message. | 783 | * @param cp peer to drop paths to |
1162 | * @param message Message to send. | ||
1163 | * @param payload_type Type of the message's payload, for debug messages. | ||
1164 | * 0 if the message is a retransmission (unknown payload). | ||
1165 | * UINT16_MAX if the message does not have payload. | ||
1166 | * @param payload_id ID of the payload (MID, ACK #, etc) | ||
1167 | * @param c Connection this message belongs to (can be NULL). | ||
1168 | * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) | ||
1169 | * @param cont Continuation to be called once CORE has sent the message. | ||
1170 | * @param cont_cls Closure for @c cont. | ||
1171 | * | ||
1172 | * @return A handle to the message in the queue or NULL (if dropped). | ||
1173 | */ | 784 | */ |
1174 | struct CadetPeerQueue * | 785 | void |
1175 | GCP_send (struct CadetPeer *peer, | 786 | GCP_drop_owned_paths (struct CadetPeer *cp) |
1176 | const struct GNUNET_MessageHeader *message, | ||
1177 | uint16_t payload_type, | ||
1178 | struct CadetEncryptedMessageIdentifier payload_id, | ||
1179 | struct CadetConnection *c, | ||
1180 | int fwd, | ||
1181 | GCP_sent cont, | ||
1182 | void *cont_cls) | ||
1183 | { | 787 | { |
1184 | struct CadetPeerQueue *q; | 788 | struct CadetPeerPath *path; |
1185 | uint16_t type; | ||
1186 | uint16_t size; | ||
1187 | |||
1188 | GCC_check_connections (); | ||
1189 | type = ntohs (message->type); | ||
1190 | size = ntohs (message->size); | ||
1191 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1192 | "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n", | ||
1193 | GC_m2s (type), GC_m2s (payload_type), | ||
1194 | ntohl (payload_id.pid), | ||
1195 | GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size); | ||
1196 | |||
1197 | if (NULL == peer->connections) | ||
1198 | { | ||
1199 | /* We are not connected to this peer, ignore request. */ | ||
1200 | GNUNET_break (0); | ||
1201 | LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer)); | ||
1202 | GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1, | ||
1203 | GNUNET_NO); | ||
1204 | return NULL; | ||
1205 | } | ||
1206 | 789 | ||
1207 | q = GNUNET_new (struct CadetPeerQueue); | 790 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1208 | q->env = GNUNET_MQ_msg_copy (message); | 791 | "Destroying all paths to %s\n", |
1209 | q->peer = peer; | 792 | GCP_2s (cp)); |
1210 | q->cont = cont; | 793 | while (NULL != (path = |
1211 | q->cont_cls = cont_cls; | 794 | GNUNET_CONTAINER_heap_remove_root (cp->path_heap))) |
1212 | q->queue_timestamp = GNUNET_TIME_absolute_get (); | 795 | GCPP_release (path); |
1213 | q->management_traffic = is_connection_management (type); | 796 | GNUNET_CONTAINER_heap_destroy (cp->path_heap); |
1214 | q->type = type; | 797 | cp->path_heap = NULL; |
1215 | q->size = size; | ||
1216 | q->payload_type = payload_type; | ||
1217 | q->payload_id = payload_id; | ||
1218 | q->c = c; | ||
1219 | q->c_fwd = fwd; | ||
1220 | GNUNET_MQ_notify_sent (q->env, &mq_sent, q); | ||
1221 | GNUNET_CONTAINER_DLL_insert (peer->q_head, peer->q_tail, q); | ||
1222 | |||
1223 | if (GNUNET_YES == q->management_traffic) | ||
1224 | { | ||
1225 | GNUNET_MQ_send (peer->core_mq, q->env); // FIXME implement "_urgent", use | ||
1226 | } | ||
1227 | else | ||
1228 | { | ||
1229 | if (GNUNET_YES == should_I_drop ()) | ||
1230 | { | ||
1231 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1232 | "DD %s (%s %u) on conn %s %s (random drop for testing)\n", | ||
1233 | GC_m2s (q->type), | ||
1234 | GC_m2s (q->payload_type), | ||
1235 | ntohl (q->payload_id.pid), | ||
1236 | GCC_2s (c), | ||
1237 | GC_f2s (q->c_fwd)); | ||
1238 | q->drop_task = GNUNET_SCHEDULER_add_now (&drop_cb, | ||
1239 | q); | ||
1240 | return q; | ||
1241 | } | ||
1242 | GNUNET_MQ_send (peer->core_mq, q->env); | ||
1243 | peer->queue_n++; | ||
1244 | } | ||
1245 | |||
1246 | GCC_check_connections (); | ||
1247 | return q; | ||
1248 | } | 798 | } |
1249 | 799 | ||
1250 | 800 | ||
1251 | /** | 801 | /** |
1252 | * Cancel sending a message. Message must have been sent with | 802 | * Add an entry to the DLL of all of the paths that this peer is on. |
1253 | * #GCP_send before. May not be called after the notify sent | ||
1254 | * callback has been called. | ||
1255 | * | ||
1256 | * It DOES call the continuation given to #GCP_send. | ||
1257 | * | 803 | * |
1258 | * @param q Queue handle to cancel | 804 | * @param cp peer to modify |
805 | * @param entry an entry on a path | ||
806 | * @param off offset of this peer on the path | ||
1259 | */ | 807 | */ |
1260 | void | 808 | void |
1261 | GCP_send_cancel (struct CadetPeerQueue *q) | 809 | GCP_path_entry_add (struct CadetPeer *cp, |
1262 | { | 810 | struct CadetPeerPathEntry *entry, |
1263 | if (NULL != q->drop_task) | 811 | unsigned int off) |
812 | { | ||
813 | GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path, | ||
814 | off)); | ||
815 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
816 | "Discovered that peer %s is on path %s at offset %u\n", | ||
817 | GCP_2s (cp), | ||
818 | GCPP_2s (entry->path), | ||
819 | off); | ||
820 | if (off >= cp->path_dll_length) | ||
1264 | { | 821 | { |
1265 | GNUNET_SCHEDULER_cancel (q->drop_task); | 822 | unsigned int len = cp->path_dll_length; |
1266 | q->drop_task = NULL; | 823 | |
1267 | GNUNET_MQ_discard (q->env); | 824 | GNUNET_array_grow (cp->path_heads, |
825 | len, | ||
826 | off + 4); | ||
827 | GNUNET_array_grow (cp->path_tails, | ||
828 | cp->path_dll_length, | ||
829 | off + 4); | ||
1268 | } | 830 | } |
1269 | else | 831 | GNUNET_CONTAINER_DLL_insert (cp->path_heads[off], |
832 | cp->path_tails[off], | ||
833 | entry); | ||
834 | cp->off_sum += off; | ||
835 | cp->num_paths++; | ||
836 | |||
837 | /* If we have a tunnel to this peer, tell the tunnel that there is a | ||
838 | new path available. */ | ||
839 | if (NULL != cp->t) | ||
840 | GCT_consider_path (cp->t, | ||
841 | entry->path, | ||
842 | off); | ||
843 | |||
844 | if ( (NULL != cp->search_h) && | ||
845 | (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ) | ||
1270 | { | 846 | { |
1271 | GNUNET_MQ_send_cancel (q->env); | 847 | /* Now I have enough paths, stop search */ |
848 | GCD_search_stop (cp->search_h); | ||
849 | cp->search_h = NULL; | ||
850 | } | ||
851 | if (NULL != cp->destroy_task) | ||
852 | { | ||
853 | /* paths changed, this resets the destroy timeout counter | ||
854 | and aborts a destroy task that may no longer be valid | ||
855 | to have (as we now have more paths via this peer). */ | ||
856 | consider_peer_destroy (cp); | ||
1272 | } | 857 | } |
1273 | call_peer_cont (q, GNUNET_NO); | ||
1274 | GNUNET_free (q); | ||
1275 | } | 858 | } |
1276 | 859 | ||
1277 | 860 | ||
1278 | /** | 861 | /** |
1279 | * Initialize the peer subsystem. | 862 | * Remove an entry from the DLL of all of the paths that this peer is on. |
1280 | * | 863 | * |
1281 | * @param c Configuration. | 864 | * @param cp peer to modify |
1282 | */ | 865 | * @param entry an entry on a path |
1283 | void | 866 | * @param off offset of this peer on the path |
1284 | GCP_init (const struct GNUNET_CONFIGURATION_Handle *c) | ||
1285 | { | ||
1286 | cfg = c; | ||
1287 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1288 | "GCP_init\n"); | ||
1289 | in_shutdown = GNUNET_NO; | ||
1290 | peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); | ||
1291 | if (GNUNET_OK != | ||
1292 | GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS", | ||
1293 | &max_peers)) | ||
1294 | { | ||
1295 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1296 | "CADET", "MAX_PEERS", "USING DEFAULT"); | ||
1297 | max_peers = 1000; | ||
1298 | } | ||
1299 | |||
1300 | if (GNUNET_OK != | ||
1301 | GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT", | ||
1302 | &drop_percent)) | ||
1303 | { | ||
1304 | drop_percent = 0; | ||
1305 | } | ||
1306 | else | ||
1307 | { | ||
1308 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1309 | LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); | ||
1310 | LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); | ||
1311 | LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); | ||
1312 | LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); | ||
1313 | } | ||
1314 | ats_ch = GNUNET_ATS_connectivity_init (c); | ||
1315 | connect_to_core (c); | ||
1316 | if (NULL == core_handle) | ||
1317 | { | ||
1318 | GNUNET_break (0); | ||
1319 | GNUNET_SCHEDULER_shutdown (); | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * Shut down the peer subsystem. | ||
1326 | */ | 867 | */ |
1327 | void | 868 | void |
1328 | GCP_shutdown (void) | 869 | GCP_path_entry_remove (struct CadetPeer *cp, |
1329 | { | 870 | struct CadetPeerPathEntry *entry, |
1330 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 871 | unsigned int off) |
1331 | "Shutting down peer subsystem\n"); | 872 | { |
1332 | in_shutdown = GNUNET_YES; | 873 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1333 | if (NULL != core_handle) | 874 | "Removing knowledge about peer %s beging on path %s at offset %u\n", |
1334 | { | 875 | GCP_2s (cp), |
1335 | GNUNET_CORE_disconnect (core_handle); | 876 | GCPP_2s (entry->path), |
1336 | core_handle = NULL; | 877 | off); |
1337 | } | 878 | GNUNET_CONTAINER_DLL_remove (cp->path_heads[off], |
1338 | GNUNET_PEER_change_rc (myid, -1); | 879 | cp->path_tails[off], |
1339 | /* With MQ API, CORE calls the disconnect handler for every peer | 880 | entry); |
1340 | * after calling GNUNET_CORE_disconnect, shutdown must occur *after* that. | 881 | GNUNET_assert (0 < cp->num_paths); |
1341 | */ | 882 | cp->off_sum -= off; |
1342 | GNUNET_CONTAINER_multipeermap_iterate (peers, | 883 | cp->num_paths--; |
1343 | &shutdown_peer, | 884 | if ( (NULL == cp->core_mq) && |
1344 | NULL); | 885 | (NULL != cp->t) && |
1345 | if (NULL != ats_ch) | 886 | (NULL == cp->search_h) && |
1346 | { | 887 | (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) ) |
1347 | GNUNET_ATS_connectivity_done (ats_ch); | 888 | cp->search_h |
1348 | ats_ch = NULL; | 889 | = GCD_search (&cp->pid); |
1349 | } | 890 | if (NULL == cp->destroy_task) |
1350 | GNUNET_CONTAINER_multipeermap_destroy (peers); | 891 | { |
1351 | peers = NULL; | 892 | /* paths changed, we might now be ready for destruction, check again */ |
1352 | } | 893 | consider_peer_destroy (cp); |
1353 | 894 | } | |
1354 | |||
1355 | /** | ||
1356 | * Retrieve the CadetPeer stucture associated with the peer. Optionally create | ||
1357 | * one and insert it in the appropriate structures if the peer is not known yet. | ||
1358 | * | ||
1359 | * @param peer_id Full identity of the peer. | ||
1360 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
1361 | * #GNUNET_NO otherwise. | ||
1362 | * | ||
1363 | * @return Existing or newly created peer structure. | ||
1364 | * NULL if unknown and not requested @a create | ||
1365 | */ | ||
1366 | struct CadetPeer * | ||
1367 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create) | ||
1368 | { | ||
1369 | struct CadetPeer *peer; | ||
1370 | |||
1371 | peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id); | ||
1372 | if (NULL == peer) | ||
1373 | { | ||
1374 | peer = GNUNET_new (struct CadetPeer); | ||
1375 | if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers) | ||
1376 | { | ||
1377 | peer_delete_oldest (); | ||
1378 | } | ||
1379 | GNUNET_assert (GNUNET_OK == | ||
1380 | GNUNET_CONTAINER_multipeermap_put (peers, | ||
1381 | peer_id, | ||
1382 | peer, | ||
1383 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1384 | peer->id = GNUNET_PEER_intern (peer_id); | ||
1385 | } | ||
1386 | peer->last_contact = GNUNET_TIME_absolute_get (); | ||
1387 | |||
1388 | return peer; | ||
1389 | } | ||
1390 | |||
1391 | |||
1392 | /** | ||
1393 | * Retrieve the CadetPeer stucture associated with the | ||
1394 | * peer. Optionally create one and insert it in the appropriate | ||
1395 | * structures if the peer is not known yet. | ||
1396 | * | ||
1397 | * @param peer Short identity of the peer. | ||
1398 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
1399 | * #GNUNET_NO otherwise. | ||
1400 | * | ||
1401 | * @return Existing or newly created peer structure. | ||
1402 | * NULL if unknown and not requested @a create | ||
1403 | */ | ||
1404 | struct CadetPeer * | ||
1405 | GCP_get_short (const GNUNET_PEER_Id peer, int create) | ||
1406 | { | ||
1407 | return GCP_get (GNUNET_PEER_resolve2 (peer), create); | ||
1408 | } | 895 | } |
1409 | 896 | ||
1410 | 897 | ||
1411 | /** | 898 | /** |
1412 | * Function called once #GNUNET_TRANSPORT_offer_hello() is done. | 899 | * Prune down the number of paths to this peer, we seem to |
1413 | * Marks the operation as finished. | 900 | * have way too many. |
1414 | * | 901 | * |
1415 | * @param cls Closure (our `struct CadetPeer`). | 902 | * @param cls the `struct CadetPeer` to maintain the path heap for |
1416 | */ | 903 | */ |
1417 | static void | 904 | static void |
1418 | hello_offer_done (void *cls) | 905 | path_heap_cleanup (void *cls) |
1419 | { | 906 | { |
1420 | struct CadetPeer *peer = cls; | 907 | struct CadetPeer *cp = cls; |
908 | struct CadetPeerPath *root; | ||
1421 | 909 | ||
1422 | peer->hello_offer = NULL; | 910 | cp->heap_cleanup_task = NULL; |
911 | while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >= | ||
912 | 2 * DESIRED_CONNECTIONS_PER_TUNNEL) | ||
913 | { | ||
914 | /* Now we have way too many, drop least desirable UNLESS it is in use! | ||
915 | (Note that this intentionally keeps highly desireable, but currently | ||
916 | unused paths around in the hope that we might be able to switch, even | ||
917 | if the number of paths exceeds the threshold.) */ | ||
918 | root = GNUNET_CONTAINER_heap_peek (cp->path_heap); | ||
919 | GNUNET_assert (NULL != root); | ||
920 | if (NULL != | ||
921 | GCPP_get_connection (root, | ||
922 | cp, | ||
923 | GCPP_get_length (root) - 1)) | ||
924 | break; /* can't fix */ | ||
925 | /* Got plenty of paths to this destination, and this is a low-quality | ||
926 | one that we don't care about. Allow it to die. */ | ||
927 | GNUNET_assert (root == | ||
928 | GNUNET_CONTAINER_heap_remove_root (cp->path_heap)); | ||
929 | GCPP_release (root); | ||
930 | } | ||
1423 | } | 931 | } |
1424 | 932 | ||
1425 | 933 | ||
1426 | /** | 934 | /** |
1427 | * Try to establish a new connection to this peer (in its tunnel). | 935 | * Try adding a @a path to this @a peer. If the peer already |
1428 | * If the peer doesn't have any path to it yet, try to get one. | 936 | * has plenty of paths, return NULL. |
1429 | * If the peer already has some path, send a CREATE CONNECTION towards it. | ||
1430 | * | 937 | * |
1431 | * @param peer Peer to connect to. | 938 | * @param cp peer to which the @a path leads to |
939 | * @param path a path looking for an owner; may not be fully initialized yet! | ||
940 | * @param off offset of @a cp in @a path | ||
941 | * @param force force attaching the path | ||
942 | * @return NULL if this peer does not care to become a new owner, | ||
943 | * otherwise the node in the peer's path heap for the @a path. | ||
1432 | */ | 944 | */ |
1433 | void | 945 | struct GNUNET_CONTAINER_HeapNode * |
1434 | GCP_connect (struct CadetPeer *peer) | 946 | GCP_attach_path (struct CadetPeer *cp, |
947 | struct CadetPeerPath *path, | ||
948 | unsigned int off, | ||
949 | int force) | ||
1435 | { | 950 | { |
1436 | struct CadetTunnel *t; | 951 | GNUNET_CONTAINER_HeapCostType desirability; |
1437 | struct CadetPeerPath *path; | 952 | struct CadetPeerPath *root; |
1438 | struct CadetConnection *c; | 953 | GNUNET_CONTAINER_HeapCostType root_desirability; |
1439 | int rerun_search; | 954 | struct GNUNET_CONTAINER_HeapNode *hn; |
1440 | |||
1441 | GCC_check_connections (); | ||
1442 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1443 | "peer_connect towards %s\n", | ||
1444 | GCP_2s (peer)); | ||
1445 | /* If we have a current hello, try to connect using it. */ | ||
1446 | GCP_try_connect (peer); | ||
1447 | 955 | ||
1448 | t = peer->tunnel; | 956 | GNUNET_assert (off == GCPP_get_length (path) - 1); |
1449 | c = NULL; | 957 | GNUNET_assert (cp == GCPP_get_peer_at_offset (path, |
1450 | rerun_search = GNUNET_NO; | 958 | off)); |
1451 | 959 | if (NULL == cp->path_heap) | |
1452 | if (NULL != peer->path_head) | 960 | { |
961 | /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */ | ||
962 | GNUNET_assert (GNUNET_NO == force); | ||
963 | return NULL; | ||
964 | } | ||
965 | desirability = GCPP_get_desirability (path); | ||
966 | if (GNUNET_NO == force) | ||
967 | { | ||
968 | /* FIXME: desirability is not yet initialized; tricky! */ | ||
969 | if (GNUNET_NO == | ||
970 | GNUNET_CONTAINER_heap_peek2 (cp->path_heap, | ||
971 | (void **) &root, | ||
972 | &root_desirability)) | ||
1453 | { | 973 | { |
1454 | LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n"); | 974 | root = NULL; |
1455 | path = peer_get_best_path (peer); | 975 | root_desirability = 0; |
1456 | if (NULL != path) | ||
1457 | { | ||
1458 | char *s; | ||
1459 | |||
1460 | s = path_2s (path); | ||
1461 | LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s); | ||
1462 | GNUNET_free (s); | ||
1463 | |||
1464 | c = GCT_use_path (t, path); | ||
1465 | if (NULL == c) | ||
1466 | { | ||
1467 | /* This case can happen when the path includes a first hop that is | ||
1468 | * not yet known to be connected. | ||
1469 | * | ||
1470 | * This happens quite often during testing when running cadet | ||
1471 | * under valgrind: core connect notifications come very late | ||
1472 | * and the DHT result has already come and created a valid | ||
1473 | * path. In this case, the peer->connections | ||
1474 | * hashmaps will be NULL and tunnel_use_path will not be able | ||
1475 | * to create a connection from that path. | ||
1476 | * | ||
1477 | * Re-running the DHT GET should give core time to callback. | ||
1478 | * | ||
1479 | * GCT_use_path -> GCC_new -> register_neighbors takes care of | ||
1480 | * updating statistics about this issue. | ||
1481 | */ | ||
1482 | rerun_search = GNUNET_YES; | ||
1483 | } | ||
1484 | else | ||
1485 | { | ||
1486 | GCC_send_create (c); | ||
1487 | return; | ||
1488 | } | ||
1489 | } | ||
1490 | else | ||
1491 | { | ||
1492 | LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n"); | ||
1493 | } | ||
1494 | } | 976 | } |
1495 | 977 | ||
1496 | if (GNUNET_YES == rerun_search) | 978 | if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) && |
979 | (desirability < root_desirability) ) | ||
1497 | { | 980 | { |
1498 | struct GNUNET_TIME_Relative delay; | 981 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1499 | 982 | "Decided to not attach path %p to peer %s due to undesirability\n", | |
1500 | GCP_stop_search (peer); | 983 | GCPP_2s (path), |
1501 | delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100); | 984 | GCP_2s (cp)); |
1502 | peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay, | 985 | return NULL; |
1503 | &delayed_search, | ||
1504 | peer); | ||
1505 | GCC_check_connections (); | ||
1506 | return; | ||
1507 | } | 986 | } |
987 | } | ||
1508 | 988 | ||
1509 | if (GNUNET_NO == is_searching (peer)) | 989 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1510 | GCP_start_search (peer); | 990 | "Attaching path %s to peer %s (%s)\n", |
1511 | GCC_check_connections (); | 991 | GCPP_2s (path), |
1512 | } | 992 | GCP_2s (cp), |
1513 | 993 | (GNUNET_NO == force) ? "desirable" : "forced"); | |
1514 | |||
1515 | /** | ||
1516 | * Chech whether there is a direct (core level) connection to peer. | ||
1517 | * | ||
1518 | * @param peer Peer to check. | ||
1519 | * | ||
1520 | * @return #GNUNET_YES if there is a direct connection. | ||
1521 | */ | ||
1522 | int | ||
1523 | GCP_is_neighbor (const struct CadetPeer *peer) | ||
1524 | { | ||
1525 | struct CadetPeerPath *path; | ||
1526 | |||
1527 | if (NULL == peer->connections) | ||
1528 | return GNUNET_NO; | ||
1529 | 994 | ||
1530 | for (path = peer->path_head; NULL != path; path = path->next) | 995 | /* Yes, we'd like to add this path, add to our heap */ |
1531 | { | 996 | hn = GNUNET_CONTAINER_heap_insert (cp->path_heap, |
1532 | if (3 > path->length) | 997 | path, |
1533 | return GNUNET_YES; | 998 | desirability); |
1534 | } | ||
1535 | 999 | ||
1536 | /* Is not a neighbor but connections is not NULL, probably disconnecting */ | 1000 | /* Consider maybe dropping other paths because of the new one */ |
1537 | return GNUNET_NO; | 1001 | if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >= |
1002 | 2 * DESIRED_CONNECTIONS_PER_TUNNEL) && | ||
1003 | (NULL != cp->heap_cleanup_task) ) | ||
1004 | cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup, | ||
1005 | cp); | ||
1006 | return hn; | ||
1538 | } | 1007 | } |
1539 | 1008 | ||
1540 | 1009 | ||
1541 | /** | 1010 | /** |
1542 | * Create and initialize a new tunnel towards a peer, in case it has none. | 1011 | * This peer can no longer own @a path as the path |
1543 | * In case the peer already has a tunnel, nothing is done. | 1012 | * has been extended and a peer further down the line |
1013 | * is now the new owner. | ||
1544 | * | 1014 | * |
1545 | * Does not generate any traffic, just creates the local data structures. | 1015 | * @param cp old owner of the @a path |
1546 | * | 1016 | * @param path path where the ownership is lost |
1547 | * @param peer Peer towards which to create the tunnel. | 1017 | * @param hn note in @a cp's path heap that must be deleted |
1548 | */ | 1018 | */ |
1549 | void | 1019 | void |
1550 | GCP_add_tunnel (struct CadetPeer *peer) | 1020 | GCP_detach_path (struct CadetPeer *cp, |
1021 | struct CadetPeerPath *path, | ||
1022 | struct GNUNET_CONTAINER_HeapNode *hn) | ||
1551 | { | 1023 | { |
1552 | GCC_check_connections (); | 1024 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1553 | if (NULL != peer->tunnel) | 1025 | "Detatching path %s from peer %s\n", |
1554 | return; | 1026 | GCPP_2s (path), |
1555 | peer->tunnel = GCT_new (peer); | 1027 | GCP_2s (cp)); |
1556 | GCC_check_connections (); | 1028 | GNUNET_assert (path == |
1029 | GNUNET_CONTAINER_heap_remove_node (hn)); | ||
1557 | } | 1030 | } |
1558 | 1031 | ||
1559 | 1032 | ||
1560 | /** | 1033 | /** |
1561 | * Add a connection to a neighboring peer. | 1034 | * Add a @a connection to this @a cp. |
1562 | * | ||
1563 | * Store that the peer is the first hop of the connection in one | ||
1564 | * direction and that on peer disconnect the connection must be | ||
1565 | * notified and destroyed, for it will no longer be valid. | ||
1566 | * | 1035 | * |
1567 | * @param peer Peer to add connection to. | 1036 | * @param cp peer via which the @a connection goes |
1568 | * @param c Connection to add. | 1037 | * @param cc the connection to add |
1569 | * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor | ||
1570 | */ | 1038 | */ |
1571 | void | 1039 | void |
1572 | GCP_add_connection (struct CadetPeer *peer, | 1040 | GCP_add_connection (struct CadetPeer *cp, |
1573 | struct CadetConnection *c, | 1041 | struct CadetConnection *cc) |
1574 | int pred) | 1042 | { |
1575 | { | 1043 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1576 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1044 | "Adding connection %s to peer %s\n", |
1577 | "adding connection %s\n", | 1045 | GCC_2s (cc), |
1578 | GCC_2s (c)); | 1046 | GCP_2s (cp)); |
1579 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1047 | GNUNET_assert (GNUNET_OK == |
1580 | "to peer %s\n", | 1048 | GNUNET_CONTAINER_multishortmap_put (cp->connections, |
1581 | GCP_2s (peer)); | 1049 | &GCC_get_id (cc)->connection_of_tunnel, |
1582 | GNUNET_assert (NULL != peer->connections); | 1050 | cc, |
1583 | GNUNET_assert (GNUNET_OK == | 1051 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
1584 | GNUNET_CONTAINER_multishortmap_put (peer->connections, | 1052 | if (NULL != cp->destroy_task) |
1585 | &GCC_get_id (c)->connection_of_tunnel, | 1053 | { |
1586 | c, | 1054 | GNUNET_SCHEDULER_cancel (cp->destroy_task); |
1587 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 1055 | cp->destroy_task = NULL; |
1588 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1056 | } |
1589 | "Peer %s has now %u connections.\n", | ||
1590 | GCP_2s (peer), | ||
1591 | GNUNET_CONTAINER_multishortmap_size (peer->connections)); | ||
1592 | } | ||
1593 | |||
1594 | |||
1595 | /** | ||
1596 | * Add the path to the peer and update the path used to reach it in case this | ||
1597 | * is the shortest. | ||
1598 | * | ||
1599 | * @param peer Destination peer to add the path to. | ||
1600 | * @param path New path to add. Last peer must be @c peer. | ||
1601 | * Path will be either used of freed if already known. | ||
1602 | * @param trusted Do we trust that this path is real? | ||
1603 | * | ||
1604 | * @return path if path was taken, pointer to existing duplicate if exists | ||
1605 | * NULL on error. | ||
1606 | */ | ||
1607 | struct CadetPeerPath * | ||
1608 | GCP_add_path (struct CadetPeer *peer, | ||
1609 | struct CadetPeerPath *path, | ||
1610 | int trusted) | ||
1611 | { | ||
1612 | struct CadetPeerPath *aux; | ||
1613 | unsigned int l; | ||
1614 | unsigned int l2; | ||
1615 | |||
1616 | GCC_check_connections (); | ||
1617 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1618 | "adding path [%u] to peer %s\n", | ||
1619 | path->length, GCP_2s (peer)); | ||
1620 | |||
1621 | if (NULL == peer || NULL == path | ||
1622 | || path->peers[path->length - 1] != peer->id) | ||
1623 | { | ||
1624 | GNUNET_break (0); | ||
1625 | path_destroy (path); | ||
1626 | return NULL; | ||
1627 | } | ||
1628 | |||
1629 | for (l = 1; l < path->length; l++) | ||
1630 | { | ||
1631 | if (path->peers[l] == myid) | ||
1632 | { | ||
1633 | LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l); | ||
1634 | for (l2 = 0; l2 < path->length - l; l2++) | ||
1635 | { | ||
1636 | path->peers[l2] = path->peers[l + l2]; | ||
1637 | } | ||
1638 | path->length -= l; | ||
1639 | l = 1; | ||
1640 | path->peers = GNUNET_realloc (path->peers, | ||
1641 | path->length * sizeof (GNUNET_PEER_Id)); | ||
1642 | } | ||
1643 | } | ||
1644 | |||
1645 | LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length); | ||
1646 | |||
1647 | if (2 >= path->length && GNUNET_NO == trusted) | ||
1648 | { | ||
1649 | /* Only allow CORE to tell us about direct paths */ | ||
1650 | path_destroy (path); | ||
1651 | return NULL; | ||
1652 | } | ||
1653 | |||
1654 | l = path_get_length (path); | ||
1655 | if (0 == l) | ||
1656 | { | ||
1657 | path_destroy (path); | ||
1658 | return NULL; | ||
1659 | } | ||
1660 | |||
1661 | GNUNET_assert (peer->id == path->peers[path->length - 1]); | ||
1662 | for (aux = peer->path_head; aux != NULL; aux = aux->next) | ||
1663 | { | ||
1664 | l2 = path_get_length (aux); | ||
1665 | if (l2 > l) | ||
1666 | { | ||
1667 | LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n"); | ||
1668 | GNUNET_CONTAINER_DLL_insert_before (peer->path_head, | ||
1669 | peer->path_tail, aux, path); | ||
1670 | goto finish; | ||
1671 | } | ||
1672 | else | ||
1673 | { | ||
1674 | if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) | ||
1675 | { | ||
1676 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n"); | ||
1677 | path_destroy (path); | ||
1678 | return aux; | ||
1679 | } | ||
1680 | } | ||
1681 | } | ||
1682 | GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, | ||
1683 | peer->path_tail, | ||
1684 | path); | ||
1685 | LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n"); | ||
1686 | |||
1687 | finish: | ||
1688 | if (NULL != peer->tunnel | ||
1689 | && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel) | ||
1690 | && 2 < path->length) /* Direct paths are handled by core_connect */ | ||
1691 | { | ||
1692 | GCP_connect (peer); | ||
1693 | } | ||
1694 | GCC_check_connections (); | ||
1695 | return path; | ||
1696 | } | 1057 | } |
1697 | 1058 | ||
1698 | 1059 | ||
1699 | /** | 1060 | /** |
1700 | * Add the path to the origin peer and update the path used to reach it in case | 1061 | * Remove a @a connection that went via this @a cp. |
1701 | * this is the shortest. | ||
1702 | * The path is given in peer_info -> destination, therefore we turn the path | ||
1703 | * upside down first. | ||
1704 | * | ||
1705 | * @param peer Peer to add the path to, being the origin of the path. | ||
1706 | * @param path New path to add after being inversed. | ||
1707 | * Path will be either used or freed. | ||
1708 | * @param trusted Do we trust that this path is real? | ||
1709 | * | 1062 | * |
1710 | * @return path if path was taken, pointer to existing duplicate if exists | 1063 | * @param cp peer via which the @a connection went |
1711 | * NULL on error. | 1064 | * @param cc the connection to remove |
1712 | */ | 1065 | */ |
1713 | struct CadetPeerPath * | 1066 | void |
1714 | GCP_add_path_to_origin (struct CadetPeer *peer, | 1067 | GCP_remove_connection (struct CadetPeer *cp, |
1715 | struct CadetPeerPath *path, | 1068 | struct CadetConnection *cc) |
1716 | int trusted) | ||
1717 | { | 1069 | { |
1718 | if (NULL == path) | 1070 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1719 | return NULL; | 1071 | "Removing connection %s from peer %s\n", |
1720 | path_invert (path); | 1072 | GCC_2s (cc), |
1721 | return GCP_add_path (peer, path, trusted); | 1073 | GCP_2s (cp)); |
1074 | GNUNET_assert (GNUNET_YES == | ||
1075 | GNUNET_CONTAINER_multishortmap_remove (cp->connections, | ||
1076 | &GCC_get_id (cc)->connection_of_tunnel, | ||
1077 | cc)); | ||
1078 | consider_peer_destroy (cp); | ||
1722 | } | 1079 | } |
1723 | 1080 | ||
1724 | 1081 | ||
1725 | /** | 1082 | /** |
1726 | * Adds a path to the info of all the peers in the path | 1083 | * Retrieve the CadetPeer stucture associated with the |
1084 | * peer. Optionally create one and insert it in the appropriate | ||
1085 | * structures if the peer is not known yet. | ||
1727 | * | 1086 | * |
1728 | * @param p Path to process. | 1087 | * @param peer_id Full identity of the peer. |
1729 | * @param confirmed Whether we know if the path works or not. | 1088 | * @param create #GNUNET_YES if a new peer should be created if unknown. |
1089 | * #GNUNET_NO to return NULL if peer is unknown. | ||
1090 | * @return Existing or newly created peer structure. | ||
1091 | * NULL if unknown and not requested @a create | ||
1730 | */ | 1092 | */ |
1731 | void | 1093 | struct CadetPeer * |
1732 | GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed) | 1094 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, |
1095 | int create) | ||
1733 | { | 1096 | { |
1734 | unsigned int i; | 1097 | struct CadetPeer *cp; |
1735 | 1098 | ||
1736 | /* TODO: invert and add to origin */ | 1099 | cp = GNUNET_CONTAINER_multipeermap_get (peers, |
1737 | /* TODO: replace all "GCP_add_path" with this, make the other one static */ | 1100 | peer_id); |
1738 | GCC_check_connections (); | 1101 | if (NULL != cp) |
1739 | for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; | 1102 | return cp; |
1740 | for (i++; i < p->length; i++) | 1103 | if (GNUNET_NO == create) |
1741 | { | 1104 | return NULL; |
1742 | struct CadetPeer *peer; | 1105 | cp = GNUNET_new (struct CadetPeer); |
1743 | struct CadetPeerPath *copy; | 1106 | cp->pid = *peer_id; |
1744 | 1107 | cp->connections = GNUNET_CONTAINER_multishortmap_create (32, | |
1745 | peer = GCP_get_short (p->peers[i], GNUNET_YES); | 1108 | GNUNET_YES); |
1746 | copy = path_duplicate (p); | 1109 | cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); |
1747 | copy->length = i + 1; | 1110 | GNUNET_assert (GNUNET_YES == |
1748 | GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed); | 1111 | GNUNET_CONTAINER_multipeermap_put (peers, |
1749 | } | 1112 | &cp->pid, |
1750 | GCC_check_connections (); | 1113 | cp, |
1114 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1115 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1116 | "Creating peer %s\n", | ||
1117 | GCP_2s (cp)); | ||
1118 | return cp; | ||
1751 | } | 1119 | } |
1752 | 1120 | ||
1753 | 1121 | ||
1754 | /** | 1122 | /** |
1755 | * Remove any path to the peer that has the exact same peers as the one given. | 1123 | * Obtain the peer identity for a `struct CadetPeer`. |
1756 | * | 1124 | * |
1757 | * @param peer Peer to remove the path from. | 1125 | * @param cp our peer handle |
1758 | * @param path Path to remove. Is always destroyed . | 1126 | * @return the peer identity |
1759 | */ | 1127 | */ |
1760 | void | 1128 | const struct GNUNET_PeerIdentity * |
1761 | GCP_remove_path (struct CadetPeer *peer, | 1129 | GCP_get_id (struct CadetPeer *cp) |
1762 | struct CadetPeerPath *path) | ||
1763 | { | 1130 | { |
1764 | struct CadetPeerPath *iter; | 1131 | return &cp->pid; |
1765 | struct CadetPeerPath *next; | ||
1766 | |||
1767 | GCC_check_connections (); | ||
1768 | GNUNET_assert (myid == path->peers[0]); | ||
1769 | GNUNET_assert (peer->id == path->peers[path->length - 1]); | ||
1770 | |||
1771 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1772 | "Removing path %p (%u) from %s\n", | ||
1773 | path, path->length, GCP_2s (peer)); | ||
1774 | |||
1775 | for (iter = peer->path_head; NULL != iter; iter = next) | ||
1776 | { | ||
1777 | next = iter->next; | ||
1778 | if (0 == path_cmp (path, iter)) | ||
1779 | { | ||
1780 | GNUNET_CONTAINER_DLL_remove (peer->path_head, | ||
1781 | peer->path_tail, | ||
1782 | iter); | ||
1783 | if (iter != path) | ||
1784 | path_destroy (iter); | ||
1785 | } | ||
1786 | } | ||
1787 | path_destroy (path); | ||
1788 | GCC_check_connections (); | ||
1789 | } | 1132 | } |
1790 | 1133 | ||
1791 | 1134 | ||
1792 | /** | 1135 | /** |
1793 | * Check that we are aware of a connection from a neighboring peer. | 1136 | * Iterate over all known peers. |
1794 | * | 1137 | * |
1795 | * @param peer Peer to the connection is with | 1138 | * @param iter Iterator. |
1796 | * @param c Connection that should be in the map with this peer. | 1139 | * @param cls Closure for @c iter. |
1797 | */ | 1140 | */ |
1798 | void | 1141 | void |
1799 | GCP_check_connection (const struct CadetPeer *peer, | 1142 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, |
1800 | const struct CadetConnection *c) | 1143 | void *cls) |
1801 | { | 1144 | { |
1802 | GNUNET_assert (NULL != peer); | 1145 | GNUNET_CONTAINER_multipeermap_iterate (peers, |
1803 | GNUNET_assert (NULL != peer->connections); | 1146 | iter, |
1804 | return; // ???? | 1147 | cls); |
1805 | GNUNET_assert (GNUNET_YES == | ||
1806 | GNUNET_CONTAINER_multishortmap_contains_value (peer->connections, | ||
1807 | &GCC_get_id (c)->connection_of_tunnel, | ||
1808 | c)); | ||
1809 | } | 1148 | } |
1810 | 1149 | ||
1811 | 1150 | ||
1812 | /** | 1151 | /** |
1813 | * Remove a connection from a neighboring peer. | 1152 | * Count the number of known paths toward the peer. |
1814 | * | 1153 | * |
1815 | * @param peer Peer to remove connection from. | 1154 | * @param cp Peer to get path info. |
1816 | * @param c Connection to remove. | 1155 | * @return Number of known paths. |
1817 | */ | 1156 | */ |
1818 | void | 1157 | unsigned int |
1819 | GCP_remove_connection (struct CadetPeer *peer, | 1158 | GCP_count_paths (const struct CadetPeer *cp) |
1820 | const struct CadetConnection *c) | ||
1821 | { | 1159 | { |
1822 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1160 | return cp->num_paths; |
1823 | "Removing connection %s\n", | ||
1824 | GCC_2s (c)); | ||
1825 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1826 | "from peer %s\n", | ||
1827 | GCP_2s (peer)); | ||
1828 | if ( (NULL == peer) || | ||
1829 | (NULL == peer->connections) ) | ||
1830 | return; | ||
1831 | GNUNET_assert (GNUNET_YES == | ||
1832 | GNUNET_CONTAINER_multishortmap_remove (peer->connections, | ||
1833 | &GCC_get_id (c)->connection_of_tunnel, | ||
1834 | c)); | ||
1835 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1836 | "Peer %s remains with %u connections.\n", | ||
1837 | GCP_2s (peer), | ||
1838 | GNUNET_CONTAINER_multishortmap_size (peer->connections)); | ||
1839 | } | 1161 | } |
1840 | 1162 | ||
1841 | 1163 | ||
1842 | /** | 1164 | /** |
1843 | * Start the DHT search for new paths towards the peer: we don't have | 1165 | * Iterate over the paths to a peer. |
1844 | * enough good connections. | ||
1845 | * | 1166 | * |
1846 | * @param peer Destination peer. | 1167 | * @param cp Peer to get path info. |
1168 | * @param callback Function to call for every path. | ||
1169 | * @param callback_cls Closure for @a callback. | ||
1170 | * @return Number of iterated paths. | ||
1847 | */ | 1171 | */ |
1848 | void | 1172 | unsigned int |
1849 | GCP_start_search (struct CadetPeer *peer) | 1173 | GCP_iterate_paths (struct CadetPeer *cp, |
1174 | GCP_PathIterator callback, | ||
1175 | void *callback_cls) | ||
1850 | { | 1176 | { |
1851 | const struct GNUNET_PeerIdentity *id; | 1177 | unsigned int ret = 0; |
1852 | struct CadetTunnel *t = peer->tunnel; | ||
1853 | |||
1854 | GCC_check_connections (); | ||
1855 | if (NULL != peer->search_h) | ||
1856 | { | ||
1857 | GNUNET_break (0); | ||
1858 | return; | ||
1859 | } | ||
1860 | |||
1861 | if (NULL != peer->search_delayed) | ||
1862 | GCP_stop_search (peer); | ||
1863 | |||
1864 | id = GNUNET_PEER_resolve2 (peer->id); | ||
1865 | peer->search_h = GCD_search (id, &search_handler, peer); | ||
1866 | |||
1867 | if (NULL == t) | ||
1868 | { | ||
1869 | /* Why would we search for a peer with no tunnel towards it? */ | ||
1870 | GNUNET_break (0); | ||
1871 | return; | ||
1872 | } | ||
1873 | |||
1874 | if (CADET_TUNNEL_NEW == GCT_get_cstate (t) | ||
1875 | || 0 == GCT_count_any_connections (t)) | ||
1876 | { | ||
1877 | GCT_change_cstate (t, CADET_TUNNEL_SEARCHING); | ||
1878 | } | ||
1879 | GCC_check_connections (); | ||
1880 | } | ||
1881 | 1178 | ||
1179 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1180 | "Iterating over paths to peer %s%s\n", | ||
1181 | GCP_2s (cp), | ||
1182 | (NULL == cp->core_mq) ? "" : " including direct link"); | ||
1183 | if (NULL != cp->core_mq) | ||
1184 | { | ||
1185 | struct CadetPeerPath *path; | ||
1882 | 1186 | ||
1883 | /** | 1187 | path = GCPP_get_path_from_route (1, |
1884 | * Stop the DHT search for new paths towards the peer: we already have | 1188 | &cp->pid); |
1885 | * enough good connections. | 1189 | ret++; |
1886 | * | 1190 | if (GNUNET_NO == |
1887 | * @param peer Destination peer. | 1191 | callback (callback_cls, |
1888 | */ | 1192 | path, |
1889 | void | 1193 | 0)) |
1890 | GCP_stop_search (struct CadetPeer *peer) | 1194 | return ret; |
1891 | { | 1195 | } |
1892 | GCC_check_connections (); | 1196 | for (unsigned int i=0;i<cp->path_dll_length;i++) |
1893 | if (NULL != peer->search_h) | 1197 | { |
1894 | { | 1198 | for (struct CadetPeerPathEntry *pe = cp->path_heads[i]; |
1895 | GCD_search_stop (peer->search_h); | 1199 | NULL != pe; |
1896 | peer->search_h = NULL; | 1200 | pe = pe->next) |
1897 | } | ||
1898 | if (NULL != peer->search_delayed) | ||
1899 | { | 1201 | { |
1900 | GNUNET_SCHEDULER_cancel (peer->search_delayed); | 1202 | ret++; |
1901 | peer->search_delayed = NULL; | 1203 | if (GNUNET_NO == |
1204 | callback (callback_cls, | ||
1205 | pe->path, | ||
1206 | i)) | ||
1207 | return ret; | ||
1902 | } | 1208 | } |
1903 | GCC_check_connections (); | 1209 | } |
1904 | } | 1210 | return ret; |
1905 | |||
1906 | |||
1907 | /** | ||
1908 | * Get the Full ID of a peer. | ||
1909 | * | ||
1910 | * @param peer Peer to get from. | ||
1911 | * | ||
1912 | * @return Full ID of peer. | ||
1913 | */ | ||
1914 | const struct GNUNET_PeerIdentity * | ||
1915 | GCP_get_id (const struct CadetPeer *peer) | ||
1916 | { | ||
1917 | return GNUNET_PEER_resolve2 (peer->id); | ||
1918 | } | 1211 | } |
1919 | 1212 | ||
1920 | 1213 | ||
1921 | /** | 1214 | /** |
1922 | * Get the Short ID of a peer. | 1215 | * Iterate over the paths to @a cp where |
1923 | * | 1216 | * @a cp is at distance @a dist from us. |
1924 | * @param peer Peer to get from. | ||
1925 | * | 1217 | * |
1926 | * @return Short ID of peer. | 1218 | * @param cp Peer to get path info. |
1219 | * @param dist desired distance of @a cp to us on the path | ||
1220 | * @param callback Function to call for every path. | ||
1221 | * @param callback_cls Closure for @a callback. | ||
1222 | * @return Number of iterated paths. | ||
1927 | */ | 1223 | */ |
1928 | GNUNET_PEER_Id | 1224 | unsigned int |
1929 | GCP_get_short_id (const struct CadetPeer *peer) | 1225 | GCP_iterate_paths_at (struct CadetPeer *cp, |
1226 | unsigned int dist, | ||
1227 | GCP_PathIterator callback, | ||
1228 | void *callback_cls) | ||
1930 | { | 1229 | { |
1931 | return peer->id; | 1230 | unsigned int ret = 0; |
1932 | } | ||
1933 | |||
1934 | 1231 | ||
1935 | /** | 1232 | if (dist >= cp->path_dll_length) |
1936 | * Set tunnel. | 1233 | { |
1937 | * | 1234 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1938 | * If tunnel is NULL and there was a search active, stop it, as it's useless. | 1235 | "Asked to look for paths at distance %u, but maximum for me is < %u\n", |
1939 | * | 1236 | dist, |
1940 | * @param peer Peer. | 1237 | cp->path_dll_length); |
1941 | * @param t Tunnel. | 1238 | return 0; |
1942 | */ | 1239 | } |
1943 | void | 1240 | for (struct CadetPeerPathEntry *pe = cp->path_heads[dist]; |
1944 | GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t) | 1241 | NULL != pe; |
1945 | { | 1242 | pe = pe->next) |
1946 | peer->tunnel = t; | 1243 | { |
1947 | if (NULL == t && GNUNET_YES == is_searching (peer)) | 1244 | if (GNUNET_NO == |
1948 | { | 1245 | callback (callback_cls, |
1949 | GCP_stop_search (peer); | 1246 | pe->path, |
1950 | } | 1247 | dist)) |
1248 | return ret; | ||
1249 | ret++; | ||
1250 | } | ||
1251 | return ret; | ||
1951 | } | 1252 | } |
1952 | 1253 | ||
1953 | 1254 | ||
1954 | /** | 1255 | /** |
1955 | * Get the tunnel towards a peer. | 1256 | * Get the tunnel towards a peer. |
1956 | * | 1257 | * |
1957 | * @param peer Peer to get from. | 1258 | * @param cp Peer to get from. |
1958 | * | 1259 | * @param create #GNUNET_YES to create a tunnel if we do not have one |
1959 | * @return Tunnel towards peer. | 1260 | * @return Tunnel towards peer. |
1960 | */ | 1261 | */ |
1961 | struct CadetTunnel * | 1262 | struct CadetTunnel * |
1962 | GCP_get_tunnel (const struct CadetPeer *peer) | 1263 | GCP_get_tunnel (struct CadetPeer *cp, |
1264 | int create) | ||
1963 | { | 1265 | { |
1964 | if (NULL == peer) | 1266 | if (NULL == cp) |
1965 | return NULL; | 1267 | return NULL; |
1966 | return peer->tunnel; | 1268 | if ( (NULL != cp->t) || |
1269 | (GNUNET_NO == create) ) | ||
1270 | return cp->t; | ||
1271 | cp->t = GCT_create_tunnel (cp); | ||
1272 | consider_peer_activate (cp); | ||
1273 | return cp->t; | ||
1967 | } | 1274 | } |
1968 | 1275 | ||
1969 | 1276 | ||
1970 | /** | 1277 | /** |
1971 | * Set the hello message. | 1278 | * Hello offer was passed to the transport service. Mark it |
1279 | * as done. | ||
1972 | * | 1280 | * |
1973 | * @param peer Peer whose message to set. | 1281 | * @param cls the `struct CadetPeer` where the offer completed |
1974 | * @param hello Hello message. | ||
1975 | */ | 1282 | */ |
1976 | void | 1283 | static void |
1977 | GCP_set_hello (struct CadetPeer *peer, | 1284 | hello_offer_done (void *cls) |
1978 | const struct GNUNET_HELLO_Message *hello) | ||
1979 | { | 1285 | { |
1980 | struct GNUNET_HELLO_Message *old; | 1286 | struct CadetPeer *cp = cls; |
1981 | size_t size; | ||
1982 | 1287 | ||
1983 | GCC_check_connections (); | 1288 | cp->hello_offer = NULL; |
1984 | LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer)); | ||
1985 | if (NULL == hello) | ||
1986 | return; | ||
1987 | |||
1988 | old = GCP_get_hello (peer); | ||
1989 | if (NULL == old) | ||
1990 | { | ||
1991 | size = GNUNET_HELLO_size (hello); | ||
1992 | peer->hello = GNUNET_malloc (size); | ||
1993 | GNUNET_memcpy (peer->hello, hello, size); | ||
1994 | } | ||
1995 | else | ||
1996 | { | ||
1997 | peer->hello = GNUNET_HELLO_merge (old, hello); | ||
1998 | GNUNET_free (old); | ||
1999 | } | ||
2000 | GCC_check_connections (); | ||
2001 | } | 1289 | } |
2002 | 1290 | ||
2003 | 1291 | ||
2004 | /** | 1292 | /** |
2005 | * Get the hello message. | 1293 | * We got a HELLO for a @a peer, remember it, and possibly |
2006 | * | 1294 | * trigger adequate actions (like trying to connect). |
2007 | * @param peer Peer whose message to get. | ||
2008 | * | 1295 | * |
2009 | * @return Hello message. | 1296 | * @param cp the peer we got a HELLO for |
1297 | * @param hello the HELLO to remember | ||
2010 | */ | 1298 | */ |
2011 | struct GNUNET_HELLO_Message * | 1299 | void |
2012 | GCP_get_hello (struct CadetPeer *peer) | 1300 | GCP_set_hello (struct CadetPeer *cp, |
1301 | const struct GNUNET_HELLO_Message *hello) | ||
2013 | { | 1302 | { |
2014 | struct GNUNET_TIME_Absolute expiration; | 1303 | struct GNUNET_HELLO_Message *mrg; |
2015 | struct GNUNET_TIME_Relative remaining; | ||
2016 | |||
2017 | if (NULL == peer->hello) | ||
2018 | return NULL; | ||
2019 | 1304 | ||
2020 | expiration = GNUNET_HELLO_get_last_expiration (peer->hello); | 1305 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2021 | remaining = GNUNET_TIME_absolute_get_remaining (expiration); | 1306 | "Got %u byte HELLO for peer %s\n", |
2022 | if (0 == remaining.rel_value_us) | 1307 | (unsigned int) GNUNET_HELLO_size (hello), |
2023 | { | 1308 | GCP_2s (cp)); |
2024 | LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n", | 1309 | if (NULL != cp->hello_offer) |
2025 | GNUNET_STRINGS_absolute_time_to_string (expiration)); | 1310 | { |
2026 | GNUNET_free (peer->hello); | 1311 | GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer); |
2027 | peer->hello = NULL; | 1312 | cp->hello_offer = NULL; |
2028 | } | 1313 | } |
2029 | return peer->hello; | 1314 | if (NULL != cp->hello) |
1315 | { | ||
1316 | mrg = GNUNET_HELLO_merge (hello, | ||
1317 | cp->hello); | ||
1318 | GNUNET_free (cp->hello); | ||
1319 | cp->hello = mrg; | ||
1320 | } | ||
1321 | else | ||
1322 | { | ||
1323 | cp->hello = GNUNET_memdup (hello, | ||
1324 | GNUNET_HELLO_size (hello)); | ||
1325 | } | ||
1326 | cp->hello_offer | ||
1327 | = GNUNET_TRANSPORT_offer_hello (cfg, | ||
1328 | GNUNET_HELLO_get_header (cp->hello) , | ||
1329 | &hello_offer_done, | ||
1330 | cp); | ||
1331 | /* New HELLO means cp's destruction time may change... */ | ||
1332 | consider_peer_destroy (cp); | ||
2030 | } | 1333 | } |
2031 | 1334 | ||
2032 | 1335 | ||
2033 | /** | 1336 | /** |
2034 | * Try to connect to a peer on TRANSPORT level. | 1337 | * The tunnel to the given peer no longer exists, remove it from our |
1338 | * data structures, and possibly clean up the peer itself. | ||
2035 | * | 1339 | * |
2036 | * @param peer Peer to whom to connect. | 1340 | * @param cp the peer affected |
1341 | * @param t the dead tunnel | ||
2037 | */ | 1342 | */ |
2038 | void | 1343 | void |
2039 | GCP_try_connect (struct CadetPeer *peer) | 1344 | GCP_drop_tunnel (struct CadetPeer *cp, |
1345 | struct CadetTunnel *t) | ||
2040 | { | 1346 | { |
2041 | struct GNUNET_HELLO_Message *hello; | 1347 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2042 | struct GNUNET_MessageHeader *mh; | 1348 | "Dropping tunnel %s to peer %s\n", |
2043 | 1349 | GCT_2s (t), | |
2044 | if (GNUNET_YES != | 1350 | GCP_2s (cp)); |
2045 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | 1351 | GNUNET_assert (cp->t == t); |
2046 | "CADET", | 1352 | cp->t = NULL; |
2047 | "DISABLE_TRY_CONNECT")) | 1353 | consider_peer_destroy (cp); |
2048 | return; | ||
2049 | GCC_check_connections (); | ||
2050 | if (GNUNET_YES == GCP_is_neighbor (peer)) | ||
2051 | return; | ||
2052 | hello = GCP_get_hello (peer); | ||
2053 | if (NULL == hello) | ||
2054 | return; | ||
2055 | |||
2056 | mh = GNUNET_HELLO_get_header (hello); | ||
2057 | if (NULL != peer->hello_offer) | ||
2058 | { | ||
2059 | GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer); | ||
2060 | peer->hello_offer = NULL; | ||
2061 | } | ||
2062 | peer->hello_offer = GNUNET_TRANSPORT_offer_hello (cfg, | ||
2063 | mh, | ||
2064 | &hello_offer_done, | ||
2065 | peer); | ||
2066 | if (NULL == peer->connectivity_suggestion) | ||
2067 | peer->connectivity_suggestion | ||
2068 | = GNUNET_ATS_connectivity_suggest (ats_ch, | ||
2069 | GCP_get_id (peer), | ||
2070 | 1); /* strength */ | ||
2071 | GCC_check_connections (); | ||
2072 | } | 1354 | } |
2073 | 1355 | ||
2074 | 1356 | ||
2075 | /** | 1357 | /** |
2076 | * Notify a peer that a link between two other peers is broken. If any path | 1358 | * Test if @a cp has a core-level connection |
2077 | * used that link, eliminate it. | ||
2078 | * | 1359 | * |
2079 | * @param peer Peer affected by the change. | 1360 | * @param cp peer to test |
2080 | * @param peer1 Peer whose link is broken. | 1361 | * @return #GNUNET_YES if @a cp has a core-level connection |
2081 | * @param peer2 Peer whose link is broken. | ||
2082 | */ | 1362 | */ |
2083 | void | 1363 | int |
2084 | GCP_notify_broken_link (struct CadetPeer *peer, | 1364 | GCP_has_core_connection (struct CadetPeer *cp) |
2085 | const struct GNUNET_PeerIdentity *peer1, | ||
2086 | const struct GNUNET_PeerIdentity *peer2) | ||
2087 | { | 1365 | { |
2088 | struct CadetPeerPath *iter; | 1366 | return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO; |
2089 | struct CadetPeerPath *next; | ||
2090 | unsigned int i; | ||
2091 | GNUNET_PEER_Id p1; | ||
2092 | GNUNET_PEER_Id p2; | ||
2093 | |||
2094 | GCC_check_connections (); | ||
2095 | p1 = GNUNET_PEER_search (peer1); | ||
2096 | p2 = GNUNET_PEER_search (peer2); | ||
2097 | |||
2098 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2); | ||
2099 | if (0 == p1 || 0 == p2) | ||
2100 | { | ||
2101 | /* We don't even know them */ | ||
2102 | return; | ||
2103 | } | ||
2104 | |||
2105 | for (iter = peer->path_head; NULL != iter; iter = next) | ||
2106 | { | ||
2107 | next = iter->next; | ||
2108 | for (i = 0; i < iter->length - 1; i++) | ||
2109 | { | ||
2110 | if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2) | ||
2111 | || (iter->peers[i] == p2 && iter->peers[i + 1] == p1)) | ||
2112 | { | ||
2113 | char *s; | ||
2114 | |||
2115 | s = path_2s (iter); | ||
2116 | LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s); | ||
2117 | GNUNET_free (s); | ||
2118 | |||
2119 | path_invalidate (iter); | ||
2120 | } | ||
2121 | } | ||
2122 | } | ||
2123 | GCC_check_connections (); | ||
2124 | } | 1367 | } |
2125 | 1368 | ||
2126 | 1369 | ||
2127 | /** | 1370 | /** |
2128 | * Count the number of known paths toward the peer. | 1371 | * Start message queue change notifications. |
2129 | * | ||
2130 | * @param peer Peer to get path info. | ||
2131 | * | 1372 | * |
2132 | * @return Number of known paths. | 1373 | * @param cp peer to notify for |
1374 | * @param cb function to call if mq becomes available or unavailable | ||
1375 | * @param cb_cls closure for @a cb | ||
1376 | * @return handle to cancel request | ||
2133 | */ | 1377 | */ |
2134 | unsigned int | 1378 | struct GCP_MessageQueueManager * |
2135 | GCP_count_paths (const struct CadetPeer *peer) | 1379 | GCP_request_mq (struct CadetPeer *cp, |
1380 | GCP_MessageQueueNotificationCallback cb, | ||
1381 | void *cb_cls) | ||
2136 | { | 1382 | { |
2137 | struct CadetPeerPath *iter; | 1383 | struct GCP_MessageQueueManager *mqm; |
2138 | unsigned int i; | ||
2139 | 1384 | ||
2140 | for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) | 1385 | mqm = GNUNET_new (struct GCP_MessageQueueManager); |
2141 | i++; | 1386 | mqm->cb = cb; |
2142 | 1387 | mqm->cb_cls = cb_cls; | |
2143 | return i; | 1388 | mqm->cp = cp; |
1389 | GNUNET_CONTAINER_DLL_insert (cp->mqm_head, | ||
1390 | cp->mqm_tail, | ||
1391 | mqm); | ||
1392 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1393 | "Creating MQM %p for peer %s\n", | ||
1394 | mqm, | ||
1395 | GCP_2s (cp)); | ||
1396 | if (NULL != cp->core_mq) | ||
1397 | cb (cb_cls, | ||
1398 | GNUNET_YES); | ||
1399 | return mqm; | ||
2144 | } | 1400 | } |
2145 | 1401 | ||
2146 | 1402 | ||
2147 | /** | 1403 | /** |
2148 | * Iterate over the paths to a peer. | 1404 | * Stops message queue change notifications. |
2149 | * | 1405 | * |
2150 | * @param peer Peer to get path info. | 1406 | * @param mqm handle matching request to cancel |
2151 | * @param callback Function to call for every path. | 1407 | * @param last_env final message to transmit, or NULL |
2152 | * @param cls Closure for @a callback. | ||
2153 | * | ||
2154 | * @return Number of iterated paths. | ||
2155 | */ | 1408 | */ |
2156 | unsigned int | 1409 | void |
2157 | GCP_iterate_paths (struct CadetPeer *peer, | 1410 | GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm, |
2158 | GCP_path_iterator callback, | 1411 | struct GNUNET_MQ_Envelope *last_env) |
2159 | void *cls) | 1412 | { |
2160 | { | 1413 | struct CadetPeer *cp = mqm->cp; |
2161 | struct CadetPeerPath *iter; | 1414 | |
2162 | unsigned int i; | 1415 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2163 | 1416 | "Destroying MQM %p for peer %s%s\n", | |
2164 | for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) | 1417 | mqm, |
1418 | GCP_2s (cp), | ||
1419 | (NULL == last_env) ? "" : " with last ditch transmission"); | ||
1420 | if (NULL != mqm->env) | ||
1421 | GNUNET_MQ_discard (mqm->env); | ||
1422 | if (NULL != last_env) | ||
1423 | { | ||
1424 | if (NULL != cp->core_mq) | ||
2165 | { | 1425 | { |
2166 | i++; | 1426 | GNUNET_MQ_notify_sent (last_env, |
2167 | if (GNUNET_YES != callback (cls, peer, iter)) | 1427 | &mqm_send_done, |
2168 | break; | 1428 | cp); |
1429 | GNUNET_MQ_send (cp->core_mq, | ||
1430 | last_env); | ||
2169 | } | 1431 | } |
2170 | 1432 | else | |
2171 | return i; | 1433 | { |
1434 | GNUNET_MQ_discard (last_env); | ||
1435 | } | ||
1436 | } | ||
1437 | if (cp->mqm_ready_ptr == mqm) | ||
1438 | cp->mqm_ready_ptr = mqm->next; | ||
1439 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
1440 | cp->mqm_tail, | ||
1441 | mqm); | ||
1442 | GNUNET_free (mqm); | ||
2172 | } | 1443 | } |
2173 | 1444 | ||
2174 | 1445 | ||
2175 | /** | 1446 | /** |
2176 | * Iterate all known peers. | 1447 | * Send the message in @a env to @a cp, overriding queueing logic. |
1448 | * This function should only be used to send error messages outside | ||
1449 | * of flow and congestion control, similar to ICMP. Note that | ||
1450 | * the envelope may be silently discarded as well. | ||
2177 | * | 1451 | * |
2178 | * @param iter Iterator. | 1452 | * @param cp peer to send the message to |
2179 | * @param cls Closure for @c iter. | 1453 | * @param env envelope with the message to send |
2180 | */ | 1454 | */ |
2181 | void | 1455 | void |
2182 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, | 1456 | GCP_send_ooo (struct CadetPeer *cp, |
2183 | void *cls) | 1457 | struct GNUNET_MQ_Envelope *env) |
2184 | { | 1458 | { |
2185 | GCC_check_connections (); | 1459 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2186 | GNUNET_CONTAINER_multipeermap_iterate (peers, | 1460 | "Sending message to %s out of management\n", |
2187 | iter, | 1461 | GCP_2s (cp)); |
2188 | cls); | 1462 | if (NULL == cp->core_mq) |
2189 | GCC_check_connections (); | 1463 | { |
1464 | GNUNET_MQ_discard (env); | ||
1465 | return; | ||
1466 | } | ||
1467 | GNUNET_MQ_notify_sent (env, | ||
1468 | &mqm_send_done, | ||
1469 | cp); | ||
1470 | GNUNET_MQ_send (cp->core_mq, | ||
1471 | env); | ||
2190 | } | 1472 | } |
2191 | 1473 | ||
2192 | 1474 | ||
2193 | /** | ||
2194 | * Get the static string for a peer ID. | ||
2195 | * | ||
2196 | * @param peer Peer. | ||
2197 | * | ||
2198 | * @return Static string for it's ID. | ||
2199 | */ | ||
2200 | const char * | ||
2201 | GCP_2s (const struct CadetPeer *peer) | ||
2202 | { | ||
2203 | if (NULL == peer) | ||
2204 | return "(NULL)"; | ||
2205 | return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id)); | ||
2206 | } | ||
2207 | 1475 | ||
2208 | 1476 | ||
2209 | /* end of gnunet-service-cadet_peer.c */ | 1477 | /* end of gnunet-service-cadet-new_peer.c */ |
diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h index 1e206e10f..a2a6c6a92 100644 --- a/src/cadet/gnunet-service-cadet_peer.h +++ b/src/cadet/gnunet-service-cadet_peer.h | |||
@@ -1,6 +1,7 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | This file is part of GNUnet. | 3 | This file is part of GNUnet. |
3 | Copyright (C) 2013 GNUnet e.V. | 4 | Copyright (C) 2001-2017 GNUnet e.V. |
4 | 5 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 6 | 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 | it under the terms of the GNU General Public License as published |
@@ -19,465 +20,375 @@ | |||
19 | */ | 20 | */ |
20 | 21 | ||
21 | /** | 22 | /** |
22 | * @file cadet/gnunet-service-cadet_peer.h | 23 | * @file cadet/gnunet-service-cadet-new_peer.h |
23 | * @brief cadet service; dealing with remote peers | 24 | * @brief Information we track per peer. |
24 | * @author Bartlomiej Polot | 25 | * @author Bartlomiej Polot |
25 | * | 26 | * @author Christian Grothoff |
26 | * All functions in this file should use the prefix GMP (Gnunet Cadet Peer) | ||
27 | */ | 27 | */ |
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_PEER_H | 28 | #ifndef GNUNET_SERVICE_CADET_PEER_H |
30 | #define GNUNET_SERVICE_CADET_PEER_H | 29 | #define GNUNET_SERVICE_CADET_PEER_H |
31 | 30 | ||
32 | #ifdef __cplusplus | 31 | #include "gnunet-service-cadet.h" |
33 | extern "C" | 32 | #include "gnunet_hello_lib.h" |
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "platform.h" | ||
41 | #include "gnunet_util_lib.h" | ||
42 | #include "cadet_path.h" | ||
43 | |||
44 | /** | ||
45 | * Struct containing all information regarding a given peer | ||
46 | */ | ||
47 | struct CadetPeer; | ||
48 | 33 | ||
49 | /** | ||
50 | * Handle to queued messages on a peer level. | ||
51 | */ | ||
52 | struct CadetPeerQueue; | ||
53 | |||
54 | #include "gnunet-service-cadet_connection.h" | ||
55 | |||
56 | |||
57 | /** | ||
58 | * Callback called when a queued message is sent. | ||
59 | * | ||
60 | * @param cls Closure. | ||
61 | * @param c Connection this message was on. | ||
62 | * @param fwd Was this a FWD going message? | ||
63 | * @param sent Was it really sent? (Could have been canceled) | ||
64 | * @param type Type of message sent. | ||
65 | * @param payload_type Type of payload, if applicable. | ||
66 | * @param pid Message ID, or 0 if not applicable (create, destroy, etc). | ||
67 | * @param size Size of the message. | ||
68 | * @param wait Time spent waiting for core (only the time for THIS message) | ||
69 | */ | ||
70 | typedef void | ||
71 | (*GCP_sent) (void *cls, | ||
72 | struct CadetConnection *c, | ||
73 | int fwd, | ||
74 | int sent, | ||
75 | uint16_t type, | ||
76 | uint16_t payload_type, | ||
77 | struct CadetEncryptedMessageIdentifier pid, | ||
78 | size_t size, | ||
79 | struct GNUNET_TIME_Relative wait); | ||
80 | 34 | ||
81 | /** | 35 | /** |
82 | * Peer path iterator. | 36 | * Get the static string for a peer ID. |
83 | * | 37 | * |
84 | * @param cls Closure. | 38 | * @param peer Peer. |
85 | * @param peer Peer this path is towards. | ||
86 | * @param path Path itself | ||
87 | * @return #GNUNET_YES if should keep iterating. | ||
88 | * #GNUNET_NO otherwise. | ||
89 | */ | ||
90 | typedef int | ||
91 | (*GCP_path_iterator) (void *cls, | ||
92 | struct CadetPeer *peer, | ||
93 | struct CadetPeerPath *path); | ||
94 | |||
95 | |||
96 | /******************************************************************************/ | ||
97 | /******************************** API ***********************************/ | ||
98 | /******************************************************************************/ | ||
99 | |||
100 | /** | ||
101 | * Initialize peer subsystem. | ||
102 | * | 39 | * |
103 | * @param c Configuration. | 40 | * @return Static string for it's ID. |
104 | */ | ||
105 | void | ||
106 | GCP_init (const struct GNUNET_CONFIGURATION_Handle *c); | ||
107 | |||
108 | /** | ||
109 | * Shut down the peer subsystem. | ||
110 | */ | 41 | */ |
111 | void | 42 | const char * |
112 | GCP_shutdown (void); | 43 | GCP_2s (const struct CadetPeer *peer); |
113 | 44 | ||
114 | 45 | ||
115 | /** | 46 | /** |
116 | * Retrieve the CadetPeer stucture associated with the peer. Optionally create | 47 | * Retrieve the CadetPeer stucture associated with the |
117 | * one and insert it in the appropriate structures if the peer is not known yet. | 48 | * peer. Optionally create one and insert it in the appropriate |
49 | * structures if the peer is not known yet. | ||
118 | * | 50 | * |
119 | * @param peer_id Full identity of the peer. | 51 | * @param peer_id Full identity of the peer. |
120 | * @param create #GNUNET_YES if a new peer should be created if unknown. | 52 | * @param create #GNUNET_YES if a new peer should be created if unknown. |
121 | * #GNUNET_NO otherwise. | 53 | * #GNUNET_NO to return NULL if peer is unknown. |
122 | * | ||
123 | * @return Existing or newly created peer structure. | 54 | * @return Existing or newly created peer structure. |
124 | * NULL if unknown and not requested @a create | 55 | * NULL if unknown and not requested @a create |
125 | */ | 56 | */ |
126 | struct CadetPeer * | 57 | struct CadetPeer * |
127 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create); | 58 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, |
59 | int create); | ||
128 | 60 | ||
129 | 61 | ||
130 | /** | 62 | /** |
131 | * Retrieve the CadetPeer stucture associated with the peer. Optionally create | 63 | * Calculate how desirable a path is for @a cp if |
132 | * one and insert it in the appropriate structures if the peer is not known yet. | 64 | * @a cp is at offset @a off in the path. |
133 | * | ||
134 | * @param peer Short identity of the peer. | ||
135 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
136 | * #GNUNET_NO otherwise. | ||
137 | * | 65 | * |
138 | * @return Existing or newly created peer structure. | 66 | * @param cp a peer reachable via a path |
139 | * NULL if unknown and not requested @a create | 67 | * @param off offset of @a cp in a path |
68 | * @return score how useful a path is to reach @a cp, | ||
69 | * positive scores mean path is more desirable | ||
140 | */ | 70 | */ |
141 | struct CadetPeer * | 71 | double |
142 | GCP_get_short (const GNUNET_PEER_Id peer, int create); | 72 | GCP_get_desirability_of_path (struct CadetPeer *cp, |
143 | 73 | unsigned int off); | |
144 | 74 | ||
145 | /** | ||
146 | * Try to establish a new connection to this peer (in its tunnel). | ||
147 | * If the peer doesn't have any path to it yet, try to get one. | ||
148 | * If the peer already has some path, send a CREATE CONNECTION towards it. | ||
149 | * | ||
150 | * @param peer Peer to connect to. | ||
151 | */ | ||
152 | void | ||
153 | GCP_connect (struct CadetPeer *peer); | ||
154 | 75 | ||
155 | /** | 76 | /** |
156 | * @brief Send a message to another peer (using CORE). | 77 | * Obtain the peer identity for a `struct CadetPeer`. |
157 | * | 78 | * |
158 | * @param peer Peer towards which to queue the message. | 79 | * @param cp our peer handle |
159 | * @param message Message to send. | 80 | * @return the peer identity |
160 | * @param payload_type Type of the message's payload, for debug messages. | ||
161 | * 0 if the message is a retransmission (unknown payload). | ||
162 | * UINT16_MAX if the message does not have payload. | ||
163 | * @param payload_id ID of the payload (MID, ACK #, etc) | ||
164 | * @param c Connection this message belongs to (can be NULL). | ||
165 | * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) | ||
166 | * @param cont Continuation to be called once CORE has sent the message. | ||
167 | * @param cont_cls Closure for @c cont. | ||
168 | */ | 81 | */ |
169 | struct CadetPeerQueue * | 82 | const struct GNUNET_PeerIdentity * |
170 | GCP_send (struct CadetPeer *peer, | 83 | GCP_get_id (struct CadetPeer *cp); |
171 | const struct GNUNET_MessageHeader *message, | ||
172 | uint16_t payload_type, | ||
173 | struct CadetEncryptedMessageIdentifier payload_id, | ||
174 | struct CadetConnection *c, | ||
175 | int fwd, | ||
176 | GCP_sent cont, | ||
177 | void *cont_cls); | ||
178 | 84 | ||
179 | /** | ||
180 | * Cancel sending a message. Message must have been sent with | ||
181 | * #GCP_send before. May not be called after the notify sent | ||
182 | * callback has been called. | ||
183 | * | ||
184 | * It does NOT call the continuation given to #GCP_send. | ||
185 | * | ||
186 | * @param q Queue handle to cancel | ||
187 | */ | ||
188 | void | ||
189 | GCP_send_cancel (struct CadetPeerQueue *q); | ||
190 | 85 | ||
191 | /** | 86 | /** |
192 | * Set tunnel. | 87 | * Iterate over all known peers. |
193 | * | 88 | * |
194 | * @param peer Peer. | 89 | * @param iter Iterator. |
195 | * @param t Tunnel. | 90 | * @param cls Closure for @c iter. |
196 | */ | 91 | */ |
197 | void | 92 | void |
198 | GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t); | 93 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, |
94 | void *cls); | ||
199 | 95 | ||
200 | 96 | ||
201 | /** | 97 | /** |
202 | * Check whether there is a direct (core level) connection to peer. | 98 | * Count the number of known paths toward the peer. |
203 | * | ||
204 | * @param peer Peer to check. | ||
205 | * | 99 | * |
206 | * @return #GNUNET_YES if there is a direct connection. | 100 | * @param cp Peer to get path info. |
101 | * @return Number of known paths. | ||
207 | */ | 102 | */ |
208 | int | 103 | unsigned int |
209 | GCP_is_neighbor (const struct CadetPeer *peer); | 104 | GCP_count_paths (const struct CadetPeer *cp); |
210 | 105 | ||
211 | 106 | ||
212 | /** | 107 | /** |
213 | * Create and initialize a new tunnel towards a peer, in case it has none. | 108 | * Drop all paths owned by this peer, and do not |
214 | * | 109 | * allow new ones to be added: We are shutting down. |
215 | * Does not generate any traffic, just creates the local data structures. | ||
216 | * | 110 | * |
217 | * @param peer Peer towards which to create the tunnel. | 111 | * @param cp peer to drop paths to |
218 | */ | 112 | */ |
219 | void | 113 | void |
220 | GCP_add_tunnel (struct CadetPeer *peer); | 114 | GCP_drop_owned_paths (struct CadetPeer *cp); |
221 | 115 | ||
222 | 116 | ||
223 | /** | 117 | /** |
224 | * Add a connection to a neighboring peer. | 118 | * Peer path iterator. |
225 | * | ||
226 | * Store that the peer is the first hop of the connection in one | ||
227 | * direction and that on peer disconnect the connection must be | ||
228 | * notified and destroyed, for it will no longer be valid. | ||
229 | * | 119 | * |
230 | * @param peer Peer to add connection to. | 120 | * @param cls Closure. |
231 | * @param c Connection to add. | 121 | * @param path Path itself |
232 | * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor | 122 | * @param off offset of the target peer in @a path |
123 | * @return #GNUNET_YES if should keep iterating. | ||
124 | * #GNUNET_NO otherwise. | ||
233 | */ | 125 | */ |
234 | void | 126 | typedef int |
235 | GCP_add_connection (struct CadetPeer *peer, | 127 | (*GCP_PathIterator) (void *cls, |
236 | struct CadetConnection *c, | 128 | struct CadetPeerPath *path, |
237 | int pred); | 129 | unsigned int off); |
238 | 130 | ||
239 | 131 | ||
240 | /** | 132 | /** |
241 | * Add the path to the peer and update the path used to reach it in case this | 133 | * Iterate over the paths to a peer. |
242 | * is the shortest. | ||
243 | * | ||
244 | * @param peer Destination peer to add the path to. | ||
245 | * @param path New path to add. Last peer must be the peer in arg 1. | ||
246 | * Path will be either used of freed if already known. | ||
247 | * @param trusted Do we trust that this path is real? | ||
248 | * | 134 | * |
249 | * @return path if path was taken, pointer to existing duplicate if exists | 135 | * @param cp Peer to get path info. |
250 | * NULL on error. | 136 | * @param callback Function to call for every path. |
137 | * @param callback_cls Closure for @a callback. | ||
138 | * @return Number of iterated paths. | ||
251 | */ | 139 | */ |
252 | struct CadetPeerPath * | 140 | unsigned int |
253 | GCP_add_path (struct CadetPeer *peer, | 141 | GCP_iterate_paths (struct CadetPeer *cp, |
254 | struct CadetPeerPath *p, | 142 | GCP_PathIterator callback, |
255 | int trusted); | 143 | void *callback_cls); |
256 | 144 | ||
257 | 145 | ||
258 | /** | 146 | /** |
259 | * Add the path to the origin peer and update the path used to reach it in case | 147 | * Iterate over the paths to @a peer where |
260 | * this is the shortest. | 148 | * @a peer is at distance @a dist from us. |
261 | * The path is given in peer_info -> destination, therefore we turn the path | ||
262 | * upside down first. | ||
263 | * | 149 | * |
264 | * @param peer Peer to add the path to, being the origin of the path. | 150 | * @param cp Peer to get path info. |
265 | * @param path New path to add after being inversed. | 151 | * @param dist desired distance of @a peer to us on the path |
266 | * Path will be either used or freed. | 152 | * @param callback Function to call for every path. |
267 | * @param trusted Do we trust that this path is real? | 153 | * @param callback_cls Closure for @a callback. |
268 | * | 154 | * @return Number of iterated paths. |
269 | * @return path if path was taken, pointer to existing duplicate if exists | ||
270 | * NULL on error. | ||
271 | */ | 155 | */ |
272 | struct CadetPeerPath * | 156 | unsigned int |
273 | GCP_add_path_to_origin (struct CadetPeer *peer, | 157 | GCP_iterate_paths_at (struct CadetPeer *cp, |
274 | struct CadetPeerPath *path, | 158 | unsigned int dist, |
275 | int trusted); | 159 | GCP_PathIterator callback, |
160 | void *callback_cls); | ||
161 | |||
276 | 162 | ||
277 | /** | 163 | /** |
278 | * Adds a path to the info of all the peers in the path | 164 | * Remove an entry from the DLL of all of the paths that this peer is on. |
279 | * | 165 | * |
280 | * @param p Path to process. | 166 | * @param cp peer to modify |
281 | * @param confirmed Whether we know if the path works or not. | 167 | * @param entry an entry on a path |
168 | * @param off offset of this peer on the path | ||
282 | */ | 169 | */ |
283 | void | 170 | void |
284 | GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); | 171 | GCP_path_entry_remove (struct CadetPeer *cp, |
172 | struct CadetPeerPathEntry *entry, | ||
173 | unsigned int off); | ||
285 | 174 | ||
286 | 175 | ||
287 | /** | 176 | /** |
288 | * Remove any path to the peer that has the extact same peers as the one given. | 177 | * Add an entry to the DLL of all of the paths that this peer is on. |
289 | * | 178 | * |
290 | * @param peer Peer to remove the path from. | 179 | * @param cp peer to modify |
291 | * @param path Path to remove. Is always destroyed . | 180 | * @param entry an entry on a path |
181 | * @param off offset of this peer on the path | ||
292 | */ | 182 | */ |
293 | void | 183 | void |
294 | GCP_remove_path (struct CadetPeer *peer, | 184 | GCP_path_entry_add (struct CadetPeer *cp, |
295 | struct CadetPeerPath *path); | 185 | struct CadetPeerPathEntry *entry, |
186 | unsigned int off); | ||
296 | 187 | ||
297 | 188 | ||
298 | /** | 189 | /** |
299 | * Check that we are aware of a connection from a neighboring peer. | 190 | * Get the tunnel towards a peer. |
300 | * | 191 | * |
301 | * @param peer Peer to the connection is with | 192 | * @param cp Peer to get from. |
302 | * @param c Connection that should be in the map with this peer. | 193 | * @param create #GNUNET_YES to create a tunnel if we do not have one |
194 | * @return Tunnel towards peer. | ||
303 | */ | 195 | */ |
304 | void | 196 | struct CadetTunnel * |
305 | GCP_check_connection (const struct CadetPeer *peer, | 197 | GCP_get_tunnel (struct CadetPeer *cp, |
306 | const struct CadetConnection *c); | 198 | int create); |
307 | 199 | ||
308 | 200 | ||
309 | /** | 201 | /** |
310 | * Remove a connection from a neighboring peer. | 202 | * The tunnel to the given peer no longer exists, remove it from our |
203 | * data structures, and possibly clean up the peer itself. | ||
311 | * | 204 | * |
312 | * @param peer Peer to remove connection from. | 205 | * @param cp the peer affected |
313 | * @param c Connection to remove. | 206 | * @param t the dead tunnel |
314 | */ | 207 | */ |
315 | void | 208 | void |
316 | GCP_remove_connection (struct CadetPeer *peer, | 209 | GCP_drop_tunnel (struct CadetPeer *cp, |
317 | const struct CadetConnection *c); | 210 | struct CadetTunnel *t); |
318 | 211 | ||
319 | 212 | ||
320 | /** | 213 | /** |
321 | * Start the DHT search for new paths towards the peer: we don't have | 214 | * Try adding a @a path to this @a cp. If the peer already |
322 | * enough good connections. | 215 | * has plenty of paths, return NULL. |
323 | * | 216 | * |
324 | * @param peer Destination peer. | 217 | * @param cp peer to which the @a path leads to |
218 | * @param path a path looking for an owner; may not be fully initialized yet! | ||
219 | * @param off offset of @a cp in @a path | ||
220 | * @param force for attaching the path | ||
221 | * @return NULL if this peer does not care to become a new owner, | ||
222 | * otherwise the node in the peer's path heap for the @a path. | ||
325 | */ | 223 | */ |
326 | void | 224 | struct GNUNET_CONTAINER_HeapNode * |
327 | GCP_start_search (struct CadetPeer *peer); | 225 | GCP_attach_path (struct CadetPeer *cp, |
226 | struct CadetPeerPath *path, | ||
227 | unsigned int off, | ||
228 | int force); | ||
328 | 229 | ||
329 | 230 | ||
330 | /** | 231 | /** |
331 | * Stop the DHT search for new paths towards the peer: we already have | 232 | * This peer can no longer own @a path as the path |
332 | * enough good connections. | 233 | * has been extended and a peer further down the line |
234 | * is now the new owner. | ||
333 | * | 235 | * |
334 | * @param peer Destination peer. | 236 | * @param cp old owner of the @a path |
237 | * @param path path where the ownership is lost | ||
238 | * @param hn note in @a cp's path heap that must be deleted | ||
335 | */ | 239 | */ |
336 | void | 240 | void |
337 | GCP_stop_search (struct CadetPeer *peer); | 241 | GCP_detach_path (struct CadetPeer *cp, |
242 | struct CadetPeerPath *path, | ||
243 | struct GNUNET_CONTAINER_HeapNode *hn); | ||
338 | 244 | ||
339 | 245 | ||
340 | /** | 246 | /** |
341 | * Get the Full ID of a peer. | 247 | * Add a @a connection to this @a cp. |
342 | * | ||
343 | * @param peer Peer to get from. | ||
344 | * | 248 | * |
345 | * @return Full ID of peer. | 249 | * @param cp peer via which the @a connection goes |
250 | * @param cc the connection to add | ||
346 | */ | 251 | */ |
347 | const struct GNUNET_PeerIdentity * | 252 | void |
348 | GCP_get_id (const struct CadetPeer *peer); | 253 | GCP_add_connection (struct CadetPeer *cp, |
254 | struct CadetConnection *cc); | ||
349 | 255 | ||
350 | 256 | ||
351 | /** | 257 | /** |
352 | * Get the Short ID of a peer. | 258 | * Remove a @a connection that went via this @a cp. |
353 | * | 259 | * |
354 | * @param peer Peer to get from. | 260 | * @param cp peer via which the @a connection went |
355 | * | 261 | * @param cc the connection to remove |
356 | * @return Short ID of peer. | ||
357 | */ | 262 | */ |
358 | GNUNET_PEER_Id | 263 | void |
359 | GCP_get_short_id (const struct CadetPeer *peer); | 264 | GCP_remove_connection (struct CadetPeer *cp, |
265 | struct CadetConnection *cc); | ||
360 | 266 | ||
361 | 267 | ||
362 | /** | 268 | /** |
363 | * Get the tunnel towards a peer. | 269 | * We got a HELLO for a @a cp, remember it, and possibly |
364 | * | 270 | * trigger adequate actions (like trying to connect). |
365 | * @param peer Peer to get from. | ||
366 | * | 271 | * |
367 | * @return Tunnel towards peer. | 272 | * @param cp the peer we got a HELLO for |
273 | * @param hello the HELLO to remember | ||
368 | */ | 274 | */ |
369 | struct CadetTunnel * | 275 | void |
370 | GCP_get_tunnel (const struct CadetPeer *peer); | 276 | GCP_set_hello (struct CadetPeer *cp, |
277 | const struct GNUNET_HELLO_Message *hello); | ||
371 | 278 | ||
372 | 279 | ||
373 | /** | 280 | /** |
374 | * Set the hello message. | 281 | * Clean up all entries about all peers. |
375 | * | 282 | * Must only be called after all tunnels, CORE-connections and |
376 | * @param peer Peer whose message to set. | 283 | * connections are down. |
377 | * @param hello Hello message. | ||
378 | */ | 284 | */ |
379 | void | 285 | void |
380 | GCP_set_hello (struct CadetPeer *peer, | 286 | GCP_destroy_all_peers (void); |
381 | const struct GNUNET_HELLO_Message *hello); | ||
382 | 287 | ||
383 | 288 | ||
384 | /** | 289 | /** |
385 | * Get the hello message. | 290 | * Data structure used to track whom we have to notify about changes |
386 | * | 291 | * in our ability to transmit to a given peer. |
387 | * @param peer Peer whose message to get. | ||
388 | * | 292 | * |
389 | * @return Hello message. | 293 | * All queue managers will be given equal chance for sending messages |
294 | * to @a cp. This construct this guarantees fairness for access to @a | ||
295 | * cp among the different message queues. Each connection or route | ||
296 | * will have its respective message queue managers for each direction. | ||
390 | */ | 297 | */ |
391 | struct GNUNET_HELLO_Message * | 298 | struct GCP_MessageQueueManager; |
392 | GCP_get_hello (struct CadetPeer *peer); | ||
393 | 299 | ||
394 | 300 | ||
395 | /** | 301 | /** |
396 | * Try to connect to a peer on TRANSPORT level. | 302 | * Function to call with updated message queue object. |
397 | * | 303 | * |
398 | * @param peer Peer to whom to connect. | 304 | * @param cls closure |
305 | * @param available #GNUNET_YES if sending is now possible, | ||
306 | * #GNUNET_NO if sending is no longer possible | ||
307 | * #GNUNET_SYSERR if sending is no longer possible | ||
308 | * and the last envelope was discarded | ||
399 | */ | 309 | */ |
400 | void | 310 | typedef void |
401 | GCP_try_connect (struct CadetPeer *peer); | 311 | (*GCP_MessageQueueNotificationCallback)(void *cls, |
312 | int available); | ||
313 | |||
402 | 314 | ||
403 | /** | 315 | /** |
404 | * Notify a peer that a link between two other peers is broken. If any path | 316 | * Start message queue change notifications. Will create a new slot |
405 | * used that link, eliminate it. | 317 | * to manage the message queue to the given @a cp. |
406 | * | 318 | * |
407 | * @param peer Peer affected by the change. | 319 | * @param cp peer to notify for |
408 | * @param peer1 Peer whose link is broken. | 320 | * @param cb function to call if mq becomes available or unavailable |
409 | * @param peer2 Peer whose link is broken. | 321 | * @param cb_cls closure for @a cb |
322 | * @return handle to cancel request | ||
410 | */ | 323 | */ |
411 | void | 324 | struct GCP_MessageQueueManager * |
412 | GCP_notify_broken_link (struct CadetPeer *peer, | 325 | GCP_request_mq (struct CadetPeer *cp, |
413 | const struct GNUNET_PeerIdentity *peer1, | 326 | GCP_MessageQueueNotificationCallback cb, |
414 | const struct GNUNET_PeerIdentity *peer2); | 327 | void *cb_cls); |
415 | 328 | ||
416 | 329 | ||
417 | /** | 330 | /** |
418 | * Count the number of known paths toward the peer. | 331 | * Test if @a cp has a core-level connection |
419 | * | ||
420 | * @param peer Peer to get path info. | ||
421 | * | 332 | * |
422 | * @return Number of known paths. | 333 | * @param cp peer to test |
334 | * @return #GNUNET_YES if @a cp has a core-level connection | ||
423 | */ | 335 | */ |
424 | unsigned int | 336 | int |
425 | GCP_count_paths (const struct CadetPeer *peer); | 337 | GCP_has_core_connection (struct CadetPeer *cp); |
338 | |||
426 | 339 | ||
427 | /** | 340 | /** |
428 | * Iterate over the paths to a peer. | 341 | * Send the message in @a env via a @a mqm. Must only be called at |
429 | * | 342 | * most once after the respective |
430 | * @param peer Peer to get path info. | 343 | * #GCP_MessageQueueNotificationCallback was called with `available` |
431 | * @param callback Function to call for every path. | 344 | * set to #GNUNET_YES, and not after the callback was called with |
432 | * @param cls Closure for @a callback. | 345 | * `available` set to #GNUNET_NO or #GNUNET_SYSERR. |
433 | * | 346 | * |
434 | * @return Number of iterated paths. | 347 | * @param mqm message queue manager for the transmission |
348 | * @param env envelope with the message to send; must NOT | ||
349 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
435 | */ | 350 | */ |
436 | unsigned int | 351 | void |
437 | GCP_iterate_paths (struct CadetPeer *peer, | 352 | GCP_send (struct GCP_MessageQueueManager *mqm, |
438 | GCP_path_iterator callback, | 353 | struct GNUNET_MQ_Envelope *env); |
439 | void *cls); | ||
440 | 354 | ||
441 | 355 | ||
442 | /** | 356 | /** |
443 | * Iterate all known peers. | 357 | * Send the message in @a env to @a cp, overriding queueing logic. |
358 | * This function should only be used to send error messages outside | ||
359 | * of flow and congestion control, similar to ICMP. Note that | ||
360 | * the envelope may be silently discarded as well. | ||
444 | * | 361 | * |
445 | * @param iter Iterator. | 362 | * @param cp peer to send the message to |
446 | * @param cls Closure for @c iter. | 363 | * @param env envelope with the message to send |
447 | */ | 364 | */ |
448 | void | 365 | void |
449 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, | 366 | GCP_send_ooo (struct CadetPeer *cp, |
450 | void *cls); | 367 | struct GNUNET_MQ_Envelope *env); |
451 | 368 | ||
452 | 369 | ||
453 | /** | 370 | /** |
454 | * Get the static string for a peer ID. | 371 | * Stops message queue change notifications and sends a last message. |
455 | * | 372 | * In practice, this is implemented by sending that @a last_env |
456 | * @param peer Peer. | 373 | * message immediately (if any), ignoring queue order. |
457 | * | 374 | * |
458 | * @return Static string for it's ID. | 375 | * @param mqm handle matching request to cancel |
376 | * @param last_env final message to transmit, or NULL | ||
459 | */ | 377 | */ |
460 | const char * | 378 | void |
461 | GCP_2s (const struct CadetPeer *peer); | 379 | GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm, |
380 | struct GNUNET_MQ_Envelope *last_env); | ||
462 | 381 | ||
463 | 382 | ||
464 | /** | 383 | /** |
465 | * Log all kinds of info about a peer. | 384 | * Set the message queue to @a mq for peer @a cp and notify watchers. |
466 | * | 385 | * |
467 | * @param peer Peer. | 386 | * @param cp peer to modify |
387 | * @param mq message queue to set (can be NULL) | ||
468 | */ | 388 | */ |
469 | void | 389 | void |
470 | GCP_debug (const struct CadetPeer *p, | 390 | GCP_set_mq (struct CadetPeer *cp, |
471 | enum GNUNET_ErrorType level); | 391 | struct GNUNET_MQ_Handle *mq); |
472 | |||
473 | 392 | ||
474 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
475 | { | ||
476 | #endif | ||
477 | #ifdef __cplusplus | ||
478 | } | ||
479 | #endif | ||
480 | 393 | ||
481 | /* ifndef GNUNET_CADET_SERVICE_PEER_H */ | ||
482 | #endif | 394 | #endif |
483 | /* end of gnunet-cadet-service_peer.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet_tunnel.c b/src/cadet/gnunet-service-cadet_tunnel.c deleted file mode 100644 index a94e8f4ff..000000000 --- a/src/cadet/gnunet-service-cadet_tunnel.c +++ /dev/null | |||
@@ -1,3501 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/gnunet-service-cadet_tunnel.c | ||
22 | * @brief logical links between CADET clients | ||
23 | * @author Bartlomiej Polot | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_signatures.h" | ||
28 | #include "gnunet_statistics_service.h" | ||
29 | #include "cadet_protocol.h" | ||
30 | #include "cadet_path.h" | ||
31 | #include "gnunet-service-cadet_tunnel.h" | ||
32 | #include "gnunet-service-cadet_connection.h" | ||
33 | #include "gnunet-service-cadet_channel.h" | ||
34 | #include "gnunet-service-cadet_peer.h" | ||
35 | |||
36 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) | ||
37 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__) | ||
38 | |||
39 | #define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5) | ||
40 | |||
41 | #if !defined(GNUNET_CULL_LOGGING) | ||
42 | #define DUMP_KEYS_TO_STDERR GNUNET_YES | ||
43 | #else | ||
44 | #define DUMP_KEYS_TO_STDERR GNUNET_NO | ||
45 | #endif | ||
46 | |||
47 | #define MIN_TUNNEL_BUFFER 8 | ||
48 | #define MAX_TUNNEL_BUFFER 64 | ||
49 | #define MAX_SKIPPED_KEYS 64 | ||
50 | #define MAX_KEY_GAP 256 | ||
51 | #define AX_HEADER_SIZE (sizeof (uint32_t) * 2\ | ||
52 | + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)) | ||
53 | |||
54 | /******************************************************************************/ | ||
55 | /******************************** STRUCTS **********************************/ | ||
56 | /******************************************************************************/ | ||
57 | |||
58 | struct CadetTChannel | ||
59 | { | ||
60 | struct CadetTChannel *next; | ||
61 | struct CadetTChannel *prev; | ||
62 | struct CadetChannel *ch; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Entry in list of connections used by tunnel, with metadata. | ||
68 | */ | ||
69 | struct CadetTConnection | ||
70 | { | ||
71 | /** | ||
72 | * Next in DLL. | ||
73 | */ | ||
74 | struct CadetTConnection *next; | ||
75 | |||
76 | /** | ||
77 | * Prev in DLL. | ||
78 | */ | ||
79 | struct CadetTConnection *prev; | ||
80 | |||
81 | /** | ||
82 | * Connection handle. | ||
83 | */ | ||
84 | struct CadetConnection *c; | ||
85 | |||
86 | /** | ||
87 | * Creation time, to keep oldest connection alive. | ||
88 | */ | ||
89 | struct GNUNET_TIME_Absolute created; | ||
90 | |||
91 | /** | ||
92 | * Connection throughput, to keep fastest connection alive. | ||
93 | */ | ||
94 | uint32_t throughput; | ||
95 | }; | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Struct to old keys for skipped messages while advancing the Axolotl ratchet. | ||
100 | */ | ||
101 | struct CadetTunnelSkippedKey | ||
102 | { | ||
103 | /** | ||
104 | * DLL next. | ||
105 | */ | ||
106 | struct CadetTunnelSkippedKey *next; | ||
107 | |||
108 | /** | ||
109 | * DLL prev. | ||
110 | */ | ||
111 | struct CadetTunnelSkippedKey *prev; | ||
112 | |||
113 | /** | ||
114 | * When was this key stored (for timeout). | ||
115 | */ | ||
116 | struct GNUNET_TIME_Absolute timestamp; | ||
117 | |||
118 | /** | ||
119 | * Header key. | ||
120 | */ | ||
121 | struct GNUNET_CRYPTO_SymmetricSessionKey HK; | ||
122 | |||
123 | /** | ||
124 | * Message key. | ||
125 | */ | ||
126 | struct GNUNET_CRYPTO_SymmetricSessionKey MK; | ||
127 | |||
128 | /** | ||
129 | * Key number for a given HK. | ||
130 | */ | ||
131 | unsigned int Kn; | ||
132 | }; | ||
133 | |||
134 | |||
135 | /** | ||
136 | * Axolotl data, according to https://github.com/trevp/axolotl/wiki . | ||
137 | */ | ||
138 | struct CadetTunnelAxolotl | ||
139 | { | ||
140 | /** | ||
141 | * A (double linked) list of stored message keys and associated header keys | ||
142 | * for "skipped" messages, i.e. messages that have not been | ||
143 | * received despite the reception of more recent messages, (head). | ||
144 | */ | ||
145 | struct CadetTunnelSkippedKey *skipped_head; | ||
146 | |||
147 | /** | ||
148 | * Skipped messages' keys DLL, tail. | ||
149 | */ | ||
150 | struct CadetTunnelSkippedKey *skipped_tail; | ||
151 | |||
152 | /** | ||
153 | * Elements in @a skipped_head <-> @a skipped_tail. | ||
154 | */ | ||
155 | unsigned int skipped; | ||
156 | |||
157 | /** | ||
158 | * 32-byte root key which gets updated by DH ratchet. | ||
159 | */ | ||
160 | struct GNUNET_CRYPTO_SymmetricSessionKey RK; | ||
161 | |||
162 | /** | ||
163 | * 32-byte header key (send). | ||
164 | */ | ||
165 | struct GNUNET_CRYPTO_SymmetricSessionKey HKs; | ||
166 | |||
167 | /** | ||
168 | * 32-byte header key (recv) | ||
169 | */ | ||
170 | struct GNUNET_CRYPTO_SymmetricSessionKey HKr; | ||
171 | |||
172 | /** | ||
173 | * 32-byte next header key (send). | ||
174 | */ | ||
175 | struct GNUNET_CRYPTO_SymmetricSessionKey NHKs; | ||
176 | |||
177 | /** | ||
178 | * 32-byte next header key (recv). | ||
179 | */ | ||
180 | struct GNUNET_CRYPTO_SymmetricSessionKey NHKr; | ||
181 | |||
182 | /** | ||
183 | * 32-byte chain keys (used for forward-secrecy updating, send). | ||
184 | */ | ||
185 | struct GNUNET_CRYPTO_SymmetricSessionKey CKs; | ||
186 | |||
187 | /** | ||
188 | * 32-byte chain keys (used for forward-secrecy updating, recv). | ||
189 | */ | ||
190 | struct GNUNET_CRYPTO_SymmetricSessionKey CKr; | ||
191 | |||
192 | /** | ||
193 | * ECDH for key exchange (A0 / B0). | ||
194 | */ | ||
195 | struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0; | ||
196 | |||
197 | /** | ||
198 | * ECDH Ratchet key (send). | ||
199 | */ | ||
200 | struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs; | ||
201 | |||
202 | /** | ||
203 | * ECDH Ratchet key (recv). | ||
204 | */ | ||
205 | struct GNUNET_CRYPTO_EcdhePublicKey DHRr; | ||
206 | |||
207 | /** | ||
208 | * Message number (reset to 0 with each new ratchet, next message to send). | ||
209 | */ | ||
210 | uint32_t Ns; | ||
211 | |||
212 | /** | ||
213 | * Message number (reset to 0 with each new ratchet, next message to recv). | ||
214 | */ | ||
215 | uint32_t Nr; | ||
216 | |||
217 | /** | ||
218 | * Previous message numbers (# of msgs sent under prev ratchet) | ||
219 | */ | ||
220 | uint32_t PNs; | ||
221 | |||
222 | /** | ||
223 | * True (#GNUNET_YES) if we have to send a new ratchet key in next msg. | ||
224 | */ | ||
225 | int ratchet_flag; | ||
226 | |||
227 | /** | ||
228 | * Number of messages recieved since our last ratchet advance. | ||
229 | * - If this counter = 0, we cannot send a new ratchet key in next msg. | ||
230 | * - If this counter > 0, we can (but don't yet have to) send a new key. | ||
231 | */ | ||
232 | unsigned int ratchet_allowed; | ||
233 | |||
234 | /** | ||
235 | * Number of messages recieved since our last ratchet advance. | ||
236 | * - If this counter = 0, we cannot send a new ratchet key in next msg. | ||
237 | * - If this counter > 0, we can (but don't yet have to) send a new key. | ||
238 | */ | ||
239 | unsigned int ratchet_counter; | ||
240 | |||
241 | /** | ||
242 | * When does this ratchet expire and a new one is triggered. | ||
243 | */ | ||
244 | struct GNUNET_TIME_Absolute ratchet_expiration; | ||
245 | }; | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Struct containing all information regarding a tunnel to a peer. | ||
250 | */ | ||
251 | struct CadetTunnel | ||
252 | { | ||
253 | /** | ||
254 | * Endpoint of the tunnel. | ||
255 | */ | ||
256 | struct CadetPeer *peer; | ||
257 | |||
258 | /** | ||
259 | * Axolotl info. | ||
260 | */ | ||
261 | struct CadetTunnelAxolotl *ax; | ||
262 | |||
263 | /** | ||
264 | * State of the tunnel connectivity. | ||
265 | */ | ||
266 | enum CadetTunnelCState cstate; | ||
267 | |||
268 | /** | ||
269 | * State of the tunnel encryption. | ||
270 | */ | ||
271 | enum CadetTunnelEState estate; | ||
272 | |||
273 | /** | ||
274 | * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral | ||
275 | * key changes. | ||
276 | */ | ||
277 | struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key; | ||
278 | |||
279 | /** | ||
280 | * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL. | ||
281 | */ | ||
282 | struct GNUNET_CRYPTO_SymmetricSessionKey e_key; | ||
283 | |||
284 | /** | ||
285 | * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL. | ||
286 | */ | ||
287 | struct GNUNET_CRYPTO_SymmetricSessionKey d_key; | ||
288 | |||
289 | /** | ||
290 | * Task to start the rekey process. | ||
291 | */ | ||
292 | struct GNUNET_SCHEDULER_Task *rekey_task; | ||
293 | |||
294 | /** | ||
295 | * Paths that are actively used to reach the destination peer. | ||
296 | */ | ||
297 | struct CadetTConnection *connection_head; | ||
298 | struct CadetTConnection *connection_tail; | ||
299 | |||
300 | /** | ||
301 | * Next connection number. | ||
302 | */ | ||
303 | uint32_t next_cid; | ||
304 | |||
305 | /** | ||
306 | * Channels inside this tunnel. | ||
307 | */ | ||
308 | struct CadetTChannel *channel_head; | ||
309 | struct CadetTChannel *channel_tail; | ||
310 | |||
311 | /** | ||
312 | * Channel ID for the next created channel. | ||
313 | */ | ||
314 | struct GNUNET_CADET_ChannelTunnelNumber next_ctn; | ||
315 | |||
316 | /** | ||
317 | * Destroy flag: if true, destroy on last message. | ||
318 | */ | ||
319 | struct GNUNET_SCHEDULER_Task * destroy_task; | ||
320 | |||
321 | /** | ||
322 | * Queued messages, to transmit once tunnel gets connected. | ||
323 | */ | ||
324 | struct CadetTunnelDelayed *tq_head; | ||
325 | struct CadetTunnelDelayed *tq_tail; | ||
326 | |||
327 | /** | ||
328 | * Task to trim connections if too many are present. | ||
329 | */ | ||
330 | struct GNUNET_SCHEDULER_Task * trim_connections_task; | ||
331 | |||
332 | /** | ||
333 | * Ephemeral message in the queue (to avoid queueing more than one). | ||
334 | */ | ||
335 | struct CadetConnectionQueue *ephm_h; | ||
336 | |||
337 | /** | ||
338 | * Pong message in the queue. | ||
339 | */ | ||
340 | struct CadetConnectionQueue *pong_h; | ||
341 | }; | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Struct used to save messages in a non-ready tunnel to send once connected. | ||
346 | */ | ||
347 | struct CadetTunnelDelayed | ||
348 | { | ||
349 | /** | ||
350 | * DLL | ||
351 | */ | ||
352 | struct CadetTunnelDelayed *next; | ||
353 | struct CadetTunnelDelayed *prev; | ||
354 | |||
355 | /** | ||
356 | * Tunnel. | ||
357 | */ | ||
358 | struct CadetTunnel *t; | ||
359 | |||
360 | /** | ||
361 | * Tunnel queue given to the channel to cancel request. Update on send_queued. | ||
362 | */ | ||
363 | struct CadetTunnelQueue *tq; | ||
364 | |||
365 | /** | ||
366 | * Message to send. | ||
367 | */ | ||
368 | /* struct GNUNET_MessageHeader *msg; */ | ||
369 | }; | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Handle for messages queued but not yet sent. | ||
374 | */ | ||
375 | struct CadetTunnelQueue | ||
376 | { | ||
377 | /** | ||
378 | * Connection queue handle, to cancel if necessary. | ||
379 | */ | ||
380 | struct CadetConnectionQueue *cq; | ||
381 | |||
382 | /** | ||
383 | * Handle in case message hasn't been given to a connection yet. | ||
384 | */ | ||
385 | struct CadetTunnelDelayed *tqd; | ||
386 | |||
387 | /** | ||
388 | * Continuation to call once sent. | ||
389 | */ | ||
390 | GCT_sent cont; | ||
391 | |||
392 | /** | ||
393 | * Closure for @c cont. | ||
394 | */ | ||
395 | void *cont_cls; | ||
396 | }; | ||
397 | |||
398 | |||
399 | /******************************************************************************/ | ||
400 | /******************************* GLOBALS ***********************************/ | ||
401 | /******************************************************************************/ | ||
402 | |||
403 | /** | ||
404 | * Global handle to the statistics service. | ||
405 | */ | ||
406 | extern struct GNUNET_STATISTICS_Handle *stats; | ||
407 | |||
408 | /** | ||
409 | * Local peer own ID (memory efficient handle). | ||
410 | */ | ||
411 | extern GNUNET_PEER_Id myid; | ||
412 | |||
413 | /** | ||
414 | * Local peer own ID (full value). | ||
415 | */ | ||
416 | extern struct GNUNET_PeerIdentity my_full_id; | ||
417 | |||
418 | |||
419 | /** | ||
420 | * Don't try to recover tunnels if shutting down. | ||
421 | */ | ||
422 | extern int shutting_down; | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Set of all tunnels, in order to trigger a new exchange on rekey. | ||
427 | * Indexed by peer's ID. | ||
428 | */ | ||
429 | static struct GNUNET_CONTAINER_MultiPeerMap *tunnels; | ||
430 | |||
431 | /** | ||
432 | * Own Peer ID private key. | ||
433 | */ | ||
434 | const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key; | ||
435 | |||
436 | |||
437 | /******************************** AXOLOTL ************************************/ | ||
438 | |||
439 | /** | ||
440 | * How many messages are needed to trigger a ratchet advance. | ||
441 | */ | ||
442 | static unsigned long long ratchet_messages; | ||
443 | |||
444 | /** | ||
445 | * How long until we trigger a ratched advance. | ||
446 | */ | ||
447 | static struct GNUNET_TIME_Relative ratchet_time; | ||
448 | |||
449 | |||
450 | /******************************************************************************/ | ||
451 | /******************************** STATIC ***********************************/ | ||
452 | /******************************************************************************/ | ||
453 | |||
454 | /** | ||
455 | * Get string description for tunnel connectivity state. | ||
456 | * | ||
457 | * @param cs Tunnel state. | ||
458 | * | ||
459 | * @return String representation. | ||
460 | */ | ||
461 | static const char * | ||
462 | cstate2s (enum CadetTunnelCState cs) | ||
463 | { | ||
464 | static char buf[32]; | ||
465 | |||
466 | switch (cs) | ||
467 | { | ||
468 | case CADET_TUNNEL_NEW: | ||
469 | return "CADET_TUNNEL_NEW"; | ||
470 | case CADET_TUNNEL_SEARCHING: | ||
471 | return "CADET_TUNNEL_SEARCHING"; | ||
472 | case CADET_TUNNEL_WAITING: | ||
473 | return "CADET_TUNNEL_WAITING"; | ||
474 | case CADET_TUNNEL_READY: | ||
475 | return "CADET_TUNNEL_READY"; | ||
476 | case CADET_TUNNEL_SHUTDOWN: | ||
477 | return "CADET_TUNNEL_SHUTDOWN"; | ||
478 | default: | ||
479 | SPRINTF (buf, "%u (UNKNOWN STATE)", cs); | ||
480 | return buf; | ||
481 | } | ||
482 | return ""; | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Get string description for tunnel encryption state. | ||
488 | * | ||
489 | * @param es Tunnel state. | ||
490 | * | ||
491 | * @return String representation. | ||
492 | */ | ||
493 | static const char * | ||
494 | estate2s (enum CadetTunnelEState es) | ||
495 | { | ||
496 | static char buf[32]; | ||
497 | |||
498 | switch (es) | ||
499 | { | ||
500 | case CADET_TUNNEL_KEY_UNINITIALIZED: | ||
501 | return "CADET_TUNNEL_KEY_UNINITIALIZED"; | ||
502 | case CADET_TUNNEL_KEY_AX_SENT: | ||
503 | return "CADET_TUNNEL_KEY_AX_SENT"; | ||
504 | case CADET_TUNNEL_KEY_AX_AUTH_SENT: | ||
505 | return "CADET_TUNNEL_KEY_AX_AUTH_SENT"; | ||
506 | case CADET_TUNNEL_KEY_OK: | ||
507 | return "CADET_TUNNEL_KEY_OK"; | ||
508 | case CADET_TUNNEL_KEY_REKEY: | ||
509 | return "CADET_TUNNEL_KEY_REKEY"; | ||
510 | default: | ||
511 | SPRINTF (buf, "%u (UNKNOWN STATE)", es); | ||
512 | return buf; | ||
513 | } | ||
514 | return ""; | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * @brief Check if tunnel is ready to send traffic. | ||
520 | * | ||
521 | * Tunnel must be connected and with encryption correctly set up. | ||
522 | * | ||
523 | * @param t Tunnel to check. | ||
524 | * | ||
525 | * @return #GNUNET_YES if ready, #GNUNET_NO otherwise | ||
526 | */ | ||
527 | static int | ||
528 | is_ready (struct CadetTunnel *t) | ||
529 | { | ||
530 | int ready; | ||
531 | int conn_ok; | ||
532 | int enc_ok; | ||
533 | |||
534 | conn_ok = CADET_TUNNEL_READY == t->cstate; | ||
535 | enc_ok = CADET_TUNNEL_KEY_OK == t->estate | ||
536 | || CADET_TUNNEL_KEY_REKEY == t->estate | ||
537 | || CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate; | ||
538 | ready = conn_ok && enc_ok; | ||
539 | ready = ready || GCT_is_loopback (t); | ||
540 | return ready; | ||
541 | } | ||
542 | |||
543 | |||
544 | /** | ||
545 | * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!! | ||
546 | * | ||
547 | * @param tch Tunnel's channel handle. | ||
548 | * | ||
549 | * @return Amount of messages the channel can still buffer towards the client. | ||
550 | */ | ||
551 | static unsigned int | ||
552 | get_channel_buffer (const struct CadetTChannel *tch) | ||
553 | { | ||
554 | int fwd; | ||
555 | |||
556 | /* If channel is incoming, is terminal in the FWD direction and fwd is YES */ | ||
557 | fwd = GCCH_is_terminal (tch->ch, GNUNET_YES); | ||
558 | |||
559 | return GCCH_get_buffer (tch->ch, fwd); | ||
560 | } | ||
561 | |||
562 | |||
563 | /** | ||
564 | * Get the channel's allowance status. | ||
565 | * | ||
566 | * @param tch Tunnel's channel handle. | ||
567 | * | ||
568 | * @return #GNUNET_YES if we allowed the client to send data to us. | ||
569 | */ | ||
570 | static int | ||
571 | get_channel_allowed (const struct CadetTChannel *tch) | ||
572 | { | ||
573 | int fwd; | ||
574 | |||
575 | /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ | ||
576 | fwd = GCCH_is_origin (tch->ch, GNUNET_YES); | ||
577 | |||
578 | return GCCH_get_allowed (tch->ch, fwd); | ||
579 | } | ||
580 | |||
581 | |||
582 | /** | ||
583 | * Get the connection's buffer. | ||
584 | * | ||
585 | * @param tc Tunnel's connection handle. | ||
586 | * | ||
587 | * @return Amount of messages the connection can still buffer. | ||
588 | */ | ||
589 | static unsigned int | ||
590 | get_connection_buffer (const struct CadetTConnection *tc) | ||
591 | { | ||
592 | int fwd; | ||
593 | |||
594 | /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ | ||
595 | fwd = GCC_is_origin (tc->c, GNUNET_YES); | ||
596 | |||
597 | return GCC_get_buffer (tc->c, fwd); | ||
598 | } | ||
599 | |||
600 | |||
601 | /** | ||
602 | * Get the connection's allowance. | ||
603 | * | ||
604 | * @param tc Tunnel's connection handle. | ||
605 | * | ||
606 | * @return Amount of messages we have allowed the next peer to send us. | ||
607 | */ | ||
608 | static unsigned int | ||
609 | get_connection_allowed (const struct CadetTConnection *tc) | ||
610 | { | ||
611 | int fwd; | ||
612 | |||
613 | /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ | ||
614 | fwd = GCC_is_origin (tc->c, GNUNET_YES); | ||
615 | |||
616 | return GCC_get_allowed (tc->c, fwd); | ||
617 | } | ||
618 | |||
619 | |||
620 | /** | ||
621 | * Create a new Axolotl ephemeral (ratchet) key. | ||
622 | * | ||
623 | * @param t Tunnel. | ||
624 | */ | ||
625 | static void | ||
626 | new_ephemeral (struct CadetTunnel *t) | ||
627 | { | ||
628 | GNUNET_free_non_null (t->ax->DHRs); | ||
629 | t->ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create(); | ||
630 | #if DUMP_KEYS_TO_STDERR | ||
631 | { | ||
632 | struct GNUNET_CRYPTO_EcdhePublicKey pub; | ||
633 | GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &pub); | ||
634 | LOG (GNUNET_ERROR_TYPE_DEBUG, " new DHRs generated: pub %s\n", | ||
635 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub)); | ||
636 | } | ||
637 | #endif | ||
638 | } | ||
639 | |||
640 | |||
641 | /** | ||
642 | * Calculate HMAC. | ||
643 | * | ||
644 | * @param plaintext Content to HMAC. | ||
645 | * @param size Size of @c plaintext. | ||
646 | * @param iv Initialization vector for the message. | ||
647 | * @param key Key to use. | ||
648 | * @param hmac[out] Destination to store the HMAC. | ||
649 | */ | ||
650 | static void | ||
651 | t_hmac (const void *plaintext, size_t size, | ||
652 | uint32_t iv, const struct GNUNET_CRYPTO_SymmetricSessionKey *key, | ||
653 | struct GNUNET_ShortHashCode *hmac) | ||
654 | { | ||
655 | static const char ctx[] = "cadet authentication key"; | ||
656 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
657 | struct GNUNET_HashCode hash; | ||
658 | |||
659 | #if DUMP_KEYS_TO_STDERR | ||
660 | LOG (GNUNET_ERROR_TYPE_INFO, " HMAC %u bytes with key %s\n", size, | ||
661 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) key)); | ||
662 | #endif | ||
663 | GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, | ||
664 | &iv, sizeof (iv), | ||
665 | key, sizeof (*key), | ||
666 | ctx, sizeof (ctx), | ||
667 | NULL); | ||
668 | /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */ | ||
669 | GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash); | ||
670 | GNUNET_memcpy (hmac, &hash, sizeof (*hmac)); | ||
671 | } | ||
672 | |||
673 | |||
674 | /** | ||
675 | * Perform a HMAC. | ||
676 | * | ||
677 | * @param key Key to use. | ||
678 | * @param hash[out] Resulting HMAC. | ||
679 | * @param source Source key material (data to HMAC). | ||
680 | * @param len Length of @a source. | ||
681 | */ | ||
682 | static void | ||
683 | t_ax_hmac_hash (struct GNUNET_CRYPTO_SymmetricSessionKey *key, | ||
684 | struct GNUNET_HashCode *hash, | ||
685 | void *source, unsigned int len) | ||
686 | { | ||
687 | static const char ctx[] = "axolotl HMAC-HASH"; | ||
688 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
689 | |||
690 | GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, | ||
691 | ctx, sizeof (ctx), | ||
692 | NULL); | ||
693 | GNUNET_CRYPTO_hmac (&auth_key, source, len, hash); | ||
694 | } | ||
695 | |||
696 | |||
697 | /** | ||
698 | * Derive a key from a HMAC-HASH. | ||
699 | * | ||
700 | * @param key Key to use for the HMAC. | ||
701 | * @param out Key to generate. | ||
702 | * @param source Source key material (data to HMAC). | ||
703 | * @param len Length of @a source. | ||
704 | */ | ||
705 | static void | ||
706 | t_hmac_derive_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key, | ||
707 | struct GNUNET_CRYPTO_SymmetricSessionKey *out, | ||
708 | void *source, unsigned int len) | ||
709 | { | ||
710 | static const char ctx[] = "axolotl derive key"; | ||
711 | struct GNUNET_HashCode h; | ||
712 | |||
713 | t_ax_hmac_hash (key, &h, source, len); | ||
714 | GNUNET_CRYPTO_kdf (out, sizeof (*out), ctx, sizeof (ctx), | ||
715 | &h, sizeof (h), NULL); | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * Encrypt data with the axolotl tunnel key. | ||
721 | * | ||
722 | * @param t Tunnel whose key to use. | ||
723 | * @param dst Destination for the encrypted data. | ||
724 | * @param src Source of the plaintext. Can overlap with @c dst. | ||
725 | * @param size Size of the plaintext. | ||
726 | * | ||
727 | * @return Size of the encrypted data. | ||
728 | */ | ||
729 | static int | ||
730 | t_ax_encrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size) | ||
731 | { | ||
732 | struct GNUNET_CRYPTO_SymmetricSessionKey MK; | ||
733 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
734 | struct CadetTunnelAxolotl *ax; | ||
735 | size_t out_size; | ||
736 | |||
737 | CADET_TIMING_START; | ||
738 | |||
739 | ax = t->ax; | ||
740 | ax->ratchet_counter++; | ||
741 | if (GNUNET_YES == ax->ratchet_allowed | ||
742 | && (ratchet_messages <= ax->ratchet_counter | ||
743 | || 0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) | ||
744 | { | ||
745 | ax->ratchet_flag = GNUNET_YES; | ||
746 | } | ||
747 | |||
748 | if (GNUNET_YES == ax->ratchet_flag) | ||
749 | { | ||
750 | /* Advance ratchet */ | ||
751 | struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; | ||
752 | struct GNUNET_HashCode dh; | ||
753 | struct GNUNET_HashCode hmac; | ||
754 | static const char ctx[] = "axolotl ratchet"; | ||
755 | |||
756 | new_ephemeral (t); | ||
757 | ax->HKs = ax->NHKs; | ||
758 | |||
759 | /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */ | ||
760 | GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, &ax->DHRr, &dh); | ||
761 | t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh)); | ||
762 | GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx), | ||
763 | &hmac, sizeof (hmac), NULL); | ||
764 | ax->RK = keys[0]; | ||
765 | ax->NHKs = keys[1]; | ||
766 | ax->CKs = keys[2]; | ||
767 | |||
768 | ax->PNs = ax->Ns; | ||
769 | ax->Ns = 0; | ||
770 | ax->ratchet_flag = GNUNET_NO; | ||
771 | ax->ratchet_allowed = GNUNET_NO; | ||
772 | ax->ratchet_counter = 0; | ||
773 | ax->ratchet_expiration = | ||
774 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time); | ||
775 | } | ||
776 | |||
777 | t_hmac_derive_key (&ax->CKs, &MK, "0", 1); | ||
778 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL); | ||
779 | |||
780 | #if DUMP_KEYS_TO_STDERR | ||
781 | LOG (GNUNET_ERROR_TYPE_DEBUG, " CKs: %s\n", | ||
782 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs)); | ||
783 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC with key %u: %s\n", ax->Ns, | ||
784 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK)); | ||
785 | #endif | ||
786 | |||
787 | out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &MK, &iv, dst); | ||
788 | t_hmac_derive_key (&ax->CKs, &ax->CKs, "1", 1); | ||
789 | |||
790 | CADET_TIMING_END; | ||
791 | |||
792 | return out_size; | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Decrypt data with the axolotl tunnel key. | ||
798 | * | ||
799 | * @param t Tunnel whose key to use. | ||
800 | * @param dst Destination for the decrypted data. | ||
801 | * @param src Source of the ciphertext. Can overlap with @c dst. | ||
802 | * @param size Size of the ciphertext. | ||
803 | * | ||
804 | * @return Size of the decrypted data. | ||
805 | */ | ||
806 | static int | ||
807 | t_ax_decrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size) | ||
808 | { | ||
809 | struct GNUNET_CRYPTO_SymmetricSessionKey MK; | ||
810 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
811 | struct CadetTunnelAxolotl *ax; | ||
812 | size_t out_size; | ||
813 | |||
814 | CADET_TIMING_START; | ||
815 | |||
816 | ax = t->ax; | ||
817 | |||
818 | t_hmac_derive_key (&ax->CKr, &MK, "0", 1); | ||
819 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL); | ||
820 | |||
821 | #if DUMP_KEYS_TO_STDERR | ||
822 | LOG (GNUNET_ERROR_TYPE_DEBUG, " CKr: %s\n", | ||
823 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr)); | ||
824 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with key %u: %s\n", ax->Nr, | ||
825 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK)); | ||
826 | #endif | ||
827 | |||
828 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); | ||
829 | out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, &MK, &iv, dst); | ||
830 | GNUNET_assert (out_size == size); | ||
831 | |||
832 | t_hmac_derive_key (&ax->CKr, &ax->CKr, "1", 1); | ||
833 | |||
834 | CADET_TIMING_END; | ||
835 | |||
836 | return out_size; | ||
837 | } | ||
838 | |||
839 | |||
840 | /** | ||
841 | * Encrypt header with the axolotl header key. | ||
842 | * | ||
843 | * @param t Tunnel whose key to use. | ||
844 | * @param msg Message whose header to encrypt. | ||
845 | */ | ||
846 | static void | ||
847 | t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
848 | { | ||
849 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
850 | struct CadetTunnelAxolotl *ax; | ||
851 | size_t out_size; | ||
852 | |||
853 | CADET_TIMING_START; | ||
854 | ax = t->ax; | ||
855 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL); | ||
856 | |||
857 | #if DUMP_KEYS_TO_STDERR | ||
858 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC_H with key %s\n", | ||
859 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs)); | ||
860 | #endif | ||
861 | |||
862 | out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE, | ||
863 | &ax->HKs, &iv, &msg->Ns); | ||
864 | |||
865 | GNUNET_assert (AX_HEADER_SIZE == out_size); | ||
866 | CADET_TIMING_END; | ||
867 | } | ||
868 | |||
869 | |||
870 | /** | ||
871 | * Decrypt header with the current axolotl header key. | ||
872 | * | ||
873 | * @param t Tunnel whose current ax HK to use. | ||
874 | * @param src Message whose header to decrypt. | ||
875 | * @param dst Where to decrypt header to. | ||
876 | */ | ||
877 | static void | ||
878 | t_h_decrypt (struct CadetTunnel *t, const struct GNUNET_CADET_TunnelEncryptedMessage *src, | ||
879 | struct GNUNET_CADET_TunnelEncryptedMessage *dst) | ||
880 | { | ||
881 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
882 | struct CadetTunnelAxolotl *ax; | ||
883 | size_t out_size; | ||
884 | |||
885 | CADET_TIMING_START; | ||
886 | |||
887 | ax = t->ax; | ||
888 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKr, NULL, 0, NULL); | ||
889 | |||
890 | #if DUMP_KEYS_TO_STDERR | ||
891 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with key %s\n", | ||
892 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr)); | ||
893 | #endif | ||
894 | |||
895 | out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE, | ||
896 | &ax->HKr, &iv, &dst->Ns); | ||
897 | |||
898 | GNUNET_assert (AX_HEADER_SIZE == out_size); | ||
899 | |||
900 | CADET_TIMING_END; | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * Decrypt and verify data with the appropriate tunnel key and verify that the | ||
906 | * data has not been altered since it was sent by the remote peer. | ||
907 | * | ||
908 | * @param t Tunnel whose key to use. | ||
909 | * @param dst Destination for the plaintext. | ||
910 | * @param src Source of the message. Can overlap with @c dst. | ||
911 | * @param size Size of the message. | ||
912 | * | ||
913 | * @return Size of the decrypted data, -1 if an error was encountered. | ||
914 | */ | ||
915 | static int | ||
916 | try_old_ax_keys (struct CadetTunnel *t, void *dst, | ||
917 | const struct GNUNET_CADET_TunnelEncryptedMessage *src, size_t size) | ||
918 | { | ||
919 | struct CadetTunnelSkippedKey *key; | ||
920 | struct GNUNET_ShortHashCode *hmac; | ||
921 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
922 | struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header; | ||
923 | struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK; | ||
924 | size_t esize; | ||
925 | size_t res; | ||
926 | size_t len; | ||
927 | unsigned int N; | ||
928 | |||
929 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying old keys\n"); | ||
930 | hmac = &plaintext_header.hmac; | ||
931 | esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); | ||
932 | |||
933 | /* Find a correct Header Key */ | ||
934 | for (key = t->ax->skipped_head; NULL != key; key = key->next) | ||
935 | { | ||
936 | #if DUMP_KEYS_TO_STDERR | ||
937 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Trying hmac with key %s\n", | ||
938 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK)); | ||
939 | #endif | ||
940 | t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &key->HK, hmac); | ||
941 | if (0 == memcmp (hmac, &src->hmac, sizeof (*hmac))) | ||
942 | { | ||
943 | LOG (GNUNET_ERROR_TYPE_DEBUG, " hmac correct\n"); | ||
944 | valid_HK = &key->HK; | ||
945 | break; | ||
946 | } | ||
947 | } | ||
948 | if (NULL == key) | ||
949 | return -1; | ||
950 | |||
951 | /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */ | ||
952 | GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage)); | ||
953 | len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); | ||
954 | GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader)); | ||
955 | |||
956 | /* Decrypt header */ | ||
957 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->HK, NULL, 0, NULL); | ||
958 | res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE, | ||
959 | &key->HK, &iv, &plaintext_header.Ns); | ||
960 | GNUNET_assert (AX_HEADER_SIZE == res); | ||
961 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Message %u, previous: %u\n", | ||
962 | ntohl (plaintext_header.Ns), ntohl (plaintext_header.PNs)); | ||
963 | |||
964 | /* Find the correct Message Key */ | ||
965 | N = ntohl (plaintext_header.Ns); | ||
966 | while (NULL != key && N != key->Kn) | ||
967 | key = key->next; | ||
968 | if (NULL == key || 0 != memcmp (&key->HK, valid_HK, sizeof (*valid_HK))) | ||
969 | return -1; | ||
970 | |||
971 | #if DUMP_KEYS_TO_STDERR | ||
972 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with skipped key %s\n", | ||
973 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK)); | ||
974 | LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with skipped key %u: %s\n", | ||
975 | key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK)); | ||
976 | #endif | ||
977 | |||
978 | /* Decrypt payload */ | ||
979 | GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->MK, NULL, 0, NULL); | ||
980 | res = GNUNET_CRYPTO_symmetric_decrypt (&src[1], len, &key->MK, &iv, dst); | ||
981 | |||
982 | /* Remove key */ | ||
983 | GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key); | ||
984 | t->ax->skipped--; | ||
985 | GNUNET_free (key); /* GNUNET_free overwrites memory with 0xbaadf00d */ | ||
986 | |||
987 | return res; | ||
988 | } | ||
989 | |||
990 | |||
991 | /** | ||
992 | * Delete a key from the list of skipped keys. | ||
993 | * | ||
994 | * @param t Tunnel to delete from. | ||
995 | * @param HKr Header Key to use. | ||
996 | */ | ||
997 | static void | ||
998 | store_skipped_key (struct CadetTunnel *t, | ||
999 | const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr) | ||
1000 | { | ||
1001 | struct CadetTunnelSkippedKey *key; | ||
1002 | |||
1003 | key = GNUNET_new (struct CadetTunnelSkippedKey); | ||
1004 | key->timestamp = GNUNET_TIME_absolute_get (); | ||
1005 | key->Kn = t->ax->Nr; | ||
1006 | key->HK = t->ax->HKr; | ||
1007 | t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1); | ||
1008 | #if DUMP_KEYS_TO_STDERR | ||
1009 | LOG (GNUNET_ERROR_TYPE_DEBUG, " storing MK for Nr %u: %s\n", | ||
1010 | key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK)); | ||
1011 | LOG (GNUNET_ERROR_TYPE_DEBUG, " for CKr: %s\n", | ||
1012 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &t->ax->CKr)); | ||
1013 | #endif | ||
1014 | t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1); | ||
1015 | GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key); | ||
1016 | t->ax->Nr++; | ||
1017 | t->ax->skipped++; | ||
1018 | } | ||
1019 | |||
1020 | |||
1021 | /** | ||
1022 | * Delete a key from the list of skipped keys. | ||
1023 | * | ||
1024 | * @param t Tunnel to delete from. | ||
1025 | * @param key Key to delete. | ||
1026 | */ | ||
1027 | static void | ||
1028 | delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key) | ||
1029 | { | ||
1030 | GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key); | ||
1031 | GNUNET_free (key); | ||
1032 | t->ax->skipped--; | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /** | ||
1037 | * Stage skipped AX keys and calculate the message key. | ||
1038 | * | ||
1039 | * Stores each HK and MK for skipped messages. | ||
1040 | * | ||
1041 | * @param t Tunnel where to stage the keys. | ||
1042 | * @param HKr Header key. | ||
1043 | * @param Np Received meesage number. | ||
1044 | * | ||
1045 | * @return GNUNET_OK if keys were stored. | ||
1046 | * GNUNET_SYSERR if an error ocurred (Np not expected). | ||
1047 | */ | ||
1048 | static int | ||
1049 | store_ax_keys (struct CadetTunnel *t, | ||
1050 | const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr, | ||
1051 | uint32_t Np) | ||
1052 | { | ||
1053 | int gap; | ||
1054 | |||
1055 | |||
1056 | gap = Np - t->ax->Nr; | ||
1057 | LOG (GNUNET_ERROR_TYPE_INFO, "Storing keys [%u, %u)\n", t->ax->Nr, Np); | ||
1058 | if (MAX_KEY_GAP < gap) | ||
1059 | { | ||
1060 | /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */ | ||
1061 | /* TODO: start new key exchange on return */ | ||
1062 | GNUNET_break_op (0); | ||
1063 | LOG (GNUNET_ERROR_TYPE_WARNING, "Got message %u, expected %u+\n", | ||
1064 | Np, t->ax->Nr); | ||
1065 | return GNUNET_SYSERR; | ||
1066 | } | ||
1067 | if (0 > gap) | ||
1068 | { | ||
1069 | /* Delayed message: don't store keys, flag to try old keys. */ | ||
1070 | return GNUNET_SYSERR; | ||
1071 | } | ||
1072 | |||
1073 | while (t->ax->Nr < Np) | ||
1074 | store_skipped_key (t, HKr); | ||
1075 | |||
1076 | while (t->ax->skipped > MAX_SKIPPED_KEYS) | ||
1077 | delete_skipped_key (t, t->ax->skipped_tail); | ||
1078 | |||
1079 | return GNUNET_OK; | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | /** | ||
1084 | * Decrypt and verify data with the appropriate tunnel key and verify that the | ||
1085 | * data has not been altered since it was sent by the remote peer. | ||
1086 | * | ||
1087 | * @param t Tunnel whose key to use. | ||
1088 | * @param dst Destination for the plaintext. | ||
1089 | * @param src Source of the message. Can overlap with @c dst. | ||
1090 | * @param size Size of the message. | ||
1091 | * | ||
1092 | * @return Size of the decrypted data, -1 if an error was encountered. | ||
1093 | */ | ||
1094 | static int | ||
1095 | t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst, | ||
1096 | const struct GNUNET_CADET_TunnelEncryptedMessage *src, | ||
1097 | size_t size) | ||
1098 | { | ||
1099 | struct CadetTunnelAxolotl *ax; | ||
1100 | struct GNUNET_ShortHashCode msg_hmac; | ||
1101 | struct GNUNET_HashCode hmac; | ||
1102 | struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header; | ||
1103 | uint32_t Np; | ||
1104 | uint32_t PNp; | ||
1105 | size_t esize; /* Size of encryped payload */ | ||
1106 | size_t osize; /* Size of output (decrypted payload) */ | ||
1107 | |||
1108 | esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); | ||
1109 | ax = t->ax; | ||
1110 | if (NULL == ax) | ||
1111 | return -1; | ||
1112 | |||
1113 | /* Try current HK */ | ||
1114 | t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->HKr, &msg_hmac); | ||
1115 | if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac))) | ||
1116 | { | ||
1117 | static const char ctx[] = "axolotl ratchet"; | ||
1118 | struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */ | ||
1119 | struct GNUNET_CRYPTO_SymmetricSessionKey HK; | ||
1120 | struct GNUNET_HashCode dh; | ||
1121 | struct GNUNET_CRYPTO_EcdhePublicKey *DHRp; | ||
1122 | |||
1123 | /* Try Next HK */ | ||
1124 | LOG (GNUNET_ERROR_TYPE_DEBUG, " trying next HK\n"); | ||
1125 | t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->NHKr, &msg_hmac); | ||
1126 | if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac))) | ||
1127 | { | ||
1128 | /* Try the skipped keys, if that fails, we're out of luck. */ | ||
1129 | return try_old_ax_keys (t, dst, src, size); | ||
1130 | } | ||
1131 | LOG (GNUNET_ERROR_TYPE_INFO, "next HK worked\n"); | ||
1132 | |||
1133 | HK = ax->HKr; | ||
1134 | ax->HKr = ax->NHKr; | ||
1135 | t_h_decrypt (t, src, &plaintext_header); | ||
1136 | Np = ntohl (plaintext_header.Ns); | ||
1137 | PNp = ntohl (plaintext_header.PNs); | ||
1138 | DHRp = &plaintext_header.DHRs; | ||
1139 | store_ax_keys (t, &HK, PNp); | ||
1140 | |||
1141 | /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */ | ||
1142 | GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh); | ||
1143 | t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh)); | ||
1144 | GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx), | ||
1145 | &hmac, sizeof (hmac), NULL); | ||
1146 | |||
1147 | /* Commit "purported" keys */ | ||
1148 | ax->RK = keys[0]; | ||
1149 | ax->NHKr = keys[1]; | ||
1150 | ax->CKr = keys[2]; | ||
1151 | ax->DHRr = *DHRp; | ||
1152 | ax->Nr = 0; | ||
1153 | ax->ratchet_allowed = GNUNET_YES; | ||
1154 | } | ||
1155 | else | ||
1156 | { | ||
1157 | LOG (GNUNET_ERROR_TYPE_DEBUG, "current HK\n"); | ||
1158 | t_h_decrypt (t, src, &plaintext_header); | ||
1159 | Np = ntohl (plaintext_header.Ns); | ||
1160 | PNp = ntohl (plaintext_header.PNs); | ||
1161 | } | ||
1162 | LOG (GNUNET_ERROR_TYPE_INFO, " got AX Nr %u\n", Np); | ||
1163 | if (Np != ax->Nr) | ||
1164 | if (GNUNET_OK != store_ax_keys (t, &ax->HKr, Np)) | ||
1165 | /* Try the skipped keys, if that fails, we're out of luck. */ | ||
1166 | return try_old_ax_keys (t, dst, src, size); | ||
1167 | |||
1168 | osize = t_ax_decrypt (t, dst, &src[1], esize); | ||
1169 | ax->Nr = Np + 1; | ||
1170 | |||
1171 | if (osize != esize) | ||
1172 | { | ||
1173 | GNUNET_break_op (0); | ||
1174 | return -1; | ||
1175 | } | ||
1176 | |||
1177 | return osize; | ||
1178 | } | ||
1179 | |||
1180 | |||
1181 | /** | ||
1182 | * Pick a connection on which send the next data message. | ||
1183 | * | ||
1184 | * @param t Tunnel on which to send the message. | ||
1185 | * | ||
1186 | * @return The connection on which to send the next message. | ||
1187 | */ | ||
1188 | static struct CadetConnection * | ||
1189 | tunnel_get_connection (struct CadetTunnel *t) | ||
1190 | { | ||
1191 | struct CadetTConnection *iter; | ||
1192 | struct CadetConnection *best; | ||
1193 | unsigned int qn; | ||
1194 | unsigned int lowest_q; | ||
1195 | |||
1196 | LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_2s (t)); | ||
1197 | best = NULL; | ||
1198 | lowest_q = UINT_MAX; | ||
1199 | for (iter = t->connection_head; NULL != iter; iter = iter->next) | ||
1200 | { | ||
1201 | LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", | ||
1202 | GCC_2s (iter->c), GCC_get_state (iter->c)); | ||
1203 | if (CADET_CONNECTION_READY == GCC_get_state (iter->c)) | ||
1204 | { | ||
1205 | qn = GCC_get_qn (iter->c, GCC_is_origin (iter->c, GNUNET_YES)); | ||
1206 | LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn); | ||
1207 | if (qn < lowest_q) | ||
1208 | { | ||
1209 | best = iter->c; | ||
1210 | lowest_q = qn; | ||
1211 | } | ||
1212 | } | ||
1213 | } | ||
1214 | LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GCC_2s (best)); | ||
1215 | return best; | ||
1216 | } | ||
1217 | |||
1218 | |||
1219 | /** | ||
1220 | * Callback called when a queued message is sent. | ||
1221 | * | ||
1222 | * Calculates the average time and connection packet tracking. | ||
1223 | * | ||
1224 | * @param cls Closure (TunnelQueue handle). | ||
1225 | * @param c Connection this message was on. | ||
1226 | * @param q Connection queue handle (unused). | ||
1227 | * @param type Type of message sent. | ||
1228 | * @param fwd Was this a FWD going message? | ||
1229 | * @param size Size of the message. | ||
1230 | */ | ||
1231 | static void | ||
1232 | tun_message_sent (void *cls, | ||
1233 | struct CadetConnection *c, | ||
1234 | struct CadetConnectionQueue *q, | ||
1235 | uint16_t type, int fwd, size_t size) | ||
1236 | { | ||
1237 | struct CadetTunnelQueue *qt = cls; | ||
1238 | struct CadetTunnel *t; | ||
1239 | |||
1240 | LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n"); | ||
1241 | |||
1242 | GNUNET_assert (NULL != qt->cont); | ||
1243 | t = NULL == c ? NULL : GCC_get_tunnel (c); | ||
1244 | qt->cont (qt->cont_cls, t, qt, type, size); | ||
1245 | GNUNET_free (qt); | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | static unsigned int | ||
1250 | count_queued_data (const struct CadetTunnel *t) | ||
1251 | { | ||
1252 | struct CadetTunnelDelayed *iter; | ||
1253 | unsigned int count; | ||
1254 | |||
1255 | for (count = 0, iter = t->tq_head; iter != NULL; iter = iter->next) | ||
1256 | count++; | ||
1257 | |||
1258 | return count; | ||
1259 | } | ||
1260 | |||
1261 | /** | ||
1262 | * Delete a queued message: either was sent or the channel was destroyed | ||
1263 | * before the tunnel's key exchange had a chance to finish. | ||
1264 | * | ||
1265 | * @param tqd Delayed queue handle. | ||
1266 | */ | ||
1267 | static void | ||
1268 | unqueue_data (struct CadetTunnelDelayed *tqd) | ||
1269 | { | ||
1270 | GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd); | ||
1271 | GNUNET_free (tqd); | ||
1272 | } | ||
1273 | |||
1274 | |||
1275 | /** | ||
1276 | * Cache a message to be sent once tunnel is online. | ||
1277 | * | ||
1278 | * @param t Tunnel to hold the message. | ||
1279 | * @param msg Message itself (copy will be made). | ||
1280 | */ | ||
1281 | static struct CadetTunnelDelayed * | ||
1282 | queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg) | ||
1283 | { | ||
1284 | struct CadetTunnelDelayed *tqd; | ||
1285 | uint16_t size = ntohs (msg->size); | ||
1286 | |||
1287 | LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t)); | ||
1288 | |||
1289 | GNUNET_assert (GNUNET_NO == is_ready (t)); | ||
1290 | |||
1291 | tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size); | ||
1292 | |||
1293 | tqd->t = t; | ||
1294 | GNUNET_memcpy (&tqd[1], msg, size); | ||
1295 | GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd); | ||
1296 | return tqd; | ||
1297 | } | ||
1298 | |||
1299 | |||
1300 | /** | ||
1301 | * Sends an already built message on a tunnel, encrypting it and | ||
1302 | * choosing the best connection. | ||
1303 | * | ||
1304 | * @param message Message to send. Function modifies it. | ||
1305 | * @param t Tunnel on which this message is transmitted. | ||
1306 | * @param c Connection to use (autoselect if NULL). | ||
1307 | * @param force Force the tunnel to take the message (buffer overfill). | ||
1308 | * @param cont Continuation to call once message is really sent. | ||
1309 | * @param cont_cls Closure for @c cont. | ||
1310 | * @param existing_q In case this a transmission of previously queued data, | ||
1311 | * this should be TunnelQueue given to the client. | ||
1312 | * Otherwise, NULL. | ||
1313 | * @return Handle to cancel message. | ||
1314 | * NULL if @c cont is NULL or an error happens and message is dropped. | ||
1315 | */ | ||
1316 | static struct CadetTunnelQueue * | ||
1317 | send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
1318 | struct CadetTunnel *t, | ||
1319 | struct CadetConnection *c, | ||
1320 | int force, | ||
1321 | GCT_sent cont, | ||
1322 | void *cont_cls, | ||
1323 | struct CadetTunnelQueue *existing_q) | ||
1324 | { | ||
1325 | struct GNUNET_MessageHeader *msg; | ||
1326 | struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg; | ||
1327 | struct CadetTunnelQueue *tq; | ||
1328 | size_t size = ntohs (message->size); | ||
1329 | char cbuf[sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size] GNUNET_ALIGN; | ||
1330 | size_t esize; | ||
1331 | uint16_t type; | ||
1332 | int fwd; | ||
1333 | |||
1334 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_2s (t)); | ||
1335 | |||
1336 | if (GNUNET_NO == is_ready (t)) | ||
1337 | { | ||
1338 | struct CadetTunnelDelayed *tqd; | ||
1339 | /* A non null existing_q indicates sending of queued data. | ||
1340 | * Should only happen after tunnel becomes ready. | ||
1341 | */ | ||
1342 | GNUNET_assert (NULL == existing_q); | ||
1343 | tqd = queue_data (t, message); | ||
1344 | if (NULL == cont) | ||
1345 | return NULL; | ||
1346 | tq = GNUNET_new (struct CadetTunnelQueue); | ||
1347 | tq->tqd = tqd; | ||
1348 | tqd->tq = tq; | ||
1349 | tq->cont = cont; | ||
1350 | tq->cont_cls = cont_cls; | ||
1351 | return tq; | ||
1352 | } | ||
1353 | |||
1354 | GNUNET_assert (GNUNET_NO == GCT_is_loopback (t)); | ||
1355 | |||
1356 | ax_msg = (struct GNUNET_CADET_TunnelEncryptedMessage *) cbuf; | ||
1357 | msg = &ax_msg->header; | ||
1358 | msg->size = htons (sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size); | ||
1359 | msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED); | ||
1360 | esize = t_ax_encrypt (t, &ax_msg[1], message, size); | ||
1361 | ax_msg->Ns = htonl (t->ax->Ns++); | ||
1362 | ax_msg->PNs = htonl (t->ax->PNs); | ||
1363 | GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &ax_msg->DHRs); | ||
1364 | t_h_encrypt (t, ax_msg); | ||
1365 | t_hmac (&ax_msg->Ns, AX_HEADER_SIZE + esize, 0, &t->ax->HKs, &ax_msg->hmac); | ||
1366 | GNUNET_assert (esize == size); | ||
1367 | |||
1368 | if (NULL == c) | ||
1369 | c = tunnel_get_connection (t); | ||
1370 | if (NULL == c) | ||
1371 | { | ||
1372 | /* Why is tunnel 'ready'? Should have been queued! */ | ||
1373 | if (NULL != t->destroy_task) | ||
1374 | { | ||
1375 | GNUNET_break (0); | ||
1376 | GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); | ||
1377 | } | ||
1378 | return NULL; /* Drop... */ | ||
1379 | } | ||
1380 | fwd = GCC_is_origin (c, GNUNET_YES); | ||
1381 | ax_msg->cid = *GCC_get_id (c); | ||
1382 | ax_msg->cemi = GCC_get_pid (c, fwd); | ||
1383 | |||
1384 | type = htons (message->type); | ||
1385 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1386 | "Sending message of type %s with CEMI %u and CID %s\n", | ||
1387 | GC_m2s (type), | ||
1388 | htonl (ax_msg->cemi.pid), | ||
1389 | GNUNET_sh2s (&ax_msg->cid.connection_of_tunnel)); | ||
1390 | |||
1391 | if (NULL == cont) | ||
1392 | { | ||
1393 | (void) GCC_send_prebuilt_message (msg, | ||
1394 | type, | ||
1395 | ax_msg->cemi, | ||
1396 | c, | ||
1397 | fwd, | ||
1398 | force, NULL, NULL); | ||
1399 | return NULL; | ||
1400 | } | ||
1401 | if (NULL == existing_q) | ||
1402 | { | ||
1403 | tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/ | ||
1404 | } | ||
1405 | else | ||
1406 | { | ||
1407 | tq = existing_q; | ||
1408 | tq->tqd = NULL; | ||
1409 | } | ||
1410 | tq->cont = cont; | ||
1411 | tq->cont_cls = cont_cls; | ||
1412 | tq->cq = GCC_send_prebuilt_message (msg, | ||
1413 | type, | ||
1414 | ax_msg->cemi, | ||
1415 | c, | ||
1416 | fwd, | ||
1417 | force, | ||
1418 | &tun_message_sent, tq); | ||
1419 | GNUNET_assert (NULL != tq->cq); | ||
1420 | |||
1421 | return tq; | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | /** | ||
1426 | * Send all cached messages that we can, tunnel is online. | ||
1427 | * | ||
1428 | * @param t Tunnel that holds the messages. Cannot be loopback. | ||
1429 | */ | ||
1430 | static void | ||
1431 | send_queued_data (struct CadetTunnel *t) | ||
1432 | { | ||
1433 | struct CadetTunnelDelayed *tqd; | ||
1434 | struct CadetTunnelDelayed *next; | ||
1435 | unsigned int room; | ||
1436 | |||
1437 | LOG (GNUNET_ERROR_TYPE_INFO, "Send queued data, tunnel %s\n", GCT_2s (t)); | ||
1438 | |||
1439 | if (GCT_is_loopback (t)) | ||
1440 | { | ||
1441 | GNUNET_break (0); | ||
1442 | return; | ||
1443 | } | ||
1444 | |||
1445 | if (GNUNET_NO == is_ready (t)) | ||
1446 | { | ||
1447 | LOG (GNUNET_ERROR_TYPE_WARNING, " not ready yet: %s/%s\n", | ||
1448 | estate2s (t->estate), cstate2s (t->cstate)); | ||
1449 | return; | ||
1450 | } | ||
1451 | |||
1452 | room = GCT_get_connections_buffer (t); | ||
1453 | LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); | ||
1454 | LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head); | ||
1455 | for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) | ||
1456 | { | ||
1457 | LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); | ||
1458 | next = tqd->next; | ||
1459 | room--; | ||
1460 | send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1], | ||
1461 | tqd->t, NULL, GNUNET_YES, | ||
1462 | NULL != tqd->tq ? tqd->tq->cont : NULL, | ||
1463 | NULL != tqd->tq ? tqd->tq->cont_cls : NULL, | ||
1464 | tqd->tq); | ||
1465 | unqueue_data (tqd); | ||
1466 | } | ||
1467 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_send_queued_data end\n", GCP_2s (t->peer)); | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | /** | ||
1472 | * @brief Resend the KX until we complete the handshake. | ||
1473 | * | ||
1474 | * @param cls Closure (tunnel). | ||
1475 | */ | ||
1476 | static void | ||
1477 | kx_resend (void *cls) | ||
1478 | { | ||
1479 | struct CadetTunnel *t = cls; | ||
1480 | |||
1481 | t->rekey_task = NULL; | ||
1482 | if (CADET_TUNNEL_KEY_OK == t->estate) | ||
1483 | { | ||
1484 | /* Should have been canceled on estate change */ | ||
1485 | GNUNET_break (0); | ||
1486 | return; | ||
1487 | } | ||
1488 | |||
1489 | GCT_send_kx (t, CADET_TUNNEL_KEY_AX_SENT >= t->estate); | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | /** | ||
1494 | * Callback called when a queued message is sent. | ||
1495 | * | ||
1496 | * @param cls Closure. | ||
1497 | * @param c Connection this message was on. | ||
1498 | * @param type Type of message sent. | ||
1499 | * @param fwd Was this a FWD going message? | ||
1500 | * @param size Size of the message. | ||
1501 | */ | ||
1502 | static void | ||
1503 | ephm_sent (void *cls, | ||
1504 | struct CadetConnection *c, | ||
1505 | struct CadetConnectionQueue *q, | ||
1506 | uint16_t type, int fwd, size_t size) | ||
1507 | { | ||
1508 | struct CadetTunnel *t = cls; | ||
1509 | LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type)); | ||
1510 | |||
1511 | t->ephm_h = NULL; | ||
1512 | |||
1513 | if (CADET_TUNNEL_KEY_OK == t->estate) | ||
1514 | return; | ||
1515 | |||
1516 | if (NULL != t->rekey_task) | ||
1517 | { | ||
1518 | GNUNET_break (0); | ||
1519 | GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); | ||
1520 | GNUNET_SCHEDULER_cancel (t->rekey_task); | ||
1521 | } | ||
1522 | t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
1523 | &kx_resend, t); | ||
1524 | |||
1525 | } | ||
1526 | |||
1527 | |||
1528 | /** | ||
1529 | * Called only on shutdown, destroy every tunnel. | ||
1530 | * | ||
1531 | * @param cls Closure (unused). | ||
1532 | * @param key Current public key. | ||
1533 | * @param value Value in the hash map (tunnel). | ||
1534 | * | ||
1535 | * @return #GNUNET_YES, so we should continue to iterate, | ||
1536 | */ | ||
1537 | static int | ||
1538 | destroy_iterator (void *cls, | ||
1539 | const struct GNUNET_PeerIdentity *key, | ||
1540 | void *value) | ||
1541 | { | ||
1542 | struct CadetTunnel *t = value; | ||
1543 | |||
1544 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1545 | "GCT_shutdown destroying tunnel at %p\n", t); | ||
1546 | GCT_destroy (t); | ||
1547 | return GNUNET_YES; | ||
1548 | } | ||
1549 | |||
1550 | |||
1551 | /** | ||
1552 | * Notify remote peer that we don't know a channel he is talking about, | ||
1553 | * probably CHANNEL_DESTROY was missed. | ||
1554 | * | ||
1555 | * @param t Tunnel on which to notify. | ||
1556 | * @param gid ID of the channel. | ||
1557 | */ | ||
1558 | static void | ||
1559 | send_channel_destroy (struct CadetTunnel *t, | ||
1560 | struct GNUNET_CADET_ChannelTunnelNumber gid) | ||
1561 | { | ||
1562 | struct GNUNET_CADET_ChannelManageMessage msg; | ||
1563 | |||
1564 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); | ||
1565 | msg.header.size = htons (sizeof (msg)); | ||
1566 | msg.ctn = gid; | ||
1567 | |||
1568 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1569 | "WARNING destroying unknown channel %u on tunnel %s\n", | ||
1570 | ntohl (gid.cn), | ||
1571 | GCT_2s (t)); | ||
1572 | send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL); | ||
1573 | } | ||
1574 | |||
1575 | |||
1576 | /** | ||
1577 | * Demultiplex data per channel and call appropriate channel handler. | ||
1578 | * | ||
1579 | * @param t Tunnel on which the data came. | ||
1580 | * @param msg Data message. | ||
1581 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1582 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1583 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1584 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1585 | */ | ||
1586 | static void | ||
1587 | handle_data (struct CadetTunnel *t, | ||
1588 | const struct GNUNET_CADET_ChannelAppDataMessage *msg, | ||
1589 | int fwd) | ||
1590 | { | ||
1591 | struct CadetChannel *ch; | ||
1592 | char buf[128]; | ||
1593 | size_t size; | ||
1594 | uint16_t type; | ||
1595 | |||
1596 | /* Check size */ | ||
1597 | size = ntohs (msg->header.size); | ||
1598 | if (size < | ||
1599 | sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + | ||
1600 | sizeof (struct GNUNET_MessageHeader)) | ||
1601 | { | ||
1602 | GNUNET_break (0); | ||
1603 | return; | ||
1604 | } | ||
1605 | type = ntohs (msg[1].header.type); | ||
1606 | LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", GC_m2s (type)); | ||
1607 | SPRINTF (buf, "# received payload of type %hu", type); | ||
1608 | GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO); | ||
1609 | |||
1610 | |||
1611 | /* Check channel */ | ||
1612 | ch = GCT_get_channel (t, msg->ctn); | ||
1613 | if (NULL == ch) | ||
1614 | { | ||
1615 | GNUNET_STATISTICS_update (stats, | ||
1616 | "# data on unknown channel", | ||
1617 | 1, | ||
1618 | GNUNET_NO); | ||
1619 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1620 | "channel 0x%X unknown\n", | ||
1621 | ntohl (msg->ctn.cn)); | ||
1622 | send_channel_destroy (t, msg->ctn); | ||
1623 | return; | ||
1624 | } | ||
1625 | |||
1626 | GCCH_handle_data (ch, msg, fwd); | ||
1627 | } | ||
1628 | |||
1629 | |||
1630 | /** | ||
1631 | * Demultiplex data ACKs per channel and update appropriate channel buffer info. | ||
1632 | * | ||
1633 | * @param t Tunnel on which the DATA ACK came. | ||
1634 | * @param msg DATA ACK message. | ||
1635 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1636 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1637 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1638 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1639 | */ | ||
1640 | static void | ||
1641 | handle_data_ack (struct CadetTunnel *t, | ||
1642 | const struct GNUNET_CADET_ChannelDataAckMessage *msg, | ||
1643 | int fwd) | ||
1644 | { | ||
1645 | struct CadetChannel *ch; | ||
1646 | size_t size; | ||
1647 | |||
1648 | /* Check size */ | ||
1649 | size = ntohs (msg->header.size); | ||
1650 | if (size != sizeof (struct GNUNET_CADET_ChannelDataAckMessage)) | ||
1651 | { | ||
1652 | GNUNET_break (0); | ||
1653 | return; | ||
1654 | } | ||
1655 | |||
1656 | /* Check channel */ | ||
1657 | ch = GCT_get_channel (t, msg->ctn); | ||
1658 | if (NULL == ch) | ||
1659 | { | ||
1660 | GNUNET_STATISTICS_update (stats, "# data ack on unknown channel", | ||
1661 | 1, GNUNET_NO); | ||
1662 | LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", | ||
1663 | ntohl (msg->ctn.cn)); | ||
1664 | return; | ||
1665 | } | ||
1666 | |||
1667 | GCCH_handle_data_ack (ch, msg, fwd); | ||
1668 | } | ||
1669 | |||
1670 | |||
1671 | /** | ||
1672 | * Handle channel create. | ||
1673 | * | ||
1674 | * @param t Tunnel on which the message came. | ||
1675 | * @param msg ChannelCreate message. | ||
1676 | */ | ||
1677 | static void | ||
1678 | handle_ch_create (struct CadetTunnel *t, | ||
1679 | const struct GNUNET_CADET_ChannelOpenMessage *msg) | ||
1680 | { | ||
1681 | struct CadetChannel *ch; | ||
1682 | size_t size; | ||
1683 | |||
1684 | /* Check size */ | ||
1685 | size = ntohs (msg->header.size); | ||
1686 | if (size != sizeof (struct GNUNET_CADET_ChannelOpenMessage)) | ||
1687 | { | ||
1688 | GNUNET_break_op (0); | ||
1689 | return; | ||
1690 | } | ||
1691 | |||
1692 | /* Check channel */ | ||
1693 | ch = GCT_get_channel (t, msg->ctn); | ||
1694 | if (NULL != ch && ! GCT_is_loopback (t)) | ||
1695 | { | ||
1696 | /* Probably a retransmission, safe to ignore */ | ||
1697 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n"); | ||
1698 | } | ||
1699 | ch = GCCH_handle_create (t, msg); | ||
1700 | if (NULL != ch) | ||
1701 | GCT_add_channel (t, ch); | ||
1702 | } | ||
1703 | |||
1704 | |||
1705 | |||
1706 | /** | ||
1707 | * Handle channel NACK: check correctness and call channel handler for NACKs. | ||
1708 | * | ||
1709 | * @param t Tunnel on which the NACK came. | ||
1710 | * @param msg NACK message. | ||
1711 | */ | ||
1712 | static void | ||
1713 | handle_ch_nack (struct CadetTunnel *t, | ||
1714 | const struct GNUNET_CADET_ChannelManageMessage *msg) | ||
1715 | { | ||
1716 | struct CadetChannel *ch; | ||
1717 | size_t size; | ||
1718 | |||
1719 | /* Check size */ | ||
1720 | size = ntohs (msg->header.size); | ||
1721 | if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) | ||
1722 | { | ||
1723 | GNUNET_break (0); | ||
1724 | return; | ||
1725 | } | ||
1726 | |||
1727 | /* Check channel */ | ||
1728 | ch = GCT_get_channel (t, msg->ctn); | ||
1729 | if (NULL == ch) | ||
1730 | { | ||
1731 | GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel", | ||
1732 | 1, GNUNET_NO); | ||
1733 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1734 | "WARNING channel %u unknown\n", | ||
1735 | ntohl (msg->ctn.cn)); | ||
1736 | return; | ||
1737 | } | ||
1738 | |||
1739 | GCCH_handle_nack (ch); | ||
1740 | } | ||
1741 | |||
1742 | |||
1743 | /** | ||
1744 | * Handle a CHANNEL ACK (SYNACK/ACK). | ||
1745 | * | ||
1746 | * @param t Tunnel on which the CHANNEL ACK came. | ||
1747 | * @param msg CHANNEL ACK message. | ||
1748 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1749 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1750 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1751 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1752 | */ | ||
1753 | static void | ||
1754 | handle_ch_ack (struct CadetTunnel *t, | ||
1755 | const struct GNUNET_CADET_ChannelManageMessage *msg, | ||
1756 | int fwd) | ||
1757 | { | ||
1758 | struct CadetChannel *ch; | ||
1759 | size_t size; | ||
1760 | |||
1761 | /* Check size */ | ||
1762 | size = ntohs (msg->header.size); | ||
1763 | if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) | ||
1764 | { | ||
1765 | GNUNET_break (0); | ||
1766 | return; | ||
1767 | } | ||
1768 | |||
1769 | /* Check channel */ | ||
1770 | ch = GCT_get_channel (t, msg->ctn); | ||
1771 | if (NULL == ch) | ||
1772 | { | ||
1773 | GNUNET_STATISTICS_update (stats, | ||
1774 | "# channel ack on unknown channel", | ||
1775 | 1, | ||
1776 | GNUNET_NO); | ||
1777 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1778 | "WARNING channel %u unknown\n", | ||
1779 | ntohl (msg->ctn.cn)); | ||
1780 | return; | ||
1781 | } | ||
1782 | |||
1783 | GCCH_handle_ack (ch, msg, fwd); | ||
1784 | } | ||
1785 | |||
1786 | |||
1787 | /** | ||
1788 | * Handle a channel destruction message. | ||
1789 | * | ||
1790 | * @param t Tunnel on which the message came. | ||
1791 | * @param msg Channel destroy message. | ||
1792 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1793 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1794 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1795 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1796 | */ | ||
1797 | static void | ||
1798 | handle_ch_destroy (struct CadetTunnel *t, | ||
1799 | const struct GNUNET_CADET_ChannelManageMessage *msg, | ||
1800 | int fwd) | ||
1801 | { | ||
1802 | struct CadetChannel *ch; | ||
1803 | size_t size; | ||
1804 | |||
1805 | /* Check size */ | ||
1806 | size = ntohs (msg->header.size); | ||
1807 | if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) | ||
1808 | { | ||
1809 | GNUNET_break (0); | ||
1810 | return; | ||
1811 | } | ||
1812 | |||
1813 | /* Check channel */ | ||
1814 | ch = GCT_get_channel (t, msg->ctn); | ||
1815 | if (NULL == ch) | ||
1816 | { | ||
1817 | /* Probably a retransmission, safe to ignore */ | ||
1818 | return; | ||
1819 | } | ||
1820 | |||
1821 | GCCH_handle_destroy (ch, msg, fwd); | ||
1822 | } | ||
1823 | |||
1824 | |||
1825 | /** | ||
1826 | * Free Axolotl data. | ||
1827 | * | ||
1828 | * @param t Tunnel. | ||
1829 | */ | ||
1830 | static void | ||
1831 | destroy_ax (struct CadetTunnel *t) | ||
1832 | { | ||
1833 | if (NULL == t->ax) | ||
1834 | return; | ||
1835 | |||
1836 | GNUNET_free_non_null (t->ax->DHRs); | ||
1837 | GNUNET_free_non_null (t->ax->kx_0); | ||
1838 | while (NULL != t->ax->skipped_head) | ||
1839 | delete_skipped_key (t, t->ax->skipped_head); | ||
1840 | GNUNET_assert (0 == t->ax->skipped); | ||
1841 | |||
1842 | GNUNET_free (t->ax); | ||
1843 | t->ax = NULL; | ||
1844 | |||
1845 | if (NULL != t->rekey_task) | ||
1846 | { | ||
1847 | GNUNET_SCHEDULER_cancel (t->rekey_task); | ||
1848 | t->rekey_task = NULL; | ||
1849 | } | ||
1850 | if (NULL != t->ephm_h) | ||
1851 | { | ||
1852 | GCC_cancel (t->ephm_h); | ||
1853 | t->ephm_h = NULL; | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1857 | |||
1858 | /** | ||
1859 | * Demultiplex by message type and call appropriate handler for a message | ||
1860 | * towards a channel of a local tunnel. | ||
1861 | * | ||
1862 | * @param t Tunnel this message came on. | ||
1863 | * @param msgh Message header. | ||
1864 | * @param fwd Is this message fwd? This only is meaningful in loopback channels. | ||
1865 | * #GNUNET_YES if message is FWD on the respective channel (loopback) | ||
1866 | * #GNUNET_NO if message is BCK on the respective channel (loopback) | ||
1867 | * #GNUNET_SYSERR if message on a one-ended channel (remote) | ||
1868 | */ | ||
1869 | static void | ||
1870 | handle_decrypted (struct CadetTunnel *t, | ||
1871 | const struct GNUNET_MessageHeader *msgh, | ||
1872 | int fwd) | ||
1873 | { | ||
1874 | uint16_t type; | ||
1875 | char buf[256]; | ||
1876 | |||
1877 | type = ntohs (msgh->type); | ||
1878 | LOG (GNUNET_ERROR_TYPE_DEBUG, "<-- %s on %s\n", GC_m2s (type), GCT_2s (t)); | ||
1879 | SPRINTF (buf, "# received encrypted of type %hu (%s)", type, GC_m2s (type)); | ||
1880 | GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO); | ||
1881 | |||
1882 | switch (type) | ||
1883 | { | ||
1884 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE: | ||
1885 | /* Do nothing, connection aleady got updated. */ | ||
1886 | GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO); | ||
1887 | break; | ||
1888 | |||
1889 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: | ||
1890 | /* Don't send hop ACK, wait for client to ACK */ | ||
1891 | handle_data (t, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd); | ||
1892 | break; | ||
1893 | |||
1894 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: | ||
1895 | handle_data_ack (t, (struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd); | ||
1896 | break; | ||
1897 | |||
1898 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: | ||
1899 | handle_ch_create (t, (struct GNUNET_CADET_ChannelOpenMessage *) msgh); | ||
1900 | break; | ||
1901 | |||
1902 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED: | ||
1903 | handle_ch_nack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh); | ||
1904 | break; | ||
1905 | |||
1906 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: | ||
1907 | handle_ch_ack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd); | ||
1908 | break; | ||
1909 | |||
1910 | case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: | ||
1911 | handle_ch_destroy (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd); | ||
1912 | break; | ||
1913 | |||
1914 | default: | ||
1915 | GNUNET_break_op (0); | ||
1916 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1917 | "end-to-end message not known (%u)\n", | ||
1918 | ntohs (msgh->type)); | ||
1919 | GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); | ||
1920 | } | ||
1921 | } | ||
1922 | |||
1923 | |||
1924 | /******************************************************************************/ | ||
1925 | /******************************** API ***********************************/ | ||
1926 | /******************************************************************************/ | ||
1927 | |||
1928 | /** | ||
1929 | * Decrypt and process an encrypted message. | ||
1930 | * | ||
1931 | * Calls the appropriate handler for a message in a channel of a local tunnel. | ||
1932 | * | ||
1933 | * @param t Tunnel this message came on. | ||
1934 | * @param msg Message header. | ||
1935 | */ | ||
1936 | void | ||
1937 | GCT_handle_encrypted (struct CadetTunnel *t, | ||
1938 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
1939 | { | ||
1940 | uint16_t size = ntohs (msg->header.size); | ||
1941 | char cbuf [size]; | ||
1942 | int decrypted_size; | ||
1943 | const struct GNUNET_MessageHeader *msgh; | ||
1944 | unsigned int off; | ||
1945 | |||
1946 | GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO); | ||
1947 | |||
1948 | decrypted_size = t_ax_decrypt_and_validate (t, cbuf, msg, size); | ||
1949 | |||
1950 | if (-1 == decrypted_size) | ||
1951 | { | ||
1952 | GNUNET_STATISTICS_update (stats, "# unable to decrypt", 1, GNUNET_NO); | ||
1953 | if (CADET_TUNNEL_KEY_AX_AUTH_SENT <= t->estate) | ||
1954 | { | ||
1955 | GNUNET_break_op (0); | ||
1956 | LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong crypto, tunnel %s\n", GCT_2s (t)); | ||
1957 | GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); | ||
1958 | } | ||
1959 | return; | ||
1960 | } | ||
1961 | GCT_change_estate (t, CADET_TUNNEL_KEY_OK); | ||
1962 | |||
1963 | /* FIXME: this is bad, as the structs returned from | ||
1964 | this loop may be unaligned, see util's MST for | ||
1965 | how to do this right. */ | ||
1966 | off = 0; | ||
1967 | while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size) | ||
1968 | { | ||
1969 | uint16_t msize; | ||
1970 | |||
1971 | msgh = (const struct GNUNET_MessageHeader *) &cbuf[off]; | ||
1972 | msize = ntohs (msgh->size); | ||
1973 | if (msize < sizeof (struct GNUNET_MessageHeader)) | ||
1974 | { | ||
1975 | GNUNET_break_op (0); | ||
1976 | return; | ||
1977 | } | ||
1978 | if (off + msize < decrypted_size) | ||
1979 | { | ||
1980 | GNUNET_break_op (0); | ||
1981 | return; | ||
1982 | } | ||
1983 | handle_decrypted (t, msgh, GNUNET_SYSERR); | ||
1984 | off += msize; | ||
1985 | } | ||
1986 | } | ||
1987 | |||
1988 | |||
1989 | /** | ||
1990 | * Handle a Key eXchange message. | ||
1991 | * | ||
1992 | * @param t Tunnel on which the message came. | ||
1993 | * @param msg KX message itself. | ||
1994 | */ | ||
1995 | void | ||
1996 | GCT_handle_kx (struct CadetTunnel *t, | ||
1997 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | ||
1998 | { | ||
1999 | struct CadetTunnelAxolotl *ax; | ||
2000 | struct GNUNET_HashCode key_material[3]; | ||
2001 | struct GNUNET_CRYPTO_SymmetricSessionKey keys[5]; | ||
2002 | const char salt[] = "CADET Axolotl salt"; | ||
2003 | const struct GNUNET_PeerIdentity *pid; | ||
2004 | int am_I_alice; | ||
2005 | |||
2006 | CADET_TIMING_START; | ||
2007 | |||
2008 | LOG (GNUNET_ERROR_TYPE_INFO, "<== { KX} on %s\n", GCT_2s (t)); | ||
2009 | |||
2010 | if (NULL == t->ax) | ||
2011 | { | ||
2012 | /* Something is wrong if ax is NULL. Whose fault it is? */ | ||
2013 | return; | ||
2014 | } | ||
2015 | ax = t->ax; | ||
2016 | |||
2017 | pid = GCT_get_destination (t); | ||
2018 | if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid)) | ||
2019 | am_I_alice = GNUNET_YES; | ||
2020 | else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid)) | ||
2021 | am_I_alice = GNUNET_NO; | ||
2022 | else | ||
2023 | { | ||
2024 | GNUNET_break_op (0); | ||
2025 | return; | ||
2026 | } | ||
2027 | |||
2028 | if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags))) | ||
2029 | { | ||
2030 | if (NULL != t->rekey_task) | ||
2031 | { | ||
2032 | GNUNET_SCHEDULER_cancel (t->rekey_task); | ||
2033 | t->rekey_task = NULL; | ||
2034 | } | ||
2035 | GCT_send_kx (t, GNUNET_NO); | ||
2036 | } | ||
2037 | |||
2038 | if (0 == memcmp (&ax->DHRr, &msg->ratchet_key, sizeof(msg->ratchet_key))) | ||
2039 | { | ||
2040 | LOG (GNUNET_ERROR_TYPE_INFO, " known ratchet key, exit\n"); | ||
2041 | return; | ||
2042 | } | ||
2043 | |||
2044 | LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO"); | ||
2045 | |||
2046 | ax->DHRr = msg->ratchet_key; | ||
2047 | |||
2048 | /* ECDH A B0 */ | ||
2049 | if (GNUNET_YES == am_I_alice) | ||
2050 | { | ||
2051 | GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */ | ||
2052 | &msg->ephemeral_key, /* B0 */ | ||
2053 | &key_material[0]); | ||
2054 | } | ||
2055 | else | ||
2056 | { | ||
2057 | GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */ | ||
2058 | &pid->public_key, /* A */ | ||
2059 | &key_material[0]); | ||
2060 | } | ||
2061 | |||
2062 | /* ECDH A0 B */ | ||
2063 | if (GNUNET_YES == am_I_alice) | ||
2064 | { | ||
2065 | GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */ | ||
2066 | &pid->public_key, /* B */ | ||
2067 | &key_material[1]); | ||
2068 | } | ||
2069 | else | ||
2070 | { | ||
2071 | GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */ | ||
2072 | &msg->ephemeral_key, /* B0 */ | ||
2073 | &key_material[1]); | ||
2074 | |||
2075 | |||
2076 | } | ||
2077 | |||
2078 | /* ECDH A0 B0 */ | ||
2079 | /* (This is the triple-DH, we could probably safely skip this, | ||
2080 | as A0/B0 are already in the key material.) */ | ||
2081 | GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */ | ||
2082 | &msg->ephemeral_key, /* B0 or A0 */ | ||
2083 | &key_material[2]); | ||
2084 | |||
2085 | #if DUMP_KEYS_TO_STDERR | ||
2086 | { | ||
2087 | unsigned int i; | ||
2088 | for (i = 0; i < 3; i++) | ||
2089 | LOG (GNUNET_ERROR_TYPE_INFO, "km[%u]: %s\n", | ||
2090 | i, GNUNET_h2s (&key_material[i])); | ||
2091 | } | ||
2092 | #endif | ||
2093 | |||
2094 | /* KDF */ | ||
2095 | GNUNET_CRYPTO_kdf (keys, sizeof (keys), | ||
2096 | salt, sizeof (salt), | ||
2097 | &key_material, sizeof (key_material), NULL); | ||
2098 | |||
2099 | if (0 == memcmp (&ax->RK, &keys[0], sizeof(ax->RK))) | ||
2100 | { | ||
2101 | LOG (GNUNET_ERROR_TYPE_INFO, " known handshake key, exit\n"); | ||
2102 | return; | ||
2103 | } | ||
2104 | ax->RK = keys[0]; | ||
2105 | if (GNUNET_YES == am_I_alice) | ||
2106 | { | ||
2107 | ax->HKr = keys[1]; | ||
2108 | ax->NHKs = keys[2]; | ||
2109 | ax->NHKr = keys[3]; | ||
2110 | ax->CKr = keys[4]; | ||
2111 | ax->ratchet_flag = GNUNET_YES; | ||
2112 | } | ||
2113 | else | ||
2114 | { | ||
2115 | ax->HKs = keys[1]; | ||
2116 | ax->NHKr = keys[2]; | ||
2117 | ax->NHKs = keys[3]; | ||
2118 | ax->CKs = keys[4]; | ||
2119 | ax->ratchet_flag = GNUNET_NO; | ||
2120 | ax->ratchet_allowed = GNUNET_NO; | ||
2121 | ax->ratchet_counter = 0; | ||
2122 | ax->ratchet_expiration = | ||
2123 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time); | ||
2124 | } | ||
2125 | ax->PNs = 0; | ||
2126 | ax->Nr = 0; | ||
2127 | ax->Ns = 0; | ||
2128 | |||
2129 | GCT_change_estate (t, CADET_TUNNEL_KEY_AX_AUTH_SENT); | ||
2130 | send_queued_data (t); | ||
2131 | |||
2132 | CADET_TIMING_END; | ||
2133 | } | ||
2134 | |||
2135 | /** | ||
2136 | * Initialize the tunnel subsystem. | ||
2137 | * | ||
2138 | * @param c Configuration handle. | ||
2139 | * @param key ECC private key, to derive all other keys and do crypto. | ||
2140 | */ | ||
2141 | void | ||
2142 | GCT_init (const struct GNUNET_CONFIGURATION_Handle *c, | ||
2143 | const struct GNUNET_CRYPTO_EddsaPrivateKey *key) | ||
2144 | { | ||
2145 | unsigned int expected_overhead; | ||
2146 | |||
2147 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); | ||
2148 | |||
2149 | expected_overhead = 0; | ||
2150 | expected_overhead += sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); | ||
2151 | expected_overhead += sizeof (struct GNUNET_CADET_ChannelAppDataMessage); | ||
2152 | expected_overhead += sizeof (struct GNUNET_CADET_ConnectionEncryptedAckMessage); | ||
2153 | GNUNET_assert (GNUNET_CONSTANTS_CADET_P2P_OVERHEAD == expected_overhead); | ||
2154 | |||
2155 | if (GNUNET_OK != | ||
2156 | GNUNET_CONFIGURATION_get_value_number (c, | ||
2157 | "CADET", | ||
2158 | "RATCHET_MESSAGES", | ||
2159 | &ratchet_messages)) | ||
2160 | { | ||
2161 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
2162 | "CADET", | ||
2163 | "RATCHET_MESSAGES", | ||
2164 | "USING DEFAULT"); | ||
2165 | ratchet_messages = 64; | ||
2166 | } | ||
2167 | if (GNUNET_OK != | ||
2168 | GNUNET_CONFIGURATION_get_value_time (c, | ||
2169 | "CADET", | ||
2170 | "RATCHET_TIME", | ||
2171 | &ratchet_time)) | ||
2172 | { | ||
2173 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
2174 | "CADET", "RATCHET_TIME", "USING DEFAULT"); | ||
2175 | ratchet_time = GNUNET_TIME_UNIT_HOURS; | ||
2176 | } | ||
2177 | |||
2178 | |||
2179 | id_key = key; | ||
2180 | tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); | ||
2181 | } | ||
2182 | |||
2183 | |||
2184 | /** | ||
2185 | * Shut down the tunnel subsystem. | ||
2186 | */ | ||
2187 | void | ||
2188 | GCT_shutdown (void) | ||
2189 | { | ||
2190 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down tunnels\n"); | ||
2191 | GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL); | ||
2192 | GNUNET_CONTAINER_multipeermap_destroy (tunnels); | ||
2193 | } | ||
2194 | |||
2195 | |||
2196 | /** | ||
2197 | * Create a tunnel. | ||
2198 | * | ||
2199 | * @param destination Peer this tunnel is towards. | ||
2200 | */ | ||
2201 | struct CadetTunnel * | ||
2202 | GCT_new (struct CadetPeer *destination) | ||
2203 | { | ||
2204 | struct CadetTunnel *t; | ||
2205 | |||
2206 | t = GNUNET_new (struct CadetTunnel); | ||
2207 | t->next_ctn.cn = 0; | ||
2208 | t->peer = destination; | ||
2209 | |||
2210 | if (GNUNET_OK != | ||
2211 | GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t, | ||
2212 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) | ||
2213 | { | ||
2214 | GNUNET_break (0); | ||
2215 | GNUNET_free (t); | ||
2216 | return NULL; | ||
2217 | } | ||
2218 | t->ax = GNUNET_new (struct CadetTunnelAxolotl); | ||
2219 | new_ephemeral (t); | ||
2220 | t->ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); | ||
2221 | return t; | ||
2222 | } | ||
2223 | |||
2224 | |||
2225 | /** | ||
2226 | * Change the tunnel's connection state. | ||
2227 | * | ||
2228 | * @param t Tunnel whose connection state to change. | ||
2229 | * @param cstate New connection state. | ||
2230 | */ | ||
2231 | void | ||
2232 | GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate) | ||
2233 | { | ||
2234 | if (NULL == t) | ||
2235 | return; | ||
2236 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n", | ||
2237 | GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate)); | ||
2238 | if (myid != GCP_get_short_id (t->peer) && | ||
2239 | CADET_TUNNEL_READY != t->cstate && | ||
2240 | CADET_TUNNEL_READY == cstate) | ||
2241 | { | ||
2242 | t->cstate = cstate; | ||
2243 | if (CADET_TUNNEL_KEY_OK == t->estate) | ||
2244 | { | ||
2245 | LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n"); | ||
2246 | send_queued_data (t); | ||
2247 | } | ||
2248 | else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) | ||
2249 | { | ||
2250 | LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered KX\n"); | ||
2251 | GCT_send_kx (t, GNUNET_NO); | ||
2252 | } | ||
2253 | else | ||
2254 | { | ||
2255 | LOG (GNUNET_ERROR_TYPE_DEBUG, "estate %s\n", estate2s (t->estate)); | ||
2256 | } | ||
2257 | } | ||
2258 | t->cstate = cstate; | ||
2259 | |||
2260 | if (CADET_TUNNEL_READY == cstate | ||
2261 | && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t)) | ||
2262 | { | ||
2263 | LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n"); | ||
2264 | GCP_stop_search (t->peer); | ||
2265 | } | ||
2266 | } | ||
2267 | |||
2268 | |||
2269 | /** | ||
2270 | * Change the tunnel encryption state. | ||
2271 | * | ||
2272 | * If the encryption state changes to OK, stop the rekey task. | ||
2273 | * | ||
2274 | * @param t Tunnel whose encryption state to change, or NULL. | ||
2275 | * @param state New encryption state. | ||
2276 | */ | ||
2277 | void | ||
2278 | GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state) | ||
2279 | { | ||
2280 | enum CadetTunnelEState old; | ||
2281 | |||
2282 | if (NULL == t) | ||
2283 | return; | ||
2284 | |||
2285 | old = t->estate; | ||
2286 | t->estate = state; | ||
2287 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate was %s\n", | ||
2288 | GCP_2s (t->peer), estate2s (old)); | ||
2289 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate is now %s\n", | ||
2290 | GCP_2s (t->peer), estate2s (t->estate)); | ||
2291 | |||
2292 | if (CADET_TUNNEL_KEY_OK != old && CADET_TUNNEL_KEY_OK == t->estate) | ||
2293 | { | ||
2294 | if (NULL != t->rekey_task) | ||
2295 | { | ||
2296 | GNUNET_SCHEDULER_cancel (t->rekey_task); | ||
2297 | t->rekey_task = NULL; | ||
2298 | } | ||
2299 | /* Send queued data if tunnel is not loopback */ | ||
2300 | if (myid != GCP_get_short_id (t->peer)) | ||
2301 | send_queued_data (t); | ||
2302 | } | ||
2303 | } | ||
2304 | |||
2305 | |||
2306 | /** | ||
2307 | * @brief Check if tunnel has too many connections, and remove one if necessary. | ||
2308 | * | ||
2309 | * Currently this means the newest connection, unless it is a direct one. | ||
2310 | * Implemented as a task to avoid freeing a connection that is in the middle | ||
2311 | * of being created/processed. | ||
2312 | * | ||
2313 | * @param cls Closure (Tunnel to check). | ||
2314 | */ | ||
2315 | static void | ||
2316 | trim_connections (void *cls) | ||
2317 | { | ||
2318 | struct CadetTunnel *t = cls; | ||
2319 | |||
2320 | t->trim_connections_task = NULL; | ||
2321 | if (GCT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL) | ||
2322 | { | ||
2323 | struct CadetTConnection *iter; | ||
2324 | struct CadetTConnection *c; | ||
2325 | |||
2326 | for (c = iter = t->connection_head; NULL != iter; iter = iter->next) | ||
2327 | { | ||
2328 | if ((iter->created.abs_value_us > c->created.abs_value_us) | ||
2329 | && GNUNET_NO == GCC_is_direct (iter->c)) | ||
2330 | { | ||
2331 | c = iter; | ||
2332 | } | ||
2333 | } | ||
2334 | if (NULL != c) | ||
2335 | { | ||
2336 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n", | ||
2337 | GCT_2s (t)); | ||
2338 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n", | ||
2339 | GCC_2s (c->c)); | ||
2340 | GCC_destroy (c->c); | ||
2341 | } | ||
2342 | else | ||
2343 | { | ||
2344 | GNUNET_break (0); | ||
2345 | } | ||
2346 | } | ||
2347 | } | ||
2348 | |||
2349 | |||
2350 | /** | ||
2351 | * Add a connection to a tunnel. | ||
2352 | * | ||
2353 | * @param t Tunnel. | ||
2354 | * @param c Connection. | ||
2355 | */ | ||
2356 | void | ||
2357 | GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c) | ||
2358 | { | ||
2359 | struct CadetTConnection *aux; | ||
2360 | |||
2361 | GNUNET_assert (NULL != c); | ||
2362 | |||
2363 | LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c)); | ||
2364 | LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_2s (t)); | ||
2365 | for (aux = t->connection_head; aux != NULL; aux = aux->next) | ||
2366 | if (aux->c == c) | ||
2367 | return; | ||
2368 | |||
2369 | aux = GNUNET_new (struct CadetTConnection); | ||
2370 | aux->c = c; | ||
2371 | aux->created = GNUNET_TIME_absolute_get (); | ||
2372 | |||
2373 | GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux); | ||
2374 | |||
2375 | if (CADET_TUNNEL_SEARCHING == t->cstate) | ||
2376 | GCT_change_cstate (t, CADET_TUNNEL_WAITING); | ||
2377 | |||
2378 | if (NULL != t->trim_connections_task) | ||
2379 | t->trim_connections_task = GNUNET_SCHEDULER_add_now (&trim_connections, t); | ||
2380 | } | ||
2381 | |||
2382 | |||
2383 | /** | ||
2384 | * Remove a connection from a tunnel. | ||
2385 | * | ||
2386 | * @param t Tunnel. | ||
2387 | * @param c Connection. | ||
2388 | */ | ||
2389 | void | ||
2390 | GCT_remove_connection (struct CadetTunnel *t, | ||
2391 | struct CadetConnection *c) | ||
2392 | { | ||
2393 | struct CadetTConnection *aux; | ||
2394 | struct CadetTConnection *next; | ||
2395 | unsigned int conns; | ||
2396 | |||
2397 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n", | ||
2398 | GCC_2s (c), GCT_2s (t)); | ||
2399 | for (aux = t->connection_head; aux != NULL; aux = next) | ||
2400 | { | ||
2401 | next = aux->next; | ||
2402 | if (aux->c == c) | ||
2403 | { | ||
2404 | GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); | ||
2405 | GNUNET_free (aux); | ||
2406 | } | ||
2407 | } | ||
2408 | |||
2409 | conns = GCT_count_connections (t); | ||
2410 | if (0 == conns | ||
2411 | && NULL == t->destroy_task | ||
2412 | && CADET_TUNNEL_SHUTDOWN != t->cstate | ||
2413 | && GNUNET_NO == shutting_down) | ||
2414 | { | ||
2415 | if (0 == GCT_count_any_connections (t)) | ||
2416 | GCT_change_cstate (t, CADET_TUNNEL_SEARCHING); | ||
2417 | else | ||
2418 | GCT_change_cstate (t, CADET_TUNNEL_WAITING); | ||
2419 | } | ||
2420 | |||
2421 | /* Start new connections if needed */ | ||
2422 | if (CONNECTIONS_PER_TUNNEL > conns | ||
2423 | && CADET_TUNNEL_SHUTDOWN != t->cstate | ||
2424 | && GNUNET_NO == shutting_down) | ||
2425 | { | ||
2426 | LOG (GNUNET_ERROR_TYPE_DEBUG, " too few connections, getting new ones\n"); | ||
2427 | GCP_connect (t->peer); /* Will change cstate to WAITING when possible */ | ||
2428 | return; | ||
2429 | } | ||
2430 | |||
2431 | /* If not marked as ready, no change is needed */ | ||
2432 | if (CADET_TUNNEL_READY != t->cstate) | ||
2433 | return; | ||
2434 | |||
2435 | /* Check if any connection is ready to maintain cstate */ | ||
2436 | for (aux = t->connection_head; aux != NULL; aux = aux->next) | ||
2437 | if (CADET_CONNECTION_READY == GCC_get_state (aux->c)) | ||
2438 | return; | ||
2439 | } | ||
2440 | |||
2441 | |||
2442 | /** | ||
2443 | * Add a channel to a tunnel. | ||
2444 | * | ||
2445 | * @param t Tunnel. | ||
2446 | * @param ch Channel. | ||
2447 | */ | ||
2448 | void | ||
2449 | GCT_add_channel (struct CadetTunnel *t, | ||
2450 | struct CadetChannel *ch) | ||
2451 | { | ||
2452 | struct CadetTChannel *aux; | ||
2453 | |||
2454 | GNUNET_assert (NULL != ch); | ||
2455 | |||
2456 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t); | ||
2457 | |||
2458 | for (aux = t->channel_head; aux != NULL; aux = aux->next) | ||
2459 | { | ||
2460 | LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch); | ||
2461 | if (aux->ch == ch) | ||
2462 | return; | ||
2463 | } | ||
2464 | |||
2465 | aux = GNUNET_new (struct CadetTChannel); | ||
2466 | aux->ch = ch; | ||
2467 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2468 | " adding %p to %p\n", aux, t->channel_head); | ||
2469 | GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, | ||
2470 | t->channel_tail, | ||
2471 | aux); | ||
2472 | |||
2473 | if (NULL != t->destroy_task) | ||
2474 | { | ||
2475 | GNUNET_SCHEDULER_cancel (t->destroy_task); | ||
2476 | t->destroy_task = NULL; | ||
2477 | LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n"); | ||
2478 | } | ||
2479 | } | ||
2480 | |||
2481 | |||
2482 | /** | ||
2483 | * Remove a channel from a tunnel. | ||
2484 | * | ||
2485 | * @param t Tunnel. | ||
2486 | * @param ch Channel. | ||
2487 | */ | ||
2488 | void | ||
2489 | GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch) | ||
2490 | { | ||
2491 | struct CadetTChannel *aux; | ||
2492 | |||
2493 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t); | ||
2494 | for (aux = t->channel_head; aux != NULL; aux = aux->next) | ||
2495 | { | ||
2496 | if (aux->ch == ch) | ||
2497 | { | ||
2498 | LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GCCH_2s (ch)); | ||
2499 | GNUNET_CONTAINER_DLL_remove (t->channel_head, | ||
2500 | t->channel_tail, | ||
2501 | aux); | ||
2502 | GNUNET_free (aux); | ||
2503 | return; | ||
2504 | } | ||
2505 | } | ||
2506 | } | ||
2507 | |||
2508 | |||
2509 | /** | ||
2510 | * Search for a channel by global ID. | ||
2511 | * | ||
2512 | * @param t Tunnel containing the channel. | ||
2513 | * @param ctn Public channel number. | ||
2514 | * | ||
2515 | * @return channel handler, NULL if doesn't exist | ||
2516 | */ | ||
2517 | struct CadetChannel * | ||
2518 | GCT_get_channel (struct CadetTunnel *t, | ||
2519 | struct GNUNET_CADET_ChannelTunnelNumber ctn) | ||
2520 | { | ||
2521 | struct CadetTChannel *iter; | ||
2522 | |||
2523 | if (NULL == t) | ||
2524 | return NULL; | ||
2525 | |||
2526 | for (iter = t->channel_head; NULL != iter; iter = iter->next) | ||
2527 | { | ||
2528 | if (GCCH_get_id (iter->ch).cn == ctn.cn) | ||
2529 | break; | ||
2530 | } | ||
2531 | |||
2532 | return NULL == iter ? NULL : iter->ch; | ||
2533 | } | ||
2534 | |||
2535 | |||
2536 | /** | ||
2537 | * @brief Destroy a tunnel and free all resources. | ||
2538 | * | ||
2539 | * Should only be called a while after the tunnel has been marked as destroyed, | ||
2540 | * in case there is a new channel added to the same peer shortly after marking | ||
2541 | * the tunnel. This way we avoid a new public key handshake. | ||
2542 | * | ||
2543 | * @param cls Closure (tunnel to destroy). | ||
2544 | */ | ||
2545 | static void | ||
2546 | delayed_destroy (void *cls) | ||
2547 | { | ||
2548 | struct CadetTunnel *t = cls; | ||
2549 | struct CadetTConnection *iter; | ||
2550 | |||
2551 | t->destroy_task = NULL; | ||
2552 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2553 | "delayed destroying tunnel %p\n", | ||
2554 | t); | ||
2555 | t->cstate = CADET_TUNNEL_SHUTDOWN; | ||
2556 | for (iter = t->connection_head; NULL != iter; iter = iter->next) | ||
2557 | { | ||
2558 | GCC_send_destroy (iter->c); | ||
2559 | } | ||
2560 | GCT_destroy (t); | ||
2561 | } | ||
2562 | |||
2563 | |||
2564 | /** | ||
2565 | * Tunnel is empty: destroy it. | ||
2566 | * | ||
2567 | * Notifies all connections about the destruction. | ||
2568 | * | ||
2569 | * @param t Tunnel to destroy. | ||
2570 | */ | ||
2571 | void | ||
2572 | GCT_destroy_empty (struct CadetTunnel *t) | ||
2573 | { | ||
2574 | if (GNUNET_YES == shutting_down) | ||
2575 | return; /* Will be destroyed immediately anyway */ | ||
2576 | |||
2577 | if (NULL != t->destroy_task) | ||
2578 | { | ||
2579 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2580 | "Tunnel %s is already scheduled for destruction. Tunnel debug dump:\n", | ||
2581 | GCT_2s (t)); | ||
2582 | GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); | ||
2583 | GNUNET_break (0); | ||
2584 | /* should never happen, tunnel can only become empty once, and the | ||
2585 | * task identifier should be NO_TASK (cleaned when the tunnel was created | ||
2586 | * or became un-empty) | ||
2587 | */ | ||
2588 | return; | ||
2589 | } | ||
2590 | |||
2591 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: scheduling destruction\n", | ||
2592 | GCT_2s (t)); | ||
2593 | |||
2594 | // FIXME make delay a config option | ||
2595 | t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2596 | &delayed_destroy, t); | ||
2597 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %p\n", | ||
2598 | t, t->destroy_task); | ||
2599 | } | ||
2600 | |||
2601 | |||
2602 | /** | ||
2603 | * Destroy tunnel if empty (no more channels). | ||
2604 | * | ||
2605 | * @param t Tunnel to destroy if empty. | ||
2606 | */ | ||
2607 | void | ||
2608 | GCT_destroy_if_empty (struct CadetTunnel *t) | ||
2609 | { | ||
2610 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t)); | ||
2611 | if (0 < GCT_count_channels (t)) | ||
2612 | return; | ||
2613 | |||
2614 | GCT_destroy_empty (t); | ||
2615 | } | ||
2616 | |||
2617 | |||
2618 | /** | ||
2619 | * Destroy the tunnel. | ||
2620 | * | ||
2621 | * This function does not generate any warning traffic to clients or peers. | ||
2622 | * | ||
2623 | * Tasks: | ||
2624 | * Cancel messages belonging to this tunnel queued to neighbors. | ||
2625 | * Free any allocated resources linked to the tunnel. | ||
2626 | * | ||
2627 | * @param t The tunnel to destroy. | ||
2628 | */ | ||
2629 | void | ||
2630 | GCT_destroy (struct CadetTunnel *t) | ||
2631 | { | ||
2632 | struct CadetTConnection *iter_c; | ||
2633 | struct CadetTConnection *next_c; | ||
2634 | struct CadetTChannel *iter_ch; | ||
2635 | struct CadetTChannel *next_ch; | ||
2636 | unsigned int keepalives_queued; | ||
2637 | |||
2638 | if (NULL == t) | ||
2639 | return; | ||
2640 | |||
2641 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2642 | "destroying tunnel %s\n", | ||
2643 | GCP_2s (t->peer)); | ||
2644 | GNUNET_break (GNUNET_YES == | ||
2645 | GNUNET_CONTAINER_multipeermap_remove (tunnels, | ||
2646 | GCP_get_id (t->peer), t)); | ||
2647 | |||
2648 | for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c) | ||
2649 | { | ||
2650 | next_c = iter_c->next; | ||
2651 | GCC_destroy (iter_c->c); | ||
2652 | } | ||
2653 | for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch) | ||
2654 | { | ||
2655 | next_ch = iter_ch->next; | ||
2656 | GCCH_destroy (iter_ch->ch); | ||
2657 | /* Should only happen on shutdown, but it's ok. */ | ||
2658 | } | ||
2659 | keepalives_queued = 0; | ||
2660 | while (NULL != t->tq_head) | ||
2661 | { | ||
2662 | /* Should have been cleaned by destuction of channel. */ | ||
2663 | struct GNUNET_MessageHeader *mh; | ||
2664 | uint16_t type; | ||
2665 | |||
2666 | mh = (struct GNUNET_MessageHeader *) &t->tq_head[1]; | ||
2667 | type = ntohs (mh->type); | ||
2668 | if (0 == keepalives_queued && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE == type) | ||
2669 | { | ||
2670 | keepalives_queued = 1; | ||
2671 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2672 | "one keepalive left behind on tunnel shutdown\n"); | ||
2673 | } | ||
2674 | else if (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY == type) | ||
2675 | { | ||
2676 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2677 | "tunnel destroyed before a CHANNEL_DESTROY was sent to peer\n"); | ||
2678 | } | ||
2679 | else | ||
2680 | { | ||
2681 | GNUNET_break (0); | ||
2682 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2683 | "message left behind on tunnel shutdown: %s\n", | ||
2684 | GC_m2s (type)); | ||
2685 | } | ||
2686 | unqueue_data (t->tq_head); | ||
2687 | } | ||
2688 | |||
2689 | |||
2690 | if (NULL != t->destroy_task) | ||
2691 | { | ||
2692 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2693 | "cancelling dest: %p\n", | ||
2694 | t->destroy_task); | ||
2695 | GNUNET_SCHEDULER_cancel (t->destroy_task); | ||
2696 | t->destroy_task = NULL; | ||
2697 | } | ||
2698 | |||
2699 | if (NULL != t->trim_connections_task) | ||
2700 | { | ||
2701 | LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling trim: %p\n", | ||
2702 | t->trim_connections_task); | ||
2703 | GNUNET_SCHEDULER_cancel (t->trim_connections_task); | ||
2704 | t->trim_connections_task = NULL; | ||
2705 | } | ||
2706 | |||
2707 | GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO); | ||
2708 | GCP_set_tunnel (t->peer, NULL); | ||
2709 | |||
2710 | if (NULL != t->rekey_task) | ||
2711 | { | ||
2712 | GNUNET_SCHEDULER_cancel (t->rekey_task); | ||
2713 | t->rekey_task = NULL; | ||
2714 | } | ||
2715 | if (NULL != t->ax) | ||
2716 | destroy_ax (t); | ||
2717 | |||
2718 | GNUNET_free (t); | ||
2719 | } | ||
2720 | |||
2721 | |||
2722 | /** | ||
2723 | * @brief Use the given path for the tunnel. | ||
2724 | * Update the next and prev hops (and RCs). | ||
2725 | * (Re)start the path refresh in case the tunnel is locally owned. | ||
2726 | * | ||
2727 | * @param t Tunnel to update. | ||
2728 | * @param p Path to use. | ||
2729 | * | ||
2730 | * @return Connection created. | ||
2731 | */ | ||
2732 | struct CadetConnection * | ||
2733 | GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *path) | ||
2734 | { | ||
2735 | struct CadetConnection *c; | ||
2736 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
2737 | unsigned int own_pos; | ||
2738 | |||
2739 | if (NULL == t || NULL == path) | ||
2740 | { | ||
2741 | GNUNET_break (0); | ||
2742 | return NULL; | ||
2743 | } | ||
2744 | |||
2745 | if (CADET_TUNNEL_SHUTDOWN == t->cstate) | ||
2746 | { | ||
2747 | GNUNET_break (0); | ||
2748 | return NULL; | ||
2749 | } | ||
2750 | |||
2751 | for (own_pos = 0; own_pos < path->length; own_pos++) | ||
2752 | { | ||
2753 | if (path->peers[own_pos] == myid) | ||
2754 | break; | ||
2755 | } | ||
2756 | if (own_pos >= path->length) | ||
2757 | { | ||
2758 | GNUNET_break_op (0); | ||
2759 | return NULL; | ||
2760 | } | ||
2761 | |||
2762 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid)); | ||
2763 | c = GCC_new (&cid, t, path, own_pos); | ||
2764 | if (NULL == c) | ||
2765 | { | ||
2766 | /* Path was flawed */ | ||
2767 | return NULL; | ||
2768 | } | ||
2769 | GCT_add_connection (t, c); | ||
2770 | return c; | ||
2771 | } | ||
2772 | |||
2773 | |||
2774 | /** | ||
2775 | * Count all created connections of a tunnel. Not necessarily ready connections! | ||
2776 | * | ||
2777 | * @param t Tunnel on which to count. | ||
2778 | * | ||
2779 | * @return Number of connections created, either being established or ready. | ||
2780 | */ | ||
2781 | unsigned int | ||
2782 | GCT_count_any_connections (struct CadetTunnel *t) | ||
2783 | { | ||
2784 | struct CadetTConnection *iter; | ||
2785 | unsigned int count; | ||
2786 | |||
2787 | if (NULL == t) | ||
2788 | return 0; | ||
2789 | |||
2790 | for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) | ||
2791 | count++; | ||
2792 | |||
2793 | return count; | ||
2794 | } | ||
2795 | |||
2796 | |||
2797 | /** | ||
2798 | * Count established (ready) connections of a tunnel. | ||
2799 | * | ||
2800 | * @param t Tunnel on which to count. | ||
2801 | * | ||
2802 | * @return Number of connections. | ||
2803 | */ | ||
2804 | unsigned int | ||
2805 | GCT_count_connections (struct CadetTunnel *t) | ||
2806 | { | ||
2807 | struct CadetTConnection *iter; | ||
2808 | unsigned int count; | ||
2809 | |||
2810 | if (NULL == t) | ||
2811 | return 0; | ||
2812 | |||
2813 | for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) | ||
2814 | if (CADET_CONNECTION_READY == GCC_get_state (iter->c)) | ||
2815 | count++; | ||
2816 | |||
2817 | return count; | ||
2818 | } | ||
2819 | |||
2820 | |||
2821 | /** | ||
2822 | * Count channels of a tunnel. | ||
2823 | * | ||
2824 | * @param t Tunnel on which to count. | ||
2825 | * | ||
2826 | * @return Number of channels. | ||
2827 | */ | ||
2828 | unsigned int | ||
2829 | GCT_count_channels (struct CadetTunnel *t) | ||
2830 | { | ||
2831 | struct CadetTChannel *iter; | ||
2832 | unsigned int count; | ||
2833 | |||
2834 | for (count = 0, iter = t->channel_head; | ||
2835 | NULL != iter; | ||
2836 | iter = iter->next, count++) /* skip */; | ||
2837 | |||
2838 | return count; | ||
2839 | } | ||
2840 | |||
2841 | |||
2842 | /** | ||
2843 | * Get the connectivity state of a tunnel. | ||
2844 | * | ||
2845 | * @param t Tunnel. | ||
2846 | * | ||
2847 | * @return Tunnel's connectivity state. | ||
2848 | */ | ||
2849 | enum CadetTunnelCState | ||
2850 | GCT_get_cstate (struct CadetTunnel *t) | ||
2851 | { | ||
2852 | if (NULL == t) | ||
2853 | { | ||
2854 | GNUNET_assert (0); | ||
2855 | return (enum CadetTunnelCState) -1; | ||
2856 | } | ||
2857 | return t->cstate; | ||
2858 | } | ||
2859 | |||
2860 | |||
2861 | /** | ||
2862 | * Get the encryption state of a tunnel. | ||
2863 | * | ||
2864 | * @param t Tunnel. | ||
2865 | * | ||
2866 | * @return Tunnel's encryption state. | ||
2867 | */ | ||
2868 | enum CadetTunnelEState | ||
2869 | GCT_get_estate (struct CadetTunnel *t) | ||
2870 | { | ||
2871 | if (NULL == t) | ||
2872 | { | ||
2873 | GNUNET_break (0); | ||
2874 | return (enum CadetTunnelEState) -1; | ||
2875 | } | ||
2876 | return t->estate; | ||
2877 | } | ||
2878 | |||
2879 | /** | ||
2880 | * Get the maximum buffer space for a tunnel towards a local client. | ||
2881 | * | ||
2882 | * @param t Tunnel. | ||
2883 | * | ||
2884 | * @return Biggest buffer space offered by any channel in the tunnel. | ||
2885 | */ | ||
2886 | unsigned int | ||
2887 | GCT_get_channels_buffer (struct CadetTunnel *t) | ||
2888 | { | ||
2889 | struct CadetTChannel *iter; | ||
2890 | unsigned int buffer; | ||
2891 | unsigned int ch_buf; | ||
2892 | |||
2893 | if (NULL == t->channel_head) | ||
2894 | { | ||
2895 | /* Probably getting buffer for a channel create/handshake. */ | ||
2896 | LOG (GNUNET_ERROR_TYPE_DEBUG, " no channels, allow max\n"); | ||
2897 | return MIN_TUNNEL_BUFFER; | ||
2898 | } | ||
2899 | |||
2900 | buffer = 0; | ||
2901 | for (iter = t->channel_head; NULL != iter; iter = iter->next) | ||
2902 | { | ||
2903 | ch_buf = get_channel_buffer (iter); | ||
2904 | if (ch_buf > buffer) | ||
2905 | buffer = ch_buf; | ||
2906 | } | ||
2907 | if (MIN_TUNNEL_BUFFER > buffer) | ||
2908 | return MIN_TUNNEL_BUFFER; | ||
2909 | |||
2910 | if (MAX_TUNNEL_BUFFER < buffer) | ||
2911 | { | ||
2912 | GNUNET_break (0); | ||
2913 | return MAX_TUNNEL_BUFFER; | ||
2914 | } | ||
2915 | return buffer; | ||
2916 | } | ||
2917 | |||
2918 | |||
2919 | /** | ||
2920 | * Get the total buffer space for a tunnel for P2P traffic. | ||
2921 | * | ||
2922 | * @param t Tunnel. | ||
2923 | * | ||
2924 | * @return Buffer space offered by all connections in the tunnel. | ||
2925 | */ | ||
2926 | unsigned int | ||
2927 | GCT_get_connections_buffer (struct CadetTunnel *t) | ||
2928 | { | ||
2929 | struct CadetTConnection *iter; | ||
2930 | unsigned int buffer; | ||
2931 | |||
2932 | if (GNUNET_NO == is_ready (t)) | ||
2933 | { | ||
2934 | if (count_queued_data (t) >= 3) | ||
2935 | return 0; | ||
2936 | else | ||
2937 | return 1; | ||
2938 | } | ||
2939 | |||
2940 | buffer = 0; | ||
2941 | for (iter = t->connection_head; NULL != iter; iter = iter->next) | ||
2942 | { | ||
2943 | if (GCC_get_state (iter->c) != CADET_CONNECTION_READY) | ||
2944 | { | ||
2945 | continue; | ||
2946 | } | ||
2947 | buffer += get_connection_buffer (iter); | ||
2948 | } | ||
2949 | |||
2950 | return buffer; | ||
2951 | } | ||
2952 | |||
2953 | |||
2954 | /** | ||
2955 | * Get the tunnel's destination. | ||
2956 | * | ||
2957 | * @param t Tunnel. | ||
2958 | * | ||
2959 | * @return ID of the destination peer. | ||
2960 | */ | ||
2961 | const struct GNUNET_PeerIdentity * | ||
2962 | GCT_get_destination (struct CadetTunnel *t) | ||
2963 | { | ||
2964 | return GCP_get_id (t->peer); | ||
2965 | } | ||
2966 | |||
2967 | |||
2968 | /** | ||
2969 | * Get the tunnel's next free global channel ID. | ||
2970 | * | ||
2971 | * @param t Tunnel. | ||
2972 | * | ||
2973 | * @return GID of a channel free to use. | ||
2974 | */ | ||
2975 | struct GNUNET_CADET_ChannelTunnelNumber | ||
2976 | GCT_get_next_ctn (struct CadetTunnel *t) | ||
2977 | { | ||
2978 | struct GNUNET_CADET_ChannelTunnelNumber ctn; | ||
2979 | struct GNUNET_CADET_ChannelTunnelNumber mask; | ||
2980 | int result; | ||
2981 | |||
2982 | /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID. | ||
2983 | * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0 | ||
2984 | * If peer's ID is bigger, start at 0x4... bit 30 = 1 | ||
2985 | */ | ||
2986 | result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer)); | ||
2987 | if (0 > result) | ||
2988 | mask.cn = htonl (0x40000000); | ||
2989 | else | ||
2990 | mask.cn = 0x0; | ||
2991 | t->next_ctn.cn |= mask.cn; | ||
2992 | |||
2993 | while (NULL != GCT_get_channel (t, t->next_ctn)) | ||
2994 | { | ||
2995 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2996 | "Channel %u exists...\n", | ||
2997 | t->next_ctn.cn); | ||
2998 | t->next_ctn.cn = htonl ((ntohl (t->next_ctn.cn) + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
2999 | t->next_ctn.cn |= mask.cn; | ||
3000 | } | ||
3001 | ctn = t->next_ctn; | ||
3002 | t->next_ctn.cn = (t->next_ctn.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; | ||
3003 | t->next_ctn.cn |= mask.cn; | ||
3004 | |||
3005 | return ctn; | ||
3006 | } | ||
3007 | |||
3008 | |||
3009 | /** | ||
3010 | * Send ACK on one or more channels due to buffer in connections. | ||
3011 | * | ||
3012 | * @param t Channel which has some free buffer space. | ||
3013 | */ | ||
3014 | void | ||
3015 | GCT_unchoke_channels (struct CadetTunnel *t) | ||
3016 | { | ||
3017 | struct CadetTChannel *iter; | ||
3018 | unsigned int buffer; | ||
3019 | unsigned int channels = GCT_count_channels (t); | ||
3020 | unsigned int choked_n; | ||
3021 | struct CadetChannel *choked[channels]; | ||
3022 | |||
3023 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_2s (t)); | ||
3024 | LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head); | ||
3025 | if (NULL != t->channel_head) | ||
3026 | LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch); | ||
3027 | |||
3028 | if (NULL != t->tq_head) | ||
3029 | send_queued_data (t); | ||
3030 | |||
3031 | /* Get buffer space */ | ||
3032 | buffer = GCT_get_connections_buffer (t); | ||
3033 | if (0 == buffer) | ||
3034 | { | ||
3035 | return; | ||
3036 | } | ||
3037 | |||
3038 | /* Count and remember choked channels */ | ||
3039 | choked_n = 0; | ||
3040 | for (iter = t->channel_head; NULL != iter; iter = iter->next) | ||
3041 | { | ||
3042 | if (GNUNET_NO == get_channel_allowed (iter)) | ||
3043 | { | ||
3044 | choked[choked_n++] = iter->ch; | ||
3045 | } | ||
3046 | } | ||
3047 | |||
3048 | /* Unchoke random channels */ | ||
3049 | while (0 < buffer && 0 < choked_n) | ||
3050 | { | ||
3051 | unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
3052 | choked_n); | ||
3053 | GCCH_allow_client (choked[r], GCCH_is_origin (choked[r], GNUNET_YES)); | ||
3054 | choked_n--; | ||
3055 | buffer--; | ||
3056 | choked[r] = choked[choked_n]; | ||
3057 | } | ||
3058 | } | ||
3059 | |||
3060 | |||
3061 | /** | ||
3062 | * Send ACK on one or more connections due to buffer space to the client. | ||
3063 | * | ||
3064 | * Iterates all connections of the tunnel and sends ACKs appropriately. | ||
3065 | * | ||
3066 | * @param t Tunnel. | ||
3067 | */ | ||
3068 | void | ||
3069 | GCT_send_connection_acks (struct CadetTunnel *t) | ||
3070 | { | ||
3071 | struct CadetTConnection *iter; | ||
3072 | uint32_t allowed; | ||
3073 | uint32_t to_allow; | ||
3074 | uint32_t allow_per_connection; | ||
3075 | unsigned int cs; | ||
3076 | unsigned int buffer; | ||
3077 | |||
3078 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n", | ||
3079 | GCT_2s (t)); | ||
3080 | |||
3081 | if (NULL == t) | ||
3082 | { | ||
3083 | GNUNET_break (0); | ||
3084 | return; | ||
3085 | } | ||
3086 | |||
3087 | if (CADET_TUNNEL_READY != t->cstate) | ||
3088 | return; | ||
3089 | |||
3090 | buffer = GCT_get_channels_buffer (t); | ||
3091 | LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer); | ||
3092 | |||
3093 | /* Count connections, how many messages are already allowed */ | ||
3094 | cs = GCT_count_connections (t); | ||
3095 | for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next) | ||
3096 | { | ||
3097 | allowed += get_connection_allowed (iter); | ||
3098 | } | ||
3099 | LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed); | ||
3100 | |||
3101 | /* Make sure there is no overflow */ | ||
3102 | if (allowed > buffer) | ||
3103 | return; | ||
3104 | |||
3105 | /* Authorize connections to send more data */ | ||
3106 | to_allow = buffer - allowed; | ||
3107 | |||
3108 | for (iter = t->connection_head; | ||
3109 | NULL != iter && to_allow > 0; | ||
3110 | iter = iter->next) | ||
3111 | { | ||
3112 | if (CADET_CONNECTION_READY != GCC_get_state (iter->c) | ||
3113 | || get_connection_allowed (iter) > 64 / 3) | ||
3114 | { | ||
3115 | continue; | ||
3116 | } | ||
3117 | GNUNET_assert(cs != 0); | ||
3118 | allow_per_connection = to_allow/cs; | ||
3119 | to_allow -= allow_per_connection; | ||
3120 | cs--; | ||
3121 | GCC_allow (iter->c, allow_per_connection, | ||
3122 | GCC_is_origin (iter->c, GNUNET_NO)); | ||
3123 | } | ||
3124 | |||
3125 | if (0 != to_allow) | ||
3126 | { | ||
3127 | /* Since we don't allow if it's allowed to send 64/3, this can happen. */ | ||
3128 | LOG (GNUNET_ERROR_TYPE_DEBUG, " reminding to_allow: %u\n", to_allow); | ||
3129 | } | ||
3130 | } | ||
3131 | |||
3132 | |||
3133 | /** | ||
3134 | * Cancel a previously sent message while it's in the queue. | ||
3135 | * | ||
3136 | * ONLY can be called before the continuation given to the send function | ||
3137 | * is called. Once the continuation is called, the message is no longer in the | ||
3138 | * queue. | ||
3139 | * | ||
3140 | * @param q Handle to the queue. | ||
3141 | */ | ||
3142 | void | ||
3143 | GCT_cancel (struct CadetTunnelQueue *q) | ||
3144 | { | ||
3145 | if (NULL != q->cq) | ||
3146 | { | ||
3147 | GNUNET_assert (NULL == q->tqd); | ||
3148 | GCC_cancel (q->cq); | ||
3149 | /* tun_message_sent() will be called and free q */ | ||
3150 | } | ||
3151 | else if (NULL != q->tqd) | ||
3152 | { | ||
3153 | unqueue_data (q->tqd); | ||
3154 | q->tqd = NULL; | ||
3155 | if (NULL != q->cont) | ||
3156 | q->cont (q->cont_cls, NULL, q, 0, 0); | ||
3157 | GNUNET_free (q); | ||
3158 | } | ||
3159 | else | ||
3160 | { | ||
3161 | GNUNET_break (0); | ||
3162 | } | ||
3163 | } | ||
3164 | |||
3165 | |||
3166 | /** | ||
3167 | * Check if the tunnel has queued traffic. | ||
3168 | * | ||
3169 | * @param t Tunnel to check. | ||
3170 | * | ||
3171 | * @return #GNUNET_YES if there is queued traffic | ||
3172 | * #GNUNET_NO otherwise | ||
3173 | */ | ||
3174 | int | ||
3175 | GCT_has_queued_traffic (struct CadetTunnel *t) | ||
3176 | { | ||
3177 | return (NULL != t->tq_head) ? GNUNET_YES : GNUNET_NO; | ||
3178 | } | ||
3179 | |||
3180 | |||
3181 | /** | ||
3182 | * Sends an already built message on a tunnel, encrypting it and | ||
3183 | * choosing the best connection if not provided. | ||
3184 | * | ||
3185 | * @param message Message to send. Function modifies it. | ||
3186 | * @param t Tunnel on which this message is transmitted. | ||
3187 | * @param c Connection to use (autoselect if NULL). | ||
3188 | * @param force Force the tunnel to take the message (buffer overfill). | ||
3189 | * @param cont Continuation to call once message is really sent. | ||
3190 | * @param cont_cls Closure for @c cont. | ||
3191 | * | ||
3192 | * @return Handle to cancel message. NULL if @c cont is NULL. | ||
3193 | */ | ||
3194 | struct CadetTunnelQueue * | ||
3195 | GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
3196 | struct CadetTunnel *t, | ||
3197 | struct CadetConnection *c, | ||
3198 | int force, GCT_sent cont, void *cont_cls) | ||
3199 | { | ||
3200 | return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL); | ||
3201 | } | ||
3202 | |||
3203 | |||
3204 | /** | ||
3205 | * Send a KX message. | ||
3206 | * | ||
3207 | * @param t Tunnel on which to send it. | ||
3208 | * @param force_reply Force the other peer to reply with a KX message. | ||
3209 | */ | ||
3210 | void | ||
3211 | GCT_send_kx (struct CadetTunnel *t, int force_reply) | ||
3212 | { | ||
3213 | static struct CadetEncryptedMessageIdentifier zero; | ||
3214 | struct CadetConnection *c; | ||
3215 | struct GNUNET_CADET_TunnelKeyExchangeMessage msg; | ||
3216 | enum GNUNET_CADET_KX_Flags flags; | ||
3217 | |||
3218 | LOG (GNUNET_ERROR_TYPE_INFO, "==> { KX} on %s\n", GCT_2s (t)); | ||
3219 | if (NULL != t->ephm_h) | ||
3220 | { | ||
3221 | LOG (GNUNET_ERROR_TYPE_INFO, " already queued, nop\n"); | ||
3222 | return; | ||
3223 | } | ||
3224 | GNUNET_assert (GNUNET_NO == GCT_is_loopback (t)); | ||
3225 | |||
3226 | c = tunnel_get_connection (t); | ||
3227 | if (NULL == c) | ||
3228 | { | ||
3229 | if (NULL == t->destroy_task && CADET_TUNNEL_READY == t->cstate) | ||
3230 | { | ||
3231 | GNUNET_break (0); | ||
3232 | GCT_debug (t, GNUNET_ERROR_TYPE_ERROR); | ||
3233 | } | ||
3234 | return; | ||
3235 | } | ||
3236 | |||
3237 | msg.header.size = htons (sizeof (msg)); | ||
3238 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX); | ||
3239 | flags = GNUNET_CADET_KX_FLAG_NONE; | ||
3240 | if (GNUNET_YES == force_reply) | ||
3241 | flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY; | ||
3242 | msg.flags = htonl (flags); | ||
3243 | msg.cid = *GCC_get_id (c); | ||
3244 | GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key); | ||
3245 | GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key); | ||
3246 | |||
3247 | t->ephm_h = GCC_send_prebuilt_message (&msg.header, | ||
3248 | UINT16_MAX, | ||
3249 | zero, | ||
3250 | c, | ||
3251 | GCC_is_origin (c, GNUNET_YES), | ||
3252 | GNUNET_YES, &ephm_sent, t); | ||
3253 | if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) | ||
3254 | GCT_change_estate (t, CADET_TUNNEL_KEY_AX_SENT); | ||
3255 | } | ||
3256 | |||
3257 | |||
3258 | /** | ||
3259 | * Is the tunnel directed towards the local peer? | ||
3260 | * | ||
3261 | * @param t Tunnel. | ||
3262 | * | ||
3263 | * @return #GNUNET_YES if it is loopback. | ||
3264 | */ | ||
3265 | int | ||
3266 | GCT_is_loopback (const struct CadetTunnel *t) | ||
3267 | { | ||
3268 | return (myid == GCP_get_short_id (t->peer)); | ||
3269 | } | ||
3270 | |||
3271 | |||
3272 | /** | ||
3273 | * Is the tunnel this path already? | ||
3274 | * | ||
3275 | * @param t Tunnel. | ||
3276 | * @param p Path. | ||
3277 | * | ||
3278 | * @return #GNUNET_YES a connection uses this path. | ||
3279 | */ | ||
3280 | int | ||
3281 | GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p) | ||
3282 | { | ||
3283 | struct CadetTConnection *iter; | ||
3284 | |||
3285 | for (iter = t->connection_head; NULL != iter; iter = iter->next) | ||
3286 | if (path_equivalent (GCC_get_path (iter->c), p)) | ||
3287 | return GNUNET_YES; | ||
3288 | |||
3289 | return GNUNET_NO; | ||
3290 | } | ||
3291 | |||
3292 | |||
3293 | /** | ||
3294 | * Get a cost of a path for a tunnel considering existing connections. | ||
3295 | * | ||
3296 | * @param t Tunnel. | ||
3297 | * @param path Candidate path. | ||
3298 | * | ||
3299 | * @return Cost of the path (path length + number of overlapping nodes) | ||
3300 | */ | ||
3301 | unsigned int | ||
3302 | GCT_get_path_cost (const struct CadetTunnel *t, | ||
3303 | const struct CadetPeerPath *path) | ||
3304 | { | ||
3305 | struct CadetTConnection *iter; | ||
3306 | const struct CadetPeerPath *aux; | ||
3307 | unsigned int overlap; | ||
3308 | unsigned int i; | ||
3309 | unsigned int j; | ||
3310 | |||
3311 | if (NULL == path) | ||
3312 | return 0; | ||
3313 | |||
3314 | overlap = 0; | ||
3315 | GNUNET_assert (NULL != t); | ||
3316 | |||
3317 | for (i = 0; i < path->length; i++) | ||
3318 | { | ||
3319 | for (iter = t->connection_head; NULL != iter; iter = iter->next) | ||
3320 | { | ||
3321 | aux = GCC_get_path (iter->c); | ||
3322 | if (NULL == aux) | ||
3323 | continue; | ||
3324 | |||
3325 | for (j = 0; j < aux->length; j++) | ||
3326 | { | ||
3327 | if (path->peers[i] == aux->peers[j]) | ||
3328 | { | ||
3329 | overlap++; | ||
3330 | break; | ||
3331 | } | ||
3332 | } | ||
3333 | } | ||
3334 | } | ||
3335 | return path->length + overlap; | ||
3336 | } | ||
3337 | |||
3338 | |||
3339 | /** | ||
3340 | * Get the static string for the peer this tunnel is directed. | ||
3341 | * | ||
3342 | * @param t Tunnel. | ||
3343 | * | ||
3344 | * @return Static string the destination peer's ID. | ||
3345 | */ | ||
3346 | const char * | ||
3347 | GCT_2s (const struct CadetTunnel *t) | ||
3348 | { | ||
3349 | if (NULL == t) | ||
3350 | return "(NULL)"; | ||
3351 | |||
3352 | return GCP_2s (t->peer); | ||
3353 | } | ||
3354 | |||
3355 | |||
3356 | /******************************************************************************/ | ||
3357 | /***************************** INFO/DEBUG *******************************/ | ||
3358 | /******************************************************************************/ | ||
3359 | |||
3360 | static void | ||
3361 | ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level) | ||
3362 | { | ||
3363 | struct GNUNET_CRYPTO_EcdhePublicKey pub; | ||
3364 | struct CadetTunnelSkippedKey *iter; | ||
3365 | |||
3366 | LOG2 (level, "TTT RK \t %s\n", | ||
3367 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->RK)); | ||
3368 | |||
3369 | LOG2 (level, "TTT HKs \t %s\n", | ||
3370 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs)); | ||
3371 | LOG2 (level, "TTT HKr \t %s\n", | ||
3372 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr)); | ||
3373 | LOG2 (level, "TTT NHKs\t %s\n", | ||
3374 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKs)); | ||
3375 | LOG2 (level, "TTT NHKr\t %s\n", | ||
3376 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKr)); | ||
3377 | |||
3378 | LOG2 (level, "TTT CKs \t %s\n", | ||
3379 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs)); | ||
3380 | LOG2 (level, "TTT CKr \t %s\n", | ||
3381 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr)); | ||
3382 | |||
3383 | GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub); | ||
3384 | LOG2 (level, "TTT DHRs\t %s\n", | ||
3385 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub)); | ||
3386 | LOG2 (level, "TTT DHRr\t %s\n", | ||
3387 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->DHRr)); | ||
3388 | |||
3389 | LOG2 (level, "TTT Nr\t %u\tNs\t%u\n", ax->Nr, ax->Ns); | ||
3390 | LOG2 (level, "TTT PNs\t %u\tSkipped\t%u\n", ax->PNs, ax->skipped); | ||
3391 | LOG2 (level, "TTT Ratchet\t%u\n", ax->ratchet_flag); | ||
3392 | |||
3393 | for (iter = ax->skipped_head; NULL != iter; iter = iter->next) | ||
3394 | { | ||
3395 | LOG2 (level, "TTT HK\t %s\n", | ||
3396 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->HK)); | ||
3397 | LOG2 (level, "TTT MK\t %s\n", | ||
3398 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->MK)); | ||
3399 | } | ||
3400 | } | ||
3401 | |||
3402 | /** | ||
3403 | * Log all possible info about the tunnel state. | ||
3404 | * | ||
3405 | * @param t Tunnel to debug. | ||
3406 | * @param level Debug level to use. | ||
3407 | */ | ||
3408 | void | ||
3409 | GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level) | ||
3410 | { | ||
3411 | struct CadetTChannel *iter_ch; | ||
3412 | struct CadetTConnection *iter_c; | ||
3413 | int do_log; | ||
3414 | |||
3415 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | ||
3416 | "cadet-tun", | ||
3417 | __FILE__, __FUNCTION__, __LINE__); | ||
3418 | if (0 == do_log) | ||
3419 | return; | ||
3420 | |||
3421 | LOG2 (level, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t)); | ||
3422 | LOG2 (level, "TTT cstate %s, estate %s\n", | ||
3423 | cstate2s (t->cstate), estate2s (t->estate)); | ||
3424 | #if DUMP_KEYS_TO_STDERR | ||
3425 | ax_debug (t->ax, level); | ||
3426 | #endif | ||
3427 | LOG2 (level, "TTT tq_head %p, tq_tail %p\n", t->tq_head, t->tq_tail); | ||
3428 | LOG2 (level, "TTT destroy %p\n", t->destroy_task); | ||
3429 | LOG2 (level, "TTT channels:\n"); | ||
3430 | for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next) | ||
3431 | { | ||
3432 | GCCH_debug (iter_ch->ch, level); | ||
3433 | } | ||
3434 | |||
3435 | LOG2 (level, "TTT connections:\n"); | ||
3436 | for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next) | ||
3437 | { | ||
3438 | GCC_debug (iter_c->c, level); | ||
3439 | } | ||
3440 | |||
3441 | LOG2 (level, "TTT DEBUG TUNNEL END\n"); | ||
3442 | } | ||
3443 | |||
3444 | |||
3445 | /** | ||
3446 | * Iterate all tunnels. | ||
3447 | * | ||
3448 | * @param iter Iterator. | ||
3449 | * @param cls Closure for @c iter. | ||
3450 | */ | ||
3451 | void | ||
3452 | GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) | ||
3453 | { | ||
3454 | GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls); | ||
3455 | } | ||
3456 | |||
3457 | |||
3458 | /** | ||
3459 | * Count all tunnels. | ||
3460 | * | ||
3461 | * @return Number of tunnels to remote peers kept by this peer. | ||
3462 | */ | ||
3463 | unsigned int | ||
3464 | GCT_count_all (void) | ||
3465 | { | ||
3466 | return GNUNET_CONTAINER_multipeermap_size (tunnels); | ||
3467 | } | ||
3468 | |||
3469 | |||
3470 | /** | ||
3471 | * Iterate all connections of a tunnel. | ||
3472 | * | ||
3473 | * @param t Tunnel whose connections to iterate. | ||
3474 | * @param iter Iterator. | ||
3475 | * @param cls Closure for @c iter. | ||
3476 | */ | ||
3477 | void | ||
3478 | GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls) | ||
3479 | { | ||
3480 | struct CadetTConnection *ct; | ||
3481 | |||
3482 | for (ct = t->connection_head; NULL != ct; ct = ct->next) | ||
3483 | iter (cls, ct->c); | ||
3484 | } | ||
3485 | |||
3486 | |||
3487 | /** | ||
3488 | * Iterate all channels of a tunnel. | ||
3489 | * | ||
3490 | * @param t Tunnel whose channels to iterate. | ||
3491 | * @param iter Iterator. | ||
3492 | * @param cls Closure for @c iter. | ||
3493 | */ | ||
3494 | void | ||
3495 | GCT_iterate_channels (struct CadetTunnel *t, GCT_chan_iter iter, void *cls) | ||
3496 | { | ||
3497 | struct CadetTChannel *cht; | ||
3498 | |||
3499 | for (cht = t->channel_head; NULL != cht; cht = cht->next) | ||
3500 | iter (cls, cht->ch); | ||
3501 | } | ||
diff --git a/src/cadet/gnunet-service-cadet_tunnel.h b/src/cadet/gnunet-service-cadet_tunnel.h deleted file mode 100644 index 1b56a0632..000000000 --- a/src/cadet/gnunet-service-cadet_tunnel.h +++ /dev/null | |||
@@ -1,616 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet_tunnel.h | ||
23 | * @brief cadet service; dealing with tunnels and crypto | ||
24 | * @author Bartlomiej Polot | ||
25 | * | ||
26 | * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel) | ||
27 | */ | ||
28 | |||
29 | #ifndef GNUNET_SERVICE_CADET_TUNNEL_H | ||
30 | #define GNUNET_SERVICE_CADET_TUNNEL_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" | ||
34 | { | ||
35 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | |||
40 | #include "platform.h" | ||
41 | #include "gnunet_util_lib.h" | ||
42 | |||
43 | #define CONNECTIONS_PER_TUNNEL 3 | ||
44 | |||
45 | /** | ||
46 | * All the connectivity states a tunnel can be in. | ||
47 | */ | ||
48 | enum CadetTunnelCState | ||
49 | { | ||
50 | /** | ||
51 | * Uninitialized status, should never appear in operation. | ||
52 | */ | ||
53 | CADET_TUNNEL_NEW, | ||
54 | |||
55 | /** | ||
56 | * No path to the peer known yet. | ||
57 | */ | ||
58 | CADET_TUNNEL_SEARCHING, | ||
59 | |||
60 | /** | ||
61 | * Request sent, not yet answered. | ||
62 | */ | ||
63 | CADET_TUNNEL_WAITING, | ||
64 | |||
65 | /** | ||
66 | * Peer connected and ready to accept data. | ||
67 | */ | ||
68 | CADET_TUNNEL_READY, | ||
69 | |||
70 | /** | ||
71 | * Tunnel being shut down, don't try to keep it alive. | ||
72 | */ | ||
73 | CADET_TUNNEL_SHUTDOWN | ||
74 | }; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * All the encryption states a tunnel can be in. | ||
79 | */ | ||
80 | enum CadetTunnelEState | ||
81 | { | ||
82 | /** | ||
83 | * Uninitialized status, should never appear in operation. | ||
84 | */ | ||
85 | CADET_TUNNEL_KEY_UNINITIALIZED, | ||
86 | |||
87 | /** | ||
88 | * Ephemeral key sent, waiting for peer's key. | ||
89 | */ | ||
90 | CADET_TUNNEL_KEY_AX_SENT, | ||
91 | |||
92 | /** | ||
93 | * In OTR: New ephemeral key and ping sent, waiting for pong. | ||
94 | * | ||
95 | * This means that we DO have the peer's ephemeral key, otherwise the | ||
96 | * state would be KEY_SENT. We DO NOT have a valid session key (either no | ||
97 | * previous key or previous key expired). | ||
98 | * | ||
99 | * | ||
100 | * In Axolotl: Key sent and received but no deciphered traffic yet. | ||
101 | * | ||
102 | * This means that we can send traffic (otherwise we would never complete | ||
103 | * the handshake), but we don't have complete confirmation. Since the first | ||
104 | * traffic MUST be a complete channel creation 3-way handshake, no payload | ||
105 | * will be sent before confirmation. | ||
106 | */ | ||
107 | CADET_TUNNEL_KEY_AX_AUTH_SENT, | ||
108 | |||
109 | /** | ||
110 | * Handshake completed: session key available. | ||
111 | */ | ||
112 | CADET_TUNNEL_KEY_OK, | ||
113 | |||
114 | /** | ||
115 | * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING, | ||
116 | * we still have a valid session key and therefore we *can* still send | ||
117 | * traffic on the tunnel. | ||
118 | */ | ||
119 | CADET_TUNNEL_KEY_REKEY | ||
120 | }; | ||
121 | |||
122 | /** | ||
123 | * Struct containing all information regarding a given peer | ||
124 | */ | ||
125 | struct CadetTunnel; | ||
126 | |||
127 | |||
128 | #include "gnunet-service-cadet_channel.h" | ||
129 | #include "gnunet-service-cadet_connection.h" | ||
130 | #include "gnunet-service-cadet_peer.h" | ||
131 | |||
132 | /** | ||
133 | * Handle for messages queued but not yet sent. | ||
134 | */ | ||
135 | struct CadetTunnelQueue; | ||
136 | |||
137 | /** | ||
138 | * Callback called when a queued message is sent. | ||
139 | * | ||
140 | * @param cls Closure. | ||
141 | * @param t Tunnel this message was on. | ||
142 | * @param type Type of message sent. | ||
143 | * @param size Size of the message. | ||
144 | */ | ||
145 | typedef void | ||
146 | (*GCT_sent) (void *cls, | ||
147 | struct CadetTunnel *t, | ||
148 | struct CadetTunnelQueue *q, | ||
149 | uint16_t type, size_t size); | ||
150 | |||
151 | typedef void | ||
152 | (*GCT_conn_iter) (void *cls, struct CadetConnection *c); | ||
153 | |||
154 | |||
155 | typedef void | ||
156 | (*GCT_chan_iter) (void *cls, struct CadetChannel *ch); | ||
157 | |||
158 | |||
159 | /******************************************************************************/ | ||
160 | /******************************** API ***********************************/ | ||
161 | /******************************************************************************/ | ||
162 | |||
163 | /** | ||
164 | * Initialize tunnel subsystem. | ||
165 | * | ||
166 | * @param c Configuration handle. | ||
167 | * @param key ECC private key, to derive all other keys and do crypto. | ||
168 | */ | ||
169 | void | ||
170 | GCT_init (const struct GNUNET_CONFIGURATION_Handle *c, | ||
171 | const struct GNUNET_CRYPTO_EddsaPrivateKey *key); | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Shut down the tunnel subsystem. | ||
176 | */ | ||
177 | void | ||
178 | GCT_shutdown (void); | ||
179 | |||
180 | |||
181 | /** | ||
182 | * Create a tunnel. | ||
183 | * | ||
184 | * @param destination Peer this tunnel is towards. | ||
185 | */ | ||
186 | struct CadetTunnel * | ||
187 | GCT_new (struct CadetPeer *destination); | ||
188 | |||
189 | |||
190 | /** | ||
191 | * Tunnel is empty: destroy it. | ||
192 | * | ||
193 | * Notifies all connections about the destruction. | ||
194 | * | ||
195 | * @param t Tunnel to destroy. | ||
196 | */ | ||
197 | void | ||
198 | GCT_destroy_empty (struct CadetTunnel *t); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Destroy tunnel if empty (no more channels). | ||
203 | * | ||
204 | * @param t Tunnel to destroy if empty. | ||
205 | */ | ||
206 | void | ||
207 | GCT_destroy_if_empty (struct CadetTunnel *t); | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Destroy the tunnel. | ||
212 | * | ||
213 | * This function does not generate any warning traffic to clients or peers. | ||
214 | * | ||
215 | * Tasks: | ||
216 | * Cancel messages belonging to this tunnel queued to neighbors. | ||
217 | * Free any allocated resources linked to the tunnel. | ||
218 | * | ||
219 | * @param t The tunnel to destroy. | ||
220 | */ | ||
221 | void | ||
222 | GCT_destroy (struct CadetTunnel *t); | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Change the tunnel's connection state. | ||
227 | * | ||
228 | * @param t Tunnel whose connection state to change. | ||
229 | * @param cstate New connection state. | ||
230 | */ | ||
231 | void | ||
232 | GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate); | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Change the tunnel encryption state. | ||
237 | * | ||
238 | * @param t Tunnel whose encryption state to change. | ||
239 | * @param state New encryption state. | ||
240 | */ | ||
241 | void | ||
242 | GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state); | ||
243 | |||
244 | |||
245 | /** | ||
246 | * Add a connection to a tunnel. | ||
247 | * | ||
248 | * @param t Tunnel. | ||
249 | * @param c Connection. | ||
250 | */ | ||
251 | void | ||
252 | GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c); | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Remove a connection from a tunnel. | ||
257 | * | ||
258 | * @param t Tunnel. | ||
259 | * @param c Connection. | ||
260 | */ | ||
261 | void | ||
262 | GCT_remove_connection (struct CadetTunnel *t, struct CadetConnection *c); | ||
263 | |||
264 | |||
265 | /** | ||
266 | * Add a channel to a tunnel. | ||
267 | * | ||
268 | * @param t Tunnel. | ||
269 | * @param ch Channel. | ||
270 | */ | ||
271 | void | ||
272 | GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch); | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Remove a channel from a tunnel. | ||
277 | * | ||
278 | * @param t Tunnel. | ||
279 | * @param ch Channel. | ||
280 | */ | ||
281 | void | ||
282 | GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch); | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Search for a channel by global ID. | ||
287 | * | ||
288 | * @param t Tunnel containing the channel. | ||
289 | * @param ctn Public channel number. | ||
290 | * | ||
291 | * @return channel handler, NULL if doesn't exist | ||
292 | */ | ||
293 | struct CadetChannel * | ||
294 | GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelTunnelNumber ctn); | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Decrypt and process an encrypted message. | ||
299 | * | ||
300 | * Calls the appropriate handler for a message in a channel of a local tunnel. | ||
301 | * | ||
302 | * @param t Tunnel this message came on. | ||
303 | * @param msg Message header. | ||
304 | */ | ||
305 | void | ||
306 | GCT_handle_encrypted (struct CadetTunnel *t, | ||
307 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg); | ||
308 | |||
309 | |||
310 | /** | ||
311 | * Handle a Key eXchange message. | ||
312 | * | ||
313 | * @param t Tunnel on which the message came. | ||
314 | * @param msg KX message itself. | ||
315 | */ | ||
316 | void | ||
317 | GCT_handle_kx (struct CadetTunnel *t, | ||
318 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); | ||
319 | |||
320 | |||
321 | /** | ||
322 | * @brief Use the given path for the tunnel. | ||
323 | * Update the next and prev hops (and RCs). | ||
324 | * (Re)start the path refresh in case the tunnel is locally owned. | ||
325 | * | ||
326 | * @param t Tunnel to update. | ||
327 | * @param p Path to use. | ||
328 | * | ||
329 | * @return Connection created. | ||
330 | */ | ||
331 | struct CadetConnection * | ||
332 | GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p); | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Count all created connections of a tunnel. Not necessarily ready connections! | ||
337 | * | ||
338 | * @param t Tunnel on which to count. | ||
339 | * | ||
340 | * @return Number of connections created, either being established or ready. | ||
341 | */ | ||
342 | unsigned int | ||
343 | GCT_count_any_connections (struct CadetTunnel *t); | ||
344 | |||
345 | |||
346 | /** | ||
347 | * Count established (ready) connections of a tunnel. | ||
348 | * | ||
349 | * @param t Tunnel on which to count. | ||
350 | * | ||
351 | * @return Number of connections. | ||
352 | */ | ||
353 | unsigned int | ||
354 | GCT_count_connections (struct CadetTunnel *t); | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Count channels of a tunnel. | ||
359 | * | ||
360 | * @param t Tunnel on which to count. | ||
361 | * | ||
362 | * @return Number of channels. | ||
363 | */ | ||
364 | unsigned int | ||
365 | GCT_count_channels (struct CadetTunnel *t); | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Get the connectivity state of a tunnel. | ||
370 | * | ||
371 | * @param t Tunnel. | ||
372 | * | ||
373 | * @return Tunnel's connectivity state. | ||
374 | */ | ||
375 | enum CadetTunnelCState | ||
376 | GCT_get_cstate (struct CadetTunnel *t); | ||
377 | |||
378 | |||
379 | /** | ||
380 | * Get the encryption state of a tunnel. | ||
381 | * | ||
382 | * @param t Tunnel. | ||
383 | * | ||
384 | * @return Tunnel's encryption state. | ||
385 | */ | ||
386 | enum CadetTunnelEState | ||
387 | GCT_get_estate (struct CadetTunnel *t); | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Get the maximum buffer space for a tunnel towards a local client. | ||
392 | * | ||
393 | * @param t Tunnel. | ||
394 | * | ||
395 | * @return Biggest buffer space offered by any channel in the tunnel. | ||
396 | */ | ||
397 | unsigned int | ||
398 | GCT_get_channels_buffer (struct CadetTunnel *t); | ||
399 | |||
400 | |||
401 | /** | ||
402 | * Get the total buffer space for a tunnel for P2P traffic. | ||
403 | * | ||
404 | * @param t Tunnel. | ||
405 | * | ||
406 | * @return Buffer space offered by all connections in the tunnel. | ||
407 | */ | ||
408 | unsigned int | ||
409 | GCT_get_connections_buffer (struct CadetTunnel *t); | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Get the tunnel's destination. | ||
414 | * | ||
415 | * @param t Tunnel. | ||
416 | * | ||
417 | * @return ID of the destination peer. | ||
418 | */ | ||
419 | const struct GNUNET_PeerIdentity * | ||
420 | GCT_get_destination (struct CadetTunnel *t); | ||
421 | |||
422 | |||
423 | /** | ||
424 | * Get the tunnel's next free Channel ID. | ||
425 | * | ||
426 | * @param t Tunnel. | ||
427 | * | ||
428 | * @return ID of a channel free to use. | ||
429 | */ | ||
430 | struct GNUNET_CADET_ChannelTunnelNumber | ||
431 | GCT_get_next_ctn (struct CadetTunnel *t); | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Send ACK on one or more channels due to buffer in connections. | ||
436 | * | ||
437 | * @param t Channel which has some free buffer space. | ||
438 | */ | ||
439 | void | ||
440 | GCT_unchoke_channels (struct CadetTunnel *t); | ||
441 | |||
442 | |||
443 | /** | ||
444 | * Send ACK on one or more connections due to buffer space to the client. | ||
445 | * | ||
446 | * Iterates all connections of the tunnel and sends ACKs appropriately. | ||
447 | * | ||
448 | * @param t Tunnel which has some free buffer space. | ||
449 | */ | ||
450 | void | ||
451 | GCT_send_connection_acks (struct CadetTunnel *t); | ||
452 | |||
453 | |||
454 | /** | ||
455 | * Cancel a previously sent message while it's in the queue. | ||
456 | * | ||
457 | * ONLY can be called before the continuation given to the send function | ||
458 | * is called. Once the continuation is called, the message is no longer in the | ||
459 | * queue. | ||
460 | * | ||
461 | * @param q Handle to the queue. | ||
462 | */ | ||
463 | void | ||
464 | GCT_cancel (struct CadetTunnelQueue *q); | ||
465 | |||
466 | |||
467 | /** | ||
468 | * Check if the tunnel has queued traffic. | ||
469 | * | ||
470 | * @param t Tunnel to check. | ||
471 | * | ||
472 | * @return #GNUNET_YES if there is queued traffic | ||
473 | * #GNUNET_NO otherwise | ||
474 | */ | ||
475 | int | ||
476 | GCT_has_queued_traffic (struct CadetTunnel *t); | ||
477 | |||
478 | /** | ||
479 | * Sends an already built message on a tunnel, encrypting it and | ||
480 | * choosing the best connection. | ||
481 | * | ||
482 | * @param message Message to send. Function modifies it. | ||
483 | * @param t Tunnel on which this message is transmitted. | ||
484 | * @param c Connection to use (autoselect if NULL). | ||
485 | * @param force Force the tunnel to take the message (buffer overfill). | ||
486 | * @param cont Continuation to call once message is really sent. | ||
487 | * @param cont_cls Closure for @c cont. | ||
488 | * | ||
489 | * @return Handle to cancel message. NULL if @c cont is NULL. | ||
490 | */ | ||
491 | struct CadetTunnelQueue * | ||
492 | GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, | ||
493 | struct CadetTunnel *t, struct CadetConnection *c, | ||
494 | int force, GCT_sent cont, void *cont_cls); | ||
495 | |||
496 | |||
497 | /** | ||
498 | * Send a KX message. | ||
499 | * | ||
500 | * @param t Tunnel on which to send it. | ||
501 | * @param force_reply Force the other peer to reply with a KX message. | ||
502 | */ | ||
503 | void | ||
504 | GCT_send_kx (struct CadetTunnel *t, int force_reply); | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Is the tunnel directed towards the local peer? | ||
509 | * | ||
510 | * @param t Tunnel. | ||
511 | * | ||
512 | * @return #GNUNET_YES if it is loopback. | ||
513 | */ | ||
514 | int | ||
515 | GCT_is_loopback (const struct CadetTunnel *t); | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Is the tunnel using this path already? | ||
520 | * | ||
521 | * @param t Tunnel. | ||
522 | * @param p Path. | ||
523 | * | ||
524 | * @return #GNUNET_YES a connection uses this path. | ||
525 | */ | ||
526 | int | ||
527 | GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p); | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Get a cost of a path for a tunnel considering existing connections. | ||
532 | * | ||
533 | * @param t Tunnel. | ||
534 | * @param path Candidate path. | ||
535 | * | ||
536 | * @return Cost of the path (path length + number of overlapping nodes) | ||
537 | */ | ||
538 | unsigned int | ||
539 | GCT_get_path_cost (const struct CadetTunnel *t, | ||
540 | const struct CadetPeerPath *path); | ||
541 | |||
542 | |||
543 | /** | ||
544 | * Get the static string for the peer this tunnel is directed. | ||
545 | * | ||
546 | * @param t Tunnel. | ||
547 | * | ||
548 | * @return Static string the destination peer's ID. | ||
549 | */ | ||
550 | const char * | ||
551 | GCT_2s (const struct CadetTunnel *t); | ||
552 | |||
553 | |||
554 | /** | ||
555 | * Log all possible info about the tunnel state. | ||
556 | * | ||
557 | * @param t Tunnel to debug. | ||
558 | * @param level Debug level to use. | ||
559 | */ | ||
560 | void | ||
561 | GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level); | ||
562 | |||
563 | |||
564 | /** | ||
565 | * Iterate all tunnels. | ||
566 | * | ||
567 | * @param iter Iterator. | ||
568 | * @param cls Closure for @c iter. | ||
569 | */ | ||
570 | void | ||
571 | GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); | ||
572 | |||
573 | |||
574 | /** | ||
575 | * Count all tunnels. | ||
576 | * | ||
577 | * @return Number of tunnels to remote peers kept by this peer. | ||
578 | */ | ||
579 | unsigned int | ||
580 | GCT_count_all (void); | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Iterate all connections of a tunnel. | ||
585 | * | ||
586 | * @param t Tunnel whose connections to iterate. | ||
587 | * @param iter Iterator. | ||
588 | * @param cls Closure for @c iter. | ||
589 | */ | ||
590 | void | ||
591 | GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls); | ||
592 | |||
593 | |||
594 | /** | ||
595 | * Iterate all channels of a tunnel. | ||
596 | * | ||
597 | * @param t Tunnel whose channels to iterate. | ||
598 | * @param iter Iterator. | ||
599 | * @param cls Closure for @c iter. | ||
600 | */ | ||
601 | void | ||
602 | GCT_iterate_channels (struct CadetTunnel *t, | ||
603 | GCT_chan_iter iter, | ||
604 | void *cls); | ||
605 | |||
606 | |||
607 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
608 | { | ||
609 | #endif | ||
610 | #ifdef __cplusplus | ||
611 | } | ||
612 | #endif | ||
613 | |||
614 | /* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */ | ||
615 | #endif | ||
616 | /* end of gnunet-cadet-service_tunnel.h */ | ||
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c index d50860629..bcdeeb4da 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.c +++ b/src/cadet/gnunet-service-cadet_tunnels.c | |||
@@ -18,7 +18,7 @@ | |||
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | /** | 20 | /** |
21 | * @file cadet/gnunet-service-cadet-new_tunnels.c | 21 | * @file cadet/gnunet-service-cadet_tunnels.c |
22 | * @brief Information we track per tunnel. | 22 | * @brief Information we track per tunnel. |
23 | * @author Bartlomiej Polot | 23 | * @author Bartlomiej Polot |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
@@ -34,13 +34,12 @@ | |||
34 | #include "gnunet_util_lib.h" | 34 | #include "gnunet_util_lib.h" |
35 | #include "gnunet_statistics_service.h" | 35 | #include "gnunet_statistics_service.h" |
36 | #include "gnunet_signatures.h" | 36 | #include "gnunet_signatures.h" |
37 | #include "gnunet-service-cadet-new.h" | ||
38 | #include "cadet_protocol.h" | 37 | #include "cadet_protocol.h" |
39 | #include "gnunet-service-cadet-new_channel.h" | 38 | #include "gnunet-service-cadet_channel.h" |
40 | #include "gnunet-service-cadet-new_connection.h" | 39 | #include "gnunet-service-cadet_connection.h" |
41 | #include "gnunet-service-cadet-new_tunnels.h" | 40 | #include "gnunet-service-cadet_tunnels.h" |
42 | #include "gnunet-service-cadet-new_peer.h" | 41 | #include "gnunet-service-cadet_peer.h" |
43 | #include "gnunet-service-cadet-new_paths.h" | 42 | #include "gnunet-service-cadet_paths.h" |
44 | 43 | ||
45 | 44 | ||
46 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) | 45 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) |
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h index a81bc2341..4a3619ab6 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.h +++ b/src/cadet/gnunet-service-cadet_tunnels.h | |||
@@ -20,7 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * @file cadet/gnunet-service-cadet-new_tunnels.h | 23 | * @file cadet/gnunet-service-cadet_tunnels.h |
24 | * @brief Information we track per tunnel. | 24 | * @brief Information we track per tunnel. |
25 | * @author Bartlomiej Polot | 25 | * @author Bartlomiej Polot |
26 | * @author Christian Grothoff | 26 | * @author Christian Grothoff |
@@ -28,7 +28,7 @@ | |||
28 | #ifndef GNUNET_SERVICE_CADET_TUNNELS_H | 28 | #ifndef GNUNET_SERVICE_CADET_TUNNELS_H |
29 | #define GNUNET_SERVICE_CADET_TUNNELS_H | 29 | #define GNUNET_SERVICE_CADET_TUNNELS_H |
30 | 30 | ||
31 | #include "gnunet-service-cadet-new.h" | 31 | #include "gnunet-service-cadet.h" |
32 | #include "cadet_protocol.h" | 32 | #include "cadet_protocol.h" |
33 | 33 | ||
34 | 34 | ||
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c index e57c01be2..4fe43b3bf 100644 --- a/src/cadet/test_cadet.c +++ b/src/cadet/test_cadet.c | |||
@@ -21,7 +21,7 @@ | |||
21 | * @file cadet/test_cadet.c | 21 | * @file cadet/test_cadet.c |
22 | * @author Bart Polot | 22 | * @author Bart Polot |
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | * @brief Test for the cadet service: retransmission of traffic. | 24 | * @brief Test for the cadet service using mq API. |
25 | */ | 25 | */ |
26 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | #include "platform.h" | 27 | #include "platform.h" |
@@ -32,9 +32,20 @@ | |||
32 | 32 | ||
33 | 33 | ||
34 | /** | 34 | /** |
35 | * How many messages to send | 35 | * Ugly workaround to unify data handlers on incoming and outgoing channels. |
36 | */ | 36 | */ |
37 | #define TOTAL_PACKETS 500 /* Cannot exceed 64k! */ | 37 | struct CadetTestChannelWrapper |
38 | { | ||
39 | /** | ||
40 | * Channel pointer. | ||
41 | */ | ||
42 | struct GNUNET_CADET_Channel *ch; | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * How many messages to send by default. | ||
47 | */ | ||
48 | #define TOTAL_PACKETS 500 /* Cannot exceed 64k! */ | ||
38 | 49 | ||
39 | /** | 50 | /** |
40 | * How long until we give up on connecting the peers? | 51 | * How long until we give up on connecting the peers? |
@@ -42,7 +53,7 @@ | |||
42 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) | 53 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) |
43 | 54 | ||
44 | /** | 55 | /** |
45 | * Time to wait for stuff that should be rather fast | 56 | * Time to wait by default for stuff that should be rather fast. |
46 | */ | 57 | */ |
47 | #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) | 58 | #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) |
48 | 59 | ||
@@ -73,6 +84,16 @@ static char *test_name; | |||
73 | static int test_backwards = GNUNET_NO; | 84 | static int test_backwards = GNUNET_NO; |
74 | 85 | ||
75 | /** | 86 | /** |
87 | * How many packets to send. | ||
88 | */ | ||
89 | static unsigned int total_packets; | ||
90 | |||
91 | /** | ||
92 | * Time to wait for fast operations. | ||
93 | */ | ||
94 | static struct GNUNET_TIME_Relative short_time; | ||
95 | |||
96 | /** | ||
76 | * How many events have happened | 97 | * How many events have happened |
77 | */ | 98 | */ |
78 | static int ok; | 99 | static int ok; |
@@ -83,9 +104,9 @@ static int ok; | |||
83 | static int ok_goal; | 104 | static int ok_goal; |
84 | 105 | ||
85 | /** | 106 | /** |
86 | * Size of each test packet | 107 | * Size of each test packet's payload |
87 | */ | 108 | */ |
88 | static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); | 109 | static size_t size_payload = sizeof (uint32_t); |
89 | 110 | ||
90 | /** | 111 | /** |
91 | * Operation to get peer ids. | 112 | * Operation to get peer ids. |
@@ -158,9 +179,9 @@ static struct GNUNET_SCHEDULER_Task *disconnect_task; | |||
158 | static struct GNUNET_SCHEDULER_Task *test_task; | 179 | static struct GNUNET_SCHEDULER_Task *test_task; |
159 | 180 | ||
160 | /** | 181 | /** |
161 | * Task runnining #data_task(). | 182 | * Task runnining #send_next_msg(). |
162 | */ | 183 | */ |
163 | static struct GNUNET_SCHEDULER_Task *data_job; | 184 | static struct GNUNET_SCHEDULER_Task *send_next_msg_task; |
164 | 185 | ||
165 | /** | 186 | /** |
166 | * Cadet handle for the root peer | 187 | * Cadet handle for the root peer |
@@ -175,7 +196,7 @@ static struct GNUNET_CADET_Handle *h2; | |||
175 | /** | 196 | /** |
176 | * Channel handle for the root peer | 197 | * Channel handle for the root peer |
177 | */ | 198 | */ |
178 | static struct GNUNET_CADET_Channel *ch; | 199 | static struct GNUNET_CADET_Channel *outgoing_ch; |
179 | 200 | ||
180 | /** | 201 | /** |
181 | * Channel handle for the dest peer | 202 | * Channel handle for the dest peer |
@@ -183,17 +204,6 @@ static struct GNUNET_CADET_Channel *ch; | |||
183 | static struct GNUNET_CADET_Channel *incoming_ch; | 204 | static struct GNUNET_CADET_Channel *incoming_ch; |
184 | 205 | ||
185 | /** | 206 | /** |
186 | * Transmit handle for root data calls | ||
187 | */ | ||
188 | static struct GNUNET_CADET_TransmitHandle *th; | ||
189 | |||
190 | /** | ||
191 | * Transmit handle for root data calls | ||
192 | */ | ||
193 | static struct GNUNET_CADET_TransmitHandle *incoming_th; | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Time we started the data transmission (after channel has been established | 207 | * Time we started the data transmission (after channel has been established |
198 | * and initilized). | 208 | * and initilized). |
199 | */ | 209 | */ |
@@ -225,20 +235,26 @@ static unsigned int ka_received; | |||
225 | static unsigned int msg_dropped; | 235 | static unsigned int msg_dropped; |
226 | 236 | ||
227 | 237 | ||
238 | /******************************************************************************/ | ||
239 | |||
240 | |||
241 | /******************************************************************************/ | ||
242 | |||
243 | |||
228 | /** | 244 | /** |
229 | * Get the client number considered as the "target" or "receiver", depending on | 245 | * Get the channel considered as the "target" or "receiver", depending on |
230 | * the test type and size. | 246 | * the test type and size. |
231 | * | 247 | * |
232 | * @return Peer # of the target client, either 0 (for backward tests) or | 248 | * @return Channel handle of the target client, either 0 (for backward tests) |
233 | * the last peer in the line (for other tests). | 249 | * or the last peer in the line (for other tests). |
234 | */ | 250 | */ |
235 | static unsigned int | 251 | static struct GNUNET_CADET_Channel * |
236 | get_expected_target () | 252 | get_target_channel () |
237 | { | 253 | { |
238 | if (SPEED == test && GNUNET_YES == test_backwards) | 254 | if (SPEED == test && GNUNET_YES == test_backwards) |
239 | return 0; | 255 | return outgoing_ch; |
240 | else | 256 | else |
241 | return peers_requested - 1; | 257 | return incoming_ch; |
242 | } | 258 | } |
243 | 259 | ||
244 | 260 | ||
@@ -251,18 +267,15 @@ show_end_data (void) | |||
251 | static struct GNUNET_TIME_Absolute end_time; | 267 | static struct GNUNET_TIME_Absolute end_time; |
252 | static struct GNUNET_TIME_Relative total_time; | 268 | static struct GNUNET_TIME_Relative total_time; |
253 | 269 | ||
254 | end_time = GNUNET_TIME_absolute_get(); | 270 | end_time = GNUNET_TIME_absolute_get (); |
255 | total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); | 271 | total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time); |
256 | FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); | 272 | FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); |
257 | FPRINTF (stderr, "Test time %s\n", | 273 | FPRINTF (stderr, "Test time %s\n", |
258 | GNUNET_STRINGS_relative_time_to_string (total_time, | 274 | GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES)); |
259 | GNUNET_YES)); | 275 | FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms |
260 | FPRINTF (stderr, "Test bandwidth: %f kb/s\n", | 276 | FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms |
261 | 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms | ||
262 | FPRINTF (stderr, "Test throughput: %f packets/s\n\n", | ||
263 | TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms | ||
264 | GAUGER ("CADET", test_name, | 277 | GAUGER ("CADET", test_name, |
265 | TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000), | 278 | total_packets * 1000.0 / (total_time.rel_value_us / 1000), |
266 | "packets/s"); | 279 | "packets/s"); |
267 | } | 280 | } |
268 | 281 | ||
@@ -281,29 +294,19 @@ disconnect_cadet_peers (void *cls) | |||
281 | 294 | ||
282 | disconnect_task = NULL; | 295 | disconnect_task = NULL; |
283 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 296 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
284 | "disconnecting cadet service of peers, called from line %ld\n", | 297 | "disconnecting cadet service of peers, called from line %ld\n", |
285 | line); | 298 | line); |
286 | for (i = 0; i < 2; i++) | 299 | for (i = 0; i < 2; i++) |
287 | { | 300 | { |
288 | GNUNET_TESTBED_operation_done (t_op[i]); | 301 | GNUNET_TESTBED_operation_done (t_op[i]); |
289 | } | 302 | } |
290 | if (NULL != ch) | 303 | if (NULL != outgoing_ch) |
291 | { | 304 | { |
292 | if (NULL != th) | 305 | GNUNET_CADET_channel_destroy (outgoing_ch); |
293 | { | 306 | outgoing_ch = NULL; |
294 | GNUNET_CADET_notify_transmit_ready_cancel (th); | ||
295 | th = NULL; | ||
296 | } | ||
297 | GNUNET_CADET_channel_destroy (ch); | ||
298 | ch = NULL; | ||
299 | } | 307 | } |
300 | if (NULL != incoming_ch) | 308 | if (NULL != incoming_ch) |
301 | { | 309 | { |
302 | if (NULL != incoming_th) | ||
303 | { | ||
304 | GNUNET_CADET_notify_transmit_ready_cancel (incoming_th); | ||
305 | incoming_th = NULL; | ||
306 | } | ||
307 | GNUNET_CADET_channel_destroy (incoming_ch); | 310 | GNUNET_CADET_channel_destroy (incoming_ch); |
308 | incoming_ch = NULL; | 311 | incoming_ch = NULL; |
309 | } | 312 | } |
@@ -322,10 +325,10 @@ static void | |||
322 | shutdown_task (void *cls) | 325 | shutdown_task (void *cls) |
323 | { | 326 | { |
324 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); | 327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); |
325 | if (NULL != data_job) | 328 | if (NULL != send_next_msg_task) |
326 | { | 329 | { |
327 | GNUNET_SCHEDULER_cancel (data_job); | 330 | GNUNET_SCHEDULER_cancel (send_next_msg_task); |
328 | data_job = NULL; | 331 | send_next_msg_task = NULL; |
329 | } | 332 | } |
330 | if (NULL != test_task) | 333 | if (NULL != test_task) |
331 | { | 334 | { |
@@ -335,8 +338,8 @@ shutdown_task (void *cls) | |||
335 | if (NULL != disconnect_task) | 338 | if (NULL != disconnect_task) |
336 | { | 339 | { |
337 | GNUNET_SCHEDULER_cancel (disconnect_task); | 340 | GNUNET_SCHEDULER_cancel (disconnect_task); |
338 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, | 341 | disconnect_task = |
339 | (void *) __LINE__); | 342 | GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__); |
340 | } | 343 | } |
341 | } | 344 | } |
342 | 345 | ||
@@ -351,17 +354,11 @@ shutdown_task (void *cls) | |||
351 | * operation has executed successfully. | 354 | * operation has executed successfully. |
352 | */ | 355 | */ |
353 | static void | 356 | static void |
354 | stats_cont (void *cls, | 357 | stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) |
355 | struct GNUNET_TESTBED_Operation *op, | ||
356 | const char *emsg) | ||
357 | { | 358 | { |
358 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 359 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n", |
359 | " KA sent: %u, KA received: %u\n", | 360 | ka_sent, ka_received); |
360 | ka_sent, | 361 | if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1))) |
361 | ka_received); | ||
362 | if ( (KEEPALIVE == test) && | ||
363 | ( (ka_sent < 2) || | ||
364 | (ka_sent > ka_received + 1)) ) | ||
365 | { | 362 | { |
366 | GNUNET_break (0); | 363 | GNUNET_break (0); |
367 | ok--; | 364 | ok--; |
@@ -370,8 +367,7 @@ stats_cont (void *cls, | |||
370 | 367 | ||
371 | if (NULL != disconnect_task) | 368 | if (NULL != disconnect_task) |
372 | GNUNET_SCHEDULER_cancel (disconnect_task); | 369 | GNUNET_SCHEDULER_cancel (disconnect_task); |
373 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, | 370 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls); |
374 | cls); | ||
375 | } | 371 | } |
376 | 372 | ||
377 | 373 | ||
@@ -387,11 +383,8 @@ stats_cont (void *cls, | |||
387 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | 383 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration |
388 | */ | 384 | */ |
389 | static int | 385 | static int |
390 | stats_iterator (void *cls, | 386 | stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, |
391 | const struct GNUNET_TESTBED_Peer *peer, | 387 | const char *subsystem, const char *name, uint64_t value, |
392 | const char *subsystem, | ||
393 | const char *name, | ||
394 | uint64_t value, | ||
395 | int is_persistent) | 388 | int is_persistent) |
396 | { | 389 | { |
397 | static const char *s_sent = "# keepalives sent"; | 390 | static const char *s_sent = "# keepalives sent"; |
@@ -401,19 +394,15 @@ stats_iterator (void *cls, | |||
401 | uint32_t i; | 394 | uint32_t i; |
402 | 395 | ||
403 | i = GNUNET_TESTBED_get_index (peer); | 396 | i = GNUNET_TESTBED_get_index (peer); |
404 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 397 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i, |
405 | "STATS PEER %u - %s [%s]: %llu\n", | 398 | subsystem, name, (unsigned long long) value); |
406 | i, | ||
407 | subsystem, | ||
408 | name, | ||
409 | (unsigned long long) value); | ||
410 | if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) | 399 | if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) |
411 | ka_sent = value; | 400 | ka_sent = value; |
412 | if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i) | 401 | if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i) |
413 | ka_received = value; | 402 | ka_received = value; |
414 | if (0 == strncmp(rdrops, name, strlen (rdrops))) | 403 | if (0 == strncmp (rdrops, name, strlen (rdrops))) |
415 | msg_dropped += value; | 404 | msg_dropped += value; |
416 | if (0 == strncmp(cdrops, name, strlen (cdrops))) | 405 | if (0 == strncmp (cdrops, name, strlen (cdrops))) |
417 | msg_dropped += value; | 406 | msg_dropped += value; |
418 | 407 | ||
419 | return GNUNET_OK; | 408 | return GNUNET_OK; |
@@ -423,7 +412,7 @@ stats_iterator (void *cls, | |||
423 | /** | 412 | /** |
424 | * Task to gather all statistics. | 413 | * Task to gather all statistics. |
425 | * | 414 | * |
426 | * @param cls Closure (NULL). | 415 | * @param cls Closure (line from which the task was scheduled). |
427 | */ | 416 | */ |
428 | static void | 417 | static void |
429 | gather_stats_and_exit (void *cls) | 418 | gather_stats_and_exit (void *cls) |
@@ -432,21 +421,20 @@ gather_stats_and_exit (void *cls) | |||
432 | 421 | ||
433 | disconnect_task = NULL; | 422 | disconnect_task = NULL; |
434 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 423 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
435 | "gathering statistics from line %d\n", | 424 | "gathering statistics from line %ld\n", |
436 | (int) l); | 425 | l); |
437 | if (NULL != ch) | 426 | if (NULL != outgoing_ch) |
438 | { | 427 | { |
439 | if (NULL != th) | 428 | GNUNET_CADET_channel_destroy (outgoing_ch); |
440 | { | 429 | outgoing_ch = NULL; |
441 | GNUNET_CADET_notify_transmit_ready_cancel (th); | ||
442 | th = NULL; | ||
443 | } | ||
444 | GNUNET_CADET_channel_destroy (ch); | ||
445 | ch = NULL; | ||
446 | } | 430 | } |
447 | stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers, | 431 | stats_op = GNUNET_TESTBED_get_statistics (peers_running, |
448 | "cadet", NULL, | 432 | testbed_peers, |
449 | &stats_iterator, stats_cont, cls); | 433 | "cadet", |
434 | NULL, | ||
435 | &stats_iterator, | ||
436 | stats_cont, | ||
437 | cls); | ||
450 | } | 438 | } |
451 | 439 | ||
452 | 440 | ||
@@ -462,163 +450,151 @@ abort_test (long line) | |||
462 | if (NULL != disconnect_task) | 450 | if (NULL != disconnect_task) |
463 | { | 451 | { |
464 | GNUNET_SCHEDULER_cancel (disconnect_task); | 452 | GNUNET_SCHEDULER_cancel (disconnect_task); |
465 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 453 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line); |
466 | "Aborting test from %ld\n", line); | 454 | disconnect_task = |
467 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, | 455 | GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line); |
468 | (void *) line); | ||
469 | } | 456 | } |
470 | } | 457 | } |
471 | 458 | ||
472 | /** | ||
473 | * Transmit ready callback. | ||
474 | * | ||
475 | * @param cls Closure (message type). | ||
476 | * @param size Size of the tranmist buffer. | ||
477 | * @param buf Pointer to the beginning of the buffer. | ||
478 | * | ||
479 | * @return Number of bytes written to buf. | ||
480 | */ | ||
481 | static size_t | ||
482 | tmt_rdy (void *cls, size_t size, void *buf); | ||
483 | |||
484 | 459 | ||
485 | /** | 460 | /** |
486 | * Task to request a new data transmission. | 461 | * Send a message on the channel with the appropriate size and payload. |
462 | * | ||
463 | * Update the appropriate *_sent counter. | ||
487 | * | 464 | * |
488 | * @param cls Closure (peer #). | 465 | * @param channel Channel to send the message on. |
489 | */ | 466 | */ |
490 | static void | 467 | static void |
491 | data_task (void *cls) | 468 | send_test_message (struct GNUNET_CADET_Channel *channel) |
492 | { | 469 | { |
493 | struct GNUNET_CADET_Channel *channel; | 470 | struct GNUNET_MQ_Envelope *env; |
494 | static struct GNUNET_CADET_TransmitHandle **pth; | 471 | struct GNUNET_MessageHeader *msg; |
495 | long src; | 472 | uint32_t *data; |
473 | int payload; | ||
474 | int size; | ||
496 | 475 | ||
497 | data_job = NULL; | 476 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
498 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n"); | 477 | "Sending test message on channel %p\n", |
499 | if (GNUNET_YES == test_backwards) | 478 | channel); |
500 | { | 479 | size = size_payload; |
501 | channel = incoming_ch; | 480 | if (GNUNET_NO == initialized) |
502 | pth = &incoming_th; | ||
503 | src = peers_requested - 1; | ||
504 | } | ||
505 | else | ||
506 | { | 481 | { |
507 | channel = ch; | 482 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n"); |
508 | pth = &th; | 483 | size += 1000; |
509 | src = 0; | 484 | payload = data_sent; |
485 | if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer | ||
486 | data_sent++; | ||
510 | } | 487 | } |
511 | 488 | else if (SPEED == test || SPEED_ACK == test) | |
512 | GNUNET_assert (NULL != channel); | ||
513 | GNUNET_assert (NULL == *pth); | ||
514 | |||
515 | *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, | ||
516 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
517 | size_payload + data_sent, | ||
518 | &tmt_rdy, (void *) src); | ||
519 | if (NULL == *pth) | ||
520 | { | 489 | { |
521 | unsigned long i = (unsigned long) cls; | 490 | if (get_target_channel() == channel) |
522 | |||
523 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n"); | ||
524 | if (0 == i) | ||
525 | { | 491 | { |
526 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " in 1 ms\n"); | 492 | payload = ack_sent; |
527 | data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | 493 | size += ack_sent; |
528 | &data_task, (void *) 1L); | 494 | ack_sent++; |
495 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
496 | "Sending ACK %u [%d bytes]\n", | ||
497 | payload, size); | ||
529 | } | 498 | } |
530 | else | 499 | else |
531 | { | 500 | { |
532 | i++; | 501 | payload = data_sent; |
533 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 502 | size += data_sent; |
534 | "in %llu ms\n", | 503 | data_sent++; |
535 | (unsigned long long) i); | 504 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
536 | data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | 505 | "Sending DATA %u [%d bytes]\n", |
537 | i), | 506 | data_sent, size); |
538 | &data_task, (void *) i); | ||
539 | } | 507 | } |
540 | } | 508 | } |
541 | } | 509 | else if (FORWARD == test) |
510 | { | ||
511 | payload = ack_sent; | ||
512 | } | ||
513 | else if (P2P_SIGNAL == test) | ||
514 | { | ||
515 | payload = data_sent; | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | GNUNET_assert (0); | ||
520 | } | ||
521 | env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY); | ||
542 | 522 | ||
523 | data = (uint32_t *) &msg[1]; | ||
524 | *data = htonl (payload); | ||
525 | GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env); | ||
526 | } | ||
543 | 527 | ||
544 | /** | 528 | /** |
545 | * Transmit ready callback | 529 | * Task to request a new data transmission in a SPEED test, without waiting |
530 | * for previous messages to be sent/arrrive. | ||
546 | * | 531 | * |
547 | * @param cls Closure (peer # which is sending the data). | 532 | * @param cls Closure (unused). |
548 | * @param size Size of the buffer we have. | ||
549 | * @param buf Buffer to copy data to. | ||
550 | */ | 533 | */ |
551 | static size_t | 534 | static void |
552 | tmt_rdy (void *cls, size_t size, void *buf) | 535 | send_next_msg (void *cls) |
553 | { | 536 | { |
554 | struct GNUNET_MessageHeader *msg = buf; | 537 | struct GNUNET_CADET_Channel *channel; |
555 | size_t msg_size; | ||
556 | uint32_t *data; | ||
557 | long id = (long) cls; | ||
558 | unsigned int counter; | ||
559 | 538 | ||
560 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 539 | send_next_msg_task = NULL; |
561 | "tmt_rdy on %ld, filling buffer\n", | 540 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent); |
562 | id); | 541 | |
563 | if (0 == id) | 542 | channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch; |
564 | th = NULL; | 543 | GNUNET_assert (NULL != channel); |
565 | else if ((peers_requested - 1) == id) | 544 | GNUNET_assert (SPEED == test); |
566 | incoming_th = NULL; | 545 | send_test_message (channel); |
567 | else | 546 | if (data_sent < total_packets) |
568 | GNUNET_assert (0); | ||
569 | counter = get_expected_target () == id ? ack_sent : data_sent; | ||
570 | msg_size = size_payload + counter; | ||
571 | GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader)); | ||
572 | if ( (size < msg_size) || | ||
573 | (NULL == buf) ) | ||
574 | { | ||
575 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
576 | "size %u, buf %p, data_sent %u, ack_received %u\n", | ||
577 | (unsigned int) size, | ||
578 | buf, | ||
579 | data_sent, | ||
580 | ack_received); | ||
581 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal); | ||
582 | GNUNET_break (ok >= ok_goal - 2); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | msg->size = htons (msg_size); | ||
587 | msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY); | ||
588 | data = (uint32_t *) &msg[1]; | ||
589 | *data = htonl (counter); | ||
590 | if (GNUNET_NO == initialized) | ||
591 | { | 547 | { |
548 | /* SPEED test: Send all messages as soon as possible */ | ||
592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
593 | "sending initializer\n"); | 550 | "Scheduling message %d\n", |
594 | msg_size = size_payload + 1000; | 551 | data_sent + 1); |
595 | msg->size = htons (msg_size); | 552 | send_next_msg_task = |
596 | if (SPEED_ACK == test) | 553 | GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, |
597 | data_sent++; | 554 | &send_next_msg, |
555 | NULL); | ||
598 | } | 556 | } |
599 | else if ( (SPEED == test) || | 557 | } |
600 | (SPEED_ACK == test) ) | 558 | |
559 | |||
560 | /** | ||
561 | * Every few messages cancel the timeout task and re-schedule it again, to | ||
562 | * avoid timing out when traffic keeps coming. | ||
563 | * | ||
564 | * @param line Code line number to log if a timeout occurs. | ||
565 | */ | ||
566 | static void | ||
567 | reschedule_timeout_task (long line) | ||
568 | { | ||
569 | if ((ok % 10) == 0) | ||
601 | { | 570 | { |
602 | if (get_expected_target() == id) | 571 | if (NULL != disconnect_task) |
603 | ack_sent++; | ||
604 | else | ||
605 | data_sent++; | ||
606 | counter++; | ||
607 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
608 | " Sent message %u size %u\n", | ||
609 | counter, | ||
610 | (unsigned int) msg_size); | ||
611 | if ( (data_sent < TOTAL_PACKETS) && | ||
612 | (SPEED == test) ) | ||
613 | { | 572 | { |
614 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 573 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
615 | " Scheduling message %d\n", | 574 | " reschedule timeout every 10 messages\n"); |
616 | counter + 1); | 575 | GNUNET_SCHEDULER_cancel (disconnect_task); |
617 | data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL); | 576 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, |
577 | &gather_stats_and_exit, | ||
578 | (void *) line); | ||
618 | } | 579 | } |
619 | } | 580 | } |
581 | } | ||
620 | 582 | ||
621 | return msg_size; | 583 | |
584 | /** | ||
585 | * Check if payload is sane (size contains payload). | ||
586 | * | ||
587 | * @param cls should match #ch | ||
588 | * @param message The actual message. | ||
589 | * @return #GNUNET_OK to keep the channel open, | ||
590 | * #GNUNET_SYSERR to close it (signal serious error). | ||
591 | */ | ||
592 | static int | ||
593 | check_data (void *cls, const struct GNUNET_MessageHeader *message) | ||
594 | { | ||
595 | if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size)) | ||
596 | return GNUNET_SYSERR; | ||
597 | return GNUNET_OK; /* all is well-formed */ | ||
622 | } | 598 | } |
623 | 599 | ||
624 | 600 | ||
@@ -626,75 +602,50 @@ tmt_rdy (void *cls, size_t size, void *buf) | |||
626 | * Function is called whenever a message is received. | 602 | * Function is called whenever a message is received. |
627 | * | 603 | * |
628 | * @param cls closure (set from GNUNET_CADET_connect(), peer number) | 604 | * @param cls closure (set from GNUNET_CADET_connect(), peer number) |
629 | * @param channel connection to the other end | ||
630 | * @param channel_ctx place to store local state associated with the channel | ||
631 | * @param message the actual message | 605 | * @param message the actual message |
632 | * @return #GNUNET_OK to keep the connection open, | ||
633 | * #GNUNET_SYSERR to close it (signal serious error) | ||
634 | */ | 606 | */ |
635 | static int | 607 | static void |
636 | data_callback (void *cls, | 608 | handle_data (void *cls, const struct GNUNET_MessageHeader *message) |
637 | struct GNUNET_CADET_Channel *channel, | ||
638 | void **channel_ctx, | ||
639 | const struct GNUNET_MessageHeader *message) | ||
640 | { | 609 | { |
641 | struct GNUNET_CADET_TransmitHandle **pth; | 610 | struct CadetTestChannelWrapper *ch = cls; |
642 | long client = (long) cls; | 611 | struct GNUNET_CADET_Channel *channel = ch->ch; |
643 | long expected_target_client; | ||
644 | uint32_t *data; | 612 | uint32_t *data; |
645 | uint32_t payload; | 613 | uint32_t payload; |
646 | unsigned int counter; | 614 | int *counter; |
647 | 615 | ||
648 | ok++; | 616 | ok++; |
649 | counter = get_expected_target () == client ? data_received : ack_received; | ||
650 | |||
651 | GNUNET_CADET_receive_done (channel); | 617 | GNUNET_CADET_receive_done (channel); |
618 | counter = get_target_channel () == channel ? &data_received : &ack_received; | ||
652 | 619 | ||
653 | if ((ok % 10) == 0) | 620 | reschedule_timeout_task ((long) __LINE__); |
621 | |||
622 | if (channel == outgoing_ch) | ||
654 | { | 623 | { |
655 | if (NULL != disconnect_task) | 624 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n"); |
656 | { | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
658 | " reschedule timeout\n"); | ||
659 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
660 | disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, | ||
661 | &gather_stats_and_exit, | ||
662 | (void *) __LINE__); | ||
663 | } | ||
664 | } | 625 | } |
665 | 626 | else if (channel == incoming_ch) | |
666 | switch (client) | ||
667 | { | 627 | { |
668 | case 0L: | 628 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n"); |
669 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n"); | 629 | } |
670 | GNUNET_assert (channel == ch); | 630 | else |
671 | pth = &th; | 631 | { |
672 | break; | 632 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel); |
673 | case 1L: | ||
674 | case 4L: | ||
675 | GNUNET_assert (client == peers_requested - 1); | ||
676 | GNUNET_assert (channel == incoming_ch); | ||
677 | pth = &incoming_th; | ||
678 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n", | ||
679 | client); | ||
680 | break; | ||
681 | default: | ||
682 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client); | ||
683 | GNUNET_assert (0); | 633 | GNUNET_assert (0); |
684 | } | 634 | } |
635 | |||
685 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); | 636 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); |
686 | data = (uint32_t *) &message[1]; | 637 | data = (uint32_t *) &message[1]; |
687 | payload = ntohl (*data); | 638 | payload = ntohl (*data); |
688 | if (payload == counter) | 639 | if (payload == *counter) |
689 | { | 640 | { |
690 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload); | 641 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload); |
691 | } | 642 | } |
692 | else | 643 | else |
693 | { | 644 | { |
694 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n", | 645 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
695 | payload, counter); | 646 | " payload %u, expected: %u\n", |
647 | payload, *counter); | ||
696 | } | 648 | } |
697 | expected_target_client = get_expected_target (); | ||
698 | 649 | ||
699 | if (GNUNET_NO == initialized) | 650 | if (GNUNET_NO == initialized) |
700 | { | 651 | { |
@@ -702,189 +653,152 @@ data_callback (void *cls, | |||
702 | start_time = GNUNET_TIME_absolute_get (); | 653 | start_time = GNUNET_TIME_absolute_get (); |
703 | if (SPEED == test) | 654 | if (SPEED == test) |
704 | { | 655 | { |
705 | GNUNET_assert (peers_requested - 1 == client); | 656 | GNUNET_assert (incoming_ch == channel); |
706 | data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL); | 657 | send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL); |
707 | return GNUNET_OK; | 658 | return; |
708 | } | 659 | } |
709 | } | 660 | } |
710 | 661 | ||
711 | counter++; | 662 | (*counter)++; |
712 | if (client == expected_target_client) /* Normally 4 */ | 663 | if (get_target_channel () == channel) /* Got "data" */ |
713 | { | 664 | { |
714 | data_received++; | ||
715 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); | 665 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); |
716 | if (SPEED != test || (ok_goal - 2) == ok) | 666 | if (SPEED != test || (ok_goal - 2) == ok) |
717 | { | 667 | { |
718 | /* Send ACK */ | 668 | /* Send ACK */ |
719 | GNUNET_assert (NULL == *pth); | 669 | send_test_message (channel); |
720 | *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, | 670 | return; |
721 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
722 | size_payload + ack_sent, | ||
723 | &tmt_rdy, (void *) client); | ||
724 | return GNUNET_OK; | ||
725 | } | 671 | } |
726 | else | 672 | else |
727 | { | 673 | { |
728 | if (data_received < TOTAL_PACKETS) | 674 | if (data_received < total_packets) |
729 | return GNUNET_OK; | 675 | return; |
730 | } | 676 | } |
731 | } | 677 | } |
732 | else /* Normally 0 */ | 678 | else /* Got "ack" */ |
733 | { | 679 | { |
734 | if (SPEED_ACK == test || SPEED == test) | 680 | if (SPEED_ACK == test || SPEED == test) |
735 | { | 681 | { |
736 | ack_received++; | ||
737 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received); | 682 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received); |
738 | /* send more data */ | 683 | /* Send more data */ |
739 | GNUNET_assert (NULL == *pth); | 684 | send_test_message (channel); |
740 | *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, | 685 | if (ack_received < total_packets && SPEED != test) |
741 | GNUNET_TIME_UNIT_FOREVER_REL, | 686 | return; |
742 | size_payload + data_sent, | ||
743 | &tmt_rdy, (void *) client); | ||
744 | if (ack_received < TOTAL_PACKETS && SPEED != test) | ||
745 | return GNUNET_OK; | ||
746 | if (ok == 2 && SPEED == test) | 687 | if (ok == 2 && SPEED == test) |
747 | return GNUNET_OK; | 688 | return; |
748 | show_end_data(); | 689 | show_end_data (); |
749 | } | 690 | } |
750 | if (test == P2P_SIGNAL) | 691 | if (test == P2P_SIGNAL) |
751 | { | 692 | { |
752 | if (NULL != incoming_th) | ||
753 | { | ||
754 | GNUNET_CADET_notify_transmit_ready_cancel (incoming_th); | ||
755 | incoming_th = NULL; | ||
756 | } | ||
757 | GNUNET_CADET_channel_destroy (incoming_ch); | 693 | GNUNET_CADET_channel_destroy (incoming_ch); |
758 | incoming_ch = NULL; | 694 | incoming_ch = NULL; |
759 | } | 695 | } |
760 | else | 696 | else |
761 | { | 697 | { |
762 | if (NULL != th) | 698 | GNUNET_CADET_channel_destroy (outgoing_ch); |
763 | { | 699 | outgoing_ch = NULL; |
764 | GNUNET_CADET_notify_transmit_ready_cancel (th); | ||
765 | th = NULL; | ||
766 | } | ||
767 | GNUNET_CADET_channel_destroy (ch); | ||
768 | ch = NULL; | ||
769 | } | 700 | } |
770 | } | 701 | } |
771 | |||
772 | return GNUNET_OK; | ||
773 | } | 702 | } |
774 | 703 | ||
775 | 704 | ||
776 | /** | 705 | /** |
777 | * Data handlers for every message type of CADET's payload. | 706 | * Method called whenever a peer connects to a port in MQ-based CADET. |
778 | * {callback_function, message_type, size_expected} | ||
779 | */ | ||
780 | static struct GNUNET_CADET_MessageHandler handlers[] = { | ||
781 | {&data_callback, | ||
782 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
783 | sizeof (struct GNUNET_MessageHeader)}, | ||
784 | {NULL, 0, 0} | ||
785 | }; | ||
786 | |||
787 | |||
788 | /** | ||
789 | * Method called whenever another peer has added us to a channel | ||
790 | * the other peer initiated. | ||
791 | * | 707 | * |
792 | * @param cls Closure. | 708 | * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long). |
793 | * @param channel New handle to the channel. | 709 | * @param channel New handle to the channel. |
794 | * @param initiator Peer that started the channel. | 710 | * @param source Peer that started this channel. |
795 | * @param port Port this channel is connected to. | 711 | * @return Closure for the incoming @a channel. It's given to: |
796 | * @param options channel option flags | 712 | * - The #GNUNET_CADET_DisconnectEventHandler (given to |
797 | * @return Initial channel context for the channel | 713 | * #GNUNET_CADET_open_porT) when the channel dies. |
798 | * (can be NULL -- that's not an error). | 714 | * - Each the #GNUNET_MQ_MessageCallback handlers for each message |
715 | * received on the @a channel. | ||
799 | */ | 716 | */ |
800 | static void * | 717 | static void * |
801 | incoming_channel (void *cls, | 718 | connect_handler (void *cls, struct GNUNET_CADET_Channel *channel, |
802 | struct GNUNET_CADET_Channel *channel, | 719 | const struct GNUNET_PeerIdentity *source) |
803 | const struct GNUNET_PeerIdentity *initiator, | ||
804 | const struct GNUNET_HashCode *port, | ||
805 | enum GNUNET_CADET_ChannelOption options) | ||
806 | { | 720 | { |
721 | struct CadetTestChannelWrapper *ch; | ||
722 | long peer = (long) cls; | ||
723 | |||
807 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 724 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
808 | "Incoming channel from %s to peer %d:%s\n", | 725 | "Incoming channel from %s to %ld: %p\n", |
809 | GNUNET_i2s (initiator), | 726 | GNUNET_i2s (source), peer, channel); |
810 | (int) (long) cls, GNUNET_h2s (port)); | ||
811 | ok++; | 727 | ok++; |
812 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); | 728 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); |
813 | if ((long) cls == peers_requested - 1) | 729 | if (peer == peers_requested - 1) |
814 | { | 730 | { |
815 | if (NULL != incoming_ch) | 731 | if (NULL != incoming_ch) |
816 | { | 732 | { |
817 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 733 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
818 | "Duplicate incoming channel for client %lu\n", | 734 | "Duplicate incoming channel for client %lu\n", (long) cls); |
819 | (long) cls); | 735 | GNUNET_assert (0); |
820 | GNUNET_break(0); | ||
821 | } | 736 | } |
822 | incoming_ch = channel; | 737 | incoming_ch = channel; |
823 | } | 738 | } |
824 | else | 739 | else |
825 | { | 740 | { |
826 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 741 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
827 | "Incoming channel for unexpected peer #%lu\n", | 742 | "Incoming channel for unexpected peer #%lu\n", (long) cls); |
828 | (long) cls); | 743 | GNUNET_assert (0); |
829 | GNUNET_break (0); | ||
830 | } | 744 | } |
831 | if (NULL != disconnect_task) | 745 | if (NULL != disconnect_task) |
832 | { | 746 | { |
833 | GNUNET_SCHEDULER_cancel (disconnect_task); | 747 | GNUNET_SCHEDULER_cancel (disconnect_task); |
834 | disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, | 748 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, |
835 | &gather_stats_and_exit, | 749 | &gather_stats_and_exit, |
836 | (void *) __LINE__); | 750 | (void *) __LINE__); |
837 | } | 751 | } |
838 | 752 | ||
839 | return NULL; | 753 | /* TODO: cannot return channel as-is, in order to unify the data handlers */ |
754 | ch = GNUNET_new (struct CadetTestChannelWrapper); | ||
755 | ch->ch = channel; | ||
756 | |||
757 | return ch; | ||
840 | } | 758 | } |
841 | 759 | ||
842 | 760 | ||
843 | /** | 761 | /** |
844 | * Function called whenever an inbound channel is destroyed. Should clean up | 762 | * Function called whenever an MQ-channel is destroyed, even if the destruction |
845 | * any associated state. | 763 | * was requested by #GNUNET_CADET_channel_destroy. |
764 | * It must NOT call #GNUNET_CADET_channel_destroy on the channel. | ||
846 | * | 765 | * |
847 | * @param cls closure (set from GNUNET_CADET_connect, peer number) | 766 | * It should clean up any associated state, including cancelling any pending |
848 | * @param channel connection to the other end (henceforth invalid) | 767 | * transmission on this channel. |
849 | * @param channel_ctx place where local state associated | 768 | * |
850 | * with the channel is stored | 769 | * @param cls Channel closure (channel wrapper). |
770 | * @param channel Connection to the other end (henceforth invalid). | ||
851 | */ | 771 | */ |
852 | static void | 772 | static void |
853 | channel_cleaner (void *cls, | 773 | disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel) |
854 | const struct GNUNET_CADET_Channel *channel, | ||
855 | void *channel_ctx) | ||
856 | { | 774 | { |
857 | long i = (long) cls; | 775 | struct CadetTestChannelWrapper *ch_w = cls; |
858 | 776 | ||
859 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 777 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n"); |
860 | "Incoming channel disconnected at peer %ld\n", | 778 | GNUNET_assert (ch_w->ch == channel); |
861 | i); | 779 | if (channel == incoming_ch) |
862 | if (peers_running - 1 == i) | ||
863 | { | 780 | { |
864 | ok++; | 781 | ok++; |
865 | GNUNET_break (channel == incoming_ch); | ||
866 | incoming_ch = NULL; | 782 | incoming_ch = NULL; |
867 | } | 783 | } |
868 | else if (0L == i) | 784 | else if (outgoing_ch == channel |
785 | ) | ||
869 | { | 786 | { |
870 | if (P2P_SIGNAL == test) | 787 | if (P2P_SIGNAL == test) |
871 | { | 788 | { |
872 | ok++; | 789 | ok++; |
873 | } | 790 | } |
874 | GNUNET_break (channel == ch); | 791 | outgoing_ch = NULL; |
875 | ch = NULL; | ||
876 | } | 792 | } |
877 | else | 793 | else |
878 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 794 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel); |
879 | "Unknown peer! %d\n", | ||
880 | (int) i); | ||
881 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); | 795 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); |
882 | 796 | ||
883 | if (NULL != disconnect_task) | 797 | if (NULL != disconnect_task) |
884 | { | 798 | { |
885 | GNUNET_SCHEDULER_cancel (disconnect_task); | 799 | GNUNET_SCHEDULER_cancel (disconnect_task); |
886 | disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, | 800 | disconnect_task = |
887 | (void *) __LINE__); | 801 | GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__); |
888 | } | 802 | } |
889 | } | 803 | } |
890 | 804 | ||
@@ -898,13 +812,20 @@ channel_cleaner (void *cls, | |||
898 | * @param cls Closure (unused). | 812 | * @param cls Closure (unused). |
899 | */ | 813 | */ |
900 | static void | 814 | static void |
901 | do_test (void *cls) | 815 | start_test (void *cls) |
902 | { | 816 | { |
817 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
818 | GNUNET_MQ_hd_var_size (data, | ||
819 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
820 | struct GNUNET_MessageHeader, | ||
821 | NULL), | ||
822 | GNUNET_MQ_handler_end () | ||
823 | }; | ||
824 | struct CadetTestChannelWrapper *ch; | ||
903 | enum GNUNET_CADET_ChannelOption flags; | 825 | enum GNUNET_CADET_ChannelOption flags; |
904 | 826 | ||
905 | test_task = NULL; | 827 | test_task = NULL; |
906 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n"); |
907 | "do_test\n"); | ||
908 | if (NULL != disconnect_task) | 829 | if (NULL != disconnect_task) |
909 | { | 830 | { |
910 | GNUNET_SCHEDULER_cancel (disconnect_task); | 831 | GNUNET_SCHEDULER_cancel (disconnect_task); |
@@ -918,30 +839,33 @@ do_test (void *cls) | |||
918 | flags |= GNUNET_CADET_OPTION_RELIABLE; | 839 | flags |= GNUNET_CADET_OPTION_RELIABLE; |
919 | } | 840 | } |
920 | 841 | ||
921 | ch = GNUNET_CADET_channel_create (h1, | 842 | ch = GNUNET_new (struct CadetTestChannelWrapper); |
922 | NULL, | 843 | outgoing_ch = GNUNET_CADET_channel_creatE (h1, |
923 | p_id[1], | 844 | ch, |
924 | &port, | 845 | p_id[1], |
925 | flags); | 846 | &port, |
847 | flags, | ||
848 | NULL, | ||
849 | &disconnect_handler, | ||
850 | handlers); | ||
851 | |||
852 | ch->ch = outgoing_ch; | ||
926 | 853 | ||
927 | disconnect_task | 854 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, |
928 | = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, | 855 | &gather_stats_and_exit, |
929 | &gather_stats_and_exit, | 856 | (void *) __LINE__); |
930 | (void *) __LINE__); | ||
931 | if (KEEPALIVE == test) | 857 | if (KEEPALIVE == test) |
932 | return; /* Don't send any data. */ | 858 | return; /* Don't send any data. */ |
859 | |||
933 | 860 | ||
934 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
935 | "Sending data initializer...\n"); | ||
936 | data_received = 0; | 861 | data_received = 0; |
937 | data_sent = 0; | 862 | data_sent = 0; |
938 | ack_received = 0; | 863 | ack_received = 0; |
939 | ack_sent = 0; | 864 | ack_sent = 0; |
940 | th = GNUNET_CADET_notify_transmit_ready (ch, | 865 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
941 | GNUNET_NO, | 866 | "Sending data initializer on channel %p...\n", |
942 | GNUNET_TIME_UNIT_FOREVER_REL, | 867 | outgoing_ch); |
943 | size_payload + 1000, | 868 | send_test_message (outgoing_ch); |
944 | &tmt_rdy, (void *) 0L); | ||
945 | } | 869 | } |
946 | 870 | ||
947 | 871 | ||
@@ -955,35 +879,26 @@ do_test (void *cls) | |||
955 | * NULL if the operation is successfull | 879 | * NULL if the operation is successfull |
956 | */ | 880 | */ |
957 | static void | 881 | static void |
958 | pi_cb (void *cls, | 882 | pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op, |
959 | struct GNUNET_TESTBED_Operation *op, | 883 | const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg) |
960 | const struct GNUNET_TESTBED_PeerInformation *pinfo, | ||
961 | const char *emsg) | ||
962 | { | 884 | { |
963 | long i = (long) cls; | 885 | long i = (long) cls; |
964 | 886 | ||
965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 887 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i); |
966 | "id callback for %ld\n", i); | ||
967 | 888 | ||
968 | if ( (NULL == pinfo) || | 889 | if ((NULL == pinfo) || (NULL != emsg)) |
969 | (NULL != emsg) ) | ||
970 | { | 890 | { |
971 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 891 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); |
972 | "pi_cb: %s\n", emsg); | ||
973 | abort_test (__LINE__); | 892 | abort_test (__LINE__); |
974 | return; | 893 | return; |
975 | } | 894 | } |
976 | p_id[i] = pinfo->result.id; | 895 | p_id[i] = pinfo->result.id; |
977 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 896 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i])); |
978 | " id: %s\n", GNUNET_i2s (p_id[i])); | ||
979 | p_ids++; | 897 | p_ids++; |
980 | if (p_ids < 2) | 898 | if (p_ids < 2) |
981 | return; | 899 | return; |
982 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 900 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); |
983 | "Got all IDs, starting test\n"); | 901 | test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL); |
984 | test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
985 | &do_test, | ||
986 | NULL); | ||
987 | } | 902 | } |
988 | 903 | ||
989 | 904 | ||
@@ -994,7 +909,7 @@ pi_cb (void *cls, | |||
994 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. | 909 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. |
995 | * @param num_peers Number of peers that are running. | 910 | * @param num_peers Number of peers that are running. |
996 | * @param peers Array of peers. | 911 | * @param peers Array of peers. |
997 | * @param cadetes Handle to each of the CADETs of the peers. | 912 | * @param cadets Handle to each of the CADETs of the peers. |
998 | */ | 913 | */ |
999 | static void | 914 | static void |
1000 | tmain (void *cls, | 915 | tmain (void *cls, |
@@ -1011,16 +926,18 @@ tmain (void *cls, | |||
1011 | testbed_peers = peers; | 926 | testbed_peers = peers; |
1012 | h1 = cadets[0]; | 927 | h1 = cadets[0]; |
1013 | h2 = cadets[num_peers - 1]; | 928 | h2 = cadets[num_peers - 1]; |
1014 | disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, | 929 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, |
1015 | &disconnect_cadet_peers, | 930 | &disconnect_cadet_peers, |
1016 | (void *) __LINE__); | 931 | (void *) __LINE__); |
1017 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | 932 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); |
1018 | t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], | 933 | t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], |
1019 | GNUNET_TESTBED_PIT_IDENTITY, | 934 | GNUNET_TESTBED_PIT_IDENTITY, |
1020 | &pi_cb, (void *) 0L); | 935 | &pi_cb, |
936 | (void *) 0L); | ||
1021 | t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], | 937 | t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], |
1022 | GNUNET_TESTBED_PIT_IDENTITY, | 938 | GNUNET_TESTBED_PIT_IDENTITY, |
1023 | &pi_cb, (void *) 1L); | 939 | &pi_cb, |
940 | (void *) 1L); | ||
1024 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); | 941 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); |
1025 | } | 942 | } |
1026 | 943 | ||
@@ -1031,16 +948,42 @@ tmain (void *cls, | |||
1031 | int | 948 | int |
1032 | main (int argc, char *argv[]) | 949 | main (int argc, char *argv[]) |
1033 | { | 950 | { |
951 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
952 | GNUNET_MQ_hd_var_size (data, | ||
953 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
954 | struct GNUNET_MessageHeader, | ||
955 | NULL), | ||
956 | GNUNET_MQ_handler_end () | ||
957 | }; | ||
958 | |||
1034 | initialized = GNUNET_NO; | 959 | initialized = GNUNET_NO; |
1035 | static const struct GNUNET_HashCode *ports[2]; | 960 | static const struct GNUNET_HashCode *ports[2]; |
1036 | const char *config_file; | 961 | const char *config_file; |
1037 | char port_id[] = "test port"; | 962 | char port_id[] = "test port"; |
1038 | GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port); | 963 | |
964 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
965 | {'t', "time", "short_time", | ||
966 | gettext_noop ("set short timeout"), | ||
967 | GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time}, | ||
968 | {'m', "messages", "NUM_MESSAGES", | ||
969 | gettext_noop ("set number of messages to send"), | ||
970 | GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets}, | ||
971 | |||
972 | GNUNET_GETOPT_OPTION_END | ||
973 | }; | ||
1039 | 974 | ||
1040 | GNUNET_log_setup ("test", "DEBUG", NULL); | 975 | GNUNET_log_setup ("test", "DEBUG", NULL); |
1041 | config_file = "test_cadet.conf"; | ||
1042 | 976 | ||
1043 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); | 977 | total_packets = TOTAL_PACKETS; |
978 | short_time = SHORT_TIME; | ||
979 | if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv)) | ||
980 | { | ||
981 | FPRINTF (stderr, "test failed: problem with CLI parameters\n"); | ||
982 | exit (1); | ||
983 | } | ||
984 | |||
985 | config_file = "test_cadet.conf"; | ||
986 | GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port); | ||
1044 | 987 | ||
1045 | /* Find out requested size */ | 988 | /* Find out requested size */ |
1046 | if (strstr (argv[0], "_2_") != NULL) | 989 | if (strstr (argv[0], "_2_") != NULL) |
@@ -1078,11 +1021,11 @@ main (int argc, char *argv[]) | |||
1078 | { | 1021 | { |
1079 | /* Test is supposed to generate the following callbacks: | 1022 | /* Test is supposed to generate the following callbacks: |
1080 | * 1 incoming channel (@dest) | 1023 | * 1 incoming channel (@dest) |
1081 | * TOTAL_PACKETS received data packet (@dest) | 1024 | * total_packets received data packet (@dest) |
1082 | * TOTAL_PACKETS received data packet (@orig) | 1025 | * total_packets received data packet (@orig) |
1083 | * 1 received channel destroy (@dest) | 1026 | * 1 received channel destroy (@dest) |
1084 | */ | 1027 | */ |
1085 | ok_goal = TOTAL_PACKETS * 2 + 2; | 1028 | ok_goal = total_packets * 2 + 2; |
1086 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); | 1029 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); |
1087 | test = SPEED_ACK; | 1030 | test = SPEED_ACK; |
1088 | test_name = "speed ack"; | 1031 | test_name = "speed ack"; |
@@ -1092,11 +1035,11 @@ main (int argc, char *argv[]) | |||
1092 | /* Test is supposed to generate the following callbacks: | 1035 | /* Test is supposed to generate the following callbacks: |
1093 | * 1 incoming channel (@dest) | 1036 | * 1 incoming channel (@dest) |
1094 | * 1 initial packet (@dest) | 1037 | * 1 initial packet (@dest) |
1095 | * TOTAL_PACKETS received data packet (@dest) | 1038 | * total_packets received data packet (@dest) |
1096 | * 1 received data packet (@orig) | 1039 | * 1 received data packet (@orig) |
1097 | * 1 received channel destroy (@dest) | 1040 | * 1 received channel destroy (@dest) |
1098 | */ | 1041 | */ |
1099 | ok_goal = TOTAL_PACKETS + 4; | 1042 | ok_goal = total_packets + 4; |
1100 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); | 1043 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); |
1101 | if (strstr (argv[0], "_reliable") != NULL) | 1044 | if (strstr (argv[0], "_reliable") != NULL) |
1102 | { | 1045 | { |
@@ -1137,22 +1080,22 @@ main (int argc, char *argv[]) | |||
1137 | p_ids = 0; | 1080 | p_ids = 0; |
1138 | ports[0] = &port; | 1081 | ports[0] = &port; |
1139 | ports[1] = NULL; | 1082 | ports[1] = NULL; |
1140 | GNUNET_CADET_TEST_run ("test_cadet_small", | 1083 | GNUNET_CADET_TEST_ruN ("test_cadet_small", |
1141 | config_file, | 1084 | config_file, |
1142 | peers_requested, | 1085 | peers_requested, |
1143 | &tmain, | 1086 | &tmain, |
1144 | NULL, /* tmain cls */ | 1087 | NULL, /* tmain cls */ |
1145 | &incoming_channel, | 1088 | &connect_handler, |
1146 | &channel_cleaner, | 1089 | NULL, |
1147 | handlers, | 1090 | &disconnect_handler, |
1148 | ports); | 1091 | handlers, |
1092 | ports); | ||
1149 | if (NULL != strstr (argv[0], "_reliable")) | 1093 | if (NULL != strstr (argv[0], "_reliable")) |
1150 | msg_dropped = 0; /* dropped should be retransmitted */ | 1094 | msg_dropped = 0; /* dropped should be retransmitted */ |
1151 | 1095 | ||
1152 | if (ok_goal > ok - msg_dropped) | 1096 | if (ok_goal > ok - msg_dropped) |
1153 | { | 1097 | { |
1154 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1098 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal); |
1155 | "FAILED! (%d/%d)\n", ok, ok_goal); | ||
1156 | return 1; | 1099 | return 1; |
1157 | } | 1100 | } |
1158 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); | 1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); |
diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c deleted file mode 100644 index 2b915ab81..000000000 --- a/src/cadet/test_cadet_local.c +++ /dev/null | |||
@@ -1,351 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/test_cadet_local.c | ||
23 | * @brief test cadet local: test of cadet channels with just one peer | ||
24 | * @author Bartlomiej Polot | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_dht_service.h" | ||
30 | #include "gnunet_testing_lib.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | |||
33 | struct GNUNET_TESTING_Peer *me; | ||
34 | |||
35 | static struct GNUNET_CADET_Handle *cadet_peer_1; | ||
36 | |||
37 | static struct GNUNET_CADET_Handle *cadet_peer_2; | ||
38 | |||
39 | static struct GNUNET_CADET_Channel *ch; | ||
40 | |||
41 | static int result = GNUNET_OK; | ||
42 | |||
43 | static int got_data = GNUNET_NO; | ||
44 | |||
45 | static struct GNUNET_SCHEDULER_Task *abort_task; | ||
46 | |||
47 | static struct GNUNET_SCHEDULER_Task *connect_task; | ||
48 | |||
49 | static struct GNUNET_CADET_TransmitHandle *mth; | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Connect to other client and send data | ||
54 | * | ||
55 | * @param cls Closue (unused). | ||
56 | */ | ||
57 | static void | ||
58 | do_connect (void *cls); | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Shutdown nicely | ||
63 | */ | ||
64 | static void | ||
65 | do_shutdown (void *cls) | ||
66 | { | ||
67 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
68 | "shutdown\n"); | ||
69 | if (NULL != abort_task) | ||
70 | { | ||
71 | GNUNET_SCHEDULER_cancel (abort_task); | ||
72 | abort_task = NULL; | ||
73 | } | ||
74 | if (NULL != ch) | ||
75 | { | ||
76 | GNUNET_CADET_channel_destroy (ch); | ||
77 | ch = NULL; | ||
78 | } | ||
79 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
80 | "Disconnect client 1\n"); | ||
81 | if (NULL != cadet_peer_1) | ||
82 | { | ||
83 | GNUNET_CADET_disconnect (cadet_peer_1); | ||
84 | cadet_peer_1 = NULL; | ||
85 | } | ||
86 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
87 | "Disconnect client 2\n"); | ||
88 | if (NULL != cadet_peer_2) | ||
89 | { | ||
90 | GNUNET_CADET_disconnect (cadet_peer_2); | ||
91 | cadet_peer_2 = NULL; | ||
92 | } | ||
93 | if (NULL != connect_task) | ||
94 | { | ||
95 | GNUNET_SCHEDULER_cancel (connect_task); | ||
96 | connect_task = NULL; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Something went wrong and timed out. Kill everything and set error flag | ||
103 | */ | ||
104 | static void | ||
105 | do_abort (void *cls) | ||
106 | { | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); | ||
108 | result = GNUNET_SYSERR; | ||
109 | abort_task = NULL; | ||
110 | GNUNET_SCHEDULER_shutdown (); | ||
111 | } | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Function is called whenever a message is received. | ||
116 | * | ||
117 | * @param cls closure (set from GNUNET_CADET_connect) | ||
118 | * @param channel connection to the other end | ||
119 | * @param channel_ctx place to store local state associated with the channel | ||
120 | * @param message the actual message | ||
121 | * @return #GNUNET_OK to keep the connection open, | ||
122 | * #GNUNET_SYSERR to close it (signal serious error) | ||
123 | */ | ||
124 | static int | ||
125 | data_callback (void *cls, | ||
126 | struct GNUNET_CADET_Channel *channel, | ||
127 | void **channel_ctx, | ||
128 | const struct GNUNET_MessageHeader *message) | ||
129 | { | ||
130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
131 | "Data callback! Shutting down.\n"); | ||
132 | got_data = GNUNET_YES; | ||
133 | GNUNET_SCHEDULER_shutdown (); | ||
134 | GNUNET_CADET_receive_done (channel); | ||
135 | return GNUNET_OK; | ||
136 | } | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Method called whenever another peer has added us to a channel | ||
141 | * the other peer initiated. | ||
142 | * | ||
143 | * @param cls closure | ||
144 | * @param channel new handle to the channel | ||
145 | * @param initiator peer that started the channel | ||
146 | * @param port port number | ||
147 | * @param options channel options | ||
148 | * @return initial channel context for the channel | ||
149 | * (can be NULL -- that's not an error) | ||
150 | */ | ||
151 | static void * | ||
152 | inbound_channel (void *cls, | ||
153 | struct GNUNET_CADET_Channel *channel, | ||
154 | const struct GNUNET_PeerIdentity *initiator, | ||
155 | const struct GNUNET_HashCode *port, | ||
156 | enum GNUNET_CADET_ChannelOption options) | ||
157 | { | ||
158 | long id = (long) cls; | ||
159 | |||
160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
161 | "received incoming channel on peer %d, port %s\n", | ||
162 | (int) id, | ||
163 | GNUNET_h2s (port)); | ||
164 | if (id != 2L) | ||
165 | { | ||
166 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
167 | "wrong peer\n"); | ||
168 | result = GNUNET_SYSERR; | ||
169 | } | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Function called whenever an channel is destroyed. Should clean up | ||
176 | * any associated state. | ||
177 | * | ||
178 | * @param cls closure (set from GNUNET_CADET_connect) | ||
179 | * @param channel connection to the other end (henceforth invalid) | ||
180 | * @param channel_ctx place where local state associated | ||
181 | * with the channel is stored | ||
182 | */ | ||
183 | static void | ||
184 | channel_end (void *cls, | ||
185 | const struct GNUNET_CADET_Channel *channel, | ||
186 | void *channel_ctx) | ||
187 | { | ||
188 | long id = (long) cls; | ||
189 | |||
190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
191 | "incoming channel closed at peer %ld\n", | ||
192 | id); | ||
193 | if (NULL != mth) | ||
194 | { | ||
195 | GNUNET_CADET_notify_transmit_ready_cancel (mth); | ||
196 | mth = NULL; | ||
197 | } | ||
198 | if (channel == ch) | ||
199 | ch = NULL; | ||
200 | if (GNUNET_NO == got_data) | ||
201 | { | ||
202 | if (NULL == connect_task) | ||
203 | connect_task | ||
204 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
205 | 2), | ||
206 | &do_connect, | ||
207 | NULL); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Handler array for traffic received on peer1 | ||
214 | */ | ||
215 | static struct GNUNET_CADET_MessageHandler handlers1[] = { | ||
216 | {&data_callback, 1, 0}, | ||
217 | {NULL, 0, 0} | ||
218 | }; | ||
219 | |||
220 | |||
221 | /** | ||
222 | * Handler array for traffic received on peer2 (none expected) | ||
223 | */ | ||
224 | static struct GNUNET_CADET_MessageHandler handlers2[] = { | ||
225 | {&data_callback, 1, 0}, | ||
226 | {NULL, 0, 0} | ||
227 | }; | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Data send callback: fillbuffer with test packet. | ||
232 | * | ||
233 | * @param cls Closure (unused). | ||
234 | * @param size Buffer size. | ||
235 | * @param buf Buffer to fill. | ||
236 | * | ||
237 | * @return size of test packet. | ||
238 | */ | ||
239 | static size_t | ||
240 | do_send (void *cls, size_t size, void *buf) | ||
241 | { | ||
242 | struct GNUNET_MessageHeader *m = buf; | ||
243 | |||
244 | mth = NULL; | ||
245 | if (NULL == buf) | ||
246 | { | ||
247 | GNUNET_break (0); | ||
248 | result = GNUNET_SYSERR; | ||
249 | return 0; | ||
250 | } | ||
251 | m->size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
252 | m->type = htons (1); | ||
253 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); | ||
254 | return sizeof (struct GNUNET_MessageHeader); | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Connect to other client and send data | ||
260 | * | ||
261 | * @param cls Closue (unused). | ||
262 | */ | ||
263 | static void | ||
264 | do_connect (void *cls) | ||
265 | { | ||
266 | struct GNUNET_PeerIdentity id; | ||
267 | |||
268 | connect_task = NULL; | ||
269 | GNUNET_TESTING_peer_get_identity (me, &id); | ||
270 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
271 | "CONNECT BY PORT\n"); | ||
272 | ch = GNUNET_CADET_channel_create (cadet_peer_1, | ||
273 | NULL, | ||
274 | &id, GC_u2h (1), | ||
275 | GNUNET_CADET_OPTION_DEFAULT); | ||
276 | mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, | ||
277 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
278 | sizeof (struct GNUNET_MessageHeader), | ||
279 | &do_send, NULL); | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Initialize framework and start test | ||
285 | * | ||
286 | * @param cls Closure (unused). | ||
287 | * @param cfg Configuration handle. | ||
288 | * @param peer Testing peer handle. | ||
289 | */ | ||
290 | static void | ||
291 | run (void *cls, | ||
292 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
293 | struct GNUNET_TESTING_Peer *peer) | ||
294 | { | ||
295 | me = peer; | ||
296 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | ||
297 | NULL); | ||
298 | abort_task = | ||
299 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
300 | (GNUNET_TIME_UNIT_SECONDS, 15), | ||
301 | &do_abort, | ||
302 | NULL); | ||
303 | cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */ | ||
304 | (void *) 1L, /* cls */ | ||
305 | &channel_end, /* channel end hndlr */ | ||
306 | handlers1); /* traffic handlers */ | ||
307 | cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */ | ||
308 | (void *) 2L, /* cls */ | ||
309 | &channel_end, /* channel end hndlr */ | ||
310 | handlers2); /* traffic handlers */ | ||
311 | |||
312 | if ( (NULL == cadet_peer_1) || | ||
313 | (NULL == cadet_peer_2) ) | ||
314 | { | ||
315 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
316 | "Couldn't connect to cadet :(\n"); | ||
317 | result = GNUNET_SYSERR; | ||
318 | GNUNET_SCHEDULER_shutdown (); | ||
319 | return; | ||
320 | } | ||
321 | GNUNET_CADET_open_port (cadet_peer_2, | ||
322 | GC_u2h (1), | ||
323 | &inbound_channel, | ||
324 | (void *) 2L); | ||
325 | if (NULL == connect_task) | ||
326 | connect_task | ||
327 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
328 | 2), | ||
329 | &do_connect, | ||
330 | NULL); | ||
331 | } | ||
332 | |||
333 | |||
334 | /** | ||
335 | * Main | ||
336 | */ | ||
337 | int | ||
338 | main (int argc, char *argv[]) | ||
339 | { | ||
340 | if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", | ||
341 | "test_cadet.conf", | ||
342 | &run, NULL)) | ||
343 | { | ||
344 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n"); | ||
345 | return 2; | ||
346 | } | ||
347 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result); | ||
348 | return (result == GNUNET_OK) ? 0 : 1; | ||
349 | } | ||
350 | |||
351 | /* end of test_cadet_local_1.c */ | ||
diff --git a/src/cadet/test_cadet_new.c b/src/cadet/test_cadet_new.c deleted file mode 100644 index 374e86bf3..000000000 --- a/src/cadet/test_cadet_new.c +++ /dev/null | |||
@@ -1,1105 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2017 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/test_cadet_mq.c | ||
22 | * @author Bart Polot | ||
23 | * @author Christian Grothoff | ||
24 | * @brief Test for the cadet service using mq API. | ||
25 | */ | ||
26 | #include <stdio.h> | ||
27 | #include "platform.h" | ||
28 | #include "cadet_test_lib_new.h" | ||
29 | #include "gnunet_cadet_service.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include <gauger.h> | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Ugly workaround to unify data handlers on incoming and outgoing channels. | ||
36 | */ | ||
37 | struct CadetTestChannelWrapper | ||
38 | { | ||
39 | /** | ||
40 | * Channel pointer. | ||
41 | */ | ||
42 | struct GNUNET_CADET_Channel *ch; | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * How many messages to send by default. | ||
47 | */ | ||
48 | #define TOTAL_PACKETS 500 /* Cannot exceed 64k! */ | ||
49 | |||
50 | /** | ||
51 | * How long until we give up on connecting the peers? | ||
52 | */ | ||
53 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) | ||
54 | |||
55 | /** | ||
56 | * Time to wait by default for stuff that should be rather fast. | ||
57 | */ | ||
58 | #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) | ||
59 | |||
60 | /** | ||
61 | * DIFFERENT TESTS TO RUN | ||
62 | */ | ||
63 | #define SETUP 0 | ||
64 | #define FORWARD 1 | ||
65 | #define KEEPALIVE 2 | ||
66 | #define SPEED 3 | ||
67 | #define SPEED_ACK 4 | ||
68 | #define SPEED_REL 8 | ||
69 | #define P2P_SIGNAL 10 | ||
70 | |||
71 | /** | ||
72 | * Which test are we running? | ||
73 | */ | ||
74 | static int test; | ||
75 | |||
76 | /** | ||
77 | * String with test name | ||
78 | */ | ||
79 | static char *test_name; | ||
80 | |||
81 | /** | ||
82 | * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic. | ||
83 | */ | ||
84 | static int test_backwards = GNUNET_NO; | ||
85 | |||
86 | /** | ||
87 | * How many packets to send. | ||
88 | */ | ||
89 | static unsigned int total_packets; | ||
90 | |||
91 | /** | ||
92 | * Time to wait for fast operations. | ||
93 | */ | ||
94 | static struct GNUNET_TIME_Relative short_time; | ||
95 | |||
96 | /** | ||
97 | * How many events have happened | ||
98 | */ | ||
99 | static int ok; | ||
100 | |||
101 | /** | ||
102 | * Number of events expected to conclude the test successfully. | ||
103 | */ | ||
104 | static int ok_goal; | ||
105 | |||
106 | /** | ||
107 | * Size of each test packet's payload | ||
108 | */ | ||
109 | static size_t size_payload = sizeof (uint32_t); | ||
110 | |||
111 | /** | ||
112 | * Operation to get peer ids. | ||
113 | */ | ||
114 | static struct GNUNET_TESTBED_Operation *t_op[2]; | ||
115 | |||
116 | /** | ||
117 | * Peer ids. | ||
118 | */ | ||
119 | static struct GNUNET_PeerIdentity *p_id[2]; | ||
120 | |||
121 | /** | ||
122 | * Port ID | ||
123 | */ | ||
124 | static struct GNUNET_HashCode port; | ||
125 | |||
126 | /** | ||
127 | * Peer ids counter. | ||
128 | */ | ||
129 | static unsigned int p_ids; | ||
130 | |||
131 | /** | ||
132 | * Is the setup initialized? | ||
133 | */ | ||
134 | static int initialized; | ||
135 | |||
136 | /** | ||
137 | * Number of payload packes sent. | ||
138 | */ | ||
139 | static int data_sent; | ||
140 | |||
141 | /** | ||
142 | * Number of payload packets received. | ||
143 | */ | ||
144 | static int data_received; | ||
145 | |||
146 | /** | ||
147 | * Number of payload packed acknowledgements sent. | ||
148 | */ | ||
149 | static int ack_sent; | ||
150 | |||
151 | /** | ||
152 | * Number of payload packed explicitly (app level) acknowledged. | ||
153 | */ | ||
154 | static int ack_received; | ||
155 | |||
156 | /** | ||
157 | * Total number of peers asked to run. | ||
158 | */ | ||
159 | static unsigned long long peers_requested; | ||
160 | |||
161 | /** | ||
162 | * Number of currently running peers (should be same as @c peers_requested). | ||
163 | */ | ||
164 | static unsigned long long peers_running; | ||
165 | |||
166 | /** | ||
167 | * Test context (to shut down). | ||
168 | */ | ||
169 | struct GNUNET_CADET_TEST_Context *test_ctx; | ||
170 | |||
171 | /** | ||
172 | * Task called to disconnect peers. | ||
173 | */ | ||
174 | static struct GNUNET_SCHEDULER_Task *disconnect_task; | ||
175 | |||
176 | /** | ||
177 | * Task To perform tests | ||
178 | */ | ||
179 | static struct GNUNET_SCHEDULER_Task *test_task; | ||
180 | |||
181 | /** | ||
182 | * Task runnining #send_next_msg(). | ||
183 | */ | ||
184 | static struct GNUNET_SCHEDULER_Task *send_next_msg_task; | ||
185 | |||
186 | /** | ||
187 | * Cadet handle for the root peer | ||
188 | */ | ||
189 | static struct GNUNET_CADET_Handle *h1; | ||
190 | |||
191 | /** | ||
192 | * Cadet handle for the first leaf peer | ||
193 | */ | ||
194 | static struct GNUNET_CADET_Handle *h2; | ||
195 | |||
196 | /** | ||
197 | * Channel handle for the root peer | ||
198 | */ | ||
199 | static struct GNUNET_CADET_Channel *outgoing_ch; | ||
200 | |||
201 | /** | ||
202 | * Channel handle for the dest peer | ||
203 | */ | ||
204 | static struct GNUNET_CADET_Channel *incoming_ch; | ||
205 | |||
206 | /** | ||
207 | * Time we started the data transmission (after channel has been established | ||
208 | * and initilized). | ||
209 | */ | ||
210 | static struct GNUNET_TIME_Absolute start_time; | ||
211 | |||
212 | /** | ||
213 | * Peers handle. | ||
214 | */ | ||
215 | static struct GNUNET_TESTBED_Peer **testbed_peers; | ||
216 | |||
217 | /** | ||
218 | * Statistics operation handle. | ||
219 | */ | ||
220 | static struct GNUNET_TESTBED_Operation *stats_op; | ||
221 | |||
222 | /** | ||
223 | * Keepalives sent. | ||
224 | */ | ||
225 | static unsigned int ka_sent; | ||
226 | |||
227 | /** | ||
228 | * Keepalives received. | ||
229 | */ | ||
230 | static unsigned int ka_received; | ||
231 | |||
232 | /** | ||
233 | * How many messages were dropped by CADET because of full buffers? | ||
234 | */ | ||
235 | static unsigned int msg_dropped; | ||
236 | |||
237 | |||
238 | /******************************************************************************/ | ||
239 | |||
240 | |||
241 | /******************************************************************************/ | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Get the channel considered as the "target" or "receiver", depending on | ||
246 | * the test type and size. | ||
247 | * | ||
248 | * @return Channel handle of the target client, either 0 (for backward tests) | ||
249 | * or the last peer in the line (for other tests). | ||
250 | */ | ||
251 | static struct GNUNET_CADET_Channel * | ||
252 | get_target_channel () | ||
253 | { | ||
254 | if (SPEED == test && GNUNET_YES == test_backwards) | ||
255 | return outgoing_ch; | ||
256 | else | ||
257 | return incoming_ch; | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Show the results of the test (banwidth acheived) and log them to GAUGER | ||
263 | */ | ||
264 | static void | ||
265 | show_end_data (void) | ||
266 | { | ||
267 | static struct GNUNET_TIME_Absolute end_time; | ||
268 | static struct GNUNET_TIME_Relative total_time; | ||
269 | |||
270 | end_time = GNUNET_TIME_absolute_get (); | ||
271 | total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time); | ||
272 | FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); | ||
273 | FPRINTF (stderr, "Test time %s\n", | ||
274 | GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES)); | ||
275 | FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms | ||
276 | FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms | ||
277 | GAUGER ("CADET", test_name, | ||
278 | total_packets * 1000.0 / (total_time.rel_value_us / 1000), | ||
279 | "packets/s"); | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Disconnect from cadet services af all peers, call shutdown. | ||
285 | * | ||
286 | * @param cls Closure (line number from which termination was requested). | ||
287 | * @param tc Task Context. | ||
288 | */ | ||
289 | static void | ||
290 | disconnect_cadet_peers (void *cls) | ||
291 | { | ||
292 | long line = (long) cls; | ||
293 | unsigned int i; | ||
294 | |||
295 | disconnect_task = NULL; | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
297 | "disconnecting cadet service of peers, called from line %ld\n", | ||
298 | line); | ||
299 | for (i = 0; i < 2; i++) | ||
300 | { | ||
301 | GNUNET_TESTBED_operation_done (t_op[i]); | ||
302 | } | ||
303 | if (NULL != outgoing_ch) | ||
304 | { | ||
305 | GNUNET_CADET_channel_destroy (outgoing_ch); | ||
306 | outgoing_ch = NULL; | ||
307 | } | ||
308 | if (NULL != incoming_ch) | ||
309 | { | ||
310 | GNUNET_CADET_channel_destroy (incoming_ch); | ||
311 | incoming_ch = NULL; | ||
312 | } | ||
313 | GNUNET_CADET_TEST_cleanup (test_ctx); | ||
314 | GNUNET_SCHEDULER_shutdown (); | ||
315 | } | ||
316 | |||
317 | |||
318 | /** | ||
319 | * Shut down peergroup, clean up. | ||
320 | * | ||
321 | * @param cls Closure (unused). | ||
322 | * @param tc Task Context. | ||
323 | */ | ||
324 | static void | ||
325 | shutdown_task (void *cls) | ||
326 | { | ||
327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); | ||
328 | if (NULL != send_next_msg_task) | ||
329 | { | ||
330 | GNUNET_SCHEDULER_cancel (send_next_msg_task); | ||
331 | send_next_msg_task = NULL; | ||
332 | } | ||
333 | if (NULL != test_task) | ||
334 | { | ||
335 | GNUNET_SCHEDULER_cancel (test_task); | ||
336 | test_task = NULL; | ||
337 | } | ||
338 | if (NULL != disconnect_task) | ||
339 | { | ||
340 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
341 | disconnect_task = | ||
342 | GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | |||
347 | /** | ||
348 | * Stats callback. Finish the stats testbed operation and when all stats have | ||
349 | * been iterated, shutdown the test. | ||
350 | * | ||
351 | * @param cls Closure (line number from which termination was requested). | ||
352 | * @param op the operation that has been finished | ||
353 | * @param emsg error message in case the operation has failed; will be NULL if | ||
354 | * operation has executed successfully. | ||
355 | */ | ||
356 | static void | ||
357 | stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) | ||
358 | { | ||
359 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n", | ||
360 | ka_sent, ka_received); | ||
361 | if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1))) | ||
362 | { | ||
363 | GNUNET_break (0); | ||
364 | ok--; | ||
365 | } | ||
366 | GNUNET_TESTBED_operation_done (stats_op); | ||
367 | |||
368 | if (NULL != disconnect_task) | ||
369 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
370 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls); | ||
371 | } | ||
372 | |||
373 | |||
374 | /** | ||
375 | * Process statistic values. | ||
376 | * | ||
377 | * @param cls closure (line number, unused) | ||
378 | * @param peer the peer the statistic belong to | ||
379 | * @param subsystem name of subsystem that created the statistic | ||
380 | * @param name the name of the datum | ||
381 | * @param value the current value | ||
382 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not | ||
383 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | ||
384 | */ | ||
385 | static int | ||
386 | stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, | ||
387 | const char *subsystem, const char *name, uint64_t value, | ||
388 | int is_persistent) | ||
389 | { | ||
390 | static const char *s_sent = "# keepalives sent"; | ||
391 | static const char *s_recv = "# keepalives received"; | ||
392 | static const char *rdrops = "# messages dropped due to full buffer"; | ||
393 | static const char *cdrops = "# messages dropped due to slow client"; | ||
394 | uint32_t i; | ||
395 | |||
396 | i = GNUNET_TESTBED_get_index (peer); | ||
397 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i, | ||
398 | subsystem, name, (unsigned long long) value); | ||
399 | if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) | ||
400 | ka_sent = value; | ||
401 | if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i) | ||
402 | ka_received = value; | ||
403 | if (0 == strncmp (rdrops, name, strlen (rdrops))) | ||
404 | msg_dropped += value; | ||
405 | if (0 == strncmp (cdrops, name, strlen (cdrops))) | ||
406 | msg_dropped += value; | ||
407 | |||
408 | return GNUNET_OK; | ||
409 | } | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Task to gather all statistics. | ||
414 | * | ||
415 | * @param cls Closure (line from which the task was scheduled). | ||
416 | */ | ||
417 | static void | ||
418 | gather_stats_and_exit (void *cls) | ||
419 | { | ||
420 | long l = (long) cls; | ||
421 | |||
422 | disconnect_task = NULL; | ||
423 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
424 | "gathering statistics from line %ld\n", | ||
425 | l); | ||
426 | if (NULL != outgoing_ch) | ||
427 | { | ||
428 | GNUNET_CADET_channel_destroy (outgoing_ch); | ||
429 | outgoing_ch = NULL; | ||
430 | } | ||
431 | stats_op = GNUNET_TESTBED_get_statistics (peers_running, | ||
432 | testbed_peers, | ||
433 | "cadet", | ||
434 | NULL, | ||
435 | &stats_iterator, | ||
436 | stats_cont, | ||
437 | cls); | ||
438 | } | ||
439 | |||
440 | |||
441 | |||
442 | /** | ||
443 | * Abort test: schedule disconnect and shutdown immediately | ||
444 | * | ||
445 | * @param line Line in the code the abort is requested from (__LINE__). | ||
446 | */ | ||
447 | static void | ||
448 | abort_test (long line) | ||
449 | { | ||
450 | if (NULL != disconnect_task) | ||
451 | { | ||
452 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
453 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line); | ||
454 | disconnect_task = | ||
455 | GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line); | ||
456 | } | ||
457 | } | ||
458 | |||
459 | |||
460 | /** | ||
461 | * Send a message on the channel with the appropriate size and payload. | ||
462 | * | ||
463 | * Update the appropriate *_sent counter. | ||
464 | * | ||
465 | * @param channel Channel to send the message on. | ||
466 | */ | ||
467 | static void | ||
468 | send_test_message (struct GNUNET_CADET_Channel *channel) | ||
469 | { | ||
470 | struct GNUNET_MQ_Envelope *env; | ||
471 | struct GNUNET_MessageHeader *msg; | ||
472 | uint32_t *data; | ||
473 | int payload; | ||
474 | int size; | ||
475 | |||
476 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
477 | "Sending test message on channel %p\n", | ||
478 | channel); | ||
479 | size = size_payload; | ||
480 | if (GNUNET_NO == initialized) | ||
481 | { | ||
482 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n"); | ||
483 | size += 1000; | ||
484 | payload = data_sent; | ||
485 | if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer | ||
486 | data_sent++; | ||
487 | } | ||
488 | else if (SPEED == test || SPEED_ACK == test) | ||
489 | { | ||
490 | if (get_target_channel() == channel) | ||
491 | { | ||
492 | payload = ack_sent; | ||
493 | size += ack_sent; | ||
494 | ack_sent++; | ||
495 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
496 | "Sending ACK %u [%d bytes]\n", | ||
497 | payload, size); | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | payload = data_sent; | ||
502 | size += data_sent; | ||
503 | data_sent++; | ||
504 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
505 | "Sending DATA %u [%d bytes]\n", | ||
506 | data_sent, size); | ||
507 | } | ||
508 | } | ||
509 | else if (FORWARD == test) | ||
510 | { | ||
511 | payload = ack_sent; | ||
512 | } | ||
513 | else if (P2P_SIGNAL == test) | ||
514 | { | ||
515 | payload = data_sent; | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | GNUNET_assert (0); | ||
520 | } | ||
521 | env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY); | ||
522 | |||
523 | data = (uint32_t *) &msg[1]; | ||
524 | *data = htonl (payload); | ||
525 | GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env); | ||
526 | } | ||
527 | |||
528 | /** | ||
529 | * Task to request a new data transmission in a SPEED test, without waiting | ||
530 | * for previous messages to be sent/arrrive. | ||
531 | * | ||
532 | * @param cls Closure (unused). | ||
533 | */ | ||
534 | static void | ||
535 | send_next_msg (void *cls) | ||
536 | { | ||
537 | struct GNUNET_CADET_Channel *channel; | ||
538 | |||
539 | send_next_msg_task = NULL; | ||
540 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent); | ||
541 | |||
542 | channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch; | ||
543 | GNUNET_assert (NULL != channel); | ||
544 | GNUNET_assert (SPEED == test); | ||
545 | send_test_message (channel); | ||
546 | if (data_sent < total_packets) | ||
547 | { | ||
548 | /* SPEED test: Send all messages as soon as possible */ | ||
549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
550 | "Scheduling message %d\n", | ||
551 | data_sent + 1); | ||
552 | send_next_msg_task = | ||
553 | GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, | ||
554 | &send_next_msg, | ||
555 | NULL); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | |||
560 | /** | ||
561 | * Every few messages cancel the timeout task and re-schedule it again, to | ||
562 | * avoid timing out when traffic keeps coming. | ||
563 | * | ||
564 | * @param line Code line number to log if a timeout occurs. | ||
565 | */ | ||
566 | static void | ||
567 | reschedule_timeout_task (long line) | ||
568 | { | ||
569 | if ((ok % 10) == 0) | ||
570 | { | ||
571 | if (NULL != disconnect_task) | ||
572 | { | ||
573 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
574 | " reschedule timeout every 10 messages\n"); | ||
575 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
576 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, | ||
577 | &gather_stats_and_exit, | ||
578 | (void *) line); | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | |||
583 | |||
584 | /** | ||
585 | * Check if payload is sane (size contains payload). | ||
586 | * | ||
587 | * @param cls should match #ch | ||
588 | * @param message The actual message. | ||
589 | * @return #GNUNET_OK to keep the channel open, | ||
590 | * #GNUNET_SYSERR to close it (signal serious error). | ||
591 | */ | ||
592 | static int | ||
593 | check_data (void *cls, const struct GNUNET_MessageHeader *message) | ||
594 | { | ||
595 | if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size)) | ||
596 | return GNUNET_SYSERR; | ||
597 | return GNUNET_OK; /* all is well-formed */ | ||
598 | } | ||
599 | |||
600 | |||
601 | /** | ||
602 | * Function is called whenever a message is received. | ||
603 | * | ||
604 | * @param cls closure (set from GNUNET_CADET_connect(), peer number) | ||
605 | * @param message the actual message | ||
606 | */ | ||
607 | static void | ||
608 | handle_data (void *cls, const struct GNUNET_MessageHeader *message) | ||
609 | { | ||
610 | struct CadetTestChannelWrapper *ch = cls; | ||
611 | struct GNUNET_CADET_Channel *channel = ch->ch; | ||
612 | uint32_t *data; | ||
613 | uint32_t payload; | ||
614 | int *counter; | ||
615 | |||
616 | ok++; | ||
617 | GNUNET_CADET_receive_done (channel); | ||
618 | counter = get_target_channel () == channel ? &data_received : &ack_received; | ||
619 | |||
620 | reschedule_timeout_task ((long) __LINE__); | ||
621 | |||
622 | if (channel == outgoing_ch) | ||
623 | { | ||
624 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n"); | ||
625 | } | ||
626 | else if (channel == incoming_ch) | ||
627 | { | ||
628 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n"); | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel); | ||
633 | GNUNET_assert (0); | ||
634 | } | ||
635 | |||
636 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); | ||
637 | data = (uint32_t *) &message[1]; | ||
638 | payload = ntohl (*data); | ||
639 | if (payload == *counter) | ||
640 | { | ||
641 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload); | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
646 | " payload %u, expected: %u\n", | ||
647 | payload, *counter); | ||
648 | } | ||
649 | |||
650 | if (GNUNET_NO == initialized) | ||
651 | { | ||
652 | initialized = GNUNET_YES; | ||
653 | start_time = GNUNET_TIME_absolute_get (); | ||
654 | if (SPEED == test) | ||
655 | { | ||
656 | GNUNET_assert (incoming_ch == channel); | ||
657 | send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL); | ||
658 | return; | ||
659 | } | ||
660 | } | ||
661 | |||
662 | (*counter)++; | ||
663 | if (get_target_channel () == channel) /* Got "data" */ | ||
664 | { | ||
665 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); | ||
666 | if (SPEED != test || (ok_goal - 2) == ok) | ||
667 | { | ||
668 | /* Send ACK */ | ||
669 | send_test_message (channel); | ||
670 | return; | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | if (data_received < total_packets) | ||
675 | return; | ||
676 | } | ||
677 | } | ||
678 | else /* Got "ack" */ | ||
679 | { | ||
680 | if (SPEED_ACK == test || SPEED == test) | ||
681 | { | ||
682 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received); | ||
683 | /* Send more data */ | ||
684 | send_test_message (channel); | ||
685 | if (ack_received < total_packets && SPEED != test) | ||
686 | return; | ||
687 | if (ok == 2 && SPEED == test) | ||
688 | return; | ||
689 | show_end_data (); | ||
690 | } | ||
691 | if (test == P2P_SIGNAL) | ||
692 | { | ||
693 | GNUNET_CADET_channel_destroy (incoming_ch); | ||
694 | incoming_ch = NULL; | ||
695 | } | ||
696 | else | ||
697 | { | ||
698 | GNUNET_CADET_channel_destroy (outgoing_ch); | ||
699 | outgoing_ch = NULL; | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Method called whenever a peer connects to a port in MQ-based CADET. | ||
707 | * | ||
708 | * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long). | ||
709 | * @param channel New handle to the channel. | ||
710 | * @param source Peer that started this channel. | ||
711 | * @return Closure for the incoming @a channel. It's given to: | ||
712 | * - The #GNUNET_CADET_DisconnectEventHandler (given to | ||
713 | * #GNUNET_CADET_open_porT) when the channel dies. | ||
714 | * - Each the #GNUNET_MQ_MessageCallback handlers for each message | ||
715 | * received on the @a channel. | ||
716 | */ | ||
717 | static void * | ||
718 | connect_handler (void *cls, struct GNUNET_CADET_Channel *channel, | ||
719 | const struct GNUNET_PeerIdentity *source) | ||
720 | { | ||
721 | struct CadetTestChannelWrapper *ch; | ||
722 | long peer = (long) cls; | ||
723 | |||
724 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
725 | "Incoming channel from %s to %ld: %p\n", | ||
726 | GNUNET_i2s (source), peer, channel); | ||
727 | ok++; | ||
728 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); | ||
729 | if (peer == peers_requested - 1) | ||
730 | { | ||
731 | if (NULL != incoming_ch) | ||
732 | { | ||
733 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
734 | "Duplicate incoming channel for client %lu\n", (long) cls); | ||
735 | GNUNET_assert (0); | ||
736 | } | ||
737 | incoming_ch = channel; | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
742 | "Incoming channel for unexpected peer #%lu\n", (long) cls); | ||
743 | GNUNET_assert (0); | ||
744 | } | ||
745 | if (NULL != disconnect_task) | ||
746 | { | ||
747 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
748 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, | ||
749 | &gather_stats_and_exit, | ||
750 | (void *) __LINE__); | ||
751 | } | ||
752 | |||
753 | /* TODO: cannot return channel as-is, in order to unify the data handlers */ | ||
754 | ch = GNUNET_new (struct CadetTestChannelWrapper); | ||
755 | ch->ch = channel; | ||
756 | |||
757 | return ch; | ||
758 | } | ||
759 | |||
760 | |||
761 | /** | ||
762 | * Function called whenever an MQ-channel is destroyed, even if the destruction | ||
763 | * was requested by #GNUNET_CADET_channel_destroy. | ||
764 | * It must NOT call #GNUNET_CADET_channel_destroy on the channel. | ||
765 | * | ||
766 | * It should clean up any associated state, including cancelling any pending | ||
767 | * transmission on this channel. | ||
768 | * | ||
769 | * @param cls Channel closure (channel wrapper). | ||
770 | * @param channel Connection to the other end (henceforth invalid). | ||
771 | */ | ||
772 | static void | ||
773 | disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel) | ||
774 | { | ||
775 | struct CadetTestChannelWrapper *ch_w = cls; | ||
776 | |||
777 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n"); | ||
778 | GNUNET_assert (ch_w->ch == channel); | ||
779 | if (channel == incoming_ch) | ||
780 | { | ||
781 | ok++; | ||
782 | incoming_ch = NULL; | ||
783 | } | ||
784 | else if (outgoing_ch == channel | ||
785 | ) | ||
786 | { | ||
787 | if (P2P_SIGNAL == test) | ||
788 | { | ||
789 | ok++; | ||
790 | } | ||
791 | outgoing_ch = NULL; | ||
792 | } | ||
793 | else | ||
794 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel); | ||
795 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); | ||
796 | |||
797 | if (NULL != disconnect_task) | ||
798 | { | ||
799 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
800 | disconnect_task = | ||
801 | GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | |||
806 | /** | ||
807 | * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. | ||
808 | * | ||
809 | * Testcase continues when the root receives confirmation of connected peers, | ||
810 | * on callback function ch. | ||
811 | * | ||
812 | * @param cls Closure (unused). | ||
813 | */ | ||
814 | static void | ||
815 | start_test (void *cls) | ||
816 | { | ||
817 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
818 | GNUNET_MQ_hd_var_size (data, | ||
819 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
820 | struct GNUNET_MessageHeader, | ||
821 | NULL), | ||
822 | GNUNET_MQ_handler_end () | ||
823 | }; | ||
824 | struct CadetTestChannelWrapper *ch; | ||
825 | enum GNUNET_CADET_ChannelOption flags; | ||
826 | |||
827 | test_task = NULL; | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n"); | ||
829 | if (NULL != disconnect_task) | ||
830 | { | ||
831 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
832 | disconnect_task = NULL; | ||
833 | } | ||
834 | |||
835 | flags = GNUNET_CADET_OPTION_DEFAULT; | ||
836 | if (SPEED_REL == test) | ||
837 | { | ||
838 | test = SPEED; | ||
839 | flags |= GNUNET_CADET_OPTION_RELIABLE; | ||
840 | } | ||
841 | |||
842 | ch = GNUNET_new (struct CadetTestChannelWrapper); | ||
843 | outgoing_ch = GNUNET_CADET_channel_creatE (h1, | ||
844 | ch, | ||
845 | p_id[1], | ||
846 | &port, | ||
847 | flags, | ||
848 | NULL, | ||
849 | &disconnect_handler, | ||
850 | handlers); | ||
851 | |||
852 | ch->ch = outgoing_ch; | ||
853 | |||
854 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, | ||
855 | &gather_stats_and_exit, | ||
856 | (void *) __LINE__); | ||
857 | if (KEEPALIVE == test) | ||
858 | return; /* Don't send any data. */ | ||
859 | |||
860 | |||
861 | data_received = 0; | ||
862 | data_sent = 0; | ||
863 | ack_received = 0; | ||
864 | ack_sent = 0; | ||
865 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
866 | "Sending data initializer on channel %p...\n", | ||
867 | outgoing_ch); | ||
868 | send_test_message (outgoing_ch); | ||
869 | } | ||
870 | |||
871 | |||
872 | /** | ||
873 | * Callback to be called when the requested peer information is available | ||
874 | * | ||
875 | * @param cls the closure from GNUNET_TESTBED_peer_get_information() | ||
876 | * @param op the operation this callback corresponds to | ||
877 | * @param pinfo the result; will be NULL if the operation has failed | ||
878 | * @param emsg error message if the operation has failed; | ||
879 | * NULL if the operation is successfull | ||
880 | */ | ||
881 | static void | ||
882 | pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op, | ||
883 | const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg) | ||
884 | { | ||
885 | long i = (long) cls; | ||
886 | |||
887 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i); | ||
888 | |||
889 | if ((NULL == pinfo) || (NULL != emsg)) | ||
890 | { | ||
891 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); | ||
892 | abort_test (__LINE__); | ||
893 | return; | ||
894 | } | ||
895 | p_id[i] = pinfo->result.id; | ||
896 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i])); | ||
897 | p_ids++; | ||
898 | if (p_ids < 2) | ||
899 | return; | ||
900 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); | ||
901 | test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL); | ||
902 | } | ||
903 | |||
904 | |||
905 | /** | ||
906 | * test main: start test when all peers are connected | ||
907 | * | ||
908 | * @param cls Closure. | ||
909 | * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. | ||
910 | * @param num_peers Number of peers that are running. | ||
911 | * @param peers Array of peers. | ||
912 | * @param cadets Handle to each of the CADETs of the peers. | ||
913 | */ | ||
914 | static void | ||
915 | tmain (void *cls, | ||
916 | struct GNUNET_CADET_TEST_Context *ctx, | ||
917 | unsigned int num_peers, | ||
918 | struct GNUNET_TESTBED_Peer **peers, | ||
919 | struct GNUNET_CADET_Handle **cadets) | ||
920 | { | ||
921 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n"); | ||
922 | ok = 0; | ||
923 | test_ctx = ctx; | ||
924 | peers_running = num_peers; | ||
925 | GNUNET_assert (peers_running == peers_requested); | ||
926 | testbed_peers = peers; | ||
927 | h1 = cadets[0]; | ||
928 | h2 = cadets[num_peers - 1]; | ||
929 | disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time, | ||
930 | &disconnect_cadet_peers, | ||
931 | (void *) __LINE__); | ||
932 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
933 | t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], | ||
934 | GNUNET_TESTBED_PIT_IDENTITY, | ||
935 | &pi_cb, | ||
936 | (void *) 0L); | ||
937 | t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], | ||
938 | GNUNET_TESTBED_PIT_IDENTITY, | ||
939 | &pi_cb, | ||
940 | (void *) 1L); | ||
941 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); | ||
942 | } | ||
943 | |||
944 | |||
945 | /** | ||
946 | * Main: start test | ||
947 | */ | ||
948 | int | ||
949 | main (int argc, char *argv[]) | ||
950 | { | ||
951 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
952 | GNUNET_MQ_hd_var_size (data, | ||
953 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
954 | struct GNUNET_MessageHeader, | ||
955 | NULL), | ||
956 | GNUNET_MQ_handler_end () | ||
957 | }; | ||
958 | |||
959 | initialized = GNUNET_NO; | ||
960 | static const struct GNUNET_HashCode *ports[2]; | ||
961 | const char *config_file; | ||
962 | char port_id[] = "test port"; | ||
963 | |||
964 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
965 | {'t', "time", "short_time", | ||
966 | gettext_noop ("set short timeout"), | ||
967 | GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time}, | ||
968 | {'m', "messages", "NUM_MESSAGES", | ||
969 | gettext_noop ("set number of messages to send"), | ||
970 | GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets}, | ||
971 | |||
972 | GNUNET_GETOPT_OPTION_END | ||
973 | }; | ||
974 | |||
975 | GNUNET_log_setup ("test", "DEBUG", NULL); | ||
976 | |||
977 | total_packets = TOTAL_PACKETS; | ||
978 | short_time = SHORT_TIME; | ||
979 | if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv)) | ||
980 | { | ||
981 | FPRINTF (stderr, "test failed: problem with CLI parameters\n"); | ||
982 | exit (1); | ||
983 | } | ||
984 | |||
985 | config_file = "test_cadet.conf"; | ||
986 | GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port); | ||
987 | |||
988 | /* Find out requested size */ | ||
989 | if (strstr (argv[0], "_2_") != NULL) | ||
990 | { | ||
991 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n"); | ||
992 | peers_requested = 2; | ||
993 | } | ||
994 | else if (strstr (argv[0], "_5_") != NULL) | ||
995 | { | ||
996 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n"); | ||
997 | peers_requested = 5; | ||
998 | } | ||
999 | else | ||
1000 | { | ||
1001 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n"); | ||
1002 | peers_requested = 2; | ||
1003 | } | ||
1004 | |||
1005 | /* Find out requested test */ | ||
1006 | if (strstr (argv[0], "_forward") != NULL) | ||
1007 | { | ||
1008 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n"); | ||
1009 | test = FORWARD; | ||
1010 | test_name = "unicast"; | ||
1011 | ok_goal = 4; | ||
1012 | } | ||
1013 | else if (strstr (argv[0], "_signal") != NULL) | ||
1014 | { | ||
1015 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n"); | ||
1016 | test = P2P_SIGNAL; | ||
1017 | test_name = "signal"; | ||
1018 | ok_goal = 4; | ||
1019 | } | ||
1020 | else if (strstr (argv[0], "_speed_ack") != NULL) | ||
1021 | { | ||
1022 | /* Test is supposed to generate the following callbacks: | ||
1023 | * 1 incoming channel (@dest) | ||
1024 | * total_packets received data packet (@dest) | ||
1025 | * total_packets received data packet (@orig) | ||
1026 | * 1 received channel destroy (@dest) | ||
1027 | */ | ||
1028 | ok_goal = total_packets * 2 + 2; | ||
1029 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); | ||
1030 | test = SPEED_ACK; | ||
1031 | test_name = "speed ack"; | ||
1032 | } | ||
1033 | else if (strstr (argv[0], "_speed") != NULL) | ||
1034 | { | ||
1035 | /* Test is supposed to generate the following callbacks: | ||
1036 | * 1 incoming channel (@dest) | ||
1037 | * 1 initial packet (@dest) | ||
1038 | * total_packets received data packet (@dest) | ||
1039 | * 1 received data packet (@orig) | ||
1040 | * 1 received channel destroy (@dest) | ||
1041 | */ | ||
1042 | ok_goal = total_packets + 4; | ||
1043 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); | ||
1044 | if (strstr (argv[0], "_reliable") != NULL) | ||
1045 | { | ||
1046 | test = SPEED_REL; | ||
1047 | test_name = "speed reliable"; | ||
1048 | config_file = "test_cadet_drop.conf"; | ||
1049 | } | ||
1050 | else | ||
1051 | { | ||
1052 | test = SPEED; | ||
1053 | test_name = "speed"; | ||
1054 | } | ||
1055 | } | ||
1056 | else if (strstr (argv[0], "_keepalive") != NULL) | ||
1057 | { | ||
1058 | test = KEEPALIVE; | ||
1059 | /* Test is supposed to generate the following callbacks: | ||
1060 | * 1 incoming channel (@dest) | ||
1061 | * [wait] | ||
1062 | * 1 received channel destroy (@dest) | ||
1063 | */ | ||
1064 | ok_goal = 2; | ||
1065 | } | ||
1066 | else | ||
1067 | { | ||
1068 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); | ||
1069 | test = SETUP; | ||
1070 | ok_goal = 0; | ||
1071 | } | ||
1072 | |||
1073 | if (strstr (argv[0], "backwards") != NULL) | ||
1074 | { | ||
1075 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n"); | ||
1076 | test_backwards = GNUNET_YES; | ||
1077 | GNUNET_asprintf (&test_name, "backwards %s", test_name); | ||
1078 | } | ||
1079 | |||
1080 | p_ids = 0; | ||
1081 | ports[0] = &port; | ||
1082 | ports[1] = NULL; | ||
1083 | GNUNET_CADET_TEST_ruN ("test_cadet_small", | ||
1084 | config_file, | ||
1085 | peers_requested, | ||
1086 | &tmain, | ||
1087 | NULL, /* tmain cls */ | ||
1088 | &connect_handler, | ||
1089 | NULL, | ||
1090 | &disconnect_handler, | ||
1091 | handlers, | ||
1092 | ports); | ||
1093 | if (NULL != strstr (argv[0], "_reliable")) | ||
1094 | msg_dropped = 0; /* dropped should be retransmitted */ | ||
1095 | |||
1096 | if (ok_goal > ok - msg_dropped) | ||
1097 | { | ||
1098 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal); | ||
1099 | return 1; | ||
1100 | } | ||
1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); | ||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | /* end of test_cadet.c */ | ||
diff --git a/src/cadet/test_cadet_single.c b/src/cadet/test_cadet_single.c deleted file mode 100644 index b45b0af5d..000000000 --- a/src/cadet/test_cadet_single.c +++ /dev/null | |||
@@ -1,354 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/test_cadet_single.c | ||
23 | * @brief test cadet single: test of cadet channels with just one client | ||
24 | * @author Bartlomiej Polot | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_dht_service.h" | ||
30 | #include "gnunet_testing_lib.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | |||
33 | #define REPETITIONS 5 | ||
34 | #define DATA_SIZE 35000 | ||
35 | |||
36 | struct GNUNET_TESTING_Peer *me; | ||
37 | |||
38 | static struct GNUNET_CADET_Handle *cadet; | ||
39 | |||
40 | static struct GNUNET_CADET_Channel *ch1; | ||
41 | |||
42 | static struct GNUNET_CADET_Channel *ch2; | ||
43 | |||
44 | static int result; | ||
45 | |||
46 | static struct GNUNET_SCHEDULER_Task *abort_task; | ||
47 | |||
48 | static struct GNUNET_SCHEDULER_Task *connect_task; | ||
49 | |||
50 | static unsigned int repetition; | ||
51 | |||
52 | static struct GNUNET_CADET_TransmitHandle *nth; | ||
53 | |||
54 | static struct GNUNET_CADET_Port *port; | ||
55 | |||
56 | |||
57 | /* forward declaration */ | ||
58 | static size_t | ||
59 | do_send (void *cls, size_t size, void *buf); | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Shutdown nicely | ||
64 | */ | ||
65 | static void | ||
66 | do_shutdown (void *cls) | ||
67 | { | ||
68 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
69 | "shutdown\n"); | ||
70 | if (NULL != port) | ||
71 | { | ||
72 | GNUNET_CADET_close_port (port); | ||
73 | port = NULL; | ||
74 | } | ||
75 | if (NULL != nth) | ||
76 | { | ||
77 | GNUNET_CADET_notify_transmit_ready_cancel (nth); | ||
78 | nth = NULL; | ||
79 | } | ||
80 | if (NULL != abort_task) | ||
81 | { | ||
82 | GNUNET_SCHEDULER_cancel (abort_task); | ||
83 | abort_task = NULL; | ||
84 | } | ||
85 | if (NULL != connect_task) | ||
86 | { | ||
87 | GNUNET_SCHEDULER_cancel (connect_task); | ||
88 | connect_task = NULL; | ||
89 | } | ||
90 | if (NULL != ch1) | ||
91 | { | ||
92 | GNUNET_CADET_channel_destroy (ch1); | ||
93 | ch1 = NULL; | ||
94 | } | ||
95 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
96 | "Disconnect clients\n"); | ||
97 | if (NULL != cadet) | ||
98 | { | ||
99 | GNUNET_CADET_disconnect (cadet); | ||
100 | cadet = NULL; | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | GNUNET_break (0); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Something went wrong and timed out. Kill everything and set error flag | ||
111 | */ | ||
112 | static void | ||
113 | do_abort (void *cls) | ||
114 | { | ||
115 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); | ||
116 | result = GNUNET_SYSERR; | ||
117 | abort_task = NULL; | ||
118 | GNUNET_SCHEDULER_shutdown (); | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Function is called whenever a message is received. | ||
124 | * | ||
125 | * @param cls closure (set from GNUNET_CADET_connect) | ||
126 | * @param channel connection to the other end | ||
127 | * @param channel_ctx place to store local state associated with the channel | ||
128 | * @param message the actual message | ||
129 | * @return #GNUNET_OK to keep the connection open, | ||
130 | * #GNUNET_SYSERR to close it (signal serious error) | ||
131 | */ | ||
132 | static int | ||
133 | data_callback (void *cls, | ||
134 | struct GNUNET_CADET_Channel *channel, | ||
135 | void **channel_ctx, | ||
136 | const struct GNUNET_MessageHeader *message) | ||
137 | { | ||
138 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
139 | "Data callback! Repetition %u/%u\n", | ||
140 | repetition, REPETITIONS); | ||
141 | repetition++; | ||
142 | if (repetition < REPETITIONS) | ||
143 | { | ||
144 | struct GNUNET_CADET_Channel *my_channel; | ||
145 | if (0 == repetition % 2) | ||
146 | my_channel = ch1; | ||
147 | else | ||
148 | my_channel = ch2; | ||
149 | nth = GNUNET_CADET_notify_transmit_ready (my_channel, | ||
150 | GNUNET_NO, | ||
151 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
152 | sizeof (struct GNUNET_MessageHeader) | ||
153 | + DATA_SIZE, | ||
154 | &do_send, NULL); | ||
155 | GNUNET_CADET_receive_done (channel); | ||
156 | return GNUNET_OK; | ||
157 | } | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
159 | "All data OK. Destroying channel.\n"); | ||
160 | GNUNET_assert (NULL == nth); | ||
161 | GNUNET_CADET_channel_destroy (ch1); | ||
162 | ch1 = NULL; | ||
163 | return GNUNET_OK; | ||
164 | } | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Method called whenever another peer has added us to a channel | ||
169 | * the other peer initiated. | ||
170 | * | ||
171 | * @param cls closure | ||
172 | * @param channel new handle to the channel | ||
173 | * @param initiator peer that started the channel | ||
174 | * @param port port number | ||
175 | * @param options channel option flags | ||
176 | * @return initial channel context for the channel | ||
177 | * (can be NULL -- that's not an error) | ||
178 | */ | ||
179 | static void * | ||
180 | inbound_channel (void *cls, | ||
181 | struct GNUNET_CADET_Channel *channel, | ||
182 | const struct GNUNET_PeerIdentity *initiator, | ||
183 | const struct GNUNET_HashCode *port, | ||
184 | enum GNUNET_CADET_ChannelOption options) | ||
185 | { | ||
186 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
187 | "received incoming channel on port %s\n", | ||
188 | GNUNET_h2s (port)); | ||
189 | ch2 = channel; | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Function called whenever an inbound channel is destroyed. Should clean up | ||
196 | * any associated state. | ||
197 | * | ||
198 | * @param cls closure (set from GNUNET_CADET_connect) | ||
199 | * @param channel connection to the other end (henceforth invalid) | ||
200 | * @param channel_ctx place where local state associated | ||
201 | * with the channel is stored | ||
202 | */ | ||
203 | static void | ||
204 | channel_end (void *cls, | ||
205 | const struct GNUNET_CADET_Channel *channel, | ||
206 | void *channel_ctx) | ||
207 | { | ||
208 | long id = (long) cls; | ||
209 | |||
210 | nth = NULL; | ||
211 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
212 | "incoming channel closed at peer %ld\n", | ||
213 | id); | ||
214 | if ( (REPETITIONS == repetition) && | ||
215 | (channel == ch2) ) | ||
216 | { | ||
217 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
218 | "everything fine! finishing!\n"); | ||
219 | result = GNUNET_OK; | ||
220 | GNUNET_SCHEDULER_shutdown (); | ||
221 | } | ||
222 | if (channel == ch2) | ||
223 | ch2 = NULL; | ||
224 | if (channel == ch1) | ||
225 | ch1 = NULL; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Handler array for traffic received on peer1 | ||
231 | */ | ||
232 | static struct GNUNET_CADET_MessageHandler handlers1[] = { | ||
233 | {&data_callback, 1, 0}, | ||
234 | {NULL, 0, 0} | ||
235 | }; | ||
236 | |||
237 | |||
238 | /** | ||
239 | * Data send callback: fillbuffer with test packet. | ||
240 | * | ||
241 | * @param cls Closure (unused). | ||
242 | * @param size Buffer size. | ||
243 | * @param buf Buffer to fill. | ||
244 | * @return size of test packet. | ||
245 | */ | ||
246 | static size_t | ||
247 | do_send (void *cls, size_t size, void *buf) | ||
248 | { | ||
249 | struct GNUNET_MessageHeader *m = buf; | ||
250 | |||
251 | nth = NULL; | ||
252 | if (NULL == buf) | ||
253 | { | ||
254 | GNUNET_break (0); | ||
255 | result = GNUNET_SYSERR; | ||
256 | return 0; | ||
257 | } | ||
258 | m->size = htons (sizeof (struct GNUNET_MessageHeader) + DATA_SIZE); | ||
259 | m->type = htons (1); | ||
260 | memset (&m[1], 0, DATA_SIZE); | ||
261 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE); | ||
262 | return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * Connect to other client and send data | ||
267 | * | ||
268 | * @param cls Closue (unused). | ||
269 | */ | ||
270 | static void | ||
271 | do_connect (void *cls) | ||
272 | { | ||
273 | struct GNUNET_PeerIdentity id; | ||
274 | size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; | ||
275 | |||
276 | connect_task = NULL; | ||
277 | GNUNET_TESTING_peer_get_identity (me, &id); | ||
278 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n"); | ||
279 | ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, GC_u2h (1), | ||
280 | GNUNET_CADET_OPTION_DEFAULT); | ||
281 | nth = GNUNET_CADET_notify_transmit_ready (ch1, | ||
282 | GNUNET_NO, | ||
283 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
284 | size, | ||
285 | &do_send, | ||
286 | NULL); | ||
287 | } | ||
288 | |||
289 | |||
290 | /** | ||
291 | * Initialize framework and start test | ||
292 | * | ||
293 | * @param cls Closure (unused). | ||
294 | * @param cfg Configuration handle. | ||
295 | * @param peer Testing peer handle. | ||
296 | */ | ||
297 | static void | ||
298 | run (void *cls, | ||
299 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
300 | struct GNUNET_TESTING_Peer *peer) | ||
301 | { | ||
302 | me = peer; | ||
303 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
304 | abort_task = | ||
305 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
306 | (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort, | ||
307 | NULL); | ||
308 | cadet = GNUNET_CADET_connect (cfg, /* configuration */ | ||
309 | (void *) 1L, /* cls */ | ||
310 | &channel_end, /* inbound end hndlr */ | ||
311 | handlers1); /* traffic handlers */ | ||
312 | port = GNUNET_CADET_open_port (cadet, | ||
313 | GC_u2h (1), | ||
314 | &inbound_channel, | ||
315 | (void *) 1L); | ||
316 | |||
317 | |||
318 | if (NULL == cadet) | ||
319 | { | ||
320 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
321 | "Couldn't connect to cadet :(\n"); | ||
322 | result = GNUNET_SYSERR; | ||
323 | return; | ||
324 | } | ||
325 | connect_task | ||
326 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
327 | &do_connect, | ||
328 | NULL); | ||
329 | } | ||
330 | |||
331 | |||
332 | /** | ||
333 | * Main | ||
334 | */ | ||
335 | int | ||
336 | main (int argc, | ||
337 | char *argv[]) | ||
338 | { | ||
339 | result = GNUNET_NO; | ||
340 | if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", | ||
341 | "test_cadet.conf", | ||
342 | &run, NULL)) | ||
343 | { | ||
344 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
345 | "run failed\n"); | ||
346 | return 2; | ||
347 | } | ||
348 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
349 | "Final result: %d\n", | ||
350 | result); | ||
351 | return (result == GNUNET_OK) ? 0 : 1; | ||
352 | } | ||
353 | |||
354 | /* end of test_cadet_single.c */ | ||
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am index 431b3179e..670a64926 100644 --- a/src/datacache/Makefile.am +++ b/src/datacache/Makefile.am | |||
@@ -53,6 +53,7 @@ libgnunet_plugin_datacache_sqlite_la_SOURCES = \ | |||
53 | plugin_datacache_sqlite.c | 53 | plugin_datacache_sqlite.c |
54 | libgnunet_plugin_datacache_sqlite_la_LIBADD = \ | 54 | libgnunet_plugin_datacache_sqlite_la_LIBADD = \ |
55 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 55 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
56 | $(top_builddir)/src/sq/libgnunetsq.la \ | ||
56 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ | 57 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ |
57 | $(LTLIBINTL) | 58 | $(LTLIBINTL) |
58 | libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ | 59 | libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ |
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c index 5567077d3..5cc48b26c 100644 --- a/src/datacache/plugin_datacache_sqlite.c +++ b/src/datacache/plugin_datacache_sqlite.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_util_lib.h" | 27 | #include "gnunet_util_lib.h" |
28 | #include "gnunet_datacache_plugin.h" | 28 | #include "gnunet_datacache_plugin.h" |
29 | #include "gnunet_sq_lib.h" | ||
29 | #include <sqlite3.h> | 30 | #include <sqlite3.h> |
30 | 31 | ||
31 | #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__) | 32 | #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__) |
@@ -60,6 +61,41 @@ struct Plugin | |||
60 | char *fn; | 61 | char *fn; |
61 | 62 | ||
62 | /** | 63 | /** |
64 | * Prepared statement for #sqlite_plugin_put. | ||
65 | */ | ||
66 | sqlite3_stmt *insert_stmt; | ||
67 | |||
68 | /** | ||
69 | * Prepared statement for #sqlite_plugin_get. | ||
70 | */ | ||
71 | sqlite3_stmt *get_count_stmt; | ||
72 | |||
73 | /** | ||
74 | * Prepared statement for #sqlite_plugin_get. | ||
75 | */ | ||
76 | sqlite3_stmt *get_stmt; | ||
77 | |||
78 | /** | ||
79 | * Prepared statement for #sqlite_plugin_del. | ||
80 | */ | ||
81 | sqlite3_stmt *del_select_stmt; | ||
82 | |||
83 | /** | ||
84 | * Prepared statement for #sqlite_plugin_del. | ||
85 | */ | ||
86 | sqlite3_stmt *del_stmt; | ||
87 | |||
88 | /** | ||
89 | * Prepared statement for #sqlite_plugin_get_random. | ||
90 | */ | ||
91 | sqlite3_stmt *get_random_stmt; | ||
92 | |||
93 | /** | ||
94 | * Prepared statement for #sqlite_plugin_get_closest. | ||
95 | */ | ||
96 | sqlite3_stmt *get_closest_stmt; | ||
97 | |||
98 | /** | ||
63 | * Number of key-value pairs in the database. | 99 | * Number of key-value pairs in the database. |
64 | */ | 100 | */ |
65 | unsigned int num_items; | 101 | unsigned int num_items; |
@@ -132,60 +168,47 @@ sqlite_plugin_put (void *cls, | |||
132 | const struct GNUNET_PeerIdentity *path_info) | 168 | const struct GNUNET_PeerIdentity *path_info) |
133 | { | 169 | { |
134 | struct Plugin *plugin = cls; | 170 | struct Plugin *plugin = cls; |
135 | sqlite3_stmt *stmt; | 171 | uint32_t type32 = type; |
136 | int64_t dval; | 172 | struct GNUNET_SQ_QueryParam params[] = { |
173 | GNUNET_SQ_query_param_uint32 (&type32), | ||
174 | GNUNET_SQ_query_param_absolute_time (&discard_time), | ||
175 | GNUNET_SQ_query_param_auto_from_type (key), | ||
176 | GNUNET_SQ_query_param_fixed_size (data, size), | ||
177 | GNUNET_SQ_query_param_fixed_size (path_info, | ||
178 | path_info_len * sizeof (struct GNUNET_PeerIdentity)), | ||
179 | GNUNET_SQ_query_param_end | ||
180 | }; | ||
137 | 181 | ||
138 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 182 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
139 | "Processing PUT of %u bytes with key `%4s' and expiration %s\n", | 183 | "Processing PUT of %u bytes with key `%s' and expiration %s\n", |
140 | (unsigned int) size, | 184 | (unsigned int) size, |
141 | GNUNET_h2s (key), | 185 | GNUNET_h2s (key), |
142 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time), GNUNET_YES)); | 186 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time), |
143 | dval = (int64_t) discard_time.abs_value_us; | 187 | GNUNET_YES)); |
144 | if (dval < 0) | 188 | if (GNUNET_OK != |
145 | dval = INT64_MAX; | 189 | GNUNET_SQ_bind (plugin->insert_stmt, |
146 | if (sq_prepare | 190 | params)) |
147 | (plugin->dbh, | ||
148 | "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)", | ||
149 | &stmt) != SQLITE_OK) | ||
150 | { | ||
151 | LOG_SQLITE (plugin->dbh, | ||
152 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
153 | "sq_prepare"); | ||
154 | return -1; | ||
155 | } | ||
156 | if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || | ||
157 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) || | ||
158 | (SQLITE_OK != | ||
159 | sqlite3_bind_blob (stmt, 3, | ||
160 | key, sizeof (struct GNUNET_HashCode), | ||
161 | SQLITE_TRANSIENT)) || | ||
162 | (SQLITE_OK != sqlite3_bind_blob (stmt, 4, | ||
163 | data, size, | ||
164 | SQLITE_TRANSIENT)) || | ||
165 | (SQLITE_OK != sqlite3_bind_blob (stmt, 5, | ||
166 | path_info, | ||
167 | path_info_len * sizeof (struct GNUNET_PeerIdentity), | ||
168 | SQLITE_TRANSIENT))) | ||
169 | { | 191 | { |
170 | LOG_SQLITE (plugin->dbh, | 192 | LOG_SQLITE (plugin->dbh, |
171 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 193 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
172 | "sqlite3_bind_xxx"); | 194 | "sqlite3_bind_xxx"); |
173 | sqlite3_finalize (stmt); | 195 | GNUNET_SQ_reset (plugin->dbh, |
196 | plugin->insert_stmt); | ||
174 | return -1; | 197 | return -1; |
175 | } | 198 | } |
176 | if (SQLITE_DONE != sqlite3_step (stmt)) | 199 | if (SQLITE_DONE != |
200 | sqlite3_step (plugin->insert_stmt)) | ||
177 | { | 201 | { |
178 | LOG_SQLITE (plugin->dbh, | 202 | LOG_SQLITE (plugin->dbh, |
179 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 203 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
180 | "sqlite3_step"); | 204 | "sqlite3_step"); |
181 | sqlite3_finalize (stmt); | 205 | GNUNET_SQ_reset (plugin->dbh, |
206 | plugin->insert_stmt); | ||
182 | return -1; | 207 | return -1; |
183 | } | 208 | } |
184 | plugin->num_items++; | 209 | plugin->num_items++; |
185 | if (SQLITE_OK != sqlite3_finalize (stmt)) | 210 | GNUNET_SQ_reset (plugin->dbh, |
186 | LOG_SQLITE (plugin->dbh, | 211 | plugin->insert_stmt); |
187 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
188 | "sqlite3_finalize"); | ||
189 | return size + OVERHEAD; | 212 | return size + OVERHEAD; |
190 | } | 213 | } |
191 | 214 | ||
@@ -209,120 +232,119 @@ sqlite_plugin_get (void *cls, | |||
209 | void *iter_cls) | 232 | void *iter_cls) |
210 | { | 233 | { |
211 | struct Plugin *plugin = cls; | 234 | struct Plugin *plugin = cls; |
212 | sqlite3_stmt *stmt; | 235 | uint32_t type32 = type; |
213 | struct GNUNET_TIME_Absolute now; | 236 | struct GNUNET_TIME_Absolute now; |
214 | struct GNUNET_TIME_Absolute exp; | 237 | struct GNUNET_TIME_Absolute exp; |
215 | unsigned int size; | 238 | size_t size; |
216 | const char *dat; | 239 | void *dat; |
217 | unsigned int cnt; | 240 | unsigned int cnt; |
218 | unsigned int off; | 241 | uint32_t off; |
219 | unsigned int total; | 242 | unsigned int total; |
220 | unsigned int psize; | 243 | size_t psize; |
221 | char scratch[256]; | 244 | struct GNUNET_PeerIdentity *path; |
222 | int64_t ntime; | 245 | struct GNUNET_SQ_QueryParam params_count[] = { |
223 | const struct GNUNET_PeerIdentity *path; | 246 | GNUNET_SQ_query_param_auto_from_type (key), |
247 | GNUNET_SQ_query_param_uint32 (&type32), | ||
248 | GNUNET_SQ_query_param_absolute_time (&now), | ||
249 | GNUNET_SQ_query_param_end | ||
250 | }; | ||
251 | struct GNUNET_SQ_QueryParam params_select[] = { | ||
252 | GNUNET_SQ_query_param_auto_from_type (key), | ||
253 | GNUNET_SQ_query_param_uint32 (&type32), | ||
254 | GNUNET_SQ_query_param_absolute_time (&now), | ||
255 | GNUNET_SQ_query_param_uint32 (&off), | ||
256 | GNUNET_SQ_query_param_end | ||
257 | }; | ||
258 | struct GNUNET_SQ_ResultSpec rs[] = { | ||
259 | GNUNET_SQ_result_spec_variable_size (&dat, | ||
260 | &size), | ||
261 | GNUNET_SQ_result_spec_absolute_time (&exp), | ||
262 | GNUNET_SQ_result_spec_variable_size ((void **) &path, | ||
263 | &psize), | ||
264 | GNUNET_SQ_result_spec_end | ||
265 | }; | ||
224 | 266 | ||
225 | now = GNUNET_TIME_absolute_get (); | 267 | now = GNUNET_TIME_absolute_get (); |
226 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 268 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
227 | "Processing GET for key `%4s'\n", | 269 | "Processing GET for key `%s'\n", |
228 | GNUNET_h2s (key)); | 270 | GNUNET_h2s (key)); |
229 | if (sq_prepare | 271 | |
230 | (plugin->dbh, | 272 | if (GNUNET_OK != |
231 | "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?", | 273 | GNUNET_SQ_bind (plugin->get_count_stmt, |
232 | &stmt) != SQLITE_OK) | 274 | params_count)) |
233 | { | ||
234 | LOG_SQLITE (plugin->dbh, | ||
235 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
236 | "sq_prepare"); | ||
237 | return 0; | ||
238 | } | ||
239 | ntime = (int64_t) now.abs_value_us; | ||
240 | GNUNET_assert (ntime >= 0); | ||
241 | if ((SQLITE_OK != | ||
242 | sqlite3_bind_blob (stmt, 1, key, sizeof (struct GNUNET_HashCode), | ||
243 | SQLITE_TRANSIENT)) || | ||
244 | (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || | ||
245 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us))) | ||
246 | { | 275 | { |
247 | LOG_SQLITE (plugin->dbh, | 276 | LOG_SQLITE (plugin->dbh, |
248 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 277 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
249 | "sqlite3_bind_xxx"); | 278 | "sqlite3_bind_xxx"); |
250 | sqlite3_finalize (stmt); | 279 | GNUNET_SQ_reset (plugin->dbh, |
280 | plugin->get_count_stmt); | ||
251 | return 0; | 281 | return 0; |
252 | } | 282 | } |
253 | 283 | if (SQLITE_ROW != | |
254 | if (SQLITE_ROW != sqlite3_step (stmt)) | 284 | sqlite3_step (plugin->get_count_stmt)) |
255 | { | 285 | { |
256 | LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 286 | LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
257 | "sqlite_step"); | 287 | "sqlite_step"); |
258 | sqlite3_finalize (stmt); | 288 | GNUNET_SQ_reset (plugin->dbh, |
289 | plugin->get_count_stmt); | ||
259 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 290 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
260 | "No content found when processing GET for key `%4s'\n", | 291 | "No content found when processing GET for key `%s'\n", |
261 | GNUNET_h2s (key)); | 292 | GNUNET_h2s (key)); |
262 | return 0; | 293 | return 0; |
263 | } | 294 | } |
264 | total = sqlite3_column_int (stmt, 0); | 295 | total = sqlite3_column_int (plugin->get_count_stmt, |
265 | sqlite3_finalize (stmt); | 296 | 0); |
266 | if ((0 == total) || (NULL == iter)) | 297 | GNUNET_SQ_reset (plugin->dbh, |
298 | plugin->get_count_stmt); | ||
299 | if ( (0 == total) || | ||
300 | (NULL == iter) ) | ||
267 | { | 301 | { |
268 | if (0 == total) | 302 | if (0 == total) |
269 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 303 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
270 | "No content found when processing GET for key `%4s'\n", | 304 | "No content found when processing GET for key `%s'\n", |
271 | GNUNET_h2s (key)); | 305 | GNUNET_h2s (key)); |
272 | return total; | 306 | return total; |
273 | } | 307 | } |
274 | 308 | ||
275 | cnt = 0; | 309 | cnt = 0; |
276 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); | 310 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, |
311 | total); | ||
277 | while (cnt < total) | 312 | while (cnt < total) |
278 | { | 313 | { |
279 | off = (off + 1) % total; | 314 | off = (off + 1) % total; |
280 | GNUNET_snprintf (scratch, sizeof (scratch), | 315 | if (GNUNET_OK != |
281 | "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", | 316 | GNUNET_SQ_bind (plugin->get_stmt, |
282 | off); | 317 | params_select)) |
283 | if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) | ||
284 | { | ||
285 | LOG_SQLITE (plugin->dbh, | ||
286 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
287 | "sq_prepare"); | ||
288 | return cnt; | ||
289 | } | ||
290 | if ((SQLITE_OK != | ||
291 | sqlite3_bind_blob (stmt, 1, | ||
292 | key, | ||
293 | sizeof (struct GNUNET_HashCode), | ||
294 | SQLITE_TRANSIENT)) || | ||
295 | (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || | ||
296 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us))) | ||
297 | { | 318 | { |
298 | LOG_SQLITE (plugin->dbh, | 319 | LOG_SQLITE (plugin->dbh, |
299 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 320 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
300 | "sqlite3_bind_xxx"); | 321 | "sqlite3_bind_xxx"); |
301 | sqlite3_finalize (stmt); | 322 | GNUNET_SQ_reset (plugin->dbh, |
323 | plugin->get_stmt); | ||
302 | return cnt; | 324 | return cnt; |
303 | } | 325 | } |
304 | if (sqlite3_step (stmt) != SQLITE_ROW) | 326 | if (SQLITE_ROW != |
327 | sqlite3_step (plugin->get_stmt)) | ||
305 | break; | 328 | break; |
306 | size = sqlite3_column_bytes (stmt, 0); | 329 | if (GNUNET_OK != |
307 | dat = sqlite3_column_blob (stmt, 0); | 330 | GNUNET_SQ_extract_result (plugin->get_stmt, |
308 | exp.abs_value_us = sqlite3_column_int64 (stmt, 1); | 331 | rs)) |
309 | psize = sqlite3_column_bytes (stmt, 2); | 332 | { |
333 | GNUNET_break (0); | ||
334 | GNUNET_SQ_reset (plugin->dbh, | ||
335 | plugin->get_stmt); | ||
336 | break; | ||
337 | } | ||
310 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) | 338 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) |
311 | { | 339 | { |
312 | GNUNET_break (0); | 340 | GNUNET_break (0); |
313 | psize = 0; | 341 | psize = 0; |
342 | path = NULL; | ||
314 | } | 343 | } |
315 | psize /= sizeof (struct GNUNET_PeerIdentity); | 344 | psize /= sizeof (struct GNUNET_PeerIdentity); |
316 | if (0 != psize) | ||
317 | path = sqlite3_column_blob (stmt, 2); | ||
318 | else | ||
319 | path = NULL; | ||
320 | ntime = (int64_t) exp.abs_value_us; | ||
321 | if (ntime == INT64_MAX) | ||
322 | exp = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
323 | cnt++; | 345 | cnt++; |
324 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 346 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
325 | "Found %u-byte result when processing GET for key `%4s'\n", | 347 | "Found %u-byte result when processing GET for key `%s'\n", |
326 | (unsigned int) size, | 348 | (unsigned int) size, |
327 | GNUNET_h2s (key)); | 349 | GNUNET_h2s (key)); |
328 | if (GNUNET_OK != iter (iter_cls, | 350 | if (GNUNET_OK != iter (iter_cls, |
@@ -334,11 +356,17 @@ sqlite_plugin_get (void *cls, | |||
334 | psize, | 356 | psize, |
335 | path)) | 357 | path)) |
336 | { | 358 | { |
337 | sqlite3_finalize (stmt); | 359 | GNUNET_SQ_cleanup_result (rs); |
360 | GNUNET_SQ_reset (plugin->dbh, | ||
361 | plugin->get_stmt); | ||
338 | break; | 362 | break; |
339 | } | 363 | } |
340 | sqlite3_finalize (stmt); | 364 | GNUNET_SQ_cleanup_result (rs); |
365 | GNUNET_SQ_reset (plugin->dbh, | ||
366 | plugin->get_stmt); | ||
341 | } | 367 | } |
368 | GNUNET_SQ_reset (plugin->dbh, | ||
369 | plugin->get_stmt); | ||
342 | return cnt; | 370 | return cnt; |
343 | } | 371 | } |
344 | 372 | ||
@@ -354,79 +382,73 @@ static int | |||
354 | sqlite_plugin_del (void *cls) | 382 | sqlite_plugin_del (void *cls) |
355 | { | 383 | { |
356 | struct Plugin *plugin = cls; | 384 | struct Plugin *plugin = cls; |
357 | unsigned long long rowid; | 385 | uint64_t rowid; |
358 | unsigned int dsize; | 386 | void *data; |
359 | sqlite3_stmt *stmt; | 387 | size_t dsize; |
360 | sqlite3_stmt *dstmt; | ||
361 | struct GNUNET_HashCode hc; | 388 | struct GNUNET_HashCode hc; |
389 | struct GNUNET_SQ_ResultSpec rs[] = { | ||
390 | GNUNET_SQ_result_spec_uint64 (&rowid), | ||
391 | GNUNET_SQ_result_spec_auto_from_type (&hc), | ||
392 | GNUNET_SQ_result_spec_variable_size ((void **) &data, | ||
393 | &dsize), | ||
394 | GNUNET_SQ_result_spec_end | ||
395 | }; | ||
396 | struct GNUNET_SQ_QueryParam params[] = { | ||
397 | GNUNET_SQ_query_param_uint64 (&rowid), | ||
398 | GNUNET_SQ_query_param_end | ||
399 | }; | ||
362 | 400 | ||
363 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 401 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
364 | "Processing DEL\n"); | 402 | "Processing DEL\n"); |
365 | stmt = NULL; | 403 | if (SQLITE_ROW != |
366 | dstmt = NULL; | 404 | sqlite3_step (plugin->del_select_stmt)) |
367 | if (SQLITE_OK != | ||
368 | sq_prepare (plugin->dbh, | ||
369 | "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1", | ||
370 | &stmt)) | ||
371 | { | ||
372 | LOG_SQLITE (plugin->dbh, | ||
373 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
374 | "sq_prepare"); | ||
375 | if (stmt != NULL) | ||
376 | (void) sqlite3_finalize (stmt); | ||
377 | return GNUNET_SYSERR; | ||
378 | } | ||
379 | if (SQLITE_ROW != sqlite3_step (stmt)) | ||
380 | { | 405 | { |
381 | LOG_SQLITE (plugin->dbh, | 406 | LOG_SQLITE (plugin->dbh, |
382 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 407 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
383 | "sqlite3_step"); | 408 | "sqlite3_step"); |
384 | (void) sqlite3_finalize (stmt); | 409 | GNUNET_SQ_reset (plugin->dbh, |
410 | plugin->del_select_stmt); | ||
385 | return GNUNET_SYSERR; | 411 | return GNUNET_SYSERR; |
386 | } | 412 | } |
387 | rowid = sqlite3_column_int64 (stmt, 0); | 413 | if (GNUNET_OK != |
388 | GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (struct GNUNET_HashCode)); | 414 | GNUNET_SQ_extract_result (plugin->del_select_stmt, |
389 | GNUNET_memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (struct GNUNET_HashCode)); | 415 | rs)) |
390 | dsize = sqlite3_column_bytes (stmt, 2); | ||
391 | if (SQLITE_OK != sqlite3_finalize (stmt)) | ||
392 | LOG_SQLITE (plugin->dbh, | ||
393 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
394 | "sqlite3_step"); | ||
395 | if (SQLITE_OK != | ||
396 | sq_prepare (plugin->dbh, | ||
397 | "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt)) | ||
398 | { | 416 | { |
399 | LOG_SQLITE (plugin->dbh, | 417 | GNUNET_break (0); |
400 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 418 | GNUNET_SQ_reset (plugin->dbh, |
401 | "sq_prepare"); | 419 | plugin->del_select_stmt); |
402 | if (stmt != NULL) | ||
403 | (void) sqlite3_finalize (stmt); | ||
404 | return GNUNET_SYSERR; | 420 | return GNUNET_SYSERR; |
405 | } | 421 | } |
406 | if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid)) | 422 | GNUNET_SQ_cleanup_result (rs); |
423 | GNUNET_SQ_reset (plugin->dbh, | ||
424 | plugin->del_select_stmt); | ||
425 | if (GNUNET_OK != | ||
426 | GNUNET_SQ_bind (plugin->del_stmt, | ||
427 | params)) | ||
407 | { | 428 | { |
408 | LOG_SQLITE (plugin->dbh, | 429 | LOG_SQLITE (plugin->dbh, |
409 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 430 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
410 | "sqlite3_bind"); | 431 | "sqlite3_bind"); |
411 | (void) sqlite3_finalize (dstmt); | 432 | GNUNET_SQ_reset (plugin->dbh, |
433 | plugin->del_stmt); | ||
412 | return GNUNET_SYSERR; | 434 | return GNUNET_SYSERR; |
413 | } | 435 | } |
414 | if (SQLITE_DONE != sqlite3_step (dstmt)) | 436 | if (SQLITE_DONE != |
437 | sqlite3_step (plugin->del_stmt)) | ||
415 | { | 438 | { |
416 | LOG_SQLITE (plugin->dbh, | 439 | LOG_SQLITE (plugin->dbh, |
417 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 440 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
418 | "sqlite3_step"); | 441 | "sqlite3_step"); |
419 | (void) sqlite3_finalize (dstmt); | 442 | GNUNET_SQ_reset (plugin->dbh, |
443 | plugin->del_stmt); | ||
420 | return GNUNET_SYSERR; | 444 | return GNUNET_SYSERR; |
421 | } | 445 | } |
422 | plugin->num_items--; | 446 | plugin->num_items--; |
423 | plugin->env->delete_notify (plugin->env->cls, | 447 | plugin->env->delete_notify (plugin->env->cls, |
424 | &hc, | 448 | &hc, |
425 | dsize + OVERHEAD); | 449 | dsize + OVERHEAD); |
426 | if (SQLITE_OK != sqlite3_finalize (dstmt)) | 450 | GNUNET_SQ_reset (plugin->dbh, |
427 | LOG_SQLITE (plugin->dbh, | 451 | plugin->del_stmt); |
428 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
429 | "sqlite3_finalize"); | ||
430 | return GNUNET_OK; | 452 | return GNUNET_OK; |
431 | } | 453 | } |
432 | 454 | ||
@@ -445,17 +467,28 @@ sqlite_plugin_get_random (void *cls, | |||
445 | void *iter_cls) | 467 | void *iter_cls) |
446 | { | 468 | { |
447 | struct Plugin *plugin = cls; | 469 | struct Plugin *plugin = cls; |
448 | sqlite3_stmt *stmt; | ||
449 | struct GNUNET_TIME_Absolute exp; | 470 | struct GNUNET_TIME_Absolute exp; |
450 | unsigned int size; | 471 | size_t size; |
451 | const char *dat; | 472 | void *dat; |
452 | unsigned int off; | 473 | uint32_t off; |
453 | unsigned int psize; | 474 | size_t psize; |
454 | unsigned int type; | 475 | uint32_t type; |
455 | char scratch[256]; | 476 | struct GNUNET_PeerIdentity *path; |
456 | int64_t ntime; | 477 | struct GNUNET_HashCode key; |
457 | const struct GNUNET_PeerIdentity *path; | 478 | struct GNUNET_SQ_QueryParam params[] = { |
458 | const struct GNUNET_HashCode *key; | 479 | GNUNET_SQ_query_param_uint32 (&off), |
480 | GNUNET_SQ_query_param_end | ||
481 | }; | ||
482 | struct GNUNET_SQ_ResultSpec rs[] = { | ||
483 | GNUNET_SQ_result_spec_variable_size (&dat, | ||
484 | &size), | ||
485 | GNUNET_SQ_result_spec_absolute_time (&exp), | ||
486 | GNUNET_SQ_result_spec_variable_size ((void **) &path, | ||
487 | &psize), | ||
488 | GNUNET_SQ_result_spec_auto_from_type (&key), | ||
489 | GNUNET_SQ_result_spec_uint32 (&type), | ||
490 | GNUNET_SQ_result_spec_end | ||
491 | }; | ||
459 | 492 | ||
460 | if (0 == plugin->num_items) | 493 | if (0 == plugin->num_items) |
461 | return 0; | 494 | return 0; |
@@ -463,60 +496,51 @@ sqlite_plugin_get_random (void *cls, | |||
463 | return 1; | 496 | return 1; |
464 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | 497 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, |
465 | plugin->num_items); | 498 | plugin->num_items); |
466 | GNUNET_snprintf (scratch, | 499 | if (GNUNET_OK != |
467 | sizeof (scratch), | 500 | GNUNET_SQ_bind (plugin->get_random_stmt, |
468 | "SELECT value,expire,path,key,type FROM ds090 ORDER BY key LIMIT 1 OFFSET %u", | 501 | params)) |
469 | off); | ||
470 | if (SQLITE_OK != | ||
471 | sq_prepare (plugin->dbh, scratch, &stmt)) | ||
472 | { | 502 | { |
473 | LOG_SQLITE (plugin->dbh, | ||
474 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
475 | "sq_prepare"); | ||
476 | return 0; | 503 | return 0; |
477 | } | 504 | } |
478 | if (SQLITE_ROW != sqlite3_step (stmt)) | 505 | if (SQLITE_ROW != |
506 | sqlite3_step (plugin->get_random_stmt)) | ||
507 | { | ||
508 | GNUNET_break (0); | ||
509 | GNUNET_SQ_reset (plugin->dbh, | ||
510 | plugin->get_random_stmt); | ||
511 | return 0; | ||
512 | } | ||
513 | if (GNUNET_OK != | ||
514 | GNUNET_SQ_extract_result (plugin->get_random_stmt, | ||
515 | rs)) | ||
479 | { | 516 | { |
480 | GNUNET_break (0); | 517 | GNUNET_break (0); |
481 | sqlite3_finalize (stmt); | 518 | GNUNET_SQ_reset (plugin->dbh, |
519 | plugin->get_random_stmt); | ||
482 | return 0; | 520 | return 0; |
483 | } | 521 | } |
484 | size = sqlite3_column_bytes (stmt, 0); | ||
485 | dat = sqlite3_column_blob (stmt, 0); | ||
486 | exp.abs_value_us = sqlite3_column_int64 (stmt, 1); | ||
487 | psize = sqlite3_column_bytes (stmt, 2); | ||
488 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) | 522 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) |
489 | { | 523 | { |
490 | GNUNET_break (0); | 524 | GNUNET_break (0); |
491 | psize = 0; | 525 | psize = 0; |
526 | path = NULL; | ||
492 | } | 527 | } |
493 | psize /= sizeof (struct GNUNET_PeerIdentity); | 528 | psize /= sizeof (struct GNUNET_PeerIdentity); |
494 | if (0 != psize) | ||
495 | path = sqlite3_column_blob (stmt, 2); | ||
496 | else | ||
497 | path = NULL; | ||
498 | |||
499 | GNUNET_assert (sizeof (struct GNUNET_HashCode) == | ||
500 | sqlite3_column_bytes (stmt, 3)); | ||
501 | key = sqlite3_column_blob (stmt, 3); | ||
502 | type = sqlite3_column_int (stmt, 4); | ||
503 | |||
504 | ntime = (int64_t) exp.abs_value_us; | ||
505 | if (ntime == INT64_MAX) | ||
506 | exp = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
507 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 529 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
508 | "Found %u-byte result with key %s when processing GET-RANDOM\n", | 530 | "Found %u-byte result with key %s when processing GET-RANDOM\n", |
509 | (unsigned int) size, | 531 | (unsigned int) size, |
510 | GNUNET_h2s (key)); | 532 | GNUNET_h2s (&key)); |
511 | (void) iter (iter_cls, | 533 | (void) iter (iter_cls, |
512 | key, | 534 | &key, |
513 | size, | 535 | size, |
514 | dat, | 536 | dat, |
515 | type, | 537 | (enum GNUNET_BLOCK_Type) type, |
516 | exp, | 538 | exp, |
517 | psize, | 539 | psize, |
518 | path); | 540 | path); |
519 | sqlite3_finalize (stmt); | 541 | GNUNET_SQ_cleanup_result (rs); |
542 | GNUNET_SQ_reset (plugin->dbh, | ||
543 | plugin->get_random_stmt); | ||
520 | return 1; | 544 | return 1; |
521 | } | 545 | } |
522 | 546 | ||
@@ -542,83 +566,73 @@ sqlite_plugin_get_closest (void *cls, | |||
542 | void *iter_cls) | 566 | void *iter_cls) |
543 | { | 567 | { |
544 | struct Plugin *plugin = cls; | 568 | struct Plugin *plugin = cls; |
545 | sqlite3_stmt *stmt; | 569 | uint32_t num_results32 = num_results; |
546 | struct GNUNET_TIME_Absolute now; | 570 | struct GNUNET_TIME_Absolute now; |
547 | struct GNUNET_TIME_Absolute exp; | 571 | struct GNUNET_TIME_Absolute exp; |
548 | unsigned int size; | 572 | size_t size; |
549 | const char *dat; | 573 | void *dat; |
550 | unsigned int cnt; | 574 | unsigned int cnt; |
551 | unsigned int psize; | 575 | size_t psize; |
552 | unsigned int type; | 576 | uint32_t type; |
553 | int64_t ntime; | 577 | struct GNUNET_HashCode hc; |
554 | const struct GNUNET_PeerIdentity *path; | 578 | struct GNUNET_PeerIdentity *path; |
579 | struct GNUNET_SQ_QueryParam params[] = { | ||
580 | GNUNET_SQ_query_param_auto_from_type (key), | ||
581 | GNUNET_SQ_query_param_absolute_time (&now), | ||
582 | GNUNET_SQ_query_param_uint32 (&num_results32), | ||
583 | GNUNET_SQ_query_param_end | ||
584 | }; | ||
585 | struct GNUNET_SQ_ResultSpec rs[] = { | ||
586 | GNUNET_SQ_result_spec_variable_size (&dat, | ||
587 | &size), | ||
588 | GNUNET_SQ_result_spec_absolute_time (&exp), | ||
589 | GNUNET_SQ_result_spec_variable_size ((void **) &path, | ||
590 | &psize), | ||
591 | GNUNET_SQ_result_spec_uint32 (&type), | ||
592 | GNUNET_SQ_result_spec_auto_from_type (&hc), | ||
593 | GNUNET_SQ_result_spec_end | ||
594 | }; | ||
555 | 595 | ||
556 | now = GNUNET_TIME_absolute_get (); | 596 | now = GNUNET_TIME_absolute_get (); |
557 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 597 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
558 | "Processing GET_CLOSEST for key `%4s'\n", | 598 | "Processing GET_CLOSEST for key `%s'\n", |
559 | GNUNET_h2s (key)); | 599 | GNUNET_h2s (key)); |
560 | if (SQLITE_OK != | 600 | if (GNUNET_OK != |
561 | sq_prepare (plugin->dbh, | 601 | GNUNET_SQ_bind (plugin->get_closest_stmt, |
562 | "SELECT value,expire,path,type,key FROM ds090 WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?", | 602 | params)) |
563 | &stmt)) | ||
564 | { | ||
565 | LOG_SQLITE (plugin->dbh, | ||
566 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
567 | "sq_prepare"); | ||
568 | return 0; | ||
569 | } | ||
570 | ntime = (int64_t) now.abs_value_us; | ||
571 | GNUNET_assert (ntime >= 0); | ||
572 | if ((SQLITE_OK != | ||
573 | sqlite3_bind_blob (stmt, | ||
574 | 1, | ||
575 | key, | ||
576 | sizeof (struct GNUNET_HashCode), | ||
577 | SQLITE_TRANSIENT)) || | ||
578 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, now.abs_value_us)) || | ||
579 | (SQLITE_OK != sqlite3_bind_int (stmt, 3, num_results)) ) | ||
580 | { | 603 | { |
581 | LOG_SQLITE (plugin->dbh, | 604 | LOG_SQLITE (plugin->dbh, |
582 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 605 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
583 | "sqlite3_bind_xxx"); | 606 | "sqlite3_bind_xxx"); |
584 | sqlite3_finalize (stmt); | 607 | GNUNET_SQ_reset (plugin->dbh, |
608 | plugin->get_closest_stmt); | ||
585 | return 0; | 609 | return 0; |
586 | } | 610 | } |
587 | cnt = 0; | 611 | cnt = 0; |
588 | while (SQLITE_ROW == sqlite3_step (stmt)) | 612 | while (SQLITE_ROW == |
613 | sqlite3_step (plugin->get_closest_stmt)) | ||
589 | { | 614 | { |
590 | if (sizeof (struct GNUNET_HashCode) != | 615 | if (GNUNET_OK != |
591 | sqlite3_column_bytes (stmt, 4)) | 616 | GNUNET_SQ_extract_result (plugin->get_closest_stmt, |
617 | rs)) | ||
592 | { | 618 | { |
593 | GNUNET_break (0); | 619 | GNUNET_break (0); |
594 | break; | 620 | break; |
595 | } | 621 | } |
596 | size = sqlite3_column_bytes (stmt, 0); | ||
597 | dat = sqlite3_column_blob (stmt, 0); | ||
598 | exp.abs_value_us = sqlite3_column_int64 (stmt, 1); | ||
599 | psize = sqlite3_column_bytes (stmt, 2); | ||
600 | type = sqlite3_column_int (stmt, 3); | ||
601 | key = sqlite3_column_blob (stmt, 4); | ||
602 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) | 622 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) |
603 | { | 623 | { |
604 | GNUNET_break (0); | 624 | GNUNET_break (0); |
605 | psize = 0; | 625 | psize = 0; |
626 | path = NULL; | ||
606 | } | 627 | } |
607 | psize /= sizeof (struct GNUNET_PeerIdentity); | 628 | psize /= sizeof (struct GNUNET_PeerIdentity); |
608 | if (0 != psize) | ||
609 | path = sqlite3_column_blob (stmt, 2); | ||
610 | else | ||
611 | path = NULL; | ||
612 | ntime = (int64_t) exp.abs_value_us; | ||
613 | if (ntime == INT64_MAX) | ||
614 | exp = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
615 | cnt++; | 629 | cnt++; |
616 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 630 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
617 | "Found %u-byte result at %s when processing GET_CLOSE\n", | 631 | "Found %u-byte result at %s when processing GET_CLOSE\n", |
618 | (unsigned int) size, | 632 | (unsigned int) size, |
619 | GNUNET_h2s (key)); | 633 | GNUNET_h2s (&hc)); |
620 | if (GNUNET_OK != iter (iter_cls, | 634 | if (GNUNET_OK != iter (iter_cls, |
621 | key, | 635 | &hc, |
622 | size, | 636 | size, |
623 | dat, | 637 | dat, |
624 | type, | 638 | type, |
@@ -626,11 +640,13 @@ sqlite_plugin_get_closest (void *cls, | |||
626 | psize, | 640 | psize, |
627 | path)) | 641 | path)) |
628 | { | 642 | { |
629 | sqlite3_finalize (stmt); | 643 | GNUNET_SQ_cleanup_result (rs); |
630 | break; | 644 | break; |
631 | } | 645 | } |
646 | GNUNET_SQ_cleanup_result (rs); | ||
632 | } | 647 | } |
633 | sqlite3_finalize (stmt); | 648 | GNUNET_SQ_reset (plugin->dbh, |
649 | plugin->get_closest_stmt); | ||
634 | return cnt; | 650 | return cnt; |
635 | } | 651 | } |
636 | 652 | ||
@@ -703,6 +719,50 @@ libgnunet_plugin_datacache_sqlite_init (void *cls) | |||
703 | plugin->env = env; | 719 | plugin->env = env; |
704 | plugin->dbh = dbh; | 720 | plugin->dbh = dbh; |
705 | plugin->fn = fn_utf8; | 721 | plugin->fn = fn_utf8; |
722 | |||
723 | if ( (SQLITE_OK != | ||
724 | sq_prepare (plugin->dbh, | ||
725 | "INSERT INTO ds090 (type, expire, key, value, path) " | ||
726 | "VALUES (?, ?, ?, ?, ?)", | ||
727 | &plugin->insert_stmt)) || | ||
728 | (SQLITE_OK != | ||
729 | sq_prepare (plugin->dbh, | ||
730 | "SELECT count(*) FROM ds090 " | ||
731 | "WHERE key=? AND type=? AND expire >= ?", | ||
732 | &plugin->get_count_stmt)) || | ||
733 | (SQLITE_OK != | ||
734 | sq_prepare (plugin->dbh, | ||
735 | "SELECT value,expire,path FROM ds090 " | ||
736 | "WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?", | ||
737 | &plugin->get_stmt)) || | ||
738 | (SQLITE_OK != | ||
739 | sq_prepare (plugin->dbh, | ||
740 | "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1", | ||
741 | &plugin->del_select_stmt)) || | ||
742 | (SQLITE_OK != | ||
743 | sq_prepare (plugin->dbh, | ||
744 | "DELETE FROM ds090 WHERE _ROWID_=?", | ||
745 | &plugin->del_stmt)) || | ||
746 | (SQLITE_OK != | ||
747 | sq_prepare (plugin->dbh, | ||
748 | "SELECT value,expire,path,key,type FROM ds090 " | ||
749 | "ORDER BY key LIMIT 1 OFFSET ?", | ||
750 | &plugin->get_random_stmt)) || | ||
751 | (SQLITE_OK != | ||
752 | sq_prepare (plugin->dbh, | ||
753 | "SELECT value,expire,path,type,key FROM ds090 " | ||
754 | "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?", | ||
755 | &plugin->get_closest_stmt)) | ||
756 | ) | ||
757 | { | ||
758 | LOG_SQLITE (plugin->dbh, | ||
759 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
760 | "sq_prepare"); | ||
761 | (void) sqlite3_close (plugin->dbh); | ||
762 | GNUNET_free (plugin); | ||
763 | return NULL; | ||
764 | } | ||
765 | |||
706 | api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions); | 766 | api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions); |
707 | api->cls = plugin; | 767 | api->cls = plugin; |
708 | api->get = &sqlite_plugin_get; | 768 | api->get = &sqlite_plugin_get; |
@@ -741,6 +801,13 @@ libgnunet_plugin_datacache_sqlite_done (void *cls) | |||
741 | plugin->fn); | 801 | plugin->fn); |
742 | GNUNET_free_non_null (plugin->fn); | 802 | GNUNET_free_non_null (plugin->fn); |
743 | #endif | 803 | #endif |
804 | sqlite3_finalize (plugin->insert_stmt); | ||
805 | sqlite3_finalize (plugin->get_count_stmt); | ||
806 | sqlite3_finalize (plugin->get_stmt); | ||
807 | sqlite3_finalize (plugin->del_select_stmt); | ||
808 | sqlite3_finalize (plugin->del_stmt); | ||
809 | sqlite3_finalize (plugin->get_random_stmt); | ||
810 | sqlite3_finalize (plugin->get_closest_stmt); | ||
744 | result = sqlite3_close (plugin->dbh); | 811 | result = sqlite3_close (plugin->dbh); |
745 | #if SQLITE_VERSION_NUMBER >= 3007000 | 812 | #if SQLITE_VERSION_NUMBER >= 3007000 |
746 | if (SQLITE_BUSY == result) | 813 | if (SQLITE_BUSY == result) |
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c index 9c67d242e..491f73ed5 100644 --- a/src/datastore/plugin_datastore_sqlite.c +++ b/src/datastore/plugin_datastore_sqlite.c | |||
@@ -128,6 +128,46 @@ struct Plugin | |||
128 | sqlite3_stmt *insertContent; | 128 | sqlite3_stmt *insertContent; |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * Precompiled SQL for selection | ||
132 | */ | ||
133 | sqlite3_stmt *count_key; | ||
134 | |||
135 | /** | ||
136 | * Precompiled SQL for selection | ||
137 | */ | ||
138 | sqlite3_stmt *count_key_vhash; | ||
139 | |||
140 | /** | ||
141 | * Precompiled SQL for selection | ||
142 | */ | ||
143 | sqlite3_stmt *count_key_type; | ||
144 | |||
145 | /** | ||
146 | * Precompiled SQL for selection | ||
147 | */ | ||
148 | sqlite3_stmt *count_key_vhash_type; | ||
149 | |||
150 | /** | ||
151 | * Precompiled SQL for selection | ||
152 | */ | ||
153 | sqlite3_stmt *get_key; | ||
154 | |||
155 | /** | ||
156 | * Precompiled SQL for selection | ||
157 | */ | ||
158 | sqlite3_stmt *get_key_vhash; | ||
159 | |||
160 | /** | ||
161 | * Precompiled SQL for selection | ||
162 | */ | ||
163 | sqlite3_stmt *get_key_type; | ||
164 | |||
165 | /** | ||
166 | * Precompiled SQL for selection | ||
167 | */ | ||
168 | sqlite3_stmt *get_key_vhash_type; | ||
169 | |||
170 | /** | ||
131 | * Should the database be dropped on shutdown? | 171 | * Should the database be dropped on shutdown? |
132 | */ | 172 | */ |
133 | int drop_on_shutdown; | 173 | int drop_on_shutdown; |
@@ -151,11 +191,17 @@ sq_prepare (sqlite3 *dbh, | |||
151 | char *dummy; | 191 | char *dummy; |
152 | int result; | 192 | int result; |
153 | 193 | ||
154 | result = | 194 | result = sqlite3_prepare_v2 (dbh, |
155 | sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, | 195 | zSql, |
156 | (const char **) &dummy); | 196 | strlen (zSql), |
157 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | 197 | ppStmt, |
158 | "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); | 198 | (const char **) &dummy); |
199 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
200 | "sqlite", | ||
201 | "Prepared `%s' / %p: %d\n", | ||
202 | zSql, | ||
203 | *ppStmt, | ||
204 | result); | ||
159 | return result; | 205 | return result; |
160 | } | 206 | } |
161 | 207 | ||
@@ -311,80 +357,134 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
311 | * we do math or inequality tests, so we can't handle the entire range of uint32_t. | 357 | * we do math or inequality tests, so we can't handle the entire range of uint32_t. |
312 | * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. | 358 | * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. |
313 | */ | 359 | */ |
314 | if ((sqlite3_step (stmt) == SQLITE_DONE) && | 360 | if ( (SQLITE_DONE == |
315 | (sqlite3_exec | 361 | sqlite3_step (stmt)) && |
316 | (plugin->dbh, | 362 | (SQLITE_OK != |
317 | "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," | 363 | sqlite3_exec (plugin->dbh, |
318 | " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," | 364 | "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," |
319 | " anonLevel INT4 NOT NULL DEFAULT 0," | 365 | " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," |
320 | " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," | 366 | " anonLevel INT4 NOT NULL DEFAULT 0," |
321 | " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," | 367 | " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," |
322 | " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK)) | 368 | " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," |
369 | " value BLOB NOT NULL DEFAULT '')", | ||
370 | NULL, | ||
371 | NULL, | ||
372 | NULL)) ) | ||
323 | { | 373 | { |
324 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); | 374 | LOG_SQLITE (plugin, |
375 | GNUNET_ERROR_TYPE_ERROR, | ||
376 | "sqlite3_exec"); | ||
325 | sqlite3_finalize (stmt); | 377 | sqlite3_finalize (stmt); |
326 | return GNUNET_SYSERR; | 378 | return GNUNET_SYSERR; |
327 | } | 379 | } |
328 | sqlite3_finalize (stmt); | 380 | sqlite3_finalize (stmt); |
329 | create_indices (plugin->dbh); | 381 | create_indices (plugin->dbh); |
330 | 382 | ||
331 | if ((sq_prepare | 383 | if ( (SQLITE_OK != |
332 | (plugin->dbh, | 384 | sq_prepare (plugin->dbh, |
333 | "UPDATE gn090 " | 385 | "UPDATE gn090 " |
334 | "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", | 386 | "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", |
335 | &plugin->updPrio) != SQLITE_OK) || | 387 | &plugin->updPrio)) || |
336 | (sq_prepare | 388 | (SQLITE_OK != |
337 | (plugin->dbh, | 389 | sq_prepare (plugin->dbh, |
338 | "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", | 390 | "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", |
339 | &plugin->updRepl) != SQLITE_OK) || | 391 | &plugin->updRepl)) || |
340 | (sq_prepare | 392 | (SQLITE_OK != |
341 | (plugin->dbh, | 393 | sq_prepare (plugin->dbh, |
342 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " | 394 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " |
343 | #if SQLITE_VERSION_NUMBER >= 3007000 | 395 | #if SQLITE_VERSION_NUMBER >= 3007000 |
344 | "INDEXED BY idx_repl_rvalue " | 396 | "INDEXED BY idx_repl_rvalue " |
345 | #endif | 397 | #endif |
346 | "WHERE repl=?2 AND " " (rvalue>=?1 OR " | 398 | "WHERE repl=?2 AND " " (rvalue>=?1 OR " |
347 | " NOT EXISTS (SELECT 1 FROM gn090 " | 399 | " NOT EXISTS (SELECT 1 FROM gn090 " |
348 | #if SQLITE_VERSION_NUMBER >= 3007000 | 400 | #if SQLITE_VERSION_NUMBER >= 3007000 |
349 | "INDEXED BY idx_repl_rvalue " | 401 | "INDEXED BY idx_repl_rvalue " |
350 | #endif | 402 | #endif |
351 | "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " | 403 | "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " |
352 | "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) || | 404 | "ORDER BY rvalue ASC LIMIT 1", |
353 | (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090" | 405 | &plugin->selRepl)) || |
406 | (SQLITE_OK != | ||
407 | sq_prepare (plugin->dbh, | ||
408 | "SELECT MAX(repl) FROM gn090" | ||
354 | #if SQLITE_VERSION_NUMBER >= 3007000 | 409 | #if SQLITE_VERSION_NUMBER >= 3007000 |
355 | " INDEXED BY idx_repl_rvalue" | 410 | " INDEXED BY idx_repl_rvalue" |
356 | #endif | 411 | #endif |
357 | "", &plugin->maxRepl) != SQLITE_OK) || | 412 | "", |
358 | (sq_prepare | 413 | &plugin->maxRepl)) || |
359 | (plugin->dbh, | 414 | (SQLITE_OK != |
360 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " | 415 | sq_prepare (plugin->dbh, |
416 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " | ||
361 | #if SQLITE_VERSION_NUMBER >= 3007000 | 417 | #if SQLITE_VERSION_NUMBER >= 3007000 |
362 | "INDEXED BY idx_expire " | 418 | "INDEXED BY idx_expire " |
363 | #endif | 419 | #endif |
364 | "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " | 420 | "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " |
365 | "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) || | 421 | "ORDER BY expire ASC LIMIT 1", |
366 | (sq_prepare | 422 | &plugin->selExpi)) || |
367 | (plugin->dbh, | 423 | (SQLITE_OK != |
368 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " | 424 | sq_prepare (plugin->dbh, |
425 | "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " | ||
369 | #if SQLITE_VERSION_NUMBER >= 3007000 | 426 | #if SQLITE_VERSION_NUMBER >= 3007000 |
370 | "INDEXED BY idx_anon_type_hash " | 427 | "INDEXED BY idx_anon_type_hash " |
371 | #endif | 428 | #endif |
372 | "WHERE (anonLevel = 0 AND type=?1) " | 429 | "WHERE (anonLevel = 0 AND type=?1) " |
373 | "ORDER BY hash DESC LIMIT 1 OFFSET ?2", | 430 | "ORDER BY hash DESC LIMIT 1 OFFSET ?2", |
374 | &plugin->selZeroAnon) != SQLITE_OK) || | 431 | &plugin->selZeroAnon)) || |
375 | (sq_prepare | 432 | (SQLITE_OK != |
376 | (plugin->dbh, | 433 | sq_prepare (plugin->dbh, |
377 | "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " | 434 | "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " |
378 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", | 435 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", |
379 | &plugin->insertContent) != SQLITE_OK) || | 436 | &plugin->insertContent)) || |
380 | (sq_prepare | 437 | (SQLITE_OK != |
381 | (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?", | 438 | sq_prepare (plugin->dbh, |
382 | &plugin->delRow) != SQLITE_OK)) | 439 | "SELECT count(*) FROM gn090 WHERE hash=?", |
440 | &plugin->count_key)) || | ||
441 | (SQLITE_OK != | ||
442 | sq_prepare (plugin->dbh, | ||
443 | "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=?", | ||
444 | &plugin->count_key_vhash)) || | ||
445 | (SQLITE_OK != | ||
446 | sq_prepare (plugin->dbh, | ||
447 | "SELECT count(*) FROM gn090 WHERE hash=? AND type=?", | ||
448 | &plugin->count_key_type)) || | ||
449 | (SQLITE_OK != | ||
450 | sq_prepare (plugin->dbh, | ||
451 | "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=? AND type=?", | ||
452 | &plugin->count_key_vhash_type)) || | ||
453 | (SQLITE_OK != | ||
454 | sq_prepare (plugin->dbh, | ||
455 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
456 | "WHERE hash=?" | ||
457 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
458 | &plugin->get_key)) || | ||
459 | (SQLITE_OK != | ||
460 | sq_prepare (plugin->dbh, | ||
461 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
462 | "WHERE hash=? AND vhash=?" | ||
463 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
464 | &plugin->get_key_vhash)) || | ||
465 | (SQLITE_OK != | ||
466 | sq_prepare (plugin->dbh, | ||
467 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
468 | "WHERE hash=? AND type=?" | ||
469 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
470 | &plugin->get_key_type)) || | ||
471 | (SQLITE_OK != | ||
472 | sq_prepare (plugin->dbh, | ||
473 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
474 | "WHERE hash=? AND vhash=? AND type=?" | ||
475 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
476 | &plugin->get_key_vhash_type)) || | ||
477 | (SQLITE_OK != | ||
478 | sq_prepare (plugin->dbh, | ||
479 | "DELETE FROM gn090 WHERE _ROWID_ = ?", | ||
480 | &plugin->delRow)) | ||
481 | ) | ||
383 | { | 482 | { |
384 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling"); | 483 | LOG_SQLITE (plugin, |
484 | GNUNET_ERROR_TYPE_ERROR, | ||
485 | "precompiling"); | ||
385 | return GNUNET_SYSERR; | 486 | return GNUNET_SYSERR; |
386 | } | 487 | } |
387 | |||
388 | return GNUNET_OK; | 488 | return GNUNET_OK; |
389 | } | 489 | } |
390 | 490 | ||
@@ -399,51 +499,74 @@ static void | |||
399 | database_shutdown (struct Plugin *plugin) | 499 | database_shutdown (struct Plugin *plugin) |
400 | { | 500 | { |
401 | int result; | 501 | int result; |
402 | |||
403 | #if SQLITE_VERSION_NUMBER >= 3007000 | 502 | #if SQLITE_VERSION_NUMBER >= 3007000 |
404 | sqlite3_stmt *stmt; | 503 | sqlite3_stmt *stmt; |
405 | #endif | 504 | #endif |
406 | 505 | ||
407 | if (plugin->delRow != NULL) | 506 | if (NULL != plugin->delRow) |
408 | sqlite3_finalize (plugin->delRow); | 507 | sqlite3_finalize (plugin->delRow); |
409 | if (plugin->updPrio != NULL) | 508 | if (NULL != plugin->updPrio) |
410 | sqlite3_finalize (plugin->updPrio); | 509 | sqlite3_finalize (plugin->updPrio); |
411 | if (plugin->updRepl != NULL) | 510 | if (NULL != plugin->updRepl) |
412 | sqlite3_finalize (plugin->updRepl); | 511 | sqlite3_finalize (plugin->updRepl); |
413 | if (plugin->selRepl != NULL) | 512 | if (NULL != plugin->selRepl) |
414 | sqlite3_finalize (plugin->selRepl); | 513 | sqlite3_finalize (plugin->selRepl); |
415 | if (plugin->maxRepl != NULL) | 514 | if (NULL != plugin->maxRepl) |
416 | sqlite3_finalize (plugin->maxRepl); | 515 | sqlite3_finalize (plugin->maxRepl); |
417 | if (plugin->selExpi != NULL) | 516 | if (NULL != plugin->selExpi) |
418 | sqlite3_finalize (plugin->selExpi); | 517 | sqlite3_finalize (plugin->selExpi); |
419 | if (plugin->selZeroAnon != NULL) | 518 | if (NULL != plugin->selZeroAnon) |
420 | sqlite3_finalize (plugin->selZeroAnon); | 519 | sqlite3_finalize (plugin->selZeroAnon); |
421 | if (plugin->insertContent != NULL) | 520 | if (NULL != plugin->insertContent) |
422 | sqlite3_finalize (plugin->insertContent); | 521 | sqlite3_finalize (plugin->insertContent); |
522 | if (NULL != plugin->count_key) | ||
523 | sqlite3_finalize (plugin->count_key); | ||
524 | if (NULL != plugin->count_key_vhash) | ||
525 | sqlite3_finalize (plugin->count_key_vhash); | ||
526 | if (NULL != plugin->count_key_type) | ||
527 | sqlite3_finalize (plugin->count_key_type); | ||
528 | if (NULL != plugin->count_key_vhash_type) | ||
529 | sqlite3_finalize (plugin->count_key_vhash_type); | ||
530 | if (NULL != plugin->count_key) | ||
531 | sqlite3_finalize (plugin->get_key); | ||
532 | if (NULL != plugin->count_key_vhash) | ||
533 | sqlite3_finalize (plugin->get_key_vhash); | ||
534 | if (NULL != plugin->count_key_type) | ||
535 | sqlite3_finalize (plugin->get_key_type); | ||
536 | if (NULL != plugin->count_key_vhash_type) | ||
537 | sqlite3_finalize (plugin->get_key_vhash_type); | ||
423 | result = sqlite3_close (plugin->dbh); | 538 | result = sqlite3_close (plugin->dbh); |
424 | #if SQLITE_VERSION_NUMBER >= 3007000 | 539 | #if SQLITE_VERSION_NUMBER >= 3007000 |
425 | if (result == SQLITE_BUSY) | 540 | if (result == SQLITE_BUSY) |
426 | { | 541 | { |
427 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", | 542 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, |
428 | _ | 543 | "sqlite", |
429 | ("Tried to close sqlite without finalizing all prepared statements.\n")); | 544 | _("Tried to close sqlite without finalizing all prepared statements.\n")); |
430 | stmt = sqlite3_next_stmt (plugin->dbh, NULL); | 545 | stmt = sqlite3_next_stmt (plugin->dbh, |
431 | while (stmt != NULL) | 546 | NULL); |
547 | while (NULL != stmt) | ||
432 | { | 548 | { |
433 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | 549 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
434 | "Closing statement %p\n", stmt); | 550 | "sqlite", |
551 | "Closing statement %p\n", | ||
552 | stmt); | ||
435 | result = sqlite3_finalize (stmt); | 553 | result = sqlite3_finalize (stmt); |
436 | if (result != SQLITE_OK) | 554 | if (result != SQLITE_OK) |
437 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", | 555 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, |
438 | "Failed to close statement %p: %d\n", stmt, result); | 556 | "sqlite", |
439 | stmt = sqlite3_next_stmt (plugin->dbh, NULL); | 557 | "Failed to close statement %p: %d\n", |
558 | stmt, | ||
559 | result); | ||
560 | stmt = sqlite3_next_stmt (plugin->dbh, | ||
561 | NULL); | ||
440 | } | 562 | } |
441 | result = sqlite3_close (plugin->dbh); | 563 | result = sqlite3_close (plugin->dbh); |
442 | } | 564 | } |
443 | #endif | 565 | #endif |
444 | if (SQLITE_OK != result) | 566 | if (SQLITE_OK != result) |
445 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); | 567 | LOG_SQLITE (plugin, |
446 | 568 | GNUNET_ERROR_TYPE_ERROR, | |
569 | "sqlite3_close"); | ||
447 | GNUNET_free_non_null (plugin->fn); | 570 | GNUNET_free_non_null (plugin->fn); |
448 | } | 571 | } |
449 | 572 | ||
@@ -472,15 +595,12 @@ delete_by_rowid (struct Plugin *plugin, | |||
472 | { | 595 | { |
473 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 596 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
474 | "sqlite3_step"); | 597 | "sqlite3_step"); |
475 | if (SQLITE_OK != sqlite3_reset (plugin->delRow)) | 598 | GNUNET_SQ_reset (plugin->dbh, |
476 | LOG_SQLITE (plugin, | 599 | plugin->delRow); |
477 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
478 | "sqlite3_reset"); | ||
479 | return GNUNET_SYSERR; | 600 | return GNUNET_SYSERR; |
480 | } | 601 | } |
481 | if (SQLITE_OK != sqlite3_reset (plugin->delRow)) | 602 | GNUNET_SQ_reset (plugin->dbh, |
482 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 603 | plugin->delRow); |
483 | "sqlite3_reset"); | ||
484 | return GNUNET_OK; | 604 | return GNUNET_OK; |
485 | } | 605 | } |
486 | 606 | ||
@@ -515,9 +635,10 @@ sqlite_plugin_put (void *cls, | |||
515 | { | 635 | { |
516 | uint64_t rvalue; | 636 | uint64_t rvalue; |
517 | struct GNUNET_HashCode vhash; | 637 | struct GNUNET_HashCode vhash; |
638 | uint32_t type32 = (uint32_t) type; | ||
518 | struct GNUNET_SQ_QueryParam params[] = { | 639 | struct GNUNET_SQ_QueryParam params[] = { |
519 | GNUNET_SQ_query_param_uint32 (&replication), | 640 | GNUNET_SQ_query_param_uint32 (&replication), |
520 | GNUNET_SQ_query_param_uint32 (&type), | 641 | GNUNET_SQ_query_param_uint32 (&type32), |
521 | GNUNET_SQ_query_param_uint32 (&priority), | 642 | GNUNET_SQ_query_param_uint32 (&priority), |
522 | GNUNET_SQ_query_param_uint32 (&anonymity), | 643 | GNUNET_SQ_query_param_uint32 (&anonymity), |
523 | GNUNET_SQ_query_param_absolute_time (&expiration), | 644 | GNUNET_SQ_query_param_absolute_time (&expiration), |
@@ -578,19 +699,16 @@ sqlite_plugin_put (void *cls, | |||
578 | default: | 699 | default: |
579 | LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 700 | LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
580 | "sqlite3_step"); | 701 | "sqlite3_step"); |
581 | if (SQLITE_OK != sqlite3_reset (stmt)) | 702 | GNUNET_SQ_reset (plugin->dbh, |
582 | LOG_SQLITE (plugin, | 703 | stmt); |
583 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
584 | "sqlite3_reset"); | ||
585 | database_shutdown (plugin); | 704 | database_shutdown (plugin); |
586 | database_setup (plugin->env->cfg, plugin); | 705 | database_setup (plugin->env->cfg, plugin); |
587 | cont (cont_cls, key, size, GNUNET_SYSERR, msg); | 706 | cont (cont_cls, key, size, GNUNET_SYSERR, msg); |
588 | GNUNET_free_non_null(msg); | 707 | GNUNET_free_non_null(msg); |
589 | return; | 708 | return; |
590 | } | 709 | } |
591 | if (SQLITE_OK != sqlite3_reset (stmt)) | 710 | GNUNET_SQ_reset (plugin->dbh, |
592 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 711 | stmt); |
593 | "sqlite3_reset"); | ||
594 | cont (cont_cls, key, size, ret, msg); | 712 | cont (cont_cls, key, size, ret, msg); |
595 | GNUNET_free_non_null(msg); | 713 | GNUNET_free_non_null(msg); |
596 | } | 714 | } |
@@ -644,9 +762,8 @@ sqlite_plugin_update (void *cls, | |||
644 | return; | 762 | return; |
645 | } | 763 | } |
646 | n = sqlite3_step (plugin->updPrio); | 764 | n = sqlite3_step (plugin->updPrio); |
647 | if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) | 765 | GNUNET_SQ_reset (plugin->dbh, |
648 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 766 | plugin->updPrio); |
649 | "sqlite3_reset"); | ||
650 | switch (n) | 767 | switch (n) |
651 | { | 768 | { |
652 | case SQLITE_DONE: | 769 | case SQLITE_DONE: |
@@ -687,75 +804,84 @@ execute_get (struct Plugin *plugin, | |||
687 | { | 804 | { |
688 | int n; | 805 | int n; |
689 | struct GNUNET_TIME_Absolute expiration; | 806 | struct GNUNET_TIME_Absolute expiration; |
690 | unsigned long long rowid; | 807 | uint32_t type; |
691 | unsigned int size; | 808 | uint32_t priority; |
809 | uint32_t anonymity; | ||
810 | uint64_t rowid; | ||
811 | void *value; | ||
812 | size_t value_size; | ||
813 | struct GNUNET_HashCode key; | ||
692 | int ret; | 814 | int ret; |
815 | struct GNUNET_SQ_ResultSpec rs[] = { | ||
816 | GNUNET_SQ_result_spec_uint32 (&type), | ||
817 | GNUNET_SQ_result_spec_uint32 (&priority), | ||
818 | GNUNET_SQ_result_spec_uint32 (&anonymity), | ||
819 | GNUNET_SQ_result_spec_absolute_time (&expiration), | ||
820 | GNUNET_SQ_result_spec_auto_from_type (&key), | ||
821 | GNUNET_SQ_result_spec_variable_size (&value, | ||
822 | &value_size), | ||
823 | GNUNET_SQ_result_spec_uint64 (&rowid), | ||
824 | GNUNET_SQ_result_spec_end | ||
825 | }; | ||
693 | 826 | ||
694 | n = sqlite3_step (stmt); | 827 | n = sqlite3_step (stmt); |
695 | switch (n) | 828 | switch (n) |
696 | { | 829 | { |
697 | case SQLITE_ROW: | 830 | case SQLITE_ROW: |
698 | size = sqlite3_column_bytes (stmt, 5); | 831 | if (GNUNET_OK != |
699 | rowid = sqlite3_column_int64 (stmt, 6); | 832 | GNUNET_SQ_extract_result (stmt, |
700 | if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode)) | 833 | rs)) |
701 | { | 834 | { |
702 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", | 835 | GNUNET_break (0); |
703 | _("Invalid data in database. Trying to fix (by deletion).\n")); | ||
704 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
705 | LOG_SQLITE (plugin, | ||
706 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
707 | "sqlite3_reset"); | ||
708 | if ( (GNUNET_OK == delete_by_rowid (plugin, rowid)) && | ||
709 | (NULL != plugin->env->duc) ) | ||
710 | plugin->env->duc (plugin->env->cls, | ||
711 | -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); | ||
712 | break; | 836 | break; |
713 | } | 837 | } |
714 | expiration.abs_value_us = sqlite3_column_int64 (stmt, 3); | 838 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
715 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | 839 | "sqlite", |
716 | "Found reply in database with expiration %s\n", | 840 | "Found reply in database with expiration %s\n", |
717 | GNUNET_STRINGS_absolute_time_to_string (expiration)); | 841 | GNUNET_STRINGS_absolute_time_to_string (expiration)); |
718 | ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , | 842 | ret = proc (proc_cls, |
719 | size, sqlite3_column_blob (stmt, 5) /* data */ , | 843 | &key, |
720 | sqlite3_column_int (stmt, 0) /* type */ , | 844 | value_size, |
721 | sqlite3_column_int (stmt, 1) /* priority */ , | 845 | value, |
722 | sqlite3_column_int (stmt, 2) /* anonymity */ , | 846 | type, |
723 | expiration, rowid); | 847 | priority, |
724 | if (SQLITE_OK != sqlite3_reset (stmt)) | 848 | anonymity, |
725 | LOG_SQLITE (plugin, | 849 | expiration, |
726 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 850 | rowid); |
727 | "sqlite3_reset"); | 851 | GNUNET_SQ_cleanup_result (rs); |
852 | GNUNET_SQ_reset (plugin->dbh, | ||
853 | stmt); | ||
728 | if ( (GNUNET_NO == ret) && | 854 | if ( (GNUNET_NO == ret) && |
729 | (GNUNET_OK == delete_by_rowid (plugin, rowid)) && | 855 | (GNUNET_OK == delete_by_rowid (plugin, |
856 | rowid)) && | ||
730 | (NULL != plugin->env->duc) ) | 857 | (NULL != plugin->env->duc) ) |
731 | plugin->env->duc (plugin->env->cls, | 858 | plugin->env->duc (plugin->env->cls, |
732 | -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); | 859 | -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); |
733 | return; | 860 | return; |
734 | case SQLITE_DONE: | 861 | case SQLITE_DONE: |
735 | /* database must be empty */ | 862 | /* database must be empty */ |
736 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
737 | LOG_SQLITE (plugin, | ||
738 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
739 | "sqlite3_reset"); | ||
740 | break; | 863 | break; |
741 | case SQLITE_BUSY: | 864 | case SQLITE_BUSY: |
742 | case SQLITE_ERROR: | 865 | case SQLITE_ERROR: |
743 | case SQLITE_MISUSE: | 866 | case SQLITE_MISUSE: |
744 | default: | 867 | default: |
745 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 868 | LOG_SQLITE (plugin, |
869 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
746 | "sqlite3_step"); | 870 | "sqlite3_step"); |
747 | if (SQLITE_OK != sqlite3_reset (stmt)) | 871 | if (SQLITE_OK != |
872 | sqlite3_reset (stmt)) | ||
748 | LOG_SQLITE (plugin, | 873 | LOG_SQLITE (plugin, |
749 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 874 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
750 | "sqlite3_reset"); | 875 | "sqlite3_reset"); |
751 | GNUNET_break (0); | 876 | GNUNET_break (0); |
877 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
752 | database_shutdown (plugin); | 878 | database_shutdown (plugin); |
753 | database_setup (plugin->env->cfg, plugin); | 879 | database_setup (plugin->env->cfg, |
754 | break; | 880 | plugin); |
881 | return; | ||
755 | } | 882 | } |
756 | if (SQLITE_OK != sqlite3_reset (stmt)) | 883 | GNUNET_SQ_reset (plugin->dbh, |
757 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 884 | stmt); |
758 | "sqlite3_reset"); | ||
759 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 885 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
760 | } | 886 | } |
761 | 887 | ||
@@ -774,7 +900,8 @@ execute_get (struct Plugin *plugin, | |||
774 | * @param proc_cls closure for @a proc | 900 | * @param proc_cls closure for @a proc |
775 | */ | 901 | */ |
776 | static void | 902 | static void |
777 | sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset, | 903 | sqlite_plugin_get_zero_anonymity (void *cls, |
904 | uint64_t offset, | ||
778 | enum GNUNET_BLOCK_Type type, | 905 | enum GNUNET_BLOCK_Type type, |
779 | PluginDatumProcessor proc, | 906 | PluginDatumProcessor proc, |
780 | void *proc_cls) | 907 | void *proc_cls) |
@@ -826,97 +953,133 @@ sqlite_plugin_get_key (void *cls, | |||
826 | void *proc_cls) | 953 | void *proc_cls) |
827 | { | 954 | { |
828 | struct Plugin *plugin = cls; | 955 | struct Plugin *plugin = cls; |
956 | uint32_t type32 = (uint32_t) type; | ||
829 | int ret; | 957 | int ret; |
830 | int total; | 958 | int total; |
831 | int limit_off; | 959 | uint32_t limit_off; |
832 | unsigned int sqoff; | 960 | struct GNUNET_SQ_QueryParam count_params_key[] = { |
833 | sqlite3_stmt *stmt; | 961 | GNUNET_SQ_query_param_auto_from_type (key), |
834 | char scratch[256]; | 962 | GNUNET_SQ_query_param_end |
835 | 963 | }; | |
836 | GNUNET_assert (proc != NULL); | 964 | struct GNUNET_SQ_QueryParam count_params_key_vhash[] = { |
837 | GNUNET_assert (key != NULL); | 965 | GNUNET_SQ_query_param_auto_from_type (key), |
838 | GNUNET_snprintf (scratch, sizeof (scratch), | 966 | GNUNET_SQ_query_param_auto_from_type (vhash), |
839 | "SELECT count(*) FROM gn090 WHERE hash=?%s%s", | 967 | GNUNET_SQ_query_param_end |
840 | vhash == NULL ? "" : " AND vhash=?", | 968 | }; |
841 | type == 0 ? "" : " AND type=?"); | 969 | struct GNUNET_SQ_QueryParam count_params_key_type[] = { |
842 | if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) | 970 | GNUNET_SQ_query_param_auto_from_type (key), |
971 | GNUNET_SQ_query_param_uint32 (&type32), | ||
972 | GNUNET_SQ_query_param_end | ||
973 | }; | ||
974 | struct GNUNET_SQ_QueryParam count_params_key_vhash_type[] = { | ||
975 | GNUNET_SQ_query_param_auto_from_type (key), | ||
976 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
977 | GNUNET_SQ_query_param_uint32 (&type32), | ||
978 | GNUNET_SQ_query_param_end | ||
979 | }; | ||
980 | struct GNUNET_SQ_QueryParam get_params_key[] = { | ||
981 | GNUNET_SQ_query_param_auto_from_type (key), | ||
982 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
983 | GNUNET_SQ_query_param_end | ||
984 | }; | ||
985 | struct GNUNET_SQ_QueryParam get_params_key_vhash[] = { | ||
986 | GNUNET_SQ_query_param_auto_from_type (key), | ||
987 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
988 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
989 | GNUNET_SQ_query_param_end | ||
990 | }; | ||
991 | struct GNUNET_SQ_QueryParam get_params_key_type[] = { | ||
992 | GNUNET_SQ_query_param_auto_from_type (key), | ||
993 | GNUNET_SQ_query_param_uint32 (&type32), | ||
994 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
995 | GNUNET_SQ_query_param_end | ||
996 | }; | ||
997 | struct GNUNET_SQ_QueryParam get_params_key_vhash_type[] = { | ||
998 | GNUNET_SQ_query_param_auto_from_type (key), | ||
999 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
1000 | GNUNET_SQ_query_param_uint32 (&type32), | ||
1001 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
1002 | GNUNET_SQ_query_param_end | ||
1003 | }; | ||
1004 | struct GNUNET_SQ_QueryParam *count_params; | ||
1005 | sqlite3_stmt *count_stmt; | ||
1006 | struct GNUNET_SQ_QueryParam *get_params; | ||
1007 | sqlite3_stmt *get_stmt; | ||
1008 | |||
1009 | if (NULL == vhash) | ||
843 | { | 1010 | { |
844 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1011 | if (GNUNET_BLOCK_TYPE_ANY == type) |
845 | "sqlite_prepare"); | 1012 | { |
846 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1013 | count_params = count_params_key; |
847 | return; | 1014 | count_stmt = plugin->count_key; |
1015 | get_params = get_params_key; | ||
1016 | get_stmt = plugin->get_key; | ||
1017 | } | ||
1018 | else | ||
1019 | { | ||
1020 | count_params = count_params_key_type; | ||
1021 | count_stmt = plugin->count_key_type; | ||
1022 | get_params = get_params_key_type; | ||
1023 | get_stmt = plugin->get_key_type; | ||
1024 | } | ||
848 | } | 1025 | } |
849 | sqoff = 1; | 1026 | else |
850 | ret = | 1027 | { |
851 | sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode), | 1028 | if (GNUNET_BLOCK_TYPE_ANY == type) |
852 | SQLITE_TRANSIENT); | 1029 | { |
853 | if ((vhash != NULL) && (ret == SQLITE_OK)) | 1030 | count_params = count_params_key_vhash; |
854 | ret = | 1031 | count_stmt = plugin->count_key_vhash; |
855 | sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode), | 1032 | get_params = get_params_key_vhash; |
856 | SQLITE_TRANSIENT); | 1033 | get_stmt = plugin->get_key_vhash; |
857 | if ((type != 0) && (ret == SQLITE_OK)) | 1034 | } |
858 | ret = sqlite3_bind_int (stmt, sqoff++, type); | 1035 | else |
859 | if (SQLITE_OK != ret) | 1036 | { |
1037 | count_params = count_params_key_vhash_type; | ||
1038 | count_stmt = plugin->count_key_vhash_type; | ||
1039 | get_params = get_params_key_vhash_type; | ||
1040 | get_stmt = plugin->get_key_vhash_type; | ||
1041 | } | ||
1042 | } | ||
1043 | if (GNUNET_OK != | ||
1044 | GNUNET_SQ_bind (count_stmt, | ||
1045 | count_params)) | ||
860 | { | 1046 | { |
861 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind"); | ||
862 | sqlite3_finalize (stmt); | ||
863 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1047 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
864 | return; | 1048 | return; |
865 | } | 1049 | } |
866 | ret = sqlite3_step (stmt); | 1050 | ret = sqlite3_step (count_stmt); |
867 | if (ret != SQLITE_ROW) | 1051 | if (ret != SQLITE_ROW) |
868 | { | 1052 | { |
869 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1053 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
870 | "sqlite_step"); | 1054 | "sqlite_step"); |
871 | sqlite3_finalize (stmt); | 1055 | GNUNET_SQ_reset (plugin->dbh, |
1056 | count_stmt); | ||
872 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1057 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
873 | return; | 1058 | return; |
874 | } | 1059 | } |
875 | total = sqlite3_column_int (stmt, 0); | 1060 | total = sqlite3_column_int (count_stmt, |
876 | sqlite3_finalize (stmt); | 1061 | 0); |
1062 | GNUNET_SQ_reset (plugin->dbh, | ||
1063 | count_stmt); | ||
877 | if (0 == total) | 1064 | if (0 == total) |
878 | { | 1065 | { |
879 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1066 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
880 | return; | 1067 | return; |
881 | } | 1068 | } |
882 | limit_off = (int) (offset % total); | 1069 | limit_off = (uint32_t) (offset % total); |
883 | if (limit_off < 0) | 1070 | if (GNUNET_OK != |
884 | limit_off += total; | 1071 | GNUNET_SQ_bind (get_stmt, |
885 | GNUNET_snprintf (scratch, sizeof (scratch), | 1072 | get_params)) |
886 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ " | ||
887 | "FROM gn090 WHERE hash=?%s%s " | ||
888 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
889 | vhash == NULL ? "" : " AND vhash=?", | ||
890 | type == 0 ? "" : " AND type=?"); | ||
891 | if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) | ||
892 | { | ||
893 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
894 | "sqlite_prepare"); | ||
895 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
896 | return; | ||
897 | } | ||
898 | sqoff = 1; | ||
899 | ret = sqlite3_bind_blob (stmt, sqoff++, key, | ||
900 | sizeof (struct GNUNET_HashCode), | ||
901 | SQLITE_TRANSIENT); | ||
902 | if ((vhash != NULL) && (ret == SQLITE_OK)) | ||
903 | ret = sqlite3_bind_blob (stmt, sqoff++, vhash, | ||
904 | sizeof (struct GNUNET_HashCode), | ||
905 | SQLITE_TRANSIENT); | ||
906 | if ((type != 0) && (ret == SQLITE_OK)) | ||
907 | ret = sqlite3_bind_int (stmt, sqoff++, type); | ||
908 | if (ret == SQLITE_OK) | ||
909 | ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off); | ||
910 | if (ret != SQLITE_OK) | ||
911 | { | 1073 | { |
912 | LOG_SQLITE (plugin, | ||
913 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
914 | "sqlite_bind"); | ||
915 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1074 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
916 | return; | 1075 | return; |
917 | } | 1076 | } |
918 | execute_get (plugin, stmt, proc, proc_cls); | 1077 | execute_get (plugin, |
919 | sqlite3_finalize (stmt); | 1078 | get_stmt, |
1079 | proc, | ||
1080 | proc_cls); | ||
1081 | GNUNET_SQ_reset (plugin->dbh, | ||
1082 | get_stmt); | ||
920 | } | 1083 | } |
921 | 1084 | ||
922 | 1085 | ||
@@ -980,13 +1143,17 @@ repl_proc (void *cls, | |||
980 | struct ReplCtx *rc = cls; | 1143 | struct ReplCtx *rc = cls; |
981 | int ret; | 1144 | int ret; |
982 | 1145 | ||
1146 | if (GNUNET_SYSERR == rc->have_uid) | ||
1147 | rc->have_uid = GNUNET_NO; | ||
983 | ret = rc->proc (rc->proc_cls, | 1148 | ret = rc->proc (rc->proc_cls, |
984 | key, | 1149 | key, |
985 | size, data, | 1150 | size, |
1151 | data, | ||
986 | type, | 1152 | type, |
987 | priority, | 1153 | priority, |
988 | anonymity, | 1154 | anonymity, |
989 | expiration, uid); | 1155 | expiration, |
1156 | uid); | ||
990 | if (NULL != key) | 1157 | if (NULL != key) |
991 | { | 1158 | { |
992 | rc->uid = uid; | 1159 | rc->uid = uid; |
@@ -1007,7 +1174,8 @@ repl_proc (void *cls, | |||
1007 | * @param proc_cls closure for @a proc | 1174 | * @param proc_cls closure for @a proc |
1008 | */ | 1175 | */ |
1009 | static void | 1176 | static void |
1010 | sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, | 1177 | sqlite_plugin_get_replication (void *cls, |
1178 | PluginDatumProcessor proc, | ||
1011 | void *proc_cls) | 1179 | void *proc_cls) |
1012 | { | 1180 | { |
1013 | struct Plugin *plugin = cls; | 1181 | struct Plugin *plugin = cls; |
@@ -1027,24 +1195,21 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, | |||
1027 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | 1195 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
1028 | "datastore-sqlite", | 1196 | "datastore-sqlite", |
1029 | "Getting random block based on replication order.\n"); | 1197 | "Getting random block based on replication order.\n"); |
1030 | rc.have_uid = GNUNET_NO; | 1198 | if (SQLITE_ROW != |
1031 | rc.proc = proc; | 1199 | sqlite3_step (plugin->maxRepl)) |
1032 | rc.proc_cls = proc_cls; | ||
1033 | if (SQLITE_ROW != sqlite3_step (plugin->maxRepl)) | ||
1034 | { | 1200 | { |
1035 | if (SQLITE_OK != sqlite3_reset (plugin->maxRepl)) | 1201 | GNUNET_SQ_reset (plugin->dbh, |
1036 | LOG_SQLITE (plugin, | 1202 | plugin->maxRepl); |
1037 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1038 | "sqlite3_reset"); | ||
1039 | /* DB empty */ | 1203 | /* DB empty */ |
1040 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1204 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
1041 | return; | 1205 | return; |
1042 | } | 1206 | } |
1043 | repl = sqlite3_column_int (plugin->maxRepl, 0); | 1207 | repl = sqlite3_column_int (plugin->maxRepl, |
1044 | if (SQLITE_OK != sqlite3_reset (plugin->maxRepl)) | 1208 | 0); |
1045 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1209 | GNUNET_SQ_reset (plugin->dbh, |
1046 | "sqlite3_reset"); | 1210 | plugin->maxRepl); |
1047 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); | 1211 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, |
1212 | UINT64_MAX); | ||
1048 | if (GNUNET_OK != | 1213 | if (GNUNET_OK != |
1049 | GNUNET_SQ_bind (plugin->selRepl, | 1214 | GNUNET_SQ_bind (plugin->selRepl, |
1050 | params_sel_repl)) | 1215 | params_sel_repl)) |
@@ -1052,7 +1217,13 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, | |||
1052 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1217 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
1053 | return; | 1218 | return; |
1054 | } | 1219 | } |
1055 | execute_get (plugin, plugin->selRepl, &repl_proc, &rc); | 1220 | rc.have_uid = GNUNET_SYSERR; |
1221 | rc.proc = proc; | ||
1222 | rc.proc_cls = proc_cls; | ||
1223 | execute_get (plugin, | ||
1224 | plugin->selRepl, | ||
1225 | &repl_proc, | ||
1226 | &rc); | ||
1056 | if (GNUNET_YES == rc.have_uid) | 1227 | if (GNUNET_YES == rc.have_uid) |
1057 | { | 1228 | { |
1058 | if (GNUNET_OK != | 1229 | if (GNUNET_OK != |
@@ -1062,14 +1233,18 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, | |||
1062 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 1233 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
1063 | return; | 1234 | return; |
1064 | } | 1235 | } |
1065 | if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) | 1236 | if (SQLITE_DONE != |
1237 | sqlite3_step (plugin->updRepl)) | ||
1066 | LOG_SQLITE (plugin, | 1238 | LOG_SQLITE (plugin, |
1067 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1239 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
1068 | "sqlite3_step"); | 1240 | "sqlite3_step"); |
1069 | if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) | 1241 | GNUNET_SQ_reset (plugin->dbh, |
1070 | LOG_SQLITE (plugin, | 1242 | plugin->updRepl); |
1071 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1243 | } |
1072 | "sqlite3_reset"); | 1244 | if (GNUNET_SYSERR == rc.have_uid) |
1245 | { | ||
1246 | /* proc was not called at all so far, do it now. */ | ||
1247 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
1073 | } | 1248 | } |
1074 | } | 1249 | } |
1075 | 1250 | ||
@@ -1094,7 +1269,8 @@ sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc, | |||
1094 | GNUNET_SQ_query_param_end | 1269 | GNUNET_SQ_query_param_end |
1095 | }; | 1270 | }; |
1096 | 1271 | ||
1097 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | 1272 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
1273 | "sqlite", | ||
1098 | "Getting random block based on expiration and priority order.\n"); | 1274 | "Getting random block based on expiration and priority order.\n"); |
1099 | now = GNUNET_TIME_absolute_get (); | 1275 | now = GNUNET_TIME_absolute_get (); |
1100 | stmt = plugin->selExpi; | 1276 | stmt = plugin->selExpi; |
@@ -1131,11 +1307,17 @@ sqlite_plugin_get_keys (void *cls, | |||
1131 | int ret; | 1307 | int ret; |
1132 | 1308 | ||
1133 | GNUNET_assert (NULL != proc); | 1309 | GNUNET_assert (NULL != proc); |
1134 | if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK) | 1310 | if (SQLITE_OK != |
1311 | sq_prepare (plugin->dbh, | ||
1312 | "SELECT hash FROM gn090", | ||
1313 | &stmt)) | ||
1135 | { | 1314 | { |
1136 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 1315 | LOG_SQLITE (plugin, |
1316 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1137 | "sqlite_prepare"); | 1317 | "sqlite_prepare"); |
1138 | proc (proc_cls, NULL, 0); | 1318 | proc (proc_cls, |
1319 | NULL, | ||
1320 | 0); | ||
1139 | return; | 1321 | return; |
1140 | } | 1322 | } |
1141 | while (SQLITE_ROW == (ret = sqlite3_step (stmt))) | 1323 | while (SQLITE_ROW == (ret = sqlite3_step (stmt))) |
@@ -1143,14 +1325,20 @@ sqlite_plugin_get_keys (void *cls, | |||
1143 | if (GNUNET_OK == | 1325 | if (GNUNET_OK == |
1144 | GNUNET_SQ_extract_result (stmt, | 1326 | GNUNET_SQ_extract_result (stmt, |
1145 | results)) | 1327 | results)) |
1146 | proc (proc_cls, &key, 1); | 1328 | proc (proc_cls, |
1329 | &key, | ||
1330 | 1); | ||
1147 | else | 1331 | else |
1148 | GNUNET_break (0); | 1332 | GNUNET_break (0); |
1149 | } | 1333 | } |
1150 | if (SQLITE_DONE != ret) | 1334 | if (SQLITE_DONE != ret) |
1151 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); | 1335 | LOG_SQLITE (plugin, |
1336 | GNUNET_ERROR_TYPE_ERROR, | ||
1337 | "sqlite_step"); | ||
1152 | sqlite3_finalize (stmt); | 1338 | sqlite3_finalize (stmt); |
1153 | proc (proc_cls, NULL, 0); | 1339 | proc (proc_cls, |
1340 | NULL, | ||
1341 | 0); | ||
1154 | } | 1342 | } |
1155 | 1343 | ||
1156 | 1344 | ||
@@ -1176,7 +1364,8 @@ sqlite_plugin_drop (void *cls) | |||
1176 | * @return the size of the database on disk (estimate) | 1364 | * @return the size of the database on disk (estimate) |
1177 | */ | 1365 | */ |
1178 | static void | 1366 | static void |
1179 | sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate) | 1367 | sqlite_plugin_estimate_size (void *cls, |
1368 | unsigned long long *estimate) | ||
1180 | { | 1369 | { |
1181 | struct Plugin *plugin = cls; | 1370 | struct Plugin *plugin = cls; |
1182 | sqlite3_stmt *stmt; | 1371 | sqlite3_stmt *stmt; |
@@ -1191,29 +1380,45 @@ sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate) | |||
1191 | return; | 1380 | return; |
1192 | if (SQLITE_VERSION_NUMBER < 3006000) | 1381 | if (SQLITE_VERSION_NUMBER < 3006000) |
1193 | { | 1382 | { |
1194 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite", | 1383 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, |
1195 | _ | 1384 | "datastore-sqlite", |
1196 | ("sqlite version to old to determine size, assuming zero\n")); | 1385 | _("sqlite version to old to determine size, assuming zero\n")); |
1197 | *estimate = 0; | 1386 | *estimate = 0; |
1198 | return; | 1387 | return; |
1199 | } | 1388 | } |
1200 | CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL)); | ||
1201 | CHECK (SQLITE_OK == | 1389 | CHECK (SQLITE_OK == |
1202 | sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, | 1390 | sqlite3_exec (plugin->dbh, |
1391 | "VACUUM", | ||
1392 | NULL, | ||
1393 | NULL, | ||
1394 | ENULL)); | ||
1395 | CHECK (SQLITE_OK == | ||
1396 | sqlite3_exec (plugin->dbh, | ||
1397 | "PRAGMA auto_vacuum=INCREMENTAL", | ||
1398 | NULL, | ||
1203 | NULL, ENULL)); | 1399 | NULL, ENULL)); |
1204 | CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt)); | 1400 | CHECK (SQLITE_OK == |
1401 | sq_prepare (plugin->dbh, | ||
1402 | "PRAGMA page_count", | ||
1403 | &stmt)); | ||
1205 | if (SQLITE_ROW == sqlite3_step (stmt)) | 1404 | if (SQLITE_ROW == sqlite3_step (stmt)) |
1206 | pages = sqlite3_column_int64 (stmt, 0); | 1405 | pages = sqlite3_column_int64 (stmt, |
1406 | 0); | ||
1207 | else | 1407 | else |
1208 | pages = 0; | 1408 | pages = 0; |
1209 | sqlite3_finalize (stmt); | 1409 | sqlite3_finalize (stmt); |
1210 | CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt)); | 1410 | CHECK (SQLITE_OK == |
1211 | CHECK (SQLITE_ROW == sqlite3_step (stmt)); | 1411 | sq_prepare (plugin->dbh, |
1412 | "PRAGMA page_size", | ||
1413 | &stmt)); | ||
1414 | CHECK (SQLITE_ROW == | ||
1415 | sqlite3_step (stmt)); | ||
1212 | page_size = sqlite3_column_int64 (stmt, 0); | 1416 | page_size = sqlite3_column_int64 (stmt, 0); |
1213 | sqlite3_finalize (stmt); | 1417 | sqlite3_finalize (stmt); |
1214 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1418 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1215 | _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), | 1419 | _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), |
1216 | (unsigned long long) pages, (unsigned long long) page_size); | 1420 | (unsigned long long) pages, |
1421 | (unsigned long long) page_size); | ||
1217 | *estimate = pages * page_size; | 1422 | *estimate = pages * page_size; |
1218 | } | 1423 | } |
1219 | 1424 | ||
@@ -1231,9 +1436,11 @@ libgnunet_plugin_datastore_sqlite_init (void *cls) | |||
1231 | struct GNUNET_DATASTORE_PluginEnvironment *env = cls; | 1436 | struct GNUNET_DATASTORE_PluginEnvironment *env = cls; |
1232 | struct GNUNET_DATASTORE_PluginFunctions *api; | 1437 | struct GNUNET_DATASTORE_PluginFunctions *api; |
1233 | 1438 | ||
1234 | if (plugin.env != NULL) | 1439 | if (NULL != plugin.env) |
1235 | return NULL; /* can only initialize once! */ | 1440 | return NULL; /* can only initialize once! */ |
1236 | memset (&plugin, 0, sizeof (struct Plugin)); | 1441 | memset (&plugin, |
1442 | 0, | ||
1443 | sizeof (struct Plugin)); | ||
1237 | plugin.env = env; | 1444 | plugin.env = env; |
1238 | if (GNUNET_OK != database_setup (env->cfg, &plugin)) | 1445 | if (GNUNET_OK != database_setup (env->cfg, &plugin)) |
1239 | { | 1446 | { |
@@ -1251,7 +1458,8 @@ libgnunet_plugin_datastore_sqlite_init (void *cls) | |||
1251 | api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; | 1458 | api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; |
1252 | api->get_keys = &sqlite_plugin_get_keys; | 1459 | api->get_keys = &sqlite_plugin_get_keys; |
1253 | api->drop = &sqlite_plugin_drop; | 1460 | api->drop = &sqlite_plugin_drop; |
1254 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", | 1461 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, |
1462 | "sqlite", | ||
1255 | _("Sqlite database running\n")); | 1463 | _("Sqlite database running\n")); |
1256 | return api; | 1464 | return api; |
1257 | } | 1465 | } |
@@ -1270,13 +1478,12 @@ libgnunet_plugin_datastore_sqlite_done (void *cls) | |||
1270 | struct GNUNET_DATASTORE_PluginFunctions *api = cls; | 1478 | struct GNUNET_DATASTORE_PluginFunctions *api = cls; |
1271 | struct Plugin *plugin = api->cls; | 1479 | struct Plugin *plugin = api->cls; |
1272 | 1480 | ||
1273 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | 1481 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
1482 | "sqlite", | ||
1274 | "sqlite plugin is done\n"); | 1483 | "sqlite plugin is done\n"); |
1275 | fn = NULL; | 1484 | fn = NULL; |
1276 | if (plugin->drop_on_shutdown) | 1485 | if (plugin->drop_on_shutdown) |
1277 | fn = GNUNET_strdup (plugin->fn); | 1486 | fn = GNUNET_strdup (plugin->fn); |
1278 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", | ||
1279 | "Shutting down database\n"); | ||
1280 | database_shutdown (plugin); | 1487 | database_shutdown (plugin); |
1281 | plugin->env = NULL; | 1488 | plugin->env = NULL; |
1282 | GNUNET_free (api); | 1489 | GNUNET_free (api); |
@@ -1288,9 +1495,6 @@ libgnunet_plugin_datastore_sqlite_done (void *cls) | |||
1288 | fn); | 1495 | fn); |
1289 | GNUNET_free (fn); | 1496 | GNUNET_free (fn); |
1290 | } | 1497 | } |
1291 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
1292 | "sqlite", | ||
1293 | "sqlite plugin is finished\n"); | ||
1294 | return NULL; | 1498 | return NULL; |
1295 | } | 1499 | } |
1296 | 1500 | ||
diff --git a/src/include/gnunet_sq_lib.h b/src/include/gnunet_sq_lib.h index 4d2510ee5..c196d7767 100644 --- a/src/include/gnunet_sq_lib.h +++ b/src/include/gnunet_sq_lib.h | |||
@@ -194,6 +194,17 @@ GNUNET_SQ_bind (sqlite3_stmt *stmt, | |||
194 | 194 | ||
195 | 195 | ||
196 | /** | 196 | /** |
197 | * Reset @a stmt and log error. | ||
198 | * | ||
199 | * @param dbh database handle | ||
200 | * @param stmt statement to reset | ||
201 | */ | ||
202 | void | ||
203 | GNUNET_SQ_reset (sqlite3 *dbh, | ||
204 | sqlite3_stmt *stmt); | ||
205 | |||
206 | |||
207 | /** | ||
197 | * Extract data from a Postgres database @a result at row @a row. | 208 | * Extract data from a Postgres database @a result at row @a row. |
198 | * | 209 | * |
199 | * @param cls closure | 210 | * @param cls closure |
diff --git a/src/revocation/test_revocation.c b/src/revocation/test_revocation.c index d3bbb879a..8d5593694 100644 --- a/src/revocation/test_revocation.c +++ b/src/revocation/test_revocation.c | |||
@@ -104,8 +104,8 @@ revocation_remote_cb (void *cls, | |||
104 | 104 | ||
105 | if (GNUNET_NO == is_valid) | 105 | if (GNUNET_NO == is_valid) |
106 | { | 106 | { |
107 | fprintf (stderr, | 107 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
108 | "Local revocation successful\n"); | 108 | "Local revocation successful\n"); |
109 | ok = 0; | 109 | ok = 0; |
110 | GNUNET_SCHEDULER_shutdown (); | 110 | GNUNET_SCHEDULER_shutdown (); |
111 | return; | 111 | return; |
@@ -118,8 +118,8 @@ revocation_remote_cb (void *cls, | |||
118 | NULL); | 118 | NULL); |
119 | return; | 119 | return; |
120 | } | 120 | } |
121 | fprintf (stderr, | 121 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
122 | "Flooding of revocation failed\n"); | 122 | "Flooding of revocation failed\n"); |
123 | ok = 2; | 123 | ok = 2; |
124 | GNUNET_SCHEDULER_shutdown (); | 124 | GNUNET_SCHEDULER_shutdown (); |
125 | } | 125 | } |
@@ -141,8 +141,8 @@ revocation_cb (void *cls, | |||
141 | testpeers[1].revok_handle = NULL; | 141 | testpeers[1].revok_handle = NULL; |
142 | if (GNUNET_NO == is_valid) | 142 | if (GNUNET_NO == is_valid) |
143 | { | 143 | { |
144 | fprintf (stderr, | 144 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
145 | "Revocation successful\n"); | 145 | "Revocation successful\n"); |
146 | check_revocation (NULL); | 146 | check_revocation (NULL); |
147 | } | 147 | } |
148 | } | 148 | } |
@@ -386,8 +386,8 @@ test_connection (void *cls, | |||
386 | /* We are generating a CLIQUE */ | 386 | /* We are generating a CLIQUE */ |
387 | if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded) | 387 | if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded) |
388 | { | 388 | { |
389 | fprintf (stderr, | 389 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
390 | "Testbed connected peers, initializing test\n"); | 390 | "Testbed connected peers, initializing test\n"); |
391 | for (c = 0; c < num_peers; c++) | 391 | for (c = 0; c < num_peers; c++) |
392 | { | 392 | { |
393 | testpeers[c].p = peers[c]; | 393 | testpeers[c].p = peers[c]; |
@@ -403,8 +403,8 @@ test_connection (void *cls, | |||
403 | } | 403 | } |
404 | else | 404 | else |
405 | { | 405 | { |
406 | fprintf (stderr, | 406 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
407 | "Testbed failed to connect peers\n"); | 407 | "Testbed failed to connect peers\n"); |
408 | ok = 5; | 408 | ok = 5; |
409 | GNUNET_SCHEDULER_shutdown (); | 409 | GNUNET_SCHEDULER_shutdown (); |
410 | return; | 410 | return; |
diff --git a/src/set/Makefile.am b/src/set/Makefile.am index cfe95bc1a..03c258352 100644 --- a/src/set/Makefile.am +++ b/src/set/Makefile.am | |||
@@ -51,7 +51,7 @@ gnunet_set_ibf_profiler_LDADD = \ | |||
51 | 51 | ||
52 | gnunet_service_set_SOURCES = \ | 52 | gnunet_service_set_SOURCES = \ |
53 | gnunet-service-set.c gnunet-service-set.h \ | 53 | gnunet-service-set.c gnunet-service-set.h \ |
54 | gnunet-service-set_union.c \ | 54 | gnunet-service-set_union.c gnunet-service-set_union.h \ |
55 | gnunet-service-set_intersection.c \ | 55 | gnunet-service-set_intersection.c \ |
56 | ibf.c ibf.h \ | 56 | ibf.c ibf.h \ |
57 | gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \ | 57 | gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \ |
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c index 454ad9784..8f1506c6a 100644 --- a/src/set/gnunet-service-set.c +++ b/src/set/gnunet-service-set.c | |||
@@ -24,6 +24,8 @@ | |||
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | */ | 25 | */ |
26 | #include "gnunet-service-set.h" | 26 | #include "gnunet-service-set.h" |
27 | #include "gnunet-service-set_union.h" | ||
28 | #include "gnunet-service-set_intersection.h" | ||
27 | #include "gnunet-service-set_protocol.h" | 29 | #include "gnunet-service-set_protocol.h" |
28 | #include "gnunet_statistics_service.h" | 30 | #include "gnunet_statistics_service.h" |
29 | 31 | ||
@@ -476,6 +478,7 @@ _GSS_operation_destroy (struct Operation *op, | |||
476 | op->channel = NULL; | 478 | op->channel = NULL; |
477 | GNUNET_CADET_channel_destroy (channel); | 479 | GNUNET_CADET_channel_destroy (channel); |
478 | } | 480 | } |
481 | |||
479 | if (GNUNET_YES == gc) | 482 | if (GNUNET_YES == gc) |
480 | collect_generation_garbage (set); | 483 | collect_generation_garbage (set); |
481 | /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL, | 484 | /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL, |
@@ -682,7 +685,7 @@ client_disconnect_cb (void *cls, | |||
682 | { | 685 | { |
683 | struct Operation *curr = op; | 686 | struct Operation *curr = op; |
684 | op = op->next; | 687 | op = op->next; |
685 | if ( (GNUNET_YES == curr->is_incoming) && | 688 | if ( (GNUNET_YES == curr->is_incoming) && |
686 | (curr->listener == listener) ) | 689 | (curr->listener == listener) ) |
687 | incoming_destroy (curr); | 690 | incoming_destroy (curr); |
688 | } | 691 | } |
@@ -733,6 +736,38 @@ incoming_suggest (struct Operation *incoming, | |||
733 | 736 | ||
734 | 737 | ||
735 | /** | 738 | /** |
739 | * Check a request for a set operation from another peer. | ||
740 | * | ||
741 | * @param cls the operation state | ||
742 | * @param msg the received message | ||
743 | * @return #GNUNET_OK if the channel should be kept alive, | ||
744 | * #GNUNET_SYSERR to destroy the channel | ||
745 | */ | ||
746 | static int | ||
747 | check_incoming_msg (void *cls, | ||
748 | const struct OperationRequestMessage *msg) | ||
749 | { | ||
750 | struct Operation *op = cls; | ||
751 | const struct GNUNET_MessageHeader *nested_context; | ||
752 | |||
753 | /* double operation request */ | ||
754 | if (NULL != op->spec) | ||
755 | { | ||
756 | GNUNET_break_op (0); | ||
757 | return GNUNET_SYSERR; | ||
758 | } | ||
759 | nested_context = GNUNET_MQ_extract_nested_mh (msg); | ||
760 | if ( (NULL != nested_context) && | ||
761 | (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) ) | ||
762 | { | ||
763 | GNUNET_break_op (0); | ||
764 | return GNUNET_SYSERR; | ||
765 | } | ||
766 | return GNUNET_OK; | ||
767 | } | ||
768 | |||
769 | |||
770 | /** | ||
736 | * Handle a request for a set operation from another peer. Checks if we | 771 | * Handle a request for a set operation from another peer. Checks if we |
737 | * have a listener waiting for such a request (and in that case initiates | 772 | * have a listener waiting for such a request (and in that case initiates |
738 | * asking the listener about accepting the connection). If no listener | 773 | * asking the listener about accepting the connection). If no listener |
@@ -744,42 +779,23 @@ incoming_suggest (struct Operation *incoming, | |||
744 | * our virtual table and subsequent msgs would be routed differently (as | 779 | * our virtual table and subsequent msgs would be routed differently (as |
745 | * we then know what type of operation this is). | 780 | * we then know what type of operation this is). |
746 | * | 781 | * |
747 | * @param op the operation state | 782 | * @param cls the operation state |
748 | * @param mh the received message | 783 | * @param msg the received message |
749 | * @return #GNUNET_OK if the channel should be kept alive, | 784 | * @return #GNUNET_OK if the channel should be kept alive, |
750 | * #GNUNET_SYSERR to destroy the channel | 785 | * #GNUNET_SYSERR to destroy the channel |
751 | */ | 786 | */ |
752 | static int | 787 | static void |
753 | handle_incoming_msg (struct Operation *op, | 788 | handle_incoming_msg (void *cls, |
754 | const struct GNUNET_MessageHeader *mh) | 789 | const struct OperationRequestMessage *msg) |
755 | { | 790 | { |
756 | const struct OperationRequestMessage *msg; | 791 | struct Operation *op = cls; |
757 | struct Listener *listener = op->listener; | 792 | struct Listener *listener = op->listener; |
758 | struct OperationSpecification *spec; | 793 | struct OperationSpecification *spec; |
759 | const struct GNUNET_MessageHeader *nested_context; | 794 | const struct GNUNET_MessageHeader *nested_context; |
760 | 795 | ||
761 | msg = (const struct OperationRequestMessage *) mh; | ||
762 | GNUNET_assert (GNUNET_YES == op->is_incoming); | 796 | GNUNET_assert (GNUNET_YES == op->is_incoming); |
763 | if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type)) | ||
764 | { | ||
765 | GNUNET_break_op (0); | ||
766 | return GNUNET_SYSERR; | ||
767 | } | ||
768 | /* double operation request */ | ||
769 | if (NULL != op->spec) | ||
770 | { | ||
771 | GNUNET_break_op (0); | ||
772 | return GNUNET_SYSERR; | ||
773 | } | ||
774 | spec = GNUNET_new (struct OperationSpecification); | 797 | spec = GNUNET_new (struct OperationSpecification); |
775 | nested_context = GNUNET_MQ_extract_nested_mh (msg); | 798 | nested_context = GNUNET_MQ_extract_nested_mh (msg); |
776 | if ( (NULL != nested_context) && | ||
777 | (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) ) | ||
778 | { | ||
779 | GNUNET_break_op (0); | ||
780 | GNUNET_free (spec); | ||
781 | return GNUNET_SYSERR; | ||
782 | } | ||
783 | /* Make a copy of the nested_context (application-specific context | 799 | /* Make a copy of the nested_context (application-specific context |
784 | information that is opaque to set) so we can pass it to the | 800 | information that is opaque to set) so we can pass it to the |
785 | listener later on */ | 801 | listener later on */ |
@@ -792,7 +808,6 @@ handle_incoming_msg (struct Operation *op, | |||
792 | spec->peer = op->peer; | 808 | spec->peer = op->peer; |
793 | spec->remote_element_count = ntohl (msg->element_count); | 809 | spec->remote_element_count = ntohl (msg->element_count); |
794 | op->spec = spec; | 810 | op->spec = spec; |
795 | |||
796 | listener = op->listener; | 811 | listener = op->listener; |
797 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 812 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
798 | "Received P2P operation request (op %u, port %s) for active listener\n", | 813 | "Received P2P operation request (op %u, port %s) for active listener\n", |
@@ -800,7 +815,6 @@ handle_incoming_msg (struct Operation *op, | |||
800 | GNUNET_h2s (&listener->app_id)); | 815 | GNUNET_h2s (&listener->app_id)); |
801 | incoming_suggest (op, | 816 | incoming_suggest (op, |
802 | listener); | 817 | listener); |
803 | return GNUNET_OK; | ||
804 | } | 818 | } |
805 | 819 | ||
806 | 820 | ||
@@ -1103,9 +1117,11 @@ handle_client_create_set (void *cls, | |||
1103 | { | 1117 | { |
1104 | case GNUNET_SET_OPERATION_INTERSECTION: | 1118 | case GNUNET_SET_OPERATION_INTERSECTION: |
1105 | set->vt = _GSS_intersection_vt (); | 1119 | set->vt = _GSS_intersection_vt (); |
1120 | set->type = OT_INTERSECTION; | ||
1106 | break; | 1121 | break; |
1107 | case GNUNET_SET_OPERATION_UNION: | 1122 | case GNUNET_SET_OPERATION_UNION: |
1108 | set->vt = _GSS_union_vt (); | 1123 | set->vt = _GSS_union_vt (); |
1124 | set->type = OT_UNION; | ||
1109 | break; | 1125 | break; |
1110 | default: | 1126 | default: |
1111 | GNUNET_free (set); | 1127 | GNUNET_free (set); |
@@ -1196,7 +1212,6 @@ channel_new_cb (void *cls, | |||
1196 | const struct GNUNET_PeerIdentity *source) | 1212 | const struct GNUNET_PeerIdentity *source) |
1197 | { | 1213 | { |
1198 | static const struct SetVT incoming_vt = { | 1214 | static const struct SetVT incoming_vt = { |
1199 | .msg_handler = &handle_incoming_msg, | ||
1200 | .peer_disconnect = &handle_incoming_disconnect | 1215 | .peer_disconnect = &handle_incoming_disconnect |
1201 | }; | 1216 | }; |
1202 | struct Listener *listener = cls; | 1217 | struct Listener *listener = cls; |
@@ -1290,60 +1305,6 @@ channel_window_cb (void *cls, | |||
1290 | /* FIXME: not implemented, we could do flow control here... */ | 1305 | /* FIXME: not implemented, we could do flow control here... */ |
1291 | } | 1306 | } |
1292 | 1307 | ||
1293 | /** | ||
1294 | * FIXME: hack-job. Migrate to proper handler array use! | ||
1295 | * | ||
1296 | * @param cls local state associated with the channel. | ||
1297 | * @param message The actual message. | ||
1298 | */ | ||
1299 | static int | ||
1300 | check_p2p_message (void *cls, | ||
1301 | const struct GNUNET_MessageHeader *message) | ||
1302 | { | ||
1303 | return GNUNET_OK; | ||
1304 | } | ||
1305 | |||
1306 | |||
1307 | /** | ||
1308 | * FIXME: hack-job. Migrate to proper handler array use! | ||
1309 | * | ||
1310 | * Functions with this signature are called whenever a message is | ||
1311 | * received via a cadet channel. | ||
1312 | * | ||
1313 | * The msg_handler is a virtual table set in initially either when a peer | ||
1314 | * creates a new channel with us, or once we create a new channel | ||
1315 | * ourselves (evaluate). | ||
1316 | * | ||
1317 | * Once we know the exact type of operation (union/intersection), the vt is | ||
1318 | * replaced with an operation specific instance (_GSS_[op]_vt). | ||
1319 | * | ||
1320 | * @param cls local state associated with the channel. | ||
1321 | * @param message The actual message. | ||
1322 | */ | ||
1323 | static void | ||
1324 | handle_p2p_message (void *cls, | ||
1325 | const struct GNUNET_MessageHeader *message) | ||
1326 | { | ||
1327 | struct Operation *op = cls; | ||
1328 | int ret; | ||
1329 | |||
1330 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1331 | "Dispatching cadet message (type: %u)\n", | ||
1332 | ntohs (message->type)); | ||
1333 | /* do this before the handler, as the handler might kill the channel */ | ||
1334 | GNUNET_CADET_receive_done (op->channel); | ||
1335 | if (NULL != op->vt) | ||
1336 | ret = op->vt->msg_handler (op, | ||
1337 | message); | ||
1338 | else | ||
1339 | ret = GNUNET_SYSERR; | ||
1340 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1341 | "Handled cadet message (type: %u)\n", | ||
1342 | ntohs (message->type)); | ||
1343 | if (GNUNET_OK != ret) | ||
1344 | GNUNET_CADET_channel_destroy (op->channel); | ||
1345 | } | ||
1346 | |||
1347 | 1308 | ||
1348 | /** | 1309 | /** |
1349 | * Called when a client wants to create a new listener. | 1310 | * Called when a client wants to create a new listener. |
@@ -1357,66 +1318,66 @@ handle_client_listen (void *cls, | |||
1357 | { | 1318 | { |
1358 | struct GNUNET_SERVICE_Client *client = cls; | 1319 | struct GNUNET_SERVICE_Client *client = cls; |
1359 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | 1320 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { |
1360 | GNUNET_MQ_hd_var_size (p2p_message, | 1321 | GNUNET_MQ_hd_var_size (incoming_msg, |
1361 | GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, | 1322 | GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, |
1362 | struct GNUNET_MessageHeader, | 1323 | struct OperationRequestMessage, |
1363 | NULL), | 1324 | NULL), |
1364 | GNUNET_MQ_hd_var_size (p2p_message, | 1325 | GNUNET_MQ_hd_var_size (union_p2p_ibf, |
1365 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, | 1326 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, |
1366 | struct GNUNET_MessageHeader, | 1327 | struct IBFMessage, |
1367 | NULL), | 1328 | NULL), |
1368 | GNUNET_MQ_hd_var_size (p2p_message, | 1329 | GNUNET_MQ_hd_var_size (union_p2p_elements, |
1369 | GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, | 1330 | GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, |
1370 | struct GNUNET_MessageHeader, | 1331 | struct GNUNET_SET_ElementMessage, |
1371 | NULL), | 1332 | NULL), |
1372 | GNUNET_MQ_hd_var_size (p2p_message, | 1333 | GNUNET_MQ_hd_var_size (union_p2p_offer, |
1373 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, | 1334 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, |
1374 | struct GNUNET_MessageHeader, | 1335 | struct GNUNET_MessageHeader, |
1375 | NULL), | 1336 | NULL), |
1376 | GNUNET_MQ_hd_var_size (p2p_message, | 1337 | GNUNET_MQ_hd_var_size (union_p2p_inquiry, |
1377 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, | 1338 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, |
1378 | struct GNUNET_MessageHeader, | 1339 | struct InquiryMessage, |
1379 | NULL), | 1340 | NULL), |
1380 | GNUNET_MQ_hd_var_size (p2p_message, | 1341 | GNUNET_MQ_hd_var_size (union_p2p_demand, |
1381 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, | 1342 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, |
1382 | struct GNUNET_MessageHeader, | 1343 | struct GNUNET_MessageHeader, |
1383 | NULL), | 1344 | NULL), |
1384 | GNUNET_MQ_hd_var_size (p2p_message, | 1345 | GNUNET_MQ_hd_fixed_size (union_p2p_done, |
1385 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, | 1346 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, |
1386 | struct GNUNET_MessageHeader, | 1347 | struct GNUNET_MessageHeader, |
1387 | NULL), | 1348 | NULL), |
1388 | GNUNET_MQ_hd_var_size (p2p_message, | 1349 | GNUNET_MQ_hd_fixed_size (union_p2p_full_done, |
1389 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, | 1350 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, |
1390 | struct GNUNET_MessageHeader, | 1351 | struct GNUNET_MessageHeader, |
1391 | NULL), | 1352 | NULL), |
1392 | GNUNET_MQ_hd_var_size (p2p_message, | 1353 | GNUNET_MQ_hd_fixed_size (union_p2p_request_full, |
1393 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL, | 1354 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL, |
1394 | struct GNUNET_MessageHeader, | 1355 | struct GNUNET_MessageHeader, |
1395 | NULL), | 1356 | NULL), |
1396 | GNUNET_MQ_hd_var_size (p2p_message, | 1357 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, |
1397 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, | 1358 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, |
1398 | struct GNUNET_MessageHeader, | 1359 | struct StrataEstimatorMessage, |
1399 | NULL), | 1360 | NULL), |
1400 | GNUNET_MQ_hd_var_size (p2p_message, | 1361 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, |
1401 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, | 1362 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, |
1402 | struct GNUNET_MessageHeader, | 1363 | struct StrataEstimatorMessage, |
1403 | NULL), | 1364 | NULL), |
1404 | GNUNET_MQ_hd_var_size (p2p_message, | 1365 | GNUNET_MQ_hd_var_size (union_p2p_full_element, |
1405 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, | 1366 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, |
1406 | struct GNUNET_MessageHeader, | 1367 | struct GNUNET_SET_ElementMessage, |
1407 | NULL), | 1368 | NULL), |
1408 | GNUNET_MQ_hd_var_size (p2p_message, | 1369 | GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info, |
1409 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, | 1370 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, |
1410 | struct GNUNET_MessageHeader, | 1371 | struct IntersectionElementInfoMessage, |
1411 | NULL), | 1372 | NULL), |
1412 | GNUNET_MQ_hd_var_size (p2p_message, | 1373 | GNUNET_MQ_hd_var_size (intersection_p2p_bf, |
1413 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, | 1374 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, |
1414 | struct GNUNET_MessageHeader, | 1375 | struct BFMessage, |
1415 | NULL), | ||
1416 | GNUNET_MQ_hd_var_size (p2p_message, | ||
1417 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, | ||
1418 | struct GNUNET_MessageHeader, | ||
1419 | NULL), | 1376 | NULL), |
1377 | GNUNET_MQ_hd_fixed_size (intersection_p2p_done, | ||
1378 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, | ||
1379 | struct IntersectionDoneMessage, | ||
1380 | NULL), | ||
1420 | GNUNET_MQ_handler_end () | 1381 | GNUNET_MQ_handler_end () |
1421 | }; | 1382 | }; |
1422 | struct Listener *listener; | 1383 | struct Listener *listener; |
@@ -1623,66 +1584,66 @@ handle_client_evaluate (void *cls, | |||
1623 | struct GNUNET_SERVICE_Client *client = cls; | 1584 | struct GNUNET_SERVICE_Client *client = cls; |
1624 | struct Operation *op = GNUNET_new (struct Operation); | 1585 | struct Operation *op = GNUNET_new (struct Operation); |
1625 | const struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | 1586 | const struct GNUNET_MQ_MessageHandler cadet_handlers[] = { |
1626 | GNUNET_MQ_hd_var_size (p2p_message, | 1587 | GNUNET_MQ_hd_var_size (incoming_msg, |
1627 | GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, | 1588 | GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, |
1628 | struct GNUNET_MessageHeader, | 1589 | struct OperationRequestMessage, |
1629 | op), | 1590 | op), |
1630 | GNUNET_MQ_hd_var_size (p2p_message, | 1591 | GNUNET_MQ_hd_var_size (union_p2p_ibf, |
1631 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, | 1592 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, |
1632 | struct GNUNET_MessageHeader, | 1593 | struct IBFMessage, |
1633 | op), | 1594 | op), |
1634 | GNUNET_MQ_hd_var_size (p2p_message, | 1595 | GNUNET_MQ_hd_var_size (union_p2p_elements, |
1635 | GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, | 1596 | GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, |
1636 | struct GNUNET_MessageHeader, | 1597 | struct GNUNET_SET_ElementMessage, |
1637 | op), | 1598 | op), |
1638 | GNUNET_MQ_hd_var_size (p2p_message, | 1599 | GNUNET_MQ_hd_var_size (union_p2p_offer, |
1639 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, | 1600 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, |
1640 | struct GNUNET_MessageHeader, | 1601 | struct GNUNET_MessageHeader, |
1641 | op), | 1602 | op), |
1642 | GNUNET_MQ_hd_var_size (p2p_message, | 1603 | GNUNET_MQ_hd_var_size (union_p2p_inquiry, |
1643 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, | 1604 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, |
1644 | struct GNUNET_MessageHeader, | 1605 | struct InquiryMessage, |
1645 | op), | 1606 | op), |
1646 | GNUNET_MQ_hd_var_size (p2p_message, | 1607 | GNUNET_MQ_hd_var_size (union_p2p_demand, |
1647 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, | 1608 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, |
1648 | struct GNUNET_MessageHeader, | 1609 | struct GNUNET_MessageHeader, |
1649 | op), | 1610 | op), |
1650 | GNUNET_MQ_hd_var_size (p2p_message, | 1611 | GNUNET_MQ_hd_fixed_size (union_p2p_done, |
1651 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, | 1612 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, |
1652 | struct GNUNET_MessageHeader, | 1613 | struct GNUNET_MessageHeader, |
1653 | op), | 1614 | op), |
1654 | GNUNET_MQ_hd_var_size (p2p_message, | 1615 | GNUNET_MQ_hd_fixed_size (union_p2p_full_done, |
1616 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, | ||
1617 | struct GNUNET_MessageHeader, | ||
1618 | op), | ||
1619 | GNUNET_MQ_hd_fixed_size (union_p2p_request_full, | ||
1620 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL, | ||
1621 | struct GNUNET_MessageHeader, | ||
1622 | op), | ||
1623 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, | ||
1655 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, | 1624 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, |
1656 | struct GNUNET_MessageHeader, | 1625 | struct StrataEstimatorMessage, |
1657 | op), | 1626 | op), |
1658 | GNUNET_MQ_hd_var_size (p2p_message, | 1627 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, |
1659 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, | 1628 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, |
1660 | struct GNUNET_MessageHeader, | 1629 | struct StrataEstimatorMessage, |
1661 | op), | ||
1662 | GNUNET_MQ_hd_var_size (p2p_message, | ||
1663 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, | ||
1664 | struct GNUNET_MessageHeader, | ||
1665 | op), | ||
1666 | GNUNET_MQ_hd_var_size (p2p_message, | ||
1667 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL, | ||
1668 | struct GNUNET_MessageHeader, | ||
1669 | op), | 1630 | op), |
1670 | GNUNET_MQ_hd_var_size (p2p_message, | 1631 | GNUNET_MQ_hd_var_size (union_p2p_full_element, |
1671 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, | 1632 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, |
1672 | struct GNUNET_MessageHeader, | 1633 | struct GNUNET_SET_ElementMessage, |
1673 | op), | ||
1674 | GNUNET_MQ_hd_var_size (p2p_message, | ||
1675 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, | ||
1676 | struct GNUNET_MessageHeader, | ||
1677 | op), | 1634 | op), |
1678 | GNUNET_MQ_hd_var_size (p2p_message, | 1635 | GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info, |
1636 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, | ||
1637 | struct IntersectionElementInfoMessage, | ||
1638 | op), | ||
1639 | GNUNET_MQ_hd_var_size (intersection_p2p_bf, | ||
1679 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, | 1640 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, |
1680 | struct GNUNET_MessageHeader, | 1641 | struct BFMessage, |
1681 | op), | ||
1682 | GNUNET_MQ_hd_var_size (p2p_message, | ||
1683 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, | ||
1684 | struct GNUNET_MessageHeader, | ||
1685 | op), | 1642 | op), |
1643 | GNUNET_MQ_hd_fixed_size (intersection_p2p_done, | ||
1644 | GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, | ||
1645 | struct IntersectionDoneMessage, | ||
1646 | op), | ||
1686 | GNUNET_MQ_handler_end () | 1647 | GNUNET_MQ_handler_end () |
1687 | }; | 1648 | }; |
1688 | struct Set *set; | 1649 | struct Set *set; |
@@ -1717,7 +1678,7 @@ handle_client_evaluate (void *cls, | |||
1717 | // mutations won't interfer with the running operation. | 1678 | // mutations won't interfer with the running operation. |
1718 | op->generation_created = set->current_generation; | 1679 | op->generation_created = set->current_generation; |
1719 | advance_generation (set); | 1680 | advance_generation (set); |
1720 | 1681 | op->type = set->type; | |
1721 | op->vt = set->vt; | 1682 | op->vt = set->vt; |
1722 | GNUNET_CONTAINER_DLL_insert (set->ops_head, | 1683 | GNUNET_CONTAINER_DLL_insert (set->ops_head, |
1723 | set->ops_tail, | 1684 | set->ops_tail, |
@@ -1886,9 +1847,11 @@ handle_client_copy_lazy_connect (void *cls, | |||
1886 | { | 1847 | { |
1887 | case GNUNET_SET_OPERATION_INTERSECTION: | 1848 | case GNUNET_SET_OPERATION_INTERSECTION: |
1888 | set->vt = _GSS_intersection_vt (); | 1849 | set->vt = _GSS_intersection_vt (); |
1850 | set->type = OT_INTERSECTION; | ||
1889 | break; | 1851 | break; |
1890 | case GNUNET_SET_OPERATION_UNION: | 1852 | case GNUNET_SET_OPERATION_UNION: |
1891 | set->vt = _GSS_union_vt (); | 1853 | set->vt = _GSS_union_vt (); |
1854 | set->type = OT_UNION; | ||
1892 | break; | 1855 | break; |
1893 | default: | 1856 | default: |
1894 | GNUNET_assert (0); | 1857 | GNUNET_assert (0); |
@@ -2057,6 +2020,7 @@ handle_client_accept (void *cls, | |||
2057 | advance_generation (set); | 2020 | advance_generation (set); |
2058 | 2021 | ||
2059 | op->vt = set->vt; | 2022 | op->vt = set->vt; |
2023 | op->type = set->type; | ||
2060 | op->vt->accept (op); | 2024 | op->vt->accept (op); |
2061 | GNUNET_SERVICE_client_continue (client); | 2025 | GNUNET_SERVICE_client_continue (client); |
2062 | } | 2026 | } |
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h index 68d8fe81f..c981430ef 100644 --- a/src/set/gnunet-service-set.h +++ b/src/set/gnunet-service-set.h | |||
@@ -213,20 +213,6 @@ typedef void | |||
213 | 213 | ||
214 | 214 | ||
215 | /** | 215 | /** |
216 | * Signature of functions that implement the message handling for | ||
217 | * the different set operations. | ||
218 | * | ||
219 | * @param op operation state | ||
220 | * @param msg received message | ||
221 | * @return #GNUNET_OK on success, #GNUNET_SYSERR to | ||
222 | * destroy the operation and the tunnel | ||
223 | */ | ||
224 | typedef int | ||
225 | (*MsgHandlerImpl) (struct Operation *op, | ||
226 | const struct GNUNET_MessageHeader *msg); | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Signature of functions that implement operation cancellation | 216 | * Signature of functions that implement operation cancellation |
231 | * | 217 | * |
232 | * @param op operation state | 218 | * @param op operation state |
@@ -276,11 +262,6 @@ struct SetVT | |||
276 | DestroySetImpl destroy_set; | 262 | DestroySetImpl destroy_set; |
277 | 263 | ||
278 | /** | 264 | /** |
279 | * Callback for handling operation-specific messages. | ||
280 | */ | ||
281 | MsgHandlerImpl msg_handler; | ||
282 | |||
283 | /** | ||
284 | * Callback for handling the remote peer's disconnect. | 265 | * Callback for handling the remote peer's disconnect. |
285 | */ | 266 | */ |
286 | PeerDisconnectImpl peer_disconnect; | 267 | PeerDisconnectImpl peer_disconnect; |
@@ -364,6 +345,27 @@ struct Listener; | |||
364 | 345 | ||
365 | 346 | ||
366 | /** | 347 | /** |
348 | * Possible set operations. | ||
349 | */ | ||
350 | enum OperationType { | ||
351 | /** | ||
352 | * Operation type unknown. | ||
353 | */ | ||
354 | OT_UNKNOWN = 0, | ||
355 | |||
356 | /** | ||
357 | * We are performing a union. | ||
358 | */ | ||
359 | OT_UNION, | ||
360 | |||
361 | /** | ||
362 | * We are performing an intersection. | ||
363 | */ | ||
364 | OT_INTERSECTION | ||
365 | }; | ||
366 | |||
367 | |||
368 | /** | ||
367 | * Operation context used to execute a set operation. | 369 | * Operation context used to execute a set operation. |
368 | */ | 370 | */ |
369 | struct Operation | 371 | struct Operation |
@@ -427,6 +429,11 @@ struct Operation | |||
427 | struct GNUNET_SCHEDULER_Task *timeout_task; | 429 | struct GNUNET_SCHEDULER_Task *timeout_task; |
428 | 430 | ||
429 | /** | 431 | /** |
432 | * What type of operation is this? | ||
433 | */ | ||
434 | enum OperationType type; | ||
435 | |||
436 | /** | ||
430 | * Unique request id for the request from a remote peer, sent to the | 437 | * Unique request id for the request from a remote peer, sent to the |
431 | * client, which will accept or reject the request. Set to '0' iff | 438 | * client, which will accept or reject the request. Set to '0' iff |
432 | * the request has not been suggested yet. | 439 | * the request has not been suggested yet. |
@@ -582,6 +589,11 @@ struct Set | |||
582 | struct Operation *ops_tail; | 589 | struct Operation *ops_tail; |
583 | 590 | ||
584 | /** | 591 | /** |
592 | * What type of operation is this set for? | ||
593 | */ | ||
594 | enum OperationType type; | ||
595 | |||
596 | /** | ||
585 | * Current generation, that is, number of previously executed | 597 | * Current generation, that is, number of previously executed |
586 | * operations and lazy copies on the underlying set content. | 598 | * operations and lazy copies on the underlying set content. |
587 | */ | 599 | */ |
diff --git a/src/set/gnunet-service-set_intersection.c b/src/set/gnunet-service-set_intersection.c index 9fe1eabe6..b298f7b41 100644 --- a/src/set/gnunet-service-set_intersection.c +++ b/src/set/gnunet-service-set_intersection.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2013, 2014 GNUnet e.V. | 3 | Copyright (C) 2013-2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -28,6 +28,7 @@ | |||
28 | #include "gnunet-service-set.h" | 28 | #include "gnunet-service-set.h" |
29 | #include "gnunet_block_lib.h" | 29 | #include "gnunet_block_lib.h" |
30 | #include "gnunet-service-set_protocol.h" | 30 | #include "gnunet-service-set_protocol.h" |
31 | #include "gnunet-service-set_intersection.h" | ||
31 | #include <gcrypt.h> | 32 | #include <gcrypt.h> |
32 | 33 | ||
33 | 34 | ||
@@ -550,6 +551,8 @@ send_remaining_elements (void *cls) | |||
550 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
551 | "Sending done and destroy because iterator ran out\n"); | 552 | "Sending done and destroy because iterator ran out\n"); |
552 | op->keep--; | 553 | op->keep--; |
554 | GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter); | ||
555 | op->state->full_result_iter = NULL; | ||
553 | send_client_done_and_destroy (op); | 556 | send_client_done_and_destroy (op); |
554 | return; | 557 | return; |
555 | } | 558 | } |
@@ -627,9 +630,6 @@ process_bf (struct Operation *op) | |||
627 | case PHASE_COUNT_SENT: | 630 | case PHASE_COUNT_SENT: |
628 | /* This is the first BF being sent, build our initial map with | 631 | /* This is the first BF being sent, build our initial map with |
629 | filtering in place */ | 632 | filtering in place */ |
630 | op->state->my_elements | ||
631 | = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count, | ||
632 | GNUNET_YES); | ||
633 | op->state->my_element_count = 0; | 633 | op->state->my_element_count = 0; |
634 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, | 634 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, |
635 | &filtered_map_initialization, | 635 | &filtered_map_initialization, |
@@ -665,41 +665,53 @@ process_bf (struct Operation *op) | |||
665 | 665 | ||
666 | 666 | ||
667 | /** | 667 | /** |
668 | * Check an BF message from a remote peer. | ||
669 | * | ||
670 | * @param cls the intersection operation | ||
671 | * @param msg the header of the message | ||
672 | * @return #GNUNET_OK if @a msg is well-formed | ||
673 | */ | ||
674 | int | ||
675 | check_intersection_p2p_bf (void *cls, | ||
676 | const struct BFMessage *msg) | ||
677 | { | ||
678 | struct Operation *op = cls; | ||
679 | |||
680 | if (OT_INTERSECTION != op->type) | ||
681 | { | ||
682 | GNUNET_break_op (0); | ||
683 | return GNUNET_SYSERR; | ||
684 | } | ||
685 | return GNUNET_OK; | ||
686 | } | ||
687 | |||
688 | |||
689 | /** | ||
668 | * Handle an BF message from a remote peer. | 690 | * Handle an BF message from a remote peer. |
669 | * | 691 | * |
670 | * @param cls the intersection operation | 692 | * @param cls the intersection operation |
671 | * @param mh the header of the message | 693 | * @param msg the header of the message |
672 | */ | 694 | */ |
673 | static void | 695 | void |
674 | handle_p2p_bf (void *cls, | 696 | handle_intersection_p2p_bf (void *cls, |
675 | const struct GNUNET_MessageHeader *mh) | 697 | const struct BFMessage *msg) |
676 | { | 698 | { |
677 | struct Operation *op = cls; | 699 | struct Operation *op = cls; |
678 | const struct BFMessage *msg; | ||
679 | uint32_t bf_size; | 700 | uint32_t bf_size; |
680 | uint32_t chunk_size; | 701 | uint32_t chunk_size; |
681 | uint32_t bf_bits_per_element; | 702 | uint32_t bf_bits_per_element; |
682 | uint16_t msize; | ||
683 | 703 | ||
684 | msize = htons (mh->size); | ||
685 | if (msize < sizeof (struct BFMessage)) | ||
686 | { | ||
687 | GNUNET_break_op (0); | ||
688 | fail_intersection_operation (op); | ||
689 | return; | ||
690 | } | ||
691 | msg = (const struct BFMessage *) mh; | ||
692 | switch (op->state->phase) | 704 | switch (op->state->phase) |
693 | { | 705 | { |
694 | case PHASE_INITIAL: | 706 | case PHASE_INITIAL: |
695 | GNUNET_break_op (0); | 707 | GNUNET_break_op (0); |
696 | fail_intersection_operation (op); | 708 | fail_intersection_operation (op); |
697 | break; | 709 | return; |
698 | case PHASE_COUNT_SENT: | 710 | case PHASE_COUNT_SENT: |
699 | case PHASE_BF_EXCHANGE: | 711 | case PHASE_BF_EXCHANGE: |
700 | bf_size = ntohl (msg->bloomfilter_total_length); | 712 | bf_size = ntohl (msg->bloomfilter_total_length); |
701 | bf_bits_per_element = ntohl (msg->bits_per_element); | 713 | bf_bits_per_element = ntohl (msg->bits_per_element); |
702 | chunk_size = msize - sizeof (struct BFMessage); | 714 | chunk_size = htons (msg->header.size) - sizeof (struct BFMessage); |
703 | op->state->other_xor = msg->element_xor_hash; | 715 | op->state->other_xor = msg->element_xor_hash; |
704 | if (bf_size == chunk_size) | 716 | if (bf_size == chunk_size) |
705 | { | 717 | { |
@@ -717,7 +729,7 @@ handle_p2p_bf (void *cls, | |||
717 | op->state->salt = ntohl (msg->sender_mutator); | 729 | op->state->salt = ntohl (msg->sender_mutator); |
718 | op->spec->remote_element_count = ntohl (msg->sender_element_count); | 730 | op->spec->remote_element_count = ntohl (msg->sender_element_count); |
719 | process_bf (op); | 731 | process_bf (op); |
720 | return; | 732 | break; |
721 | } | 733 | } |
722 | /* multipart chunk */ | 734 | /* multipart chunk */ |
723 | if (NULL == op->state->bf_data) | 735 | if (NULL == op->state->bf_data) |
@@ -764,8 +776,9 @@ handle_p2p_bf (void *cls, | |||
764 | default: | 776 | default: |
765 | GNUNET_break_op (0); | 777 | GNUNET_break_op (0); |
766 | fail_intersection_operation (op); | 778 | fail_intersection_operation (op); |
767 | break; | 779 | return; |
768 | } | 780 | } |
781 | GNUNET_CADET_receive_done (op->channel); | ||
769 | } | 782 | } |
770 | 783 | ||
771 | 784 | ||
@@ -836,6 +849,7 @@ static void | |||
836 | begin_bf_exchange (struct Operation *op) | 849 | begin_bf_exchange (struct Operation *op) |
837 | { | 850 | { |
838 | op->state->phase = PHASE_BF_EXCHANGE; | 851 | op->state->phase = PHASE_BF_EXCHANGE; |
852 | GNUNET_assert (NULL == op->state->my_elements); | ||
839 | op->state->my_elements | 853 | op->state->my_elements |
840 | = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, | 854 | = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, |
841 | GNUNET_YES); | 855 | GNUNET_YES); |
@@ -853,20 +867,18 @@ begin_bf_exchange (struct Operation *op) | |||
853 | * @param cls the intersection operation | 867 | * @param cls the intersection operation |
854 | * @param mh the header of the message | 868 | * @param mh the header of the message |
855 | */ | 869 | */ |
856 | static void | 870 | void |
857 | handle_p2p_element_info (void *cls, | 871 | handle_intersection_p2p_element_info (void *cls, |
858 | const struct GNUNET_MessageHeader *mh) | 872 | const struct IntersectionElementInfoMessage *msg) |
859 | { | 873 | { |
860 | struct Operation *op = cls; | 874 | struct Operation *op = cls; |
861 | const struct IntersectionElementInfoMessage *msg; | ||
862 | 875 | ||
863 | if (ntohs (mh->size) != sizeof (struct IntersectionElementInfoMessage)) | 876 | if (OT_INTERSECTION != op->type) |
864 | { | 877 | { |
865 | GNUNET_break_op (0); | 878 | GNUNET_break_op (0); |
866 | fail_intersection_operation(op); | 879 | fail_intersection_operation(op); |
867 | return; | 880 | return; |
868 | } | 881 | } |
869 | msg = (const struct IntersectionElementInfoMessage *) mh; | ||
870 | op->spec->remote_element_count = ntohl (msg->sender_element_count); | 882 | op->spec->remote_element_count = ntohl (msg->sender_element_count); |
871 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 883 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
872 | "Received remote element count (%u), I have %u\n", | 884 | "Received remote element count (%u), I have %u\n", |
@@ -884,6 +896,7 @@ handle_p2p_element_info (void *cls, | |||
884 | } | 896 | } |
885 | GNUNET_break (NULL == op->state->remote_bf); | 897 | GNUNET_break (NULL == op->state->remote_bf); |
886 | begin_bf_exchange (op); | 898 | begin_bf_exchange (op); |
899 | GNUNET_CADET_receive_done (op->channel); | ||
887 | } | 900 | } |
888 | 901 | ||
889 | 902 | ||
@@ -955,28 +968,26 @@ filter_all (void *cls, | |||
955 | * @param cls the intersection operation | 968 | * @param cls the intersection operation |
956 | * @param mh the message | 969 | * @param mh the message |
957 | */ | 970 | */ |
958 | static void | 971 | void |
959 | handle_p2p_done (void *cls, | 972 | handle_intersection_p2p_done (void *cls, |
960 | const struct GNUNET_MessageHeader *mh) | 973 | const struct IntersectionDoneMessage *idm) |
961 | { | 974 | { |
962 | struct Operation *op = cls; | 975 | struct Operation *op = cls; |
963 | const struct IntersectionDoneMessage *idm; | ||
964 | 976 | ||
965 | if (PHASE_BF_EXCHANGE != op->state->phase) | 977 | if (OT_INTERSECTION != op->type) |
966 | { | 978 | { |
967 | /* wrong phase to conclude? FIXME: Or should we allow this | ||
968 | if the other peer has _initially_ already an empty set? */ | ||
969 | GNUNET_break_op (0); | 979 | GNUNET_break_op (0); |
970 | fail_intersection_operation (op); | 980 | fail_intersection_operation(op); |
971 | return; | 981 | return; |
972 | } | 982 | } |
973 | if (ntohs (mh->size) != sizeof (struct IntersectionDoneMessage)) | 983 | if (PHASE_BF_EXCHANGE != op->state->phase) |
974 | { | 984 | { |
985 | /* wrong phase to conclude? FIXME: Or should we allow this | ||
986 | if the other peer has _initially_ already an empty set? */ | ||
975 | GNUNET_break_op (0); | 987 | GNUNET_break_op (0); |
976 | fail_intersection_operation (op); | 988 | fail_intersection_operation (op); |
977 | return; | 989 | return; |
978 | } | 990 | } |
979 | idm = (const struct IntersectionDoneMessage *) mh; | ||
980 | if (0 == ntohl (idm->final_element_count)) | 991 | if (0 == ntohl (idm->final_element_count)) |
981 | { | 992 | { |
982 | /* other peer determined empty set is the intersection, | 993 | /* other peer determined empty set is the intersection, |
@@ -1000,6 +1011,7 @@ handle_p2p_done (void *cls, | |||
1000 | op->state->my_element_count); | 1011 | op->state->my_element_count); |
1001 | op->state->phase = PHASE_FINISHED; | 1012 | op->state->phase = PHASE_FINISHED; |
1002 | finish_and_destroy (op); | 1013 | finish_and_destroy (op); |
1014 | GNUNET_CADET_receive_done (op->channel); | ||
1003 | } | 1015 | } |
1004 | 1016 | ||
1005 | 1017 | ||
@@ -1064,11 +1076,11 @@ intersection_accept (struct Operation *op) | |||
1064 | op->state->phase = PHASE_INITIAL; | 1076 | op->state->phase = PHASE_INITIAL; |
1065 | op->state->my_element_count | 1077 | op->state->my_element_count |
1066 | = op->spec->set->state->current_set_element_count; | 1078 | = op->spec->set->state->current_set_element_count; |
1079 | GNUNET_assert (NULL == op->state->my_elements); | ||
1067 | op->state->my_elements | 1080 | op->state->my_elements |
1068 | = GNUNET_CONTAINER_multihashmap_create | 1081 | = GNUNET_CONTAINER_multihashmap_create (GNUNET_MIN (op->state->my_element_count, |
1069 | (GNUNET_MIN (op->state->my_element_count, | 1082 | op->spec->remote_element_count), |
1070 | op->spec->remote_element_count), | 1083 | GNUNET_YES); |
1071 | GNUNET_YES); | ||
1072 | if (op->spec->remote_element_count < op->state->my_element_count) | 1084 | if (op->spec->remote_element_count < op->state->my_element_count) |
1073 | { | 1085 | { |
1074 | /* If the other peer (Alice) has fewer elements than us (Bob), | 1086 | /* If the other peer (Alice) has fewer elements than us (Bob), |
@@ -1083,43 +1095,6 @@ intersection_accept (struct Operation *op) | |||
1083 | 1095 | ||
1084 | 1096 | ||
1085 | /** | 1097 | /** |
1086 | * Dispatch messages for a intersection operation. | ||
1087 | * | ||
1088 | * @param op the state of the intersection evaluate operation | ||
1089 | * @param mh the received message | ||
1090 | * @return #GNUNET_SYSERR if the tunnel should be disconnected, | ||
1091 | * #GNUNET_OK otherwise | ||
1092 | */ | ||
1093 | static int | ||
1094 | intersection_handle_p2p_message (struct Operation *op, | ||
1095 | const struct GNUNET_MessageHeader *mh) | ||
1096 | { | ||
1097 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1098 | "Received p2p message (t: %u, s: %u)\n", | ||
1099 | ntohs (mh->type), ntohs (mh->size)); | ||
1100 | switch (ntohs (mh->type)) | ||
1101 | { | ||
1102 | /* this message handler is not active until after we received an | ||
1103 | * operation request message, thus the ops request is not handled here | ||
1104 | */ | ||
1105 | case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO: | ||
1106 | handle_p2p_element_info (op, mh); | ||
1107 | break; | ||
1108 | case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF: | ||
1109 | handle_p2p_bf (op, mh); | ||
1110 | break; | ||
1111 | case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE: | ||
1112 | handle_p2p_done (op, mh); | ||
1113 | break; | ||
1114 | default: | ||
1115 | /* something wrong with cadet's message handlers? */ | ||
1116 | GNUNET_assert (0); | ||
1117 | } | ||
1118 | return GNUNET_OK; | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | /** | ||
1123 | * Handler for peer-disconnects, notifies the client about the aborted | 1098 | * Handler for peer-disconnects, notifies the client about the aborted |
1124 | * operation. If we did not expect anything from the other peer, we | 1099 | * operation. If we did not expect anything from the other peer, we |
1125 | * gracefully terminate the operation. | 1100 | * gracefully terminate the operation. |
@@ -1168,6 +1143,11 @@ intersection_op_cancel (struct Operation *op) | |||
1168 | GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements); | 1143 | GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements); |
1169 | op->state->my_elements = NULL; | 1144 | op->state->my_elements = NULL; |
1170 | } | 1145 | } |
1146 | if (NULL != op->state->full_result_iter) | ||
1147 | { | ||
1148 | GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter); | ||
1149 | op->state->full_result_iter = NULL; | ||
1150 | } | ||
1171 | GNUNET_free (op->state); | 1151 | GNUNET_free (op->state); |
1172 | op->state = NULL; | 1152 | op->state = NULL; |
1173 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1153 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1245,7 +1225,6 @@ _GSS_intersection_vt () | |||
1245 | { | 1225 | { |
1246 | static const struct SetVT intersection_vt = { | 1226 | static const struct SetVT intersection_vt = { |
1247 | .create = &intersection_set_create, | 1227 | .create = &intersection_set_create, |
1248 | .msg_handler = &intersection_handle_p2p_message, | ||
1249 | .add = &intersection_add, | 1228 | .add = &intersection_add, |
1250 | .remove = &intersection_remove, | 1229 | .remove = &intersection_remove, |
1251 | .destroy_set = &intersection_set_destroy, | 1230 | .destroy_set = &intersection_set_destroy, |
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c index b5b602074..1ff3d7716 100644 --- a/src/set/gnunet-service-set_union.c +++ b/src/set/gnunet-service-set_union.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2013-2016 GNUnet e.V. | 3 | Copyright (C) 2013-2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,15 +19,16 @@ | |||
19 | */ | 19 | */ |
20 | /** | 20 | /** |
21 | * @file set/gnunet-service-set_union.c | 21 | * @file set/gnunet-service-set_union.c |
22 | |||
23 | * @brief two-peer set operations | 22 | * @brief two-peer set operations |
24 | * @author Florian Dold | 23 | * @author Florian Dold |
24 | * @author Christian Grothoff | ||
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_util_lib.h" | 27 | #include "gnunet_util_lib.h" |
28 | #include "gnunet_statistics_service.h" | 28 | #include "gnunet_statistics_service.h" |
29 | #include "gnunet-service-set.h" | 29 | #include "gnunet-service-set.h" |
30 | #include "ibf.h" | 30 | #include "ibf.h" |
31 | #include "gnunet-service-set_union.h" | ||
31 | #include "gnunet-service-set_union_strata_estimator.h" | 32 | #include "gnunet-service-set_union_strata_estimator.h" |
32 | #include "gnunet-service-set_protocol.h" | 33 | #include "gnunet-service-set_protocol.h" |
33 | #include <gcrypt.h> | 34 | #include <gcrypt.h> |
@@ -786,11 +787,18 @@ send_element_iterator (void *cls, | |||
786 | struct GNUNET_SET_Element *el = &ee->element; | 787 | struct GNUNET_SET_Element *el = &ee->element; |
787 | struct GNUNET_MQ_Envelope *ev; | 788 | struct GNUNET_MQ_Envelope *ev; |
788 | 789 | ||
789 | 790 | LOG (GNUNET_ERROR_TYPE_INFO, | |
790 | ev = GNUNET_MQ_msg_extra (emsg, el->size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT); | 791 | "Sending element %s\n", |
792 | GNUNET_h2s (key)); | ||
793 | ev = GNUNET_MQ_msg_extra (emsg, | ||
794 | el->size, | ||
795 | GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT); | ||
791 | emsg->element_type = htons (el->element_type); | 796 | emsg->element_type = htons (el->element_type); |
792 | GNUNET_memcpy (&emsg[1], el->data, el->size); | 797 | GNUNET_memcpy (&emsg[1], |
793 | GNUNET_MQ_send (op->mq, ev); | 798 | el->data, |
799 | el->size); | ||
800 | GNUNET_MQ_send (op->mq, | ||
801 | ev); | ||
794 | return GNUNET_YES; | 802 | return GNUNET_YES; |
795 | } | 803 | } |
796 | 804 | ||
@@ -801,11 +809,14 @@ send_full_set (struct Operation *op) | |||
801 | struct GNUNET_MQ_Envelope *ev; | 809 | struct GNUNET_MQ_Envelope *ev; |
802 | 810 | ||
803 | op->state->phase = PHASE_FULL_SENDING; | 811 | op->state->phase = PHASE_FULL_SENDING; |
804 | 812 | /* FIXME: use a more memory-friendly way of doing this with an | |
813 | iterator, just as we do in the non-full case! */ | ||
805 | (void) GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, | 814 | (void) GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, |
806 | &send_element_iterator, op); | 815 | &send_element_iterator, |
816 | op); | ||
807 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); | 817 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); |
808 | GNUNET_MQ_send (op->mq, ev); | 818 | GNUNET_MQ_send (op->mq, |
819 | ev); | ||
809 | } | 820 | } |
810 | 821 | ||
811 | 822 | ||
@@ -813,42 +824,56 @@ send_full_set (struct Operation *op) | |||
813 | * Handle a strata estimator from a remote peer | 824 | * Handle a strata estimator from a remote peer |
814 | * | 825 | * |
815 | * @param cls the union operation | 826 | * @param cls the union operation |
816 | * @param mh the message | 827 | * @param msg the message |
817 | * @param is_compressed #GNUNET_YES if the estimator is compressed | ||
818 | * @return #GNUNET_SYSERR if the tunnel should be disconnected, | ||
819 | * #GNUNET_OK otherwise | ||
820 | */ | 828 | */ |
821 | static int | 829 | int |
822 | handle_p2p_strata_estimator (void *cls, | 830 | check_union_p2p_strata_estimator (void *cls, |
823 | const struct GNUNET_MessageHeader *mh, | 831 | const struct StrataEstimatorMessage *msg) |
824 | int is_compressed) | ||
825 | { | 832 | { |
826 | struct Operation *op = cls; | 833 | struct Operation *op = cls; |
827 | struct StrataEstimator *remote_se; | 834 | int is_compressed; |
828 | struct StrataEstimatorMessage *msg = (void *) mh; | ||
829 | unsigned int diff; | ||
830 | uint64_t other_size; | ||
831 | size_t len; | 835 | size_t len; |
832 | 836 | ||
833 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
834 | "# bytes of SE received", | ||
835 | ntohs (mh->size), | ||
836 | GNUNET_NO); | ||
837 | |||
838 | if (op->state->phase != PHASE_EXPECT_SE) | 837 | if (op->state->phase != PHASE_EXPECT_SE) |
839 | { | 838 | { |
840 | GNUNET_break (0); | 839 | GNUNET_break (0); |
841 | fail_union_operation (op); | ||
842 | return GNUNET_SYSERR; | 840 | return GNUNET_SYSERR; |
843 | } | 841 | } |
844 | len = ntohs (mh->size) - sizeof (struct StrataEstimatorMessage); | 842 | is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type)); |
843 | len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage); | ||
845 | if ( (GNUNET_NO == is_compressed) && | 844 | if ( (GNUNET_NO == is_compressed) && |
846 | (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) ) | 845 | (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) ) |
847 | { | 846 | { |
848 | fail_union_operation (op); | ||
849 | GNUNET_break (0); | 847 | GNUNET_break (0); |
850 | return GNUNET_SYSERR; | 848 | return GNUNET_SYSERR; |
851 | } | 849 | } |
850 | return GNUNET_OK; | ||
851 | } | ||
852 | |||
853 | |||
854 | /** | ||
855 | * Handle a strata estimator from a remote peer | ||
856 | * | ||
857 | * @param cls the union operation | ||
858 | * @param msg the message | ||
859 | */ | ||
860 | void | ||
861 | handle_union_p2p_strata_estimator (void *cls, | ||
862 | const struct StrataEstimatorMessage *msg) | ||
863 | { | ||
864 | struct Operation *op = cls; | ||
865 | struct StrataEstimator *remote_se; | ||
866 | unsigned int diff; | ||
867 | uint64_t other_size; | ||
868 | size_t len; | ||
869 | int is_compressed; | ||
870 | |||
871 | is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type)); | ||
872 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
873 | "# bytes of SE received", | ||
874 | ntohs (msg->header.size), | ||
875 | GNUNET_NO); | ||
876 | len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage); | ||
852 | other_size = GNUNET_ntohll (msg->set_size); | 877 | other_size = GNUNET_ntohll (msg->set_size); |
853 | remote_se = strata_estimator_create (SE_STRATA_COUNT, | 878 | remote_se = strata_estimator_create (SE_STRATA_COUNT, |
854 | SE_IBF_SIZE, | 879 | SE_IBF_SIZE, |
@@ -857,7 +882,7 @@ handle_p2p_strata_estimator (void *cls, | |||
857 | { | 882 | { |
858 | /* insufficient resources, fail */ | 883 | /* insufficient resources, fail */ |
859 | fail_union_operation (op); | 884 | fail_union_operation (op); |
860 | return GNUNET_SYSERR; | 885 | return; |
861 | } | 886 | } |
862 | if (GNUNET_OK != | 887 | if (GNUNET_OK != |
863 | strata_estimator_read (&msg[1], | 888 | strata_estimator_read (&msg[1], |
@@ -866,18 +891,16 @@ handle_p2p_strata_estimator (void *cls, | |||
866 | remote_se)) | 891 | remote_se)) |
867 | { | 892 | { |
868 | /* decompression failed */ | 893 | /* decompression failed */ |
869 | fail_union_operation (op); | ||
870 | strata_estimator_destroy (remote_se); | 894 | strata_estimator_destroy (remote_se); |
871 | return GNUNET_SYSERR; | 895 | fail_union_operation (op); |
896 | return; | ||
872 | } | 897 | } |
873 | GNUNET_assert (NULL != op->state->se); | 898 | GNUNET_assert (NULL != op->state->se); |
874 | diff = strata_estimator_difference (remote_se, | 899 | diff = strata_estimator_difference (remote_se, |
875 | op->state->se); | 900 | op->state->se); |
876 | 901 | ||
877 | if (diff > 200) | 902 | if (diff > 200) |
878 | diff = diff * 3 / 2; | 903 | diff = diff * 3 / 2; |
879 | |||
880 | |||
881 | 904 | ||
882 | strata_estimator_destroy (remote_se); | 905 | strata_estimator_destroy (remote_se); |
883 | strata_estimator_destroy (op->state->se); | 906 | strata_estimator_destroy (op->state->se); |
@@ -885,12 +908,14 @@ handle_p2p_strata_estimator (void *cls, | |||
885 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 908 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
886 | "got se diff=%d, using ibf size %d\n", | 909 | "got se diff=%d, using ibf size %d\n", |
887 | diff, | 910 | diff, |
888 | 1<<get_order_from_difference (diff)); | 911 | 1U << get_order_from_difference (diff)); |
889 | 912 | ||
890 | { | 913 | { |
891 | char *set_debug; | 914 | char *set_debug; |
915 | |||
892 | set_debug = getenv ("GNUNET_SET_BENCHMARK"); | 916 | set_debug = getenv ("GNUNET_SET_BENCHMARK"); |
893 | if ( (NULL != set_debug) && (0 == strcmp (set_debug, "1")) ) | 917 | if ( (NULL != set_debug) && |
918 | (0 == strcmp (set_debug, "1")) ) | ||
894 | { | 919 | { |
895 | FILE *f = fopen ("set.log", "a"); | 920 | FILE *f = fopen ("set.log", "a"); |
896 | fprintf (f, "%llu\n", (unsigned long long) diff); | 921 | fprintf (f, "%llu\n", (unsigned long long) diff); |
@@ -898,34 +923,41 @@ handle_p2p_strata_estimator (void *cls, | |||
898 | } | 923 | } |
899 | } | 924 | } |
900 | 925 | ||
901 | if ((GNUNET_YES == op->spec->byzantine) && (other_size < op->spec->byzantine_lower_bound)) | 926 | if ( (GNUNET_YES == op->spec->byzantine) && |
927 | (other_size < op->spec->byzantine_lower_bound) ) | ||
902 | { | 928 | { |
903 | GNUNET_break (0); | 929 | GNUNET_break (0); |
904 | fail_union_operation (op); | 930 | fail_union_operation (op); |
905 | return GNUNET_SYSERR; | 931 | return; |
906 | } | 932 | } |
907 | 933 | ||
908 | 934 | if ( (GNUNET_YES == op->spec->force_full) || | |
909 | if ( (GNUNET_YES == op->spec->force_full) || (diff > op->state->initial_size / 4)) | 935 | (diff > op->state->initial_size / 4) || |
936 | (0 == other_size) ) | ||
910 | { | 937 | { |
911 | LOG (GNUNET_ERROR_TYPE_INFO, | 938 | LOG (GNUNET_ERROR_TYPE_INFO, |
912 | "Sending full set (diff=%d, own set=%u)\n", | 939 | "Deciding to go for full set transmission (diff=%d, own set=%u)\n", |
913 | diff, | 940 | diff, |
914 | op->state->initial_size); | 941 | op->state->initial_size); |
915 | GNUNET_STATISTICS_update (_GSS_statistics, | 942 | GNUNET_STATISTICS_update (_GSS_statistics, |
916 | "# of full sends", | 943 | "# of full sends", |
917 | 1, | 944 | 1, |
918 | GNUNET_NO); | 945 | GNUNET_NO); |
919 | if (op->state->initial_size <= other_size) | 946 | if ( (op->state->initial_size <= other_size) || |
947 | (0 == other_size) ) | ||
920 | { | 948 | { |
921 | send_full_set (op); | 949 | send_full_set (op); |
922 | } | 950 | } |
923 | else | 951 | else |
924 | { | 952 | { |
925 | struct GNUNET_MQ_Envelope *ev; | 953 | struct GNUNET_MQ_Envelope *ev; |
954 | |||
955 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
956 | "Telling other peer that we expect its full set\n"); | ||
926 | op->state->phase = PHASE_EXPECT_IBF; | 957 | op->state->phase = PHASE_EXPECT_IBF; |
927 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL); | 958 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL); |
928 | GNUNET_MQ_send (op->mq, ev); | 959 | GNUNET_MQ_send (op->mq, |
960 | ev); | ||
929 | } | 961 | } |
930 | } | 962 | } |
931 | else | 963 | else |
@@ -942,11 +974,10 @@ handle_p2p_strata_estimator (void *cls, | |||
942 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 974 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
943 | "Failed to send IBF, closing connection\n"); | 975 | "Failed to send IBF, closing connection\n"); |
944 | fail_union_operation (op); | 976 | fail_union_operation (op); |
945 | return GNUNET_SYSERR; | 977 | return; |
946 | } | 978 | } |
947 | } | 979 | } |
948 | 980 | GNUNET_CADET_receive_done (op->channel); | |
949 | return GNUNET_OK; | ||
950 | } | 981 | } |
951 | 982 | ||
952 | 983 | ||
@@ -1164,99 +1195,116 @@ decode_and_send (struct Operation *op) | |||
1164 | 1195 | ||
1165 | 1196 | ||
1166 | /** | 1197 | /** |
1167 | * Handle an IBF message from a remote peer. | 1198 | * Check an IBF message from a remote peer. |
1168 | * | 1199 | * |
1169 | * Reassemble the IBF from multiple pieces, and | 1200 | * Reassemble the IBF from multiple pieces, and |
1170 | * process the whole IBF once possible. | 1201 | * process the whole IBF once possible. |
1171 | * | 1202 | * |
1172 | * @param cls the union operation | 1203 | * @param cls the union operation |
1173 | * @param mh the header of the message | 1204 | * @param msg the header of the message |
1174 | * @return #GNUNET_SYSERR if the tunnel should be disconnected, | 1205 | * @return #GNUNET_OK if @a msg is well-formed |
1175 | * #GNUNET_OK otherwise | ||
1176 | */ | 1206 | */ |
1177 | static int | 1207 | int |
1178 | handle_p2p_ibf (void *cls, | 1208 | check_union_p2p_ibf (void *cls, |
1179 | const struct GNUNET_MessageHeader *mh) | 1209 | const struct IBFMessage *msg) |
1180 | { | 1210 | { |
1181 | struct Operation *op = cls; | 1211 | struct Operation *op = cls; |
1182 | const struct IBFMessage *msg; | ||
1183 | unsigned int buckets_in_message; | 1212 | unsigned int buckets_in_message; |
1184 | 1213 | ||
1185 | if (ntohs (mh->size) < sizeof (struct IBFMessage)) | 1214 | if (OT_UNION != op->type) |
1186 | { | 1215 | { |
1187 | GNUNET_break_op (0); | 1216 | GNUNET_break_op (0); |
1188 | fail_union_operation (op); | ||
1189 | return GNUNET_SYSERR; | 1217 | return GNUNET_SYSERR; |
1190 | } | 1218 | } |
1191 | msg = (const struct IBFMessage *) mh; | 1219 | buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE; |
1192 | if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) || | 1220 | if (0 == buckets_in_message) |
1193 | (op->state->phase == PHASE_EXPECT_IBF) ) | ||
1194 | { | 1221 | { |
1195 | op->state->phase = PHASE_EXPECT_IBF_CONT; | 1222 | GNUNET_break_op (0); |
1196 | GNUNET_assert (NULL == op->state->remote_ibf); | 1223 | return GNUNET_SYSERR; |
1197 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1224 | } |
1198 | "Creating new ibf of size %u\n", | 1225 | if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE) |
1199 | 1 << msg->order); | 1226 | { |
1200 | op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM); | 1227 | GNUNET_break_op (0); |
1201 | op->state->salt_receive = ntohl (msg->salt); | 1228 | return GNUNET_SYSERR; |
1202 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving new IBF with salt %u\n", op->state->salt_receive); | ||
1203 | if (NULL == op->state->remote_ibf) | ||
1204 | { | ||
1205 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1206 | "Failed to parse remote IBF, closing connection\n"); | ||
1207 | fail_union_operation (op); | ||
1208 | return GNUNET_SYSERR; | ||
1209 | } | ||
1210 | op->state->ibf_buckets_received = 0; | ||
1211 | if (0 != ntohl (msg->offset)) | ||
1212 | { | ||
1213 | GNUNET_break_op (0); | ||
1214 | fail_union_operation (op); | ||
1215 | return GNUNET_SYSERR; | ||
1216 | } | ||
1217 | } | 1229 | } |
1218 | else if (op->state->phase == PHASE_EXPECT_IBF_CONT) | 1230 | if (op->state->phase == PHASE_EXPECT_IBF_CONT) |
1219 | { | 1231 | { |
1220 | if (ntohl (msg->offset) != op->state->ibf_buckets_received) | 1232 | if (ntohl (msg->offset) != op->state->ibf_buckets_received) |
1221 | { | 1233 | { |
1222 | GNUNET_break_op (0); | 1234 | GNUNET_break_op (0); |
1223 | fail_union_operation (op); | ||
1224 | return GNUNET_SYSERR; | 1235 | return GNUNET_SYSERR; |
1225 | } | 1236 | } |
1226 | if (1<<msg->order != op->state->remote_ibf->size) | 1237 | if (1<<msg->order != op->state->remote_ibf->size) |
1227 | { | 1238 | { |
1228 | GNUNET_break_op (0); | 1239 | GNUNET_break_op (0); |
1229 | fail_union_operation (op); | ||
1230 | return GNUNET_SYSERR; | 1240 | return GNUNET_SYSERR; |
1231 | } | 1241 | } |
1232 | if (ntohl (msg->salt) != op->state->salt_receive) | 1242 | if (ntohl (msg->salt) != op->state->salt_receive) |
1233 | { | 1243 | { |
1234 | GNUNET_break_op (0); | 1244 | GNUNET_break_op (0); |
1235 | fail_union_operation (op); | ||
1236 | return GNUNET_SYSERR; | 1245 | return GNUNET_SYSERR; |
1237 | } | 1246 | } |
1238 | } | 1247 | } |
1239 | else | 1248 | else if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) && |
1249 | (op->state->phase != PHASE_EXPECT_IBF) ) | ||
1240 | { | 1250 | { |
1241 | GNUNET_assert (0); | 1251 | GNUNET_break_op (0); |
1252 | return GNUNET_SYSERR; | ||
1242 | } | 1253 | } |
1243 | 1254 | ||
1244 | buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE; | 1255 | return GNUNET_OK; |
1256 | } | ||
1245 | 1257 | ||
1246 | if (0 == buckets_in_message) | 1258 | |
1259 | /** | ||
1260 | * Handle an IBF message from a remote peer. | ||
1261 | * | ||
1262 | * Reassemble the IBF from multiple pieces, and | ||
1263 | * process the whole IBF once possible. | ||
1264 | * | ||
1265 | * @param cls the union operation | ||
1266 | * @param msg the header of the message | ||
1267 | */ | ||
1268 | void | ||
1269 | handle_union_p2p_ibf (void *cls, | ||
1270 | const struct IBFMessage *msg) | ||
1271 | { | ||
1272 | struct Operation *op = cls; | ||
1273 | unsigned int buckets_in_message; | ||
1274 | |||
1275 | buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE; | ||
1276 | if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) || | ||
1277 | (op->state->phase == PHASE_EXPECT_IBF) ) | ||
1247 | { | 1278 | { |
1248 | GNUNET_break_op (0); | 1279 | op->state->phase = PHASE_EXPECT_IBF_CONT; |
1249 | fail_union_operation (op); | 1280 | GNUNET_assert (NULL == op->state->remote_ibf); |
1250 | return GNUNET_SYSERR; | 1281 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1282 | "Creating new ibf of size %u\n", | ||
1283 | 1 << msg->order); | ||
1284 | op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM); | ||
1285 | op->state->salt_receive = ntohl (msg->salt); | ||
1286 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1287 | "Receiving new IBF with salt %u\n", | ||
1288 | op->state->salt_receive); | ||
1289 | if (NULL == op->state->remote_ibf) | ||
1290 | { | ||
1291 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1292 | "Failed to parse remote IBF, closing connection\n"); | ||
1293 | fail_union_operation (op); | ||
1294 | return; | ||
1295 | } | ||
1296 | op->state->ibf_buckets_received = 0; | ||
1297 | if (0 != ntohl (msg->offset)) | ||
1298 | { | ||
1299 | GNUNET_break_op (0); | ||
1300 | fail_union_operation (op); | ||
1301 | return; | ||
1302 | } | ||
1251 | } | 1303 | } |
1252 | 1304 | else | |
1253 | if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE) | ||
1254 | { | 1305 | { |
1255 | GNUNET_break_op (0); | 1306 | GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT); |
1256 | fail_union_operation (op); | ||
1257 | return GNUNET_SYSERR; | ||
1258 | } | 1307 | } |
1259 | |||
1260 | GNUNET_assert (NULL != op->state->remote_ibf); | 1308 | GNUNET_assert (NULL != op->state->remote_ibf); |
1261 | 1309 | ||
1262 | ibf_read_slice (&msg[1], | 1310 | ibf_read_slice (&msg[1], |
@@ -1276,10 +1324,11 @@ handle_p2p_ibf (void *cls, | |||
1276 | /* Internal error, best we can do is shut down */ | 1324 | /* Internal error, best we can do is shut down */ |
1277 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1325 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1278 | "Failed to decode IBF, closing connection\n"); | 1326 | "Failed to decode IBF, closing connection\n"); |
1279 | return GNUNET_SYSERR; | 1327 | fail_union_operation (op); |
1328 | return; | ||
1280 | } | 1329 | } |
1281 | } | 1330 | } |
1282 | return GNUNET_OK; | 1331 | GNUNET_CADET_receive_done (op->channel); |
1283 | } | 1332 | } |
1284 | 1333 | ||
1285 | 1334 | ||
@@ -1343,6 +1392,11 @@ send_done_and_destroy (void *cls) | |||
1343 | } | 1392 | } |
1344 | 1393 | ||
1345 | 1394 | ||
1395 | /** | ||
1396 | * Tests if the operation is finished, and if so notify. | ||
1397 | * | ||
1398 | * @param op operation to check | ||
1399 | */ | ||
1346 | static void | 1400 | static void |
1347 | maybe_finish (struct Operation *op) | 1401 | maybe_finish (struct Operation *op) |
1348 | { | 1402 | { |
@@ -1382,46 +1436,59 @@ maybe_finish (struct Operation *op) | |||
1382 | 1436 | ||
1383 | 1437 | ||
1384 | /** | 1438 | /** |
1385 | * Handle an element message from a remote peer. | 1439 | * Check an element message from a remote peer. |
1386 | * Sent by the other peer either because we decoded an IBF and placed a demand, | ||
1387 | * or because the other peer switched to full set transmission. | ||
1388 | * | 1440 | * |
1389 | * @param cls the union operation | 1441 | * @param cls the union operation |
1390 | * @param mh the message | 1442 | * @param emsg the message |
1391 | */ | 1443 | */ |
1392 | static void | 1444 | int |
1393 | handle_p2p_elements (void *cls, | 1445 | check_union_p2p_elements (void *cls, |
1394 | const struct GNUNET_MessageHeader *mh) | 1446 | const struct GNUNET_SET_ElementMessage *emsg) |
1395 | { | 1447 | { |
1396 | struct Operation *op = cls; | 1448 | struct Operation *op = cls; |
1397 | struct ElementEntry *ee; | ||
1398 | const struct GNUNET_SET_ElementMessage *emsg; | ||
1399 | uint16_t element_size; | ||
1400 | 1449 | ||
1401 | if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes)) | 1450 | if (OT_UNION != op->type) |
1402 | { | 1451 | { |
1403 | GNUNET_break_op (0); | 1452 | GNUNET_break_op (0); |
1404 | fail_union_operation (op); | 1453 | return GNUNET_SYSERR; |
1405 | return; | ||
1406 | } | 1454 | } |
1407 | if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage)) | 1455 | if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes)) |
1408 | { | 1456 | { |
1409 | GNUNET_break_op (0); | 1457 | GNUNET_break_op (0); |
1410 | fail_union_operation (op); | 1458 | return GNUNET_SYSERR; |
1411 | return; | ||
1412 | } | 1459 | } |
1460 | return GNUNET_OK; | ||
1461 | } | ||
1462 | |||
1413 | 1463 | ||
1414 | emsg = (const struct GNUNET_SET_ElementMessage *) mh; | 1464 | /** |
1465 | * Handle an element message from a remote peer. | ||
1466 | * Sent by the other peer either because we decoded an IBF and placed a demand, | ||
1467 | * or because the other peer switched to full set transmission. | ||
1468 | * | ||
1469 | * @param cls the union operation | ||
1470 | * @param emsg the message | ||
1471 | */ | ||
1472 | void | ||
1473 | handle_union_p2p_elements (void *cls, | ||
1474 | const struct GNUNET_SET_ElementMessage *emsg) | ||
1475 | { | ||
1476 | struct Operation *op = cls; | ||
1477 | struct ElementEntry *ee; | ||
1478 | struct KeyEntry *ke; | ||
1479 | uint16_t element_size; | ||
1415 | 1480 | ||
1416 | element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage); | 1481 | element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage); |
1417 | ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); | 1482 | ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); |
1418 | GNUNET_memcpy (&ee[1], &emsg[1], element_size); | 1483 | GNUNET_memcpy (&ee[1], |
1484 | &emsg[1], | ||
1485 | element_size); | ||
1419 | ee->element.size = element_size; | 1486 | ee->element.size = element_size; |
1420 | ee->element.data = &ee[1]; | 1487 | ee->element.data = &ee[1]; |
1421 | ee->element.element_type = ntohs (emsg->element_type); | 1488 | ee->element.element_type = ntohs (emsg->element_type); |
1422 | ee->remote = GNUNET_YES; | 1489 | ee->remote = GNUNET_YES; |
1423 | GNUNET_SET_element_hash (&ee->element, &ee->element_hash); | 1490 | GNUNET_SET_element_hash (&ee->element, |
1424 | 1491 | &ee->element_hash); | |
1425 | if (GNUNET_NO == | 1492 | if (GNUNET_NO == |
1426 | GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes, | 1493 | GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes, |
1427 | &ee->element_hash, | 1494 | &ee->element_hash, |
@@ -1429,7 +1496,6 @@ handle_p2p_elements (void *cls, | |||
1429 | { | 1496 | { |
1430 | /* We got something we didn't demand, since it's not in our map. */ | 1497 | /* We got something we didn't demand, since it's not in our map. */ |
1431 | GNUNET_break_op (0); | 1498 | GNUNET_break_op (0); |
1432 | GNUNET_free (ee); | ||
1433 | fail_union_operation (op); | 1499 | fail_union_operation (op); |
1434 | return; | 1500 | return; |
1435 | } | 1501 | } |
@@ -1448,10 +1514,9 @@ handle_p2p_elements (void *cls, | |||
1448 | 1, | 1514 | 1, |
1449 | GNUNET_NO); | 1515 | GNUNET_NO); |
1450 | 1516 | ||
1451 | op->state->received_total += 1; | 1517 | op->state->received_total++; |
1452 | |||
1453 | struct KeyEntry *ke = op_get_element (op, &ee->element_hash); | ||
1454 | 1518 | ||
1519 | ke = op_get_element (op, &ee->element_hash); | ||
1455 | if (NULL != ke) | 1520 | if (NULL != ke) |
1456 | { | 1521 | { |
1457 | /* Got repeated element. Should not happen since | 1522 | /* Got repeated element. Should not happen since |
@@ -1467,7 +1532,7 @@ handle_p2p_elements (void *cls, | |||
1467 | { | 1532 | { |
1468 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1533 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1469 | "Registering new element from remote peer\n"); | 1534 | "Registering new element from remote peer\n"); |
1470 | op->state->received_fresh += 1; | 1535 | op->state->received_fresh++; |
1471 | op_register_element (op, ee, GNUNET_YES); | 1536 | op_register_element (op, ee, GNUNET_YES); |
1472 | /* only send results immediately if the client wants it */ | 1537 | /* only send results immediately if the client wants it */ |
1473 | switch (op->spec->result_mode) | 1538 | switch (op->spec->result_mode) |
@@ -1485,43 +1550,57 @@ handle_p2p_elements (void *cls, | |||
1485 | } | 1550 | } |
1486 | } | 1551 | } |
1487 | 1552 | ||
1488 | if (op->state->received_total > 8 && op->state->received_fresh < op->state->received_total / 3) | 1553 | if ( (op->state->received_total > 8) && |
1554 | (op->state->received_fresh < op->state->received_total / 3) ) | ||
1489 | { | 1555 | { |
1490 | /* The other peer gave us lots of old elements, there's something wrong. */ | 1556 | /* The other peer gave us lots of old elements, there's something wrong. */ |
1491 | GNUNET_break_op (0); | 1557 | GNUNET_break_op (0); |
1492 | fail_union_operation (op); | 1558 | fail_union_operation (op); |
1493 | return; | 1559 | return; |
1494 | } | 1560 | } |
1495 | 1561 | GNUNET_CADET_receive_done (op->channel); | |
1496 | maybe_finish (op); | 1562 | maybe_finish (op); |
1497 | } | 1563 | } |
1498 | 1564 | ||
1499 | 1565 | ||
1500 | /** | 1566 | /** |
1501 | * Handle an element message from a remote peer. | 1567 | * Check a full element message from a remote peer. |
1502 | * | 1568 | * |
1503 | * @param cls the union operation | 1569 | * @param cls the union operation |
1504 | * @param mh the message | 1570 | * @param emsg the message |
1505 | */ | 1571 | */ |
1506 | static void | 1572 | int |
1507 | handle_p2p_full_element (void *cls, | 1573 | check_union_p2p_full_element (void *cls, |
1508 | const struct GNUNET_MessageHeader *mh) | 1574 | const struct GNUNET_SET_ElementMessage *emsg) |
1509 | { | 1575 | { |
1510 | struct Operation *op = cls; | 1576 | struct Operation *op = cls; |
1511 | struct ElementEntry *ee; | ||
1512 | const struct GNUNET_SET_ElementMessage *emsg; | ||
1513 | uint16_t element_size; | ||
1514 | 1577 | ||
1515 | if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage)) | 1578 | if (OT_UNION != op->type) |
1516 | { | 1579 | { |
1517 | GNUNET_break_op (0); | 1580 | GNUNET_break_op (0); |
1518 | fail_union_operation (op); | 1581 | return GNUNET_SYSERR; |
1519 | return; | ||
1520 | } | 1582 | } |
1583 | // FIXME: check that we expect full elements here? | ||
1584 | return GNUNET_OK; | ||
1585 | } | ||
1521 | 1586 | ||
1522 | emsg = (const struct GNUNET_SET_ElementMessage *) mh; | ||
1523 | 1587 | ||
1524 | element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage); | 1588 | /** |
1589 | * Handle an element message from a remote peer. | ||
1590 | * | ||
1591 | * @param cls the union operation | ||
1592 | * @param emsg the message | ||
1593 | */ | ||
1594 | void | ||
1595 | handle_union_p2p_full_element (void *cls, | ||
1596 | const struct GNUNET_SET_ElementMessage *emsg) | ||
1597 | { | ||
1598 | struct Operation *op = cls; | ||
1599 | struct ElementEntry *ee; | ||
1600 | struct KeyEntry *ke; | ||
1601 | uint16_t element_size; | ||
1602 | |||
1603 | element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage); | ||
1525 | ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); | 1604 | ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); |
1526 | GNUNET_memcpy (&ee[1], &emsg[1], element_size); | 1605 | GNUNET_memcpy (&ee[1], &emsg[1], element_size); |
1527 | ee->element.size = element_size; | 1606 | ee->element.size = element_size; |
@@ -1544,10 +1623,9 @@ handle_p2p_full_element (void *cls, | |||
1544 | 1, | 1623 | 1, |
1545 | GNUNET_NO); | 1624 | GNUNET_NO); |
1546 | 1625 | ||
1547 | op->state->received_total += 1; | 1626 | op->state->received_total++; |
1548 | |||
1549 | struct KeyEntry *ke = op_get_element (op, &ee->element_hash); | ||
1550 | 1627 | ||
1628 | ke = op_get_element (op, &ee->element_hash); | ||
1551 | if (NULL != ke) | 1629 | if (NULL != ke) |
1552 | { | 1630 | { |
1553 | /* Got repeated element. Should not happen since | 1631 | /* Got repeated element. Should not happen since |
@@ -1563,7 +1641,7 @@ handle_p2p_full_element (void *cls, | |||
1563 | { | 1641 | { |
1564 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1642 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1565 | "Registering new element from remote peer\n"); | 1643 | "Registering new element from remote peer\n"); |
1566 | op->state->received_fresh += 1; | 1644 | op->state->received_fresh++; |
1567 | op_register_element (op, ee, GNUNET_YES); | 1645 | op_register_element (op, ee, GNUNET_YES); |
1568 | /* only send results immediately if the client wants it */ | 1646 | /* only send results immediately if the client wants it */ |
1569 | switch (op->spec->result_mode) | 1647 | switch (op->spec->result_mode) |
@@ -1581,8 +1659,8 @@ handle_p2p_full_element (void *cls, | |||
1581 | } | 1659 | } |
1582 | } | 1660 | } |
1583 | 1661 | ||
1584 | if ( (GNUNET_YES == op->spec->byzantine) && | 1662 | if ( (GNUNET_YES == op->spec->byzantine) && |
1585 | (op->state->received_total > 384 + op->state->received_fresh * 4) && | 1663 | (op->state->received_total > 384 + op->state->received_fresh * 4) && |
1586 | (op->state->received_fresh < op->state->received_total / 6) ) | 1664 | (op->state->received_fresh < op->state->received_total / 6) ) |
1587 | { | 1665 | { |
1588 | /* The other peer gave us lots of old elements, there's something wrong. */ | 1666 | /* The other peer gave us lots of old elements, there's something wrong. */ |
@@ -1594,51 +1672,73 @@ handle_p2p_full_element (void *cls, | |||
1594 | fail_union_operation (op); | 1672 | fail_union_operation (op); |
1595 | return; | 1673 | return; |
1596 | } | 1674 | } |
1675 | GNUNET_CADET_receive_done (op->channel); | ||
1597 | } | 1676 | } |
1598 | 1677 | ||
1678 | |||
1599 | /** | 1679 | /** |
1600 | * Send offers (for GNUNET_Hash-es) in response | 1680 | * Send offers (for GNUNET_Hash-es) in response |
1601 | * to inquiries (for IBF_Key-s). | 1681 | * to inquiries (for IBF_Key-s). |
1602 | * | 1682 | * |
1603 | * @param cls the union operation | 1683 | * @param cls the union operation |
1604 | * @param mh the message | 1684 | * @param msg the message |
1605 | */ | 1685 | */ |
1606 | static void | 1686 | int |
1607 | handle_p2p_inquiry (void *cls, | 1687 | check_union_p2p_inquiry (void *cls, |
1608 | const struct GNUNET_MessageHeader *mh) | 1688 | const struct InquiryMessage *msg) |
1609 | { | 1689 | { |
1610 | struct Operation *op = cls; | 1690 | struct Operation *op = cls; |
1611 | const struct IBF_Key *ibf_key; | ||
1612 | unsigned int num_keys; | 1691 | unsigned int num_keys; |
1613 | struct InquiryMessage *msg; | ||
1614 | 1692 | ||
1615 | /* look up elements and send them */ | 1693 | if (OT_UNION != op->type) |
1694 | { | ||
1695 | GNUNET_break_op (0); | ||
1696 | return GNUNET_SYSERR; | ||
1697 | } | ||
1616 | if (op->state->phase != PHASE_INVENTORY_PASSIVE) | 1698 | if (op->state->phase != PHASE_INVENTORY_PASSIVE) |
1617 | { | 1699 | { |
1618 | GNUNET_break_op (0); | 1700 | GNUNET_break_op (0); |
1619 | fail_union_operation (op); | 1701 | return GNUNET_SYSERR; |
1620 | return; | ||
1621 | } | 1702 | } |
1622 | num_keys = (ntohs (mh->size) - sizeof (struct InquiryMessage)) | 1703 | num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage)) |
1623 | / sizeof (struct IBF_Key); | 1704 | / sizeof (struct IBF_Key); |
1624 | if ((ntohs (mh->size) - sizeof (struct InquiryMessage)) | 1705 | if ((ntohs (msg->header.size) - sizeof (struct InquiryMessage)) |
1625 | != num_keys * sizeof (struct IBF_Key)) | 1706 | != num_keys * sizeof (struct IBF_Key)) |
1626 | { | 1707 | { |
1627 | GNUNET_break_op (0); | 1708 | GNUNET_break_op (0); |
1628 | fail_union_operation (op); | 1709 | return GNUNET_SYSERR; |
1629 | return; | ||
1630 | } | 1710 | } |
1711 | return GNUNET_OK; | ||
1712 | } | ||
1713 | |||
1631 | 1714 | ||
1632 | msg = (struct InquiryMessage *) mh; | 1715 | /** |
1716 | * Send offers (for GNUNET_Hash-es) in response | ||
1717 | * to inquiries (for IBF_Key-s). | ||
1718 | * | ||
1719 | * @param cls the union operation | ||
1720 | * @param msg the message | ||
1721 | */ | ||
1722 | void | ||
1723 | handle_union_p2p_inquiry (void *cls, | ||
1724 | const struct InquiryMessage *msg) | ||
1725 | { | ||
1726 | struct Operation *op = cls; | ||
1727 | const struct IBF_Key *ibf_key; | ||
1728 | unsigned int num_keys; | ||
1633 | 1729 | ||
1730 | num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage)) | ||
1731 | / sizeof (struct IBF_Key); | ||
1634 | ibf_key = (const struct IBF_Key *) &msg[1]; | 1732 | ibf_key = (const struct IBF_Key *) &msg[1]; |
1635 | while (0 != num_keys--) | 1733 | while (0 != num_keys--) |
1636 | { | 1734 | { |
1637 | struct IBF_Key unsalted_key; | 1735 | struct IBF_Key unsalted_key; |
1736 | |||
1638 | unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key); | 1737 | unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key); |
1639 | send_offers_for_key (op, unsalted_key); | 1738 | send_offers_for_key (op, unsalted_key); |
1640 | ibf_key++; | 1739 | ibf_key++; |
1641 | } | 1740 | } |
1741 | GNUNET_CADET_receive_done (op->channel); | ||
1642 | } | 1742 | } |
1643 | 1743 | ||
1644 | 1744 | ||
@@ -1677,27 +1777,36 @@ send_missing_elements_iter (void *cls, | |||
1677 | 1777 | ||
1678 | 1778 | ||
1679 | /** | 1779 | /** |
1680 | * Handle a | 1780 | * Handle a request for full set transmission. |
1681 | * | 1781 | * |
1682 | * @parem cls closure, a set union operation | 1782 | * @parem cls closure, a set union operation |
1683 | * @param mh the demand message | 1783 | * @param mh the demand message |
1684 | */ | 1784 | */ |
1685 | static void | 1785 | void |
1686 | handle_p2p_request_full (void *cls, | 1786 | handle_union_p2p_request_full (void *cls, |
1687 | const struct GNUNET_MessageHeader *mh) | 1787 | const struct GNUNET_MessageHeader *mh) |
1688 | { | 1788 | { |
1689 | struct Operation *op = cls; | 1789 | struct Operation *op = cls; |
1690 | 1790 | ||
1691 | if (PHASE_EXPECT_IBF != op->state->phase) | 1791 | LOG (GNUNET_ERROR_TYPE_INFO, |
1792 | "Received request for full set transmission\n"); | ||
1793 | if (OT_UNION != op->type) | ||
1692 | { | 1794 | { |
1795 | GNUNET_break_op (0); | ||
1693 | fail_union_operation (op); | 1796 | fail_union_operation (op); |
1797 | return; | ||
1798 | } | ||
1799 | if (PHASE_EXPECT_IBF != op->state->phase) | ||
1800 | { | ||
1694 | GNUNET_break_op (0); | 1801 | GNUNET_break_op (0); |
1802 | fail_union_operation (op); | ||
1695 | return; | 1803 | return; |
1696 | } | 1804 | } |
1697 | 1805 | ||
1698 | // FIXME: we need to check that our set is larger than the | 1806 | // FIXME: we need to check that our set is larger than the |
1699 | // byzantine_lower_bound by some threshold | 1807 | // byzantine_lower_bound by some threshold |
1700 | send_full_set (op); | 1808 | send_full_set (op); |
1809 | GNUNET_CADET_receive_done (op->channel); | ||
1701 | } | 1810 | } |
1702 | 1811 | ||
1703 | 1812 | ||
@@ -1707,56 +1816,97 @@ handle_p2p_request_full (void *cls, | |||
1707 | * @parem cls closure, a set union operation | 1816 | * @parem cls closure, a set union operation |
1708 | * @param mh the demand message | 1817 | * @param mh the demand message |
1709 | */ | 1818 | */ |
1710 | static void | 1819 | void |
1711 | handle_p2p_full_done (void *cls, | 1820 | handle_union_p2p_full_done (void *cls, |
1712 | const struct GNUNET_MessageHeader *mh) | 1821 | const struct GNUNET_MessageHeader *mh) |
1713 | { | 1822 | { |
1714 | struct Operation *op = cls; | 1823 | struct Operation *op = cls; |
1715 | 1824 | ||
1716 | if (PHASE_EXPECT_IBF == op->state->phase) | 1825 | switch (op->state->phase) |
1717 | { | 1826 | { |
1718 | struct GNUNET_MQ_Envelope *ev; | 1827 | case PHASE_EXPECT_IBF: |
1719 | 1828 | { | |
1720 | LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, sending elements that other peer is missing\n"); | 1829 | struct GNUNET_MQ_Envelope *ev; |
1721 | 1830 | ||
1722 | /* send all the elements that did not come from the remote peer */ | 1831 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1723 | GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element, | 1832 | "got FULL DONE, sending elements that other peer is missing\n"); |
1724 | &send_missing_elements_iter, | ||
1725 | op); | ||
1726 | 1833 | ||
1727 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); | 1834 | /* send all the elements that did not come from the remote peer */ |
1728 | GNUNET_MQ_send (op->mq, ev); | 1835 | GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element, |
1729 | op->state->phase = PHASE_DONE; | 1836 | &send_missing_elements_iter, |
1837 | op); | ||
1730 | 1838 | ||
1731 | /* we now wait until the other peer shuts the tunnel down*/ | 1839 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); |
1840 | GNUNET_MQ_send (op->mq, ev); | ||
1841 | op->state->phase = PHASE_DONE; | ||
1842 | /* we now wait until the other peer shuts the tunnel down*/ | ||
1843 | } | ||
1844 | break; | ||
1845 | case PHASE_FULL_SENDING: | ||
1846 | { | ||
1847 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1848 | "got FULL DONE, finishing\n"); | ||
1849 | /* We sent the full set, and got the response for that. We're done. */ | ||
1850 | op->state->phase = PHASE_DONE; | ||
1851 | GNUNET_CADET_receive_done (op->channel); | ||
1852 | send_done_and_destroy (op); | ||
1853 | return; | ||
1854 | } | ||
1855 | break; | ||
1856 | default: | ||
1857 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1858 | "Handle full done phase is %u\n", | ||
1859 | (unsigned) op->state->phase); | ||
1860 | GNUNET_break_op (0); | ||
1861 | fail_union_operation (op); | ||
1862 | return; | ||
1732 | } | 1863 | } |
1733 | else if (PHASE_FULL_SENDING == op->state->phase) | 1864 | GNUNET_CADET_receive_done (op->channel); |
1865 | } | ||
1866 | |||
1867 | |||
1868 | /** | ||
1869 | * Check a demand by the other peer for elements based on a list | ||
1870 | * of `struct GNUNET_HashCode`s. | ||
1871 | * | ||
1872 | * @parem cls closure, a set union operation | ||
1873 | * @param mh the demand message | ||
1874 | * @return #GNUNET_OK if @a mh is well-formed | ||
1875 | */ | ||
1876 | int | ||
1877 | check_union_p2p_demand (void *cls, | ||
1878 | const struct GNUNET_MessageHeader *mh) | ||
1879 | { | ||
1880 | struct Operation *op = cls; | ||
1881 | unsigned int num_hashes; | ||
1882 | |||
1883 | if (OT_UNION != op->type) | ||
1734 | { | 1884 | { |
1735 | LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, finishing\n"); | 1885 | GNUNET_break_op (0); |
1736 | /* We sent the full set, and got the response for that. We're done. */ | 1886 | return GNUNET_SYSERR; |
1737 | op->state->phase = PHASE_DONE; | ||
1738 | send_done_and_destroy (op); | ||
1739 | } | 1887 | } |
1740 | else | 1888 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) |
1889 | / sizeof (struct GNUNET_HashCode); | ||
1890 | if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) | ||
1891 | != num_hashes * sizeof (struct GNUNET_HashCode)) | ||
1741 | { | 1892 | { |
1742 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handle full done phase is %u\n", (unsigned) op->state->phase); | ||
1743 | GNUNET_break_op (0); | 1893 | GNUNET_break_op (0); |
1744 | fail_union_operation (op); | 1894 | return GNUNET_SYSERR; |
1745 | return; | ||
1746 | } | 1895 | } |
1896 | return GNUNET_OK; | ||
1747 | } | 1897 | } |
1748 | 1898 | ||
1749 | 1899 | ||
1750 | /** | 1900 | /** |
1751 | * Handle a demand by the other peer for elements based on a list | 1901 | * Handle a demand by the other peer for elements based on a list |
1752 | * of GNUNET_HashCode-s. | 1902 | * of `struct GNUNET_HashCode`s. |
1753 | * | 1903 | * |
1754 | * @parem cls closure, a set union operation | 1904 | * @parem cls closure, a set union operation |
1755 | * @param mh the demand message | 1905 | * @param mh the demand message |
1756 | */ | 1906 | */ |
1757 | static void | 1907 | void |
1758 | handle_p2p_demand (void *cls, | 1908 | handle_union_p2p_demand (void *cls, |
1759 | const struct GNUNET_MessageHeader *mh) | 1909 | const struct GNUNET_MessageHeader *mh) |
1760 | { | 1910 | { |
1761 | struct Operation *op = cls; | 1911 | struct Operation *op = cls; |
1762 | struct ElementEntry *ee; | 1912 | struct ElementEntry *ee; |
@@ -1767,19 +1917,12 @@ handle_p2p_demand (void *cls, | |||
1767 | 1917 | ||
1768 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) | 1918 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) |
1769 | / sizeof (struct GNUNET_HashCode); | 1919 | / sizeof (struct GNUNET_HashCode); |
1770 | if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) | ||
1771 | != num_hashes * sizeof (struct GNUNET_HashCode)) | ||
1772 | { | ||
1773 | GNUNET_break_op (0); | ||
1774 | fail_union_operation (op); | ||
1775 | return; | ||
1776 | } | ||
1777 | |||
1778 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; | 1920 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; |
1779 | num_hashes > 0; | 1921 | num_hashes > 0; |
1780 | hash++, num_hashes--) | 1922 | hash++, num_hashes--) |
1781 | { | 1923 | { |
1782 | ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, hash); | 1924 | ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, |
1925 | hash); | ||
1783 | if (NULL == ee) | 1926 | if (NULL == ee) |
1784 | { | 1927 | { |
1785 | /* Demand for non-existing element. */ | 1928 | /* Demand for non-existing element. */ |
@@ -1823,31 +1966,35 @@ handle_p2p_demand (void *cls, | |||
1823 | break; | 1966 | break; |
1824 | } | 1967 | } |
1825 | } | 1968 | } |
1969 | GNUNET_CADET_receive_done (op->channel); | ||
1826 | } | 1970 | } |
1827 | 1971 | ||
1828 | 1972 | ||
1829 | /** | 1973 | /** |
1830 | * Handle offers (of GNUNET_HashCode-s) and | 1974 | * Check offer (of `struct GNUNET_HashCode`s). |
1831 | * respond with demands (of GNUNET_HashCode-s). | ||
1832 | * | 1975 | * |
1833 | * @param cls the union operation | 1976 | * @param cls the union operation |
1834 | * @param mh the message | 1977 | * @param mh the message |
1978 | * @return #GNUNET_OK if @a mh is well-formed | ||
1835 | */ | 1979 | */ |
1836 | static void | 1980 | int |
1837 | handle_p2p_offer (void *cls, | 1981 | check_union_p2p_offer (void *cls, |
1838 | const struct GNUNET_MessageHeader *mh) | 1982 | const struct GNUNET_MessageHeader *mh) |
1839 | { | 1983 | { |
1840 | struct Operation *op = cls; | 1984 | struct Operation *op = cls; |
1841 | const struct GNUNET_HashCode *hash; | ||
1842 | unsigned int num_hashes; | 1985 | unsigned int num_hashes; |
1843 | 1986 | ||
1987 | if (OT_UNION != op->type) | ||
1988 | { | ||
1989 | GNUNET_break_op (0); | ||
1990 | return GNUNET_SYSERR; | ||
1991 | } | ||
1844 | /* look up elements and send them */ | 1992 | /* look up elements and send them */ |
1845 | if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) && | 1993 | if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) && |
1846 | (op->state->phase != PHASE_INVENTORY_ACTIVE)) | 1994 | (op->state->phase != PHASE_INVENTORY_ACTIVE)) |
1847 | { | 1995 | { |
1848 | GNUNET_break_op (0); | 1996 | GNUNET_break_op (0); |
1849 | fail_union_operation (op); | 1997 | return GNUNET_SYSERR; |
1850 | return; | ||
1851 | } | 1998 | } |
1852 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) | 1999 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) |
1853 | / sizeof (struct GNUNET_HashCode); | 2000 | / sizeof (struct GNUNET_HashCode); |
@@ -1855,10 +2002,29 @@ handle_p2p_offer (void *cls, | |||
1855 | != num_hashes * sizeof (struct GNUNET_HashCode)) | 2002 | != num_hashes * sizeof (struct GNUNET_HashCode)) |
1856 | { | 2003 | { |
1857 | GNUNET_break_op (0); | 2004 | GNUNET_break_op (0); |
1858 | fail_union_operation (op); | 2005 | return GNUNET_SYSERR; |
1859 | return; | ||
1860 | } | 2006 | } |
2007 | return GNUNET_OK; | ||
2008 | } | ||
2009 | |||
2010 | |||
2011 | /** | ||
2012 | * Handle offers (of `struct GNUNET_HashCode`s) and | ||
2013 | * respond with demands (of `struct GNUNET_HashCode`s). | ||
2014 | * | ||
2015 | * @param cls the union operation | ||
2016 | * @param mh the message | ||
2017 | */ | ||
2018 | void | ||
2019 | handle_union_p2p_offer (void *cls, | ||
2020 | const struct GNUNET_MessageHeader *mh) | ||
2021 | { | ||
2022 | struct Operation *op = cls; | ||
2023 | const struct GNUNET_HashCode *hash; | ||
2024 | unsigned int num_hashes; | ||
1861 | 2025 | ||
2026 | num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) | ||
2027 | / sizeof (struct GNUNET_HashCode); | ||
1862 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; | 2028 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; |
1863 | num_hashes > 0; | 2029 | num_hashes > 0; |
1864 | hash++, num_hashes--) | 2030 | hash++, num_hashes--) |
@@ -1897,6 +2063,7 @@ handle_p2p_offer (void *cls, | |||
1897 | *(struct GNUNET_HashCode *) &demands[1] = *hash; | 2063 | *(struct GNUNET_HashCode *) &demands[1] = *hash; |
1898 | GNUNET_MQ_send (op->mq, ev); | 2064 | GNUNET_MQ_send (op->mq, ev); |
1899 | } | 2065 | } |
2066 | GNUNET_CADET_receive_done (op->channel); | ||
1900 | } | 2067 | } |
1901 | 2068 | ||
1902 | 2069 | ||
@@ -1906,16 +2073,22 @@ handle_p2p_offer (void *cls, | |||
1906 | * @param cls the union operation | 2073 | * @param cls the union operation |
1907 | * @param mh the message | 2074 | * @param mh the message |
1908 | */ | 2075 | */ |
1909 | static void | 2076 | void |
1910 | handle_p2p_done (void *cls, | 2077 | handle_union_p2p_done (void *cls, |
1911 | const struct GNUNET_MessageHeader *mh) | 2078 | const struct GNUNET_MessageHeader *mh) |
1912 | { | 2079 | { |
1913 | struct Operation *op = cls; | 2080 | struct Operation *op = cls; |
1914 | 2081 | ||
1915 | if (op->state->phase == PHASE_INVENTORY_PASSIVE) | 2082 | if (OT_UNION != op->type) |
1916 | { | 2083 | { |
2084 | GNUNET_break_op (0); | ||
2085 | fail_union_operation (op); | ||
2086 | return; | ||
2087 | } | ||
2088 | switch (op->state->phase) | ||
2089 | { | ||
2090 | case PHASE_INVENTORY_PASSIVE: | ||
1917 | /* We got all requests, but still have to send our elements in response. */ | 2091 | /* We got all requests, but still have to send our elements in response. */ |
1918 | |||
1919 | op->state->phase = PHASE_FINISH_WAITING; | 2092 | op->state->phase = PHASE_FINISH_WAITING; |
1920 | 2093 | ||
1921 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2094 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1929,11 +2102,10 @@ handle_p2p_done (void *cls, | |||
1929 | * all our demands are satisfied, so that the active | 2102 | * all our demands are satisfied, so that the active |
1930 | * peer can quit if we gave him everything. | 2103 | * peer can quit if we gave him everything. |
1931 | */ | 2104 | */ |
2105 | GNUNET_CADET_receive_done (op->channel); | ||
1932 | maybe_finish (op); | 2106 | maybe_finish (op); |
1933 | return; | 2107 | return; |
1934 | } | 2108 | case PHASE_INVENTORY_ACTIVE: |
1935 | if (op->state->phase == PHASE_INVENTORY_ACTIVE) | ||
1936 | { | ||
1937 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2109 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1938 | "got DONE (as active partner), waiting to finish\n"); | 2110 | "got DONE (as active partner), waiting to finish\n"); |
1939 | /* All demands of the other peer are satisfied, | 2111 | /* All demands of the other peer are satisfied, |
@@ -1944,11 +2116,14 @@ handle_p2p_done (void *cls, | |||
1944 | * to the other peer once our demands are met. | 2116 | * to the other peer once our demands are met. |
1945 | */ | 2117 | */ |
1946 | op->state->phase = PHASE_FINISH_CLOSING; | 2118 | op->state->phase = PHASE_FINISH_CLOSING; |
2119 | GNUNET_CADET_receive_done (op->channel); | ||
1947 | maybe_finish (op); | 2120 | maybe_finish (op); |
1948 | return; | 2121 | return; |
2122 | default: | ||
2123 | GNUNET_break_op (0); | ||
2124 | fail_union_operation (op); | ||
2125 | return; | ||
1949 | } | 2126 | } |
1950 | GNUNET_break_op (0); | ||
1951 | fail_union_operation (op); | ||
1952 | } | 2127 | } |
1953 | 2128 | ||
1954 | 2129 | ||
@@ -2119,62 +2294,6 @@ union_set_destroy (struct SetState *set_state) | |||
2119 | 2294 | ||
2120 | 2295 | ||
2121 | /** | 2296 | /** |
2122 | * Dispatch messages for a union operation. | ||
2123 | * | ||
2124 | * @param op the state of the union evaluate operation | ||
2125 | * @param mh the received message | ||
2126 | * @return #GNUNET_SYSERR if the tunnel should be disconnected, | ||
2127 | * #GNUNET_OK otherwise | ||
2128 | */ | ||
2129 | int | ||
2130 | union_handle_p2p_message (struct Operation *op, | ||
2131 | const struct GNUNET_MessageHeader *mh) | ||
2132 | { | ||
2133 | //LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2134 | // "received p2p message (t: %u, s: %u)\n", | ||
2135 | // ntohs (mh->type), | ||
2136 | // ntohs (mh->size)); | ||
2137 | switch (ntohs (mh->type)) | ||
2138 | { | ||
2139 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF: | ||
2140 | return handle_p2p_ibf (op, mh); | ||
2141 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE: | ||
2142 | return handle_p2p_strata_estimator (op, mh, GNUNET_NO); | ||
2143 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC: | ||
2144 | return handle_p2p_strata_estimator (op, mh, GNUNET_YES); | ||
2145 | case GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS: | ||
2146 | handle_p2p_elements (op, mh); | ||
2147 | break; | ||
2148 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT: | ||
2149 | handle_p2p_full_element (op, mh); | ||
2150 | break; | ||
2151 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY: | ||
2152 | handle_p2p_inquiry (op, mh); | ||
2153 | break; | ||
2154 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE: | ||
2155 | handle_p2p_done (op, mh); | ||
2156 | break; | ||
2157 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER: | ||
2158 | handle_p2p_offer (op, mh); | ||
2159 | break; | ||
2160 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND: | ||
2161 | handle_p2p_demand (op, mh); | ||
2162 | break; | ||
2163 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE: | ||
2164 | handle_p2p_full_done (op, mh); | ||
2165 | break; | ||
2166 | case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL: | ||
2167 | handle_p2p_request_full (op, mh); | ||
2168 | break; | ||
2169 | default: | ||
2170 | /* Something wrong with cadet's message handlers? */ | ||
2171 | GNUNET_assert (0); | ||
2172 | } | ||
2173 | return GNUNET_OK; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | /** | ||
2178 | * Handler for peer-disconnects, notifies the client | 2297 | * Handler for peer-disconnects, notifies the client |
2179 | * about the aborted operation in case the op was not concluded. | 2298 | * about the aborted operation in case the op was not concluded. |
2180 | * | 2299 | * |
@@ -2240,7 +2359,6 @@ _GSS_union_vt () | |||
2240 | { | 2359 | { |
2241 | static const struct SetVT union_vt = { | 2360 | static const struct SetVT union_vt = { |
2242 | .create = &union_set_create, | 2361 | .create = &union_set_create, |
2243 | .msg_handler = &union_handle_p2p_message, | ||
2244 | .add = &union_add, | 2362 | .add = &union_add, |
2245 | .remove = &union_remove, | 2363 | .remove = &union_remove, |
2246 | .destroy_set = &union_set_destroy, | 2364 | .destroy_set = &union_set_destroy, |
diff --git a/src/set/set_api.c b/src/set/set_api.c index 04a4e4910..bc428f9f6 100644 --- a/src/set/set_api.c +++ b/src/set/set_api.c | |||
@@ -76,6 +76,8 @@ struct GNUNET_SET_Handle | |||
76 | 76 | ||
77 | /** | 77 | /** |
78 | * Should the set be destroyed once all operations are gone? | 78 | * Should the set be destroyed once all operations are gone? |
79 | * #GNUNET_SYSERR if #GNUNET_SET_destroy() must raise this flag, | ||
80 | * #GNUNET_YES if #GNUNET_SET_destroy() did raise this flag. | ||
79 | */ | 81 | */ |
80 | int destroy_requested; | 82 | int destroy_requested; |
81 | 83 | ||
@@ -345,11 +347,13 @@ handle_iter_done (void *cls, | |||
345 | 347 | ||
346 | if (NULL == iter) | 348 | if (NULL == iter) |
347 | return; | 349 | return; |
350 | set->destroy_requested = GNUNET_SYSERR; | ||
348 | set->iterator = NULL; | 351 | set->iterator = NULL; |
349 | set->iteration_id++; | 352 | set->iteration_id++; |
350 | iter (set->iterator_cls, | 353 | iter (set->iterator_cls, |
351 | NULL); | 354 | NULL); |
352 | 355 | if (GNUNET_SYSERR == set->destroy_requested) | |
356 | set->destroy_requested = GNUNET_NO; | ||
353 | if (GNUNET_YES == set->destroy_requested) | 357 | if (GNUNET_YES == set->destroy_requested) |
354 | GNUNET_SET_destroy (set); | 358 | GNUNET_SET_destroy (set); |
355 | } | 359 | } |
@@ -736,7 +740,9 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set) | |||
736 | /* destroying set while iterator is active is currently | 740 | /* destroying set while iterator is active is currently |
737 | not supported; we should expand the API to allow | 741 | not supported; we should expand the API to allow |
738 | clients to explicitly cancel the iteration! */ | 742 | clients to explicitly cancel the iteration! */ |
739 | if ( (NULL != set->ops_head) || (NULL != set->iterator) ) | 743 | if ( (NULL != set->ops_head) || |
744 | (NULL != set->iterator) || | ||
745 | (GNUNET_SYSERR == set->destroy_requested) ) | ||
740 | { | 746 | { |
741 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 747 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
742 | "Set operations are pending, delaying set destruction\n"); | 748 | "Set operations are pending, delaying set destruction\n"); |
@@ -809,7 +815,7 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer, | |||
809 | msg->force_delta = GNUNET_YES; | 815 | msg->force_delta = GNUNET_YES; |
810 | break; | 816 | break; |
811 | default: | 817 | default: |
812 | LOG (GNUNET_ERROR_TYPE_ERROR, | 818 | LOG (GNUNET_ERROR_TYPE_ERROR, |
813 | "Option with type %d not recognized\n", (int) opt->type); | 819 | "Option with type %d not recognized\n", (int) opt->type); |
814 | } | 820 | } |
815 | } | 821 | } |
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c index c887a8958..a1eba6311 100644 --- a/src/set/test_set_union_copy.c +++ b/src/set/test_set_union_copy.c | |||
@@ -122,6 +122,7 @@ check_count_iter (void *cls, | |||
122 | return GNUNET_NO; | 122 | return GNUNET_NO; |
123 | } | 123 | } |
124 | ci_cls->cont (ci_cls->cont_cls); | 124 | ci_cls->cont (ci_cls->cont_cls); |
125 | GNUNET_free (ci_cls); | ||
125 | return GNUNET_NO; | 126 | return GNUNET_NO; |
126 | } | 127 | } |
127 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 128 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
diff --git a/src/sq/sq.c b/src/sq/sq.c index 114de2d88..089ebf0ff 100644 --- a/src/sq/sq.c +++ b/src/sq/sq.c | |||
@@ -90,7 +90,12 @@ GNUNET_SQ_extract_result (sqlite3_stmt *result, | |||
90 | j, | 90 | j, |
91 | rs[i].result_size, | 91 | rs[i].result_size, |
92 | rs[i].dst)) | 92 | rs[i].dst)) |
93 | { | ||
94 | for (unsigned int k=0;k<i;k++) | ||
95 | if (NULL != rs[k].cleaner) | ||
96 | rs[k].cleaner (rs[k].cls); | ||
93 | return GNUNET_SYSERR; | 97 | return GNUNET_SYSERR; |
98 | } | ||
94 | GNUNET_assert (0 != rs[i].num_params); | 99 | GNUNET_assert (0 != rs[i].num_params); |
95 | j += rs[i].num_params; | 100 | j += rs[i].num_params; |
96 | } | 101 | } |
@@ -112,4 +117,24 @@ GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs) | |||
112 | rs[i].cleaner (rs[i].cls); | 117 | rs[i].cleaner (rs[i].cls); |
113 | } | 118 | } |
114 | 119 | ||
120 | |||
121 | /** | ||
122 | * Reset @a stmt and log error. | ||
123 | * | ||
124 | * @param dbh database handle | ||
125 | * @param stmt statement to reset | ||
126 | */ | ||
127 | void | ||
128 | GNUNET_SQ_reset (sqlite3 *dbh, | ||
129 | sqlite3_stmt *stmt) | ||
130 | { | ||
131 | if (SQLITE_OK != | ||
132 | sqlite3_reset (stmt)) | ||
133 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
134 | "sqlite", | ||
135 | _("Failed to reset sqlite statement with error: %s\n"), | ||
136 | sqlite3_errmsg (dbh)); | ||
137 | } | ||
138 | |||
139 | |||
115 | /* end of sq.c */ | 140 | /* end of sq.c */ |
diff --git a/src/sq/sq_query_helper.c b/src/sq/sq_query_helper.c index 5529c5e6c..a04b4ced4 100644 --- a/src/sq/sq_query_helper.c +++ b/src/sq/sq_query_helper.c | |||
@@ -235,6 +235,40 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x) | |||
235 | 235 | ||
236 | 236 | ||
237 | /** | 237 | /** |
238 | * Function called to convert input argument into SQL parameters. | ||
239 | * | ||
240 | * @param cls closure | ||
241 | * @param data pointer to input argument | ||
242 | * @param data_len number of bytes in @a data (if applicable) | ||
243 | * @param stmt sqlite statement to bind parameters for | ||
244 | * @param off offset of the argument to bind in @a stmt, numbered from 1, | ||
245 | * so immediately suitable for passing to `sqlite3_bind`-functions. | ||
246 | * @return #GNUNET_SYSERR on error, #GNUNET_OK on success | ||
247 | */ | ||
248 | static int | ||
249 | bind_abstime (void *cls, | ||
250 | const void *data, | ||
251 | size_t data_len, | ||
252 | sqlite3_stmt *stmt, | ||
253 | unsigned int off) | ||
254 | { | ||
255 | const struct GNUNET_TIME_Absolute *u = data; | ||
256 | struct GNUNET_TIME_Absolute abs; | ||
257 | |||
258 | abs = *u; | ||
259 | if (abs.abs_value_us > INT64_MAX) | ||
260 | abs.abs_value_us = INT64_MAX; | ||
261 | GNUNET_assert (sizeof (uint64_t) == data_len); | ||
262 | if (SQLITE_OK != | ||
263 | sqlite3_bind_int64 (stmt, | ||
264 | (int) off, | ||
265 | (sqlite3_int64) abs.abs_value_us)) | ||
266 | return GNUNET_SYSERR; | ||
267 | return GNUNET_OK; | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
238 | * Generate query parameter for an absolute time value. | 272 | * Generate query parameter for an absolute time value. |
239 | * The database must store a 64-bit integer. | 273 | * The database must store a 64-bit integer. |
240 | * | 274 | * |
@@ -243,7 +277,13 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x) | |||
243 | struct GNUNET_SQ_QueryParam | 277 | struct GNUNET_SQ_QueryParam |
244 | GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x) | 278 | GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x) |
245 | { | 279 | { |
246 | return GNUNET_SQ_query_param_uint64 (&x->abs_value_us); | 280 | struct GNUNET_SQ_QueryParam qp = { |
281 | .conv = &bind_abstime, | ||
282 | .data = x, | ||
283 | .size = sizeof (struct GNUNET_TIME_Absolute), | ||
284 | .num_params = 1 | ||
285 | }; | ||
286 | return qp; | ||
247 | } | 287 | } |
248 | 288 | ||
249 | 289 | ||
@@ -269,6 +309,8 @@ bind_nbotime (void *cls, | |||
269 | struct GNUNET_TIME_Absolute abs; | 309 | struct GNUNET_TIME_Absolute abs; |
270 | 310 | ||
271 | abs = GNUNET_TIME_absolute_ntoh (*u); | 311 | abs = GNUNET_TIME_absolute_ntoh (*u); |
312 | if (abs.abs_value_us > INT64_MAX) | ||
313 | abs.abs_value_us = INT64_MAX; | ||
272 | GNUNET_assert (sizeof (uint64_t) == data_len); | 314 | GNUNET_assert (sizeof (uint64_t) == data_len); |
273 | if (SQLITE_OK != | 315 | if (SQLITE_OK != |
274 | sqlite3_bind_int64 (stmt, | 316 | sqlite3_bind_int64 (stmt, |
diff --git a/src/sq/sq_result_helper.c b/src/sq/sq_result_helper.c index eaf606aa4..fad3f3c8d 100644 --- a/src/sq/sq_result_helper.c +++ b/src/sq/sq_result_helper.c | |||
@@ -46,6 +46,15 @@ extract_var_blob (void *cls, | |||
46 | const void *ret; | 46 | const void *ret; |
47 | void **rdst = (void **) dst; | 47 | void **rdst = (void **) dst; |
48 | 48 | ||
49 | if (SQLITE_NULL == | ||
50 | sqlite3_column_type (result, | ||
51 | column)) | ||
52 | { | ||
53 | *rdst = NULL; | ||
54 | *dst_size = 0; | ||
55 | return GNUNET_YES; | ||
56 | } | ||
57 | |||
49 | if (SQLITE_BLOB != | 58 | if (SQLITE_BLOB != |
50 | sqlite3_column_type (result, | 59 | sqlite3_column_type (result, |
51 | column)) | 60 | column)) |
@@ -142,6 +151,14 @@ extract_fixed_blob (void *cls, | |||
142 | int have; | 151 | int have; |
143 | const void *ret; | 152 | const void *ret; |
144 | 153 | ||
154 | if ( (0 == *dst_size) && | ||
155 | (SQLITE_NULL == | ||
156 | sqlite3_column_type (result, | ||
157 | column)) ) | ||
158 | { | ||
159 | return GNUNET_YES; | ||
160 | } | ||
161 | |||
145 | if (SQLITE_BLOB != | 162 | if (SQLITE_BLOB != |
146 | sqlite3_column_type (result, | 163 | sqlite3_column_type (result, |
147 | column)) | 164 | column)) |
@@ -459,6 +476,45 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig) | |||
459 | 476 | ||
460 | 477 | ||
461 | /** | 478 | /** |
479 | * Extract absolute time value from a Postgres database @a result at row @a row. | ||
480 | * | ||
481 | * @param cls closure | ||
482 | * @param result where to extract data from | ||
483 | * @param column column to extract data from | ||
484 | * @param[in,out] dst_size where to store size of result, may be NULL | ||
485 | * @param[out] dst where to store the result | ||
486 | * @return | ||
487 | * #GNUNET_YES if all results could be extracted | ||
488 | * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) | ||
489 | */ | ||
490 | static int | ||
491 | extract_abs_time (void *cls, | ||
492 | sqlite3_stmt *result, | ||
493 | unsigned int column, | ||
494 | size_t *dst_size, | ||
495 | void *dst) | ||
496 | { | ||
497 | struct GNUNET_TIME_Absolute *u = dst; | ||
498 | struct GNUNET_TIME_Absolute t; | ||
499 | |||
500 | GNUNET_assert (sizeof (uint64_t) == *dst_size); | ||
501 | if (SQLITE_INTEGER != | ||
502 | sqlite3_column_type (result, | ||
503 | column)) | ||
504 | { | ||
505 | GNUNET_break (0); | ||
506 | return GNUNET_SYSERR; | ||
507 | } | ||
508 | t.abs_value_us = (uint64_t) sqlite3_column_int64 (result, | ||
509 | column); | ||
510 | if (INT64_MAX == t.abs_value_us) | ||
511 | t = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
512 | *u = t; | ||
513 | return GNUNET_OK; | ||
514 | } | ||
515 | |||
516 | |||
517 | /** | ||
462 | * Absolute time expected. | 518 | * Absolute time expected. |
463 | * | 519 | * |
464 | * @param[out] at where to store the result | 520 | * @param[out] at where to store the result |
@@ -467,7 +523,14 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig) | |||
467 | struct GNUNET_SQ_ResultSpec | 523 | struct GNUNET_SQ_ResultSpec |
468 | GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at) | 524 | GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at) |
469 | { | 525 | { |
470 | return GNUNET_SQ_result_spec_uint64 (&at->abs_value_us); | 526 | struct GNUNET_SQ_ResultSpec rs = { |
527 | .conv = &extract_abs_time, | ||
528 | .dst = at, | ||
529 | .dst_size = sizeof (struct GNUNET_TIME_Absolute), | ||
530 | .num_params = 1 | ||
531 | }; | ||
532 | |||
533 | return rs; | ||
471 | } | 534 | } |
472 | 535 | ||
473 | 536 | ||
@@ -503,6 +566,8 @@ extract_abs_time_nbo (void *cls, | |||
503 | } | 566 | } |
504 | t.abs_value_us = (uint64_t) sqlite3_column_int64 (result, | 567 | t.abs_value_us = (uint64_t) sqlite3_column_int64 (result, |
505 | column); | 568 | column); |
569 | if (INT64_MAX == t.abs_value_us) | ||
570 | t = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
506 | *u = GNUNET_TIME_absolute_hton (t); | 571 | *u = GNUNET_TIME_absolute_hton (t); |
507 | return GNUNET_OK; | 572 | return GNUNET_OK; |
508 | } | 573 | } |