diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-19 10:06:52 +0200 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-19 10:06:52 +0200 |
commit | 3bfe2d52dcac5df09783d82b3a80899ae5b5d69a (patch) | |
tree | fd082362504b71f71ee58db5d1c9b562b3b0203b /src/setu | |
parent | a93ccc1ebb57f50ce6e90c7f0e57a3e58020b05e (diff) | |
download | gnunet-3bfe2d52dcac5df09783d82b3a80899ae5b5d69a.tar.gz gnunet-3bfe2d52dcac5df09783d82b3a80899ae5b5d69a.zip |
BUILD: Move seti/setu to service
Diffstat (limited to 'src/setu')
-rw-r--r-- | src/setu/.gitignore | 7 | ||||
-rw-r--r-- | src/setu/Makefile.am | 106 | ||||
-rw-r--r-- | src/setu/gnunet-service-setu.c | 5460 | ||||
-rw-r--r-- | src/setu/gnunet-service-setu_protocol.h | 256 | ||||
-rw-r--r-- | src/setu/gnunet-service-setu_strata_estimator.c | 468 | ||||
-rw-r--r-- | src/setu/gnunet-service-setu_strata_estimator.h | 199 | ||||
-rw-r--r-- | src/setu/gnunet-setu-ibf-profiler.c | 308 | ||||
-rw-r--r-- | src/setu/gnunet-setu-profiler.c | 499 | ||||
-rw-r--r-- | src/setu/ibf.c | 585 | ||||
-rw-r--r-- | src/setu/ibf.h | 310 | ||||
-rw-r--r-- | src/setu/ibf_sim.c | 143 | ||||
-rw-r--r-- | src/setu/meson.build | 50 | ||||
-rw-r--r-- | src/setu/perf_setu_api.c | 473 | ||||
-rw-r--r-- | src/setu/plugin_block_setu_test.c | 195 | ||||
-rw-r--r-- | src/setu/setu.conf.in | 12 | ||||
-rw-r--r-- | src/setu/setu.h | 365 | ||||
-rw-r--r-- | src/setu/setu_api.c | 911 | ||||
-rw-r--r-- | src/setu/test_setu.conf | 32 | ||||
-rw-r--r-- | src/setu/test_setu_api.c | 360 |
19 files changed, 0 insertions, 10739 deletions
diff --git a/src/setu/.gitignore b/src/setu/.gitignore deleted file mode 100644 index 0ac10295e..000000000 --- a/src/setu/.gitignore +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | gnunet-setu-profiler | ||
2 | gnunet-service-setu | ||
3 | gnunet-setu-ibf-profiler | ||
4 | test_setu_api | ||
5 | test_setu_copy | ||
6 | test_setu_result_symmetric | ||
7 | perf_setu_api | ||
diff --git a/src/setu/Makefile.am b/src/setu/Makefile.am deleted file mode 100644 index f7f8ed394..000000000 --- a/src/setu/Makefile.am +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | plugindir = $(libdir)/gnunet | ||
9 | |||
10 | pkgcfg_DATA = \ | ||
11 | setu.conf | ||
12 | |||
13 | if USE_COVERAGE | ||
14 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
15 | endif | ||
16 | |||
17 | noinst_PROGRAMS = \ | ||
18 | gnunet-setu-ibf-profiler \ | ||
19 | gnunet-setu-profiler | ||
20 | |||
21 | libexec_PROGRAMS = \ | ||
22 | gnunet-service-setu | ||
23 | |||
24 | lib_LTLIBRARIES = \ | ||
25 | libgnunetsetu.la | ||
26 | |||
27 | gnunet_setu_profiler_SOURCES = \ | ||
28 | gnunet-setu-profiler.c | ||
29 | gnunet_setu_profiler_LDADD = \ | ||
30 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
31 | $(top_builddir)/src/service/statistics/libgnunetstatistics.la \ | ||
32 | libgnunetsetu.la \ | ||
33 | $(top_builddir)/src/service/testing/libgnunettesting.la \ | ||
34 | $(GN_LIBINTL) | ||
35 | |||
36 | |||
37 | gnunet_setu_ibf_profiler_SOURCES = \ | ||
38 | gnunet-setu-ibf-profiler.c \ | ||
39 | ibf.c | ||
40 | gnunet_setu_ibf_profiler_LDADD = \ | ||
41 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
42 | $(GN_LIBINTL) | ||
43 | |||
44 | gnunet_service_setu_SOURCES = \ | ||
45 | gnunet-service-setu.c gnunet-service-setu_protocol.h \ | ||
46 | ibf.c ibf.h \ | ||
47 | gnunet-service-setu_strata_estimator.c gnunet-service-setu_strata_estimator.h \ | ||
48 | gnunet-service-setu_protocol.h | ||
49 | gnunet_service_setu_LDADD = \ | ||
50 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
51 | $(top_builddir)/src/service/statistics/libgnunetstatistics.la \ | ||
52 | $(top_builddir)/src/service/core/libgnunetcore.la \ | ||
53 | $(top_builddir)/src/service/cadet/libgnunetcadet.la \ | ||
54 | $(top_builddir)/src/lib/block/libgnunetblock.la \ | ||
55 | libgnunetsetu.la \ | ||
56 | $(GN_LIBINTL) | ||
57 | |||
58 | libgnunetsetu_la_SOURCES = \ | ||
59 | setu_api.c setu.h | ||
60 | libgnunetsetu_la_LIBADD = \ | ||
61 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
62 | $(LTLIBINTL) | ||
63 | libgnunetsetu_la_LDFLAGS = \ | ||
64 | $(GN_LIB_LDFLAGS) | ||
65 | |||
66 | check_PROGRAMS = \ | ||
67 | # test_setu_api \ | ||
68 | # perf_setu_api | ||
69 | |||
70 | if ENABLE_TEST_RUN | ||
71 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
72 | TESTS = $(check_PROGRAMS) | ||
73 | endif | ||
74 | |||
75 | test_setu_api_SOURCES = \ | ||
76 | test_setu_api.c | ||
77 | test_setu_api_LDADD = \ | ||
78 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
79 | $(top_builddir)/src/service/testing/libgnunettesting.la \ | ||
80 | libgnunetsetu.la | ||
81 | |||
82 | |||
83 | perf_setu_api_SOURCES = \ | ||
84 | perf_setu_api.c | ||
85 | perf_setu_api_LDADD = \ | ||
86 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
87 | $(top_builddir)/src/service/testing/libgnunettesting.la \ | ||
88 | libgnunetsetu.la | ||
89 | |||
90 | |||
91 | plugin_LTLIBRARIES = \ | ||
92 | libgnunet_plugin_block_setu_test.la | ||
93 | |||
94 | libgnunet_plugin_block_setu_test_la_SOURCES = \ | ||
95 | plugin_block_setu_test.c | ||
96 | libgnunet_plugin_block_setu_test_la_LIBADD = \ | ||
97 | $(top_builddir)/src/lib/block/libgnunetblock.la \ | ||
98 | $(top_builddir)/src/lib/block/libgnunetblockgroup.la \ | ||
99 | $(top_builddir)/src/lib/util/libgnunetutil.la \ | ||
100 | $(LTLIBINTL) | ||
101 | libgnunet_plugin_block_setu_test_la_LDFLAGS = \ | ||
102 | $(GN_PLUGIN_LDFLAGS) | ||
103 | |||
104 | |||
105 | EXTRA_DIST = \ | ||
106 | test_setu.conf | ||
diff --git a/src/setu/gnunet-service-setu.c b/src/setu/gnunet-service-setu.c deleted file mode 100644 index 46d027cca..000000000 --- a/src/setu/gnunet-service-setu.c +++ /dev/null | |||
@@ -1,5460 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2013-2017, 2020 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file setu/gnunet-service-setu.c | ||
22 | * @brief set union operation | ||
23 | * @author Florian Dold | ||
24 | * @author Christian Grothoff | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_statistics_service.h" | ||
30 | #include "ibf.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include "gnunet_cadet_service.h" | ||
34 | #include "gnunet-service-setu_strata_estimator.h" | ||
35 | #include "gnunet-service-setu_protocol.h" | ||
36 | #include "gnunet_statistics_service.h" | ||
37 | #include <gcrypt.h> | ||
38 | #include "gnunet_setu_service.h" | ||
39 | #include "setu.h" | ||
40 | |||
41 | #define LOG(kind, ...) GNUNET_log_from (kind, "setu", __VA_ARGS__) | ||
42 | |||
43 | /** | ||
44 | * How long do we hold on to an incoming channel if there is | ||
45 | * no local listener before giving up? | ||
46 | */ | ||
47 | #define INCOMING_CHANNEL_TIMEOUT GNUNET_TIME_UNIT_MINUTES | ||
48 | |||
49 | /** | ||
50 | * Number of IBFs in a strata estimator. | ||
51 | */ | ||
52 | #define SE_STRATA_COUNT 32 | ||
53 | |||
54 | |||
55 | /** | ||
56 | * Primes for all 4 different strata estimators 61,67,71,73,79,83,89,97 348 | ||
57 | * Based on the bsc thesis of Elias Summermatter (2021) | ||
58 | */ | ||
59 | #define SE_IBFS_TOTAL_SIZE 632 | ||
60 | |||
61 | /** | ||
62 | * The hash num parameter for the difference digests and strata estimators. | ||
63 | */ | ||
64 | #define SE_IBF_HASH_NUM 3 | ||
65 | |||
66 | /** | ||
67 | * Number of buckets that can be transmitted in one message. | ||
68 | */ | ||
69 | #define MAX_BUCKETS_PER_MESSAGE ((1 << 16) / IBF_BUCKET_SIZE) | ||
70 | |||
71 | /** | ||
72 | * The maximum size of an ibf we use is MAX_IBF_SIZE=2^20. | ||
73 | * Choose this value so that computing the IBF is still cheaper | ||
74 | * than transmitting all values. | ||
75 | */ | ||
76 | #define MAX_IBF_SIZE 1048576 | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Minimal size of an ibf | ||
81 | * Based on the bsc thesis of Elias Summermatter (2021) | ||
82 | */ | ||
83 | #define IBF_MIN_SIZE 37 | ||
84 | |||
85 | /** | ||
86 | * AVG RTT for differential sync when k=2 and Factor = 2 | ||
87 | * Based on the bsc thesis of Elias Summermatter (2021) | ||
88 | */ | ||
89 | #define DIFFERENTIAL_RTT_MEAN 3.65145 | ||
90 | |||
91 | /** | ||
92 | * Security level used for byzantine checks (2^80) | ||
93 | */ | ||
94 | |||
95 | #define SECURITY_LEVEL 80 | ||
96 | |||
97 | /** | ||
98 | * Is the estimated probability for a new round this values | ||
99 | * is based on the bsc thesis of Elias Summermatter (2021) | ||
100 | */ | ||
101 | |||
102 | #define PROBABILITY_FOR_NEW_ROUND 0.15 | ||
103 | |||
104 | /** | ||
105 | * Measure the performance in a csv | ||
106 | */ | ||
107 | |||
108 | #define MEASURE_PERFORMANCE 0 | ||
109 | |||
110 | |||
111 | /** | ||
112 | * Current phase we are in for a union operation. | ||
113 | */ | ||
114 | enum UnionOperationPhase | ||
115 | { | ||
116 | /** | ||
117 | * We sent the request message, and expect a strata estimator. | ||
118 | */ | ||
119 | PHASE_EXPECT_SE, | ||
120 | |||
121 | /** | ||
122 | * We sent the strata estimator, and expect an IBF. This phase is entered once | ||
123 | * upon initialization and later via #PHASE_EXPECT_ELEMENTS_AND_REQUESTS. | ||
124 | * | ||
125 | * XXX: could use better wording. | ||
126 | * XXX: repurposed to also expect a "request full set" message, should be renamed | ||
127 | * | ||
128 | * After receiving the complete IBF, we enter #PHASE_EXPECT_ELEMENTS | ||
129 | */ | ||
130 | PHASE_EXPECT_IBF, | ||
131 | |||
132 | /** | ||
133 | * Continuation for multi part IBFs. | ||
134 | */ | ||
135 | PHASE_EXPECT_IBF_LAST, | ||
136 | |||
137 | /** | ||
138 | * We are decoding an IBF. | ||
139 | */ | ||
140 | PHASE_ACTIVE_DECODING, | ||
141 | |||
142 | /** | ||
143 | * The other peer is decoding the IBF we just sent. | ||
144 | */ | ||
145 | PHASE_PASSIVE_DECODING, | ||
146 | |||
147 | /** | ||
148 | * The protocol is almost finished, but we still have to flush our message | ||
149 | * queue and/or expect some elements. | ||
150 | */ | ||
151 | PHASE_FINISH_CLOSING, | ||
152 | |||
153 | /** | ||
154 | * In the penultimate phase, we wait until all our demands are satisfied. | ||
155 | * Then we send a done message, and wait for another done message. | ||
156 | */ | ||
157 | PHASE_FINISH_WAITING, | ||
158 | |||
159 | /** | ||
160 | * In the ultimate phase, we wait until our demands are satisfied and then | ||
161 | * quit (sending another DONE message). | ||
162 | */ | ||
163 | PHASE_FINISHED, | ||
164 | |||
165 | /** | ||
166 | * After sending the full set, wait for responses with the elements | ||
167 | * that the local peer is missing. | ||
168 | */ | ||
169 | PHASE_FULL_SENDING, | ||
170 | |||
171 | /** | ||
172 | * Phase that receives full set first and then sends elements that are | ||
173 | * the local peer missing | ||
174 | */ | ||
175 | PHASE_FULL_RECEIVING | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * Different modes of operations | ||
180 | */ | ||
181 | |||
182 | enum MODE_OF_OPERATION | ||
183 | { | ||
184 | /** | ||
185 | * Mode just synchronizes the difference between sets | ||
186 | */ | ||
187 | DIFFERENTIAL_SYNC, | ||
188 | |||
189 | /** | ||
190 | * Mode send full set sending local set first | ||
191 | */ | ||
192 | FULL_SYNC_LOCAL_SENDING_FIRST, | ||
193 | |||
194 | /** | ||
195 | * Mode request full set from remote peer | ||
196 | */ | ||
197 | FULL_SYNC_REMOTE_SENDING_FIRST | ||
198 | }; | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Information about an element element in the set. All elements are | ||
203 | * stored in a hash-table from their hash-code to their `struct | ||
204 | * Element`, so that the remove and add operations are reasonably | ||
205 | * fast. | ||
206 | */ | ||
207 | struct ElementEntry | ||
208 | { | ||
209 | /** | ||
210 | * The actual element. The data for the element | ||
211 | * should be allocated at the end of this struct. | ||
212 | */ | ||
213 | struct GNUNET_SETU_Element element; | ||
214 | |||
215 | /** | ||
216 | * Hash of the element. For set union: Will be used to derive the | ||
217 | * different IBF keys for different salts. | ||
218 | */ | ||
219 | struct GNUNET_HashCode element_hash; | ||
220 | |||
221 | /** | ||
222 | * First generation that includes this element. | ||
223 | */ | ||
224 | unsigned int generation; | ||
225 | |||
226 | /** | ||
227 | * #GNUNET_YES if the element is a remote element, and does not belong | ||
228 | * to the operation's set. | ||
229 | */ | ||
230 | int remote; | ||
231 | }; | ||
232 | |||
233 | |||
234 | /** | ||
235 | * A listener is inhabited by a client, and waits for evaluation | ||
236 | * requests from remote peers. | ||
237 | */ | ||
238 | struct Listener; | ||
239 | |||
240 | |||
241 | /** | ||
242 | * A set that supports a specific operation with other peers. | ||
243 | */ | ||
244 | struct Set; | ||
245 | |||
246 | |||
247 | /** | ||
248 | * State we keep per client. | ||
249 | */ | ||
250 | struct ClientState | ||
251 | { | ||
252 | /** | ||
253 | * Set, if associated with the client, otherwise NULL. | ||
254 | */ | ||
255 | struct Set *set; | ||
256 | |||
257 | /** | ||
258 | * Listener, if associated with the client, otherwise NULL. | ||
259 | */ | ||
260 | struct Listener *listener; | ||
261 | |||
262 | /** | ||
263 | * Client handle. | ||
264 | */ | ||
265 | struct GNUNET_SERVICE_Client *client; | ||
266 | |||
267 | /** | ||
268 | * Message queue. | ||
269 | */ | ||
270 | struct GNUNET_MQ_Handle *mq; | ||
271 | }; | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Operation context used to execute a set operation. | ||
276 | */ | ||
277 | struct Operation | ||
278 | { | ||
279 | |||
280 | /** | ||
281 | * The identity of the requesting peer. Needs to | ||
282 | * be stored here as the op spec might not have been created yet. | ||
283 | */ | ||
284 | struct GNUNET_PeerIdentity peer; | ||
285 | |||
286 | /** | ||
287 | * Initial size of our set, just before the operation started. | ||
288 | */ | ||
289 | uint64_t initial_size; | ||
290 | |||
291 | /** | ||
292 | * Kept in a DLL of the listener, if @e listener is non-NULL. | ||
293 | */ | ||
294 | struct Operation *next; | ||
295 | |||
296 | /** | ||
297 | * Kept in a DLL of the listener, if @e listener is non-NULL. | ||
298 | */ | ||
299 | struct Operation *prev; | ||
300 | |||
301 | /** | ||
302 | * Channel to the peer. | ||
303 | */ | ||
304 | struct GNUNET_CADET_Channel *channel; | ||
305 | |||
306 | /** | ||
307 | * Port this operation runs on. | ||
308 | */ | ||
309 | struct Listener *listener; | ||
310 | |||
311 | /** | ||
312 | * Message queue for the channel. | ||
313 | */ | ||
314 | struct GNUNET_MQ_Handle *mq; | ||
315 | |||
316 | /** | ||
317 | * Context message, may be NULL. | ||
318 | */ | ||
319 | struct GNUNET_MessageHeader *context_msg; | ||
320 | |||
321 | /** | ||
322 | * Set associated with the operation, NULL until the spec has been | ||
323 | * associated with a set. | ||
324 | */ | ||
325 | struct Set *set; | ||
326 | |||
327 | /** | ||
328 | * Copy of the set's strata estimator at the time of | ||
329 | * creation of this operation. | ||
330 | */ | ||
331 | struct MultiStrataEstimator *se; | ||
332 | |||
333 | /** | ||
334 | * The IBF we currently receive. | ||
335 | */ | ||
336 | struct InvertibleBloomFilter *remote_ibf; | ||
337 | |||
338 | /** | ||
339 | * The IBF with the local set's element. | ||
340 | */ | ||
341 | struct InvertibleBloomFilter *local_ibf; | ||
342 | |||
343 | /** | ||
344 | * Maps unsalted IBF-Keys to elements. | ||
345 | * Used as a multihashmap, the keys being the lower 32bit of the IBF-Key. | ||
346 | * Colliding IBF-Keys are linked. | ||
347 | */ | ||
348 | struct GNUNET_CONTAINER_MultiHashMap32 *key_to_element; | ||
349 | |||
350 | /** | ||
351 | * Timeout task, if the incoming peer has not been accepted | ||
352 | * after the timeout, it will be disconnected. | ||
353 | */ | ||
354 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
355 | |||
356 | /** | ||
357 | * Hashes for elements that we have demanded from the other peer. | ||
358 | */ | ||
359 | struct GNUNET_CONTAINER_MultiHashMap *demanded_hashes; | ||
360 | |||
361 | /** | ||
362 | * Current state of the operation. | ||
363 | */ | ||
364 | enum UnionOperationPhase phase; | ||
365 | |||
366 | /** | ||
367 | * Did we send the client that we are done? | ||
368 | */ | ||
369 | int client_done_sent; | ||
370 | |||
371 | /** | ||
372 | * Number of ibf buckets already received into the @a remote_ibf. | ||
373 | */ | ||
374 | uint64_t ibf_buckets_received; | ||
375 | |||
376 | /** | ||
377 | * Salt that we're using for sending IBFs | ||
378 | */ | ||
379 | uint32_t salt_send; | ||
380 | |||
381 | /** | ||
382 | * Salt for the IBF we've received and that we're currently decoding. | ||
383 | */ | ||
384 | uint32_t salt_receive; | ||
385 | |||
386 | /** | ||
387 | * Number of elements we received from the other peer | ||
388 | * that were not in the local set yet. | ||
389 | */ | ||
390 | uint32_t received_fresh; | ||
391 | |||
392 | /** | ||
393 | * Total number of elements received from the other peer. | ||
394 | */ | ||
395 | uint32_t received_total; | ||
396 | |||
397 | /** | ||
398 | * Salt to use for the operation. | ||
399 | */ | ||
400 | uint32_t salt; | ||
401 | |||
402 | /** | ||
403 | * Remote peers element count | ||
404 | */ | ||
405 | uint32_t remote_element_count; | ||
406 | |||
407 | /** | ||
408 | * ID used to identify an operation between service and client | ||
409 | */ | ||
410 | uint32_t client_request_id; | ||
411 | |||
412 | /** | ||
413 | * Always use delta operation instead of sending full sets, | ||
414 | * even it it's less efficient. | ||
415 | */ | ||
416 | int force_delta; | ||
417 | |||
418 | /** | ||
419 | * Always send full sets, even if delta operations would | ||
420 | * be more efficient. | ||
421 | */ | ||
422 | int force_full; | ||
423 | |||
424 | /** | ||
425 | * #GNUNET_YES to fail operations where Byzantine faults | ||
426 | * are suspected | ||
427 | */ | ||
428 | int byzantine; | ||
429 | |||
430 | /** | ||
431 | * #GNUNET_YES to also send back set elements we are sending to | ||
432 | * the remote peer. | ||
433 | */ | ||
434 | int symmetric; | ||
435 | |||
436 | /** | ||
437 | * Lower bound for the set size, used only when | ||
438 | * byzantine mode is enabled. | ||
439 | */ | ||
440 | uint64_t byzantine_lower_bound; | ||
441 | |||
442 | /** | ||
443 | * Unique request id for the request from a remote peer, sent to the | ||
444 | * client, which will accept or reject the request. Set to '0' iff | ||
445 | * the request has not been suggested yet. | ||
446 | */ | ||
447 | uint32_t suggest_id; | ||
448 | |||
449 | /** | ||
450 | * Generation in which the operation handle | ||
451 | * was created. | ||
452 | */ | ||
453 | unsigned int generation_created; | ||
454 | |||
455 | |||
456 | /** | ||
457 | * User defined Bandwidth Round Trips Tradeoff | ||
458 | */ | ||
459 | uint64_t rtt_bandwidth_tradeoff; | ||
460 | |||
461 | |||
462 | /** | ||
463 | * Number of Element per bucket in IBF | ||
464 | */ | ||
465 | uint8_t ibf_number_buckets_per_element; | ||
466 | |||
467 | |||
468 | /** | ||
469 | * Set difference is multiplied with this factor | ||
470 | * to gennerate large enough IBF | ||
471 | */ | ||
472 | uint8_t ibf_bucket_number_factor; | ||
473 | |||
474 | /** | ||
475 | * Defines which site a client is | ||
476 | * 0 = Initiating peer | ||
477 | * 1 = Receiving peer | ||
478 | */ | ||
479 | uint8_t peer_site; | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Local peer element count | ||
484 | */ | ||
485 | uint64_t local_element_count; | ||
486 | |||
487 | /** | ||
488 | * Mode of operation that was chosen by the algorithm | ||
489 | */ | ||
490 | uint8_t mode_of_operation; | ||
491 | |||
492 | /** | ||
493 | * Hashmap to keep track of the send/received messages | ||
494 | */ | ||
495 | struct GNUNET_CONTAINER_MultiHashMap *message_control_flow; | ||
496 | |||
497 | /** | ||
498 | * Hashmap to keep track of the send/received inquiries (ibf keys) | ||
499 | */ | ||
500 | struct GNUNET_CONTAINER_MultiHashMap *inquiries_sent; | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Total size of local set | ||
505 | */ | ||
506 | uint64_t total_elements_size_local; | ||
507 | |||
508 | /** | ||
509 | * Limit of number of elements in set | ||
510 | */ | ||
511 | uint64_t byzantine_upper_bound; | ||
512 | |||
513 | /** | ||
514 | * is the count of already passed differential sync iterations | ||
515 | */ | ||
516 | uint8_t differential_sync_iterations; | ||
517 | |||
518 | /** | ||
519 | * Estimated or committed set difference at the start | ||
520 | */ | ||
521 | uint64_t remote_set_diff; | ||
522 | |||
523 | /** | ||
524 | * Estimated or committed set difference at the start | ||
525 | */ | ||
526 | uint64_t local_set_diff; | ||
527 | |||
528 | /** | ||
529 | * Boolean to enforce an active passive switch | ||
530 | */ | ||
531 | bool active_passive_switch_required; | ||
532 | }; | ||
533 | |||
534 | |||
535 | /** | ||
536 | * SetContent stores the actual set elements, which may be shared by | ||
537 | * multiple generations derived from one set. | ||
538 | */ | ||
539 | struct SetContent | ||
540 | { | ||
541 | /** | ||
542 | * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`. | ||
543 | */ | ||
544 | struct GNUNET_CONTAINER_MultiHashMap *elements; | ||
545 | |||
546 | /** | ||
547 | * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *` randomized. | ||
548 | */ | ||
549 | struct GNUNET_CONTAINER_MultiHashMap *elements_randomized; | ||
550 | |||
551 | /** | ||
552 | * Salt to construct the randomized element map | ||
553 | */ | ||
554 | uint64_t elements_randomized_salt; | ||
555 | |||
556 | /** | ||
557 | * Number of references to the content. | ||
558 | */ | ||
559 | unsigned int refcount; | ||
560 | |||
561 | /** | ||
562 | * FIXME: document! | ||
563 | */ | ||
564 | unsigned int latest_generation; | ||
565 | |||
566 | /** | ||
567 | * Number of concurrently active iterators. | ||
568 | */ | ||
569 | int iterator_count; | ||
570 | }; | ||
571 | |||
572 | |||
573 | /** | ||
574 | * A set that supports a specific operation with other peers. | ||
575 | */ | ||
576 | struct Set | ||
577 | { | ||
578 | /** | ||
579 | * Sets are held in a doubly linked list (in `sets_head` and `sets_tail`). | ||
580 | */ | ||
581 | struct Set *next; | ||
582 | |||
583 | /** | ||
584 | * Sets are held in a doubly linked list. | ||
585 | */ | ||
586 | struct Set *prev; | ||
587 | |||
588 | /** | ||
589 | * Client that owns the set. Only one client may own a set, | ||
590 | * and there can only be one set per client. | ||
591 | */ | ||
592 | struct ClientState *cs; | ||
593 | |||
594 | /** | ||
595 | * Content, possibly shared by multiple sets, | ||
596 | * and thus reference counted. | ||
597 | */ | ||
598 | struct SetContent *content; | ||
599 | |||
600 | /** | ||
601 | * The strata estimator is only generated once for each set. The IBF keys | ||
602 | * are derived from the element hashes with salt=0. | ||
603 | */ | ||
604 | struct MultiStrataEstimator *se; | ||
605 | |||
606 | /** | ||
607 | * Evaluate operations are held in a linked list. | ||
608 | */ | ||
609 | struct Operation *ops_head; | ||
610 | |||
611 | /** | ||
612 | * Evaluate operations are held in a linked list. | ||
613 | */ | ||
614 | struct Operation *ops_tail; | ||
615 | |||
616 | /** | ||
617 | * Current generation, that is, number of previously executed | ||
618 | * operations and lazy copies on the underlying set content. | ||
619 | */ | ||
620 | unsigned int current_generation; | ||
621 | |||
622 | }; | ||
623 | |||
624 | |||
625 | /** | ||
626 | * The key entry is used to associate an ibf key with an element. | ||
627 | */ | ||
628 | struct KeyEntry | ||
629 | { | ||
630 | /** | ||
631 | * IBF key for the entry, derived from the current salt. | ||
632 | */ | ||
633 | struct IBF_Key ibf_key; | ||
634 | |||
635 | /** | ||
636 | * The actual element associated with the key. | ||
637 | * | ||
638 | * Only owned by the union operation if element->operation | ||
639 | * is #GNUNET_YES. | ||
640 | */ | ||
641 | struct ElementEntry *element; | ||
642 | |||
643 | /** | ||
644 | * Did we receive this element? Even if element->is_foreign is false, we | ||
645 | * might have received the element, so this indicates that the other peer | ||
646 | * has it. | ||
647 | */ | ||
648 | int received; | ||
649 | }; | ||
650 | |||
651 | |||
652 | /** | ||
653 | * Used as a closure for sending elements | ||
654 | * with a specific IBF key. | ||
655 | */ | ||
656 | struct SendElementClosure | ||
657 | { | ||
658 | /** | ||
659 | * The IBF key whose matching elements should be | ||
660 | * sent. | ||
661 | */ | ||
662 | struct IBF_Key ibf_key; | ||
663 | |||
664 | /** | ||
665 | * Operation for which the elements | ||
666 | * should be sent. | ||
667 | */ | ||
668 | struct Operation *op; | ||
669 | }; | ||
670 | |||
671 | |||
672 | /** | ||
673 | * A listener is inhabited by a client, and waits for evaluation | ||
674 | * requests from remote peers. | ||
675 | */ | ||
676 | struct Listener | ||
677 | { | ||
678 | /** | ||
679 | * Listeners are held in a doubly linked list. | ||
680 | */ | ||
681 | struct Listener *next; | ||
682 | |||
683 | /** | ||
684 | * Listeners are held in a doubly linked list. | ||
685 | */ | ||
686 | struct Listener *prev; | ||
687 | |||
688 | /** | ||
689 | * Head of DLL of operations this listener is responsible for. | ||
690 | * Once the client has accepted/declined the operation, the | ||
691 | * operation is moved to the respective set's operation DLLS. | ||
692 | */ | ||
693 | struct Operation *op_head; | ||
694 | |||
695 | /** | ||
696 | * Tail of DLL of operations this listener is responsible for. | ||
697 | * Once the client has accepted/declined the operation, the | ||
698 | * operation is moved to the respective set's operation DLLS. | ||
699 | */ | ||
700 | struct Operation *op_tail; | ||
701 | |||
702 | /** | ||
703 | * Client that owns the listener. | ||
704 | * Only one client may own a listener. | ||
705 | */ | ||
706 | struct ClientState *cs; | ||
707 | |||
708 | /** | ||
709 | * The port we are listening on with CADET. | ||
710 | */ | ||
711 | struct GNUNET_CADET_Port *open_port; | ||
712 | |||
713 | /** | ||
714 | * Application ID for the operation, used to distinguish | ||
715 | * multiple operations of the same type with the same peer. | ||
716 | */ | ||
717 | struct GNUNET_HashCode app_id; | ||
718 | |||
719 | }; | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Handle to the cadet service, used to listen for and connect to | ||
724 | * remote peers. | ||
725 | */ | ||
726 | static struct GNUNET_CADET_Handle *cadet; | ||
727 | |||
728 | /** | ||
729 | * Statistics handle. | ||
730 | */ | ||
731 | static struct GNUNET_STATISTICS_Handle *_GSS_statistics; | ||
732 | |||
733 | /** | ||
734 | * Listeners are held in a doubly linked list. | ||
735 | */ | ||
736 | static struct Listener *listener_head; | ||
737 | |||
738 | /** | ||
739 | * Listeners are held in a doubly linked list. | ||
740 | */ | ||
741 | static struct Listener *listener_tail; | ||
742 | |||
743 | /** | ||
744 | * Number of active clients. | ||
745 | */ | ||
746 | static unsigned int num_clients; | ||
747 | |||
748 | /** | ||
749 | * Are we in shutdown? if #GNUNET_YES and the number of clients | ||
750 | * drops to zero, disconnect from CADET. | ||
751 | */ | ||
752 | static int in_shutdown; | ||
753 | |||
754 | /** | ||
755 | * Counter for allocating unique IDs for clients, used to identify incoming | ||
756 | * operation requests from remote peers, that the client can choose to accept | ||
757 | * or refuse. 0 must not be used (reserved for uninitialized). | ||
758 | */ | ||
759 | static uint32_t suggest_id; | ||
760 | |||
761 | #if MEASURE_PERFORMANCE | ||
762 | /** | ||
763 | * Handles configuration file for setu performance test | ||
764 | * | ||
765 | */ | ||
766 | static const struct GNUNET_CONFIGURATION_Handle *setu_cfg; | ||
767 | |||
768 | |||
769 | /** | ||
770 | * Stores the performance data for induvidual message | ||
771 | */ | ||
772 | |||
773 | |||
774 | struct perf_num_send_received_msg | ||
775 | { | ||
776 | uint64_t sent; | ||
777 | uint64_t sent_var_bytes; | ||
778 | uint64_t received; | ||
779 | uint64_t received_var_bytes; | ||
780 | }; | ||
781 | |||
782 | /** | ||
783 | * Main struct to measure performance (data/rtts) | ||
784 | */ | ||
785 | struct per_store_struct | ||
786 | { | ||
787 | struct perf_num_send_received_msg operation_request; | ||
788 | struct perf_num_send_received_msg se; | ||
789 | struct perf_num_send_received_msg request_full; | ||
790 | struct perf_num_send_received_msg element_full; | ||
791 | struct perf_num_send_received_msg full_done; | ||
792 | struct perf_num_send_received_msg ibf; | ||
793 | struct perf_num_send_received_msg inquery; | ||
794 | struct perf_num_send_received_msg element; | ||
795 | struct perf_num_send_received_msg demand; | ||
796 | struct perf_num_send_received_msg offer; | ||
797 | struct perf_num_send_received_msg done; | ||
798 | struct perf_num_send_received_msg over; | ||
799 | uint64_t se_diff; | ||
800 | uint64_t se_diff_remote; | ||
801 | uint64_t se_diff_local; | ||
802 | uint64_t active_passive_switches; | ||
803 | uint8_t mode_of_operation; | ||
804 | }; | ||
805 | |||
806 | struct per_store_struct perf_store; | ||
807 | #endif | ||
808 | |||
809 | /** | ||
810 | * Different states to control the messages flow in differential mode | ||
811 | */ | ||
812 | |||
813 | enum MESSAGE_CONTROL_FLOW_STATE | ||
814 | { | ||
815 | /** | ||
816 | * Initial message state | ||
817 | */ | ||
818 | MSG_CFS_UNINITIALIZED, | ||
819 | |||
820 | /** | ||
821 | * Track that a message has been sent | ||
822 | */ | ||
823 | MSG_CFS_SENT, | ||
824 | |||
825 | /** | ||
826 | * Track that receiving this message is expected | ||
827 | */ | ||
828 | MSG_CFS_EXPECTED, | ||
829 | |||
830 | /** | ||
831 | * Track that message has been received | ||
832 | */ | ||
833 | MSG_CFS_RECEIVED, | ||
834 | }; | ||
835 | |||
836 | /** | ||
837 | * Message types to track in message control flow | ||
838 | */ | ||
839 | |||
840 | enum MESSAGE_TYPE | ||
841 | { | ||
842 | /** | ||
843 | * Offer message type | ||
844 | */ | ||
845 | OFFER_MESSAGE, | ||
846 | |||
847 | /** | ||
848 | * Demand message type | ||
849 | */ | ||
850 | DEMAND_MESSAGE, | ||
851 | |||
852 | /** | ||
853 | * Element message type | ||
854 | */ | ||
855 | ELEMENT_MESSAGE, | ||
856 | }; | ||
857 | |||
858 | |||
859 | /** | ||
860 | * Struct to tracked messages in message control flow | ||
861 | */ | ||
862 | struct messageControlFlowElement | ||
863 | { | ||
864 | /** | ||
865 | * Track the message control state of the offer message | ||
866 | */ | ||
867 | enum MESSAGE_CONTROL_FLOW_STATE offer; | ||
868 | /** | ||
869 | * Track the message control state of the demand message | ||
870 | */ | ||
871 | enum MESSAGE_CONTROL_FLOW_STATE demand; | ||
872 | /** | ||
873 | * Track the message control state of the element message | ||
874 | */ | ||
875 | enum MESSAGE_CONTROL_FLOW_STATE element; | ||
876 | }; | ||
877 | |||
878 | |||
879 | #if MEASURE_PERFORMANCE | ||
880 | |||
881 | /** | ||
882 | * Loads different configuration to perform performance tests | ||
883 | * | ||
884 | * @param op operation handle | ||
885 | */ | ||
886 | static void | ||
887 | load_config (struct Operation *op) | ||
888 | { | ||
889 | long long number; | ||
890 | float fl; | ||
891 | |||
892 | setu_cfg = GNUNET_CONFIGURATION_create (); | ||
893 | GNUNET_CONFIGURATION_load (setu_cfg, | ||
894 | "perf_setu.conf"); | ||
895 | GNUNET_CONFIGURATION_get_value_float (setu_cfg, | ||
896 | "IBF", | ||
897 | "BUCKET_NUMBER_FACTOR", | ||
898 | &fl); | ||
899 | op->ibf_bucket_number_factor = fl; | ||
900 | GNUNET_CONFIGURATION_get_value_number (setu_cfg, | ||
901 | "IBF", | ||
902 | "NUMBER_PER_BUCKET", | ||
903 | &number); | ||
904 | op->ibf_number_buckets_per_element = number; | ||
905 | GNUNET_CONFIGURATION_get_value_number (setu_cfg, | ||
906 | "PERFORMANCE", | ||
907 | "TRADEOFF", | ||
908 | &number); | ||
909 | op->rtt_bandwidth_tradeoff = number; | ||
910 | GNUNET_CONFIGURATION_get_value_number (setu_cfg, | ||
911 | "BOUNDARIES", | ||
912 | "UPPER_ELEMENT", | ||
913 | &number); | ||
914 | op->byzantine_upper_bound = number; | ||
915 | op->peer_site = 0; | ||
916 | } | ||
917 | |||
918 | |||
919 | /** | ||
920 | * Function to calculate total bytes used for performance measurement | ||
921 | * @param size | ||
922 | * @param perf_num_send_received_msg | ||
923 | * @return bytes used | ||
924 | */ | ||
925 | static int | ||
926 | sum_sent_received_bytes (uint64_t size, | ||
927 | struct perf_num_send_received_msg | ||
928 | perf_num_send_received_msg) | ||
929 | { | ||
930 | return (size * perf_num_send_received_msg.sent) | ||
931 | + (size * perf_num_send_received_msg.received) | ||
932 | + perf_num_send_received_msg.sent_var_bytes | ||
933 | + perf_num_send_received_msg.received_var_bytes; | ||
934 | } | ||
935 | |||
936 | |||
937 | /** | ||
938 | * Function that calculates the perfmance values and writes them down | ||
939 | */ | ||
940 | static void | ||
941 | calculate_perf_store () | ||
942 | { | ||
943 | |||
944 | /** | ||
945 | * Calculate RTT of init phase normally always 1 | ||
946 | */ | ||
947 | float rtt = 1; | ||
948 | int bytes_transmitted = 0; | ||
949 | |||
950 | /** | ||
951 | * Calculate RGNUNET_SETU_AcceptMessageRT of Fullsync normally 1 or 1.5 depending | ||
952 | */ | ||
953 | if ((perf_store.element_full.received != 0) || | ||
954 | (perf_store.element_full.sent != 0) | ||
955 | ) | ||
956 | rtt += 1; | ||
957 | |||
958 | if ((perf_store.request_full.received != 0) || | ||
959 | (perf_store.request_full.sent != 0) | ||
960 | ) | ||
961 | rtt += 0.5; | ||
962 | |||
963 | /** | ||
964 | * In case of a differential sync 3 rtt's are needed. | ||
965 | * for every active/passive switch additional 3.5 rtt's are used | ||
966 | */ | ||
967 | if ((perf_store.element.received != 0) || | ||
968 | (perf_store.element.sent != 0)) | ||
969 | { | ||
970 | int iterations = perf_store.active_passive_switches; | ||
971 | |||
972 | if (iterations > 0) | ||
973 | rtt += iterations * 0.5; | ||
974 | rtt += 2.5; | ||
975 | } | ||
976 | |||
977 | |||
978 | /** | ||
979 | * Calculate data sended size | ||
980 | */ | ||
981 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
982 | GNUNET_SETU_ResultMessage), | ||
983 | perf_store.request_full); | ||
984 | |||
985 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
986 | GNUNET_SETU_ElementMessage), | ||
987 | perf_store.element_full); | ||
988 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
989 | GNUNET_SETU_ElementMessage), | ||
990 | perf_store.element); | ||
991 | // bytes_transmitted += sum_sent_received_bytes(sizeof(GNUNET_MESSAGE_TYPE_SETU_P2P_OPERATION_REQUEST), perf_store.operation_request); | ||
992 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
993 | StrataEstimatorMessage), | ||
994 | perf_store.se); | ||
995 | bytes_transmitted += sum_sent_received_bytes (4, perf_store.full_done); | ||
996 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct IBFMessage), | ||
997 | perf_store.ibf); | ||
998 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct InquiryMessage), | ||
999 | perf_store.inquery); | ||
1000 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
1001 | GNUNET_MessageHeader), | ||
1002 | perf_store.demand); | ||
1003 | bytes_transmitted += sum_sent_received_bytes (sizeof(struct | ||
1004 | GNUNET_MessageHeader), | ||
1005 | perf_store.offer); | ||
1006 | bytes_transmitted += sum_sent_received_bytes (4, perf_store.done); | ||
1007 | |||
1008 | /** | ||
1009 | * Write IBF failure rate for different BUCKET_NUMBER_FACTOR | ||
1010 | */ | ||
1011 | float factor; | ||
1012 | GNUNET_CONFIGURATION_get_value_float (setu_cfg,"IBF", "BUCKET_NUMBER_FACTOR", | ||
1013 | &factor); | ||
1014 | long long num_per_bucket; | ||
1015 | GNUNET_CONFIGURATION_get_value_number (setu_cfg,"IBF", "NUMBER_PER_BUCKET", | ||
1016 | &num_per_bucket); | ||
1017 | |||
1018 | |||
1019 | int decoded = 0; | ||
1020 | if (perf_store.active_passive_switches == 0) | ||
1021 | decoded = 1; | ||
1022 | int ibf_bytes_transmitted = sum_sent_received_bytes (sizeof(struct | ||
1023 | IBFMessage), | ||
1024 | perf_store.ibf); | ||
1025 | |||
1026 | FILE *out1 = fopen ("perf_data.csv", "a"); | ||
1027 | fprintf (out1, "%d,%f,%d,%d,%f,%d,%d,%d,%d,%d\n",num_per_bucket,factor, | ||
1028 | decoded,ibf_bytes_transmitted,rtt,perf_store.se_diff, | ||
1029 | bytes_transmitted, | ||
1030 | perf_store.se_diff_local,perf_store.se_diff_remote, | ||
1031 | perf_store.mode_of_operation); | ||
1032 | fclose (out1); | ||
1033 | |||
1034 | } | ||
1035 | |||
1036 | |||
1037 | #endif | ||
1038 | /** | ||
1039 | * Function that chooses the optimal mode of operation depending on | ||
1040 | * operation parameters. | ||
1041 | * @param avg_element_size | ||
1042 | * @param local_set_size | ||
1043 | * @param remote_set_size | ||
1044 | * @param est_set_diff_remote | ||
1045 | * @param est_set_diff_local | ||
1046 | * @param bandwith_latency_tradeoff | ||
1047 | * @param ibf_bucket_number_factor | ||
1048 | * @return calcuated mode of operation | ||
1049 | */ | ||
1050 | static uint8_t | ||
1051 | estimate_best_mode_of_operation (uint64_t avg_element_size, | ||
1052 | uint64_t local_set_size, | ||
1053 | uint64_t remote_set_size, | ||
1054 | uint64_t est_set_diff_remote, | ||
1055 | uint64_t est_set_diff_local, | ||
1056 | uint64_t bandwith_latency_tradeoff, | ||
1057 | uint64_t ibf_bucket_number_factor) | ||
1058 | { | ||
1059 | |||
1060 | /* | ||
1061 | * In case of initial sync fall to predefined states | ||
1062 | */ | ||
1063 | |||
1064 | if (0 == local_set_size) | ||
1065 | return FULL_SYNC_REMOTE_SENDING_FIRST; | ||
1066 | if (0 == remote_set_size) | ||
1067 | return FULL_SYNC_LOCAL_SENDING_FIRST; | ||
1068 | |||
1069 | /* | ||
1070 | * Calculate bytes for full Sync | ||
1071 | */ | ||
1072 | |||
1073 | uint8_t sizeof_full_done_header = 4; | ||
1074 | uint8_t sizeof_done_header = 4; | ||
1075 | uint8_t rtt_min_full = 2; | ||
1076 | uint8_t sizeof_request_full = 4; | ||
1077 | uint64_t estimated_total_diff = (est_set_diff_remote + est_set_diff_local); | ||
1078 | |||
1079 | /* Estimate byte required if we send first */ | ||
1080 | uint64_t total_elements_to_send_local_send_first = est_set_diff_remote | ||
1081 | + local_set_size; | ||
1082 | |||
1083 | uint64_t total_bytes_full_local_send_first = (avg_element_size | ||
1084 | * | ||
1085 | total_elements_to_send_local_send_first) \ | ||
1086 | + ( | ||
1087 | total_elements_to_send_local_send_first * sizeof(struct | ||
1088 | GNUNET_SETU_ElementMessage)) \ | ||
1089 | + (sizeof_full_done_header * 2) \ | ||
1090 | + rtt_min_full | ||
1091 | * bandwith_latency_tradeoff; | ||
1092 | |||
1093 | /* Estimate bytes required if we request from remote peer */ | ||
1094 | uint64_t total_elements_to_send_remote_send_first = est_set_diff_local | ||
1095 | + remote_set_size; | ||
1096 | |||
1097 | uint64_t total_bytes_full_remote_send_first = (avg_element_size | ||
1098 | * | ||
1099 | total_elements_to_send_remote_send_first) \ | ||
1100 | + ( | ||
1101 | total_elements_to_send_remote_send_first * sizeof(struct | ||
1102 | GNUNET_SETU_ElementMessage)) \ | ||
1103 | + (sizeof_full_done_header * 2) \ | ||
1104 | + (rtt_min_full + 0.5) | ||
1105 | * bandwith_latency_tradeoff \ | ||
1106 | + sizeof_request_full; | ||
1107 | |||
1108 | /* | ||
1109 | * Calculate bytes for differential Sync | ||
1110 | */ | ||
1111 | |||
1112 | /* Estimate bytes required by IBF transmission*/ | ||
1113 | |||
1114 | long double ibf_bucket_count = estimated_total_diff | ||
1115 | * ibf_bucket_number_factor; | ||
1116 | |||
1117 | if (ibf_bucket_count <= IBF_MIN_SIZE) | ||
1118 | { | ||
1119 | ibf_bucket_count = IBF_MIN_SIZE; | ||
1120 | } | ||
1121 | uint64_t ibf_message_count = ceil ( ((float) ibf_bucket_count) | ||
1122 | / ((float) MAX_BUCKETS_PER_MESSAGE)); | ||
1123 | |||
1124 | uint64_t estimated_counter_size = ceil ( | ||
1125 | MIN (2 * log2l (((float) local_set_size) | ||
1126 | / ((float) ibf_bucket_count)), | ||
1127 | log2l (local_set_size))); | ||
1128 | |||
1129 | long double counter_bytes = (float) estimated_counter_size / 8; | ||
1130 | |||
1131 | uint64_t ibf_bytes = ceil ((sizeof (struct IBFMessage) * ibf_message_count) | ||
1132 | * 1.2 \ | ||
1133 | + (ibf_bucket_count * sizeof(struct IBF_Key)) * 1.2 \ | ||
1134 | + (ibf_bucket_count * sizeof(struct IBF_KeyHash)) | ||
1135 | * 1.2 \ | ||
1136 | + (ibf_bucket_count * counter_bytes) * 1.2); | ||
1137 | |||
1138 | /* Estimate full byte count for differential sync */ | ||
1139 | uint64_t element_size = (avg_element_size | ||
1140 | + sizeof (struct GNUNET_SETU_ElementMessage)) \ | ||
1141 | * estimated_total_diff; | ||
1142 | uint64_t done_size = sizeof_done_header; | ||
1143 | uint64_t inquery_size = (sizeof (struct IBF_Key) | ||
1144 | + sizeof (struct InquiryMessage)) | ||
1145 | * estimated_total_diff; | ||
1146 | uint64_t demand_size = | ||
1147 | (sizeof(struct GNUNET_HashCode) + sizeof(struct GNUNET_MessageHeader)) | ||
1148 | * estimated_total_diff; | ||
1149 | uint64_t offer_size = (sizeof (struct GNUNET_HashCode) | ||
1150 | + sizeof (struct GNUNET_MessageHeader)) | ||
1151 | * estimated_total_diff; | ||
1152 | |||
1153 | uint64_t total_bytes_diff = (element_size + done_size + inquery_size | ||
1154 | + demand_size + offer_size + ibf_bytes) \ | ||
1155 | + (DIFFERENTIAL_RTT_MEAN | ||
1156 | * bandwith_latency_tradeoff); | ||
1157 | |||
1158 | uint64_t full_min = MIN (total_bytes_full_local_send_first, | ||
1159 | total_bytes_full_remote_send_first); | ||
1160 | |||
1161 | /* Decide between full and differential sync */ | ||
1162 | |||
1163 | if (full_min < total_bytes_diff) | ||
1164 | { | ||
1165 | /* Decide between sending all element first or receiving all elements */ | ||
1166 | if (total_bytes_full_remote_send_first > total_bytes_full_local_send_first) | ||
1167 | { | ||
1168 | return FULL_SYNC_LOCAL_SENDING_FIRST; | ||
1169 | } | ||
1170 | else | ||
1171 | { | ||
1172 | return FULL_SYNC_REMOTE_SENDING_FIRST; | ||
1173 | } | ||
1174 | } | ||
1175 | else | ||
1176 | { | ||
1177 | return DIFFERENTIAL_SYNC; | ||
1178 | } | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | /** | ||
1183 | * Validates the if a message is received in a correct phase | ||
1184 | * @param allowed_phases | ||
1185 | * @param size_phases | ||
1186 | * @param op | ||
1187 | * @return #GNUNET_YES if message permitted in phase and #GNUNET_NO if not permitted in given | ||
1188 | * phase | ||
1189 | */ | ||
1190 | static enum GNUNET_GenericReturnValue | ||
1191 | check_valid_phase (const uint8_t allowed_phases[], | ||
1192 | size_t size_phases, | ||
1193 | struct Operation *op) | ||
1194 | { | ||
1195 | /** | ||
1196 | * Iterate over allowed phases | ||
1197 | */ | ||
1198 | for (uint32_t phase_ctr = 0; phase_ctr < size_phases; phase_ctr++) | ||
1199 | { | ||
1200 | uint8_t phase = allowed_phases[phase_ctr]; | ||
1201 | if (phase == op->phase) | ||
1202 | { | ||
1203 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1204 | "Message received in valid phase\n"); | ||
1205 | return GNUNET_YES; | ||
1206 | } | ||
1207 | } | ||
1208 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1209 | "Received message in invalid phase: %u\n", op->phase); | ||
1210 | return GNUNET_NO; | ||
1211 | } | ||
1212 | |||
1213 | |||
1214 | /** | ||
1215 | * Function to update, track and validate message received in differential | ||
1216 | * sync. This function tracks states of messages and check it against different | ||
1217 | * constraints as described in Summermatter's BSc Thesis (2021) | ||
1218 | * @param hash_map: Hashmap to store message control flow | ||
1219 | * @param new_mcfs: The new message control flow state an given message type should be set to | ||
1220 | * @param hash_code: Hash code of the element | ||
1221 | * @param mt: The message type for which the message control flow state should be set | ||
1222 | * @return GNUNET_YES message is valid in message control flow GNUNET_NO when message is not valid | ||
1223 | * at this point in message flow | ||
1224 | */ | ||
1225 | static int | ||
1226 | update_message_control_flow (struct GNUNET_CONTAINER_MultiHashMap *hash_map, | ||
1227 | enum MESSAGE_CONTROL_FLOW_STATE new_mcfs, | ||
1228 | const struct GNUNET_HashCode *hash_code, | ||
1229 | enum MESSAGE_TYPE mt) | ||
1230 | { | ||
1231 | struct messageControlFlowElement *cfe = NULL; | ||
1232 | enum MESSAGE_CONTROL_FLOW_STATE *mcfs; | ||
1233 | |||
1234 | /** | ||
1235 | * Check logic for forbidden messages | ||
1236 | */ | ||
1237 | |||
1238 | cfe = GNUNET_CONTAINER_multihashmap_get (hash_map, hash_code); | ||
1239 | if ((ELEMENT_MESSAGE == mt) && (cfe != NULL)) | ||
1240 | { | ||
1241 | if ((new_mcfs != MSG_CFS_SENT) && (MSG_CFS_RECEIVED != cfe->offer)) | ||
1242 | { | ||
1243 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1244 | "Received an element without sent offer!\n"); | ||
1245 | return GNUNET_NO; | ||
1246 | } | ||
1247 | /* Check that only requested elements are received! */ | ||
1248 | if ((ELEMENT_MESSAGE == mt) && (new_mcfs != MSG_CFS_SENT) && (cfe->demand != | ||
1249 | MSG_CFS_SENT)) | ||
1250 | { | ||
1251 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1252 | "Received an element that was not demanded\n"); | ||
1253 | return GNUNET_NO; | ||
1254 | } | ||
1255 | } | ||
1256 | |||
1257 | /** | ||
1258 | * In case the element hash is not in the hashmap create a new entry | ||
1259 | */ | ||
1260 | |||
1261 | if (NULL == cfe) | ||
1262 | { | ||
1263 | cfe = GNUNET_new (struct messageControlFlowElement); | ||
1264 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (hash_map, hash_code, | ||
1265 | cfe, | ||
1266 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1267 | { | ||
1268 | GNUNET_free (cfe); | ||
1269 | return GNUNET_SYSERR; | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | /** | ||
1274 | * Set state of message | ||
1275 | */ | ||
1276 | |||
1277 | if (OFFER_MESSAGE == mt) | ||
1278 | { | ||
1279 | mcfs = &cfe->offer; | ||
1280 | } | ||
1281 | else if (DEMAND_MESSAGE == mt) | ||
1282 | { | ||
1283 | mcfs = &cfe->demand; | ||
1284 | } | ||
1285 | else if (ELEMENT_MESSAGE == mt) | ||
1286 | { | ||
1287 | mcfs = &cfe->element; | ||
1288 | } | ||
1289 | else | ||
1290 | { | ||
1291 | return GNUNET_SYSERR; | ||
1292 | } | ||
1293 | |||
1294 | /** | ||
1295 | * Check if state is allowed | ||
1296 | */ | ||
1297 | |||
1298 | if (new_mcfs <= *mcfs) | ||
1299 | { | ||
1300 | return GNUNET_NO; | ||
1301 | } | ||
1302 | |||
1303 | *mcfs = new_mcfs; | ||
1304 | return GNUNET_YES; | ||
1305 | } | ||
1306 | |||
1307 | |||
1308 | /** | ||
1309 | * Validate if a message in differential sync si already received before. | ||
1310 | * @param hash_map | ||
1311 | * @param hash_code | ||
1312 | * @param mt | ||
1313 | * @return GNUNET_YES when message is already in store if message is not in store return GNUNET_NO | ||
1314 | */ | ||
1315 | static int | ||
1316 | is_message_in_message_control_flow (struct | ||
1317 | GNUNET_CONTAINER_MultiHashMap *hash_map, | ||
1318 | struct GNUNET_HashCode *hash_code, | ||
1319 | enum MESSAGE_TYPE mt) | ||
1320 | { | ||
1321 | struct messageControlFlowElement *cfe = NULL; | ||
1322 | enum MESSAGE_CONTROL_FLOW_STATE *mcfs; | ||
1323 | |||
1324 | cfe = GNUNET_CONTAINER_multihashmap_get (hash_map, hash_code); | ||
1325 | |||
1326 | /** | ||
1327 | * Set state of message | ||
1328 | */ | ||
1329 | |||
1330 | if (cfe != NULL) | ||
1331 | { | ||
1332 | if (OFFER_MESSAGE == mt) | ||
1333 | { | ||
1334 | mcfs = &cfe->offer; | ||
1335 | } | ||
1336 | else if (DEMAND_MESSAGE == mt) | ||
1337 | { | ||
1338 | mcfs = &cfe->demand; | ||
1339 | } | ||
1340 | else if (ELEMENT_MESSAGE == mt) | ||
1341 | { | ||
1342 | mcfs = &cfe->element; | ||
1343 | } | ||
1344 | else | ||
1345 | { | ||
1346 | return GNUNET_SYSERR; | ||
1347 | } | ||
1348 | |||
1349 | /** | ||
1350 | * Evaluate if set is in message | ||
1351 | */ | ||
1352 | if (*mcfs != MSG_CFS_UNINITIALIZED) | ||
1353 | { | ||
1354 | return GNUNET_YES; | ||
1355 | } | ||
1356 | } | ||
1357 | return GNUNET_NO; | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | /** | ||
1362 | * Iterator for determining if all demands have been | ||
1363 | * satisfied | ||
1364 | * | ||
1365 | * @param cls the union operation `struct Operation *` | ||
1366 | * @param key unused | ||
1367 | * @param value the `struct ElementEntry *` to insert | ||
1368 | * into the key-to-element mapping | ||
1369 | * @return #GNUNET_YES (to continue iterating) | ||
1370 | */ | ||
1371 | static int | ||
1372 | determinate_done_message_iterator (void *cls, | ||
1373 | const struct GNUNET_HashCode *key, | ||
1374 | void *value) | ||
1375 | { | ||
1376 | struct messageControlFlowElement *mcfe = value; | ||
1377 | |||
1378 | if (((mcfe->element == MSG_CFS_SENT) || (mcfe->element == MSG_CFS_RECEIVED) )) | ||
1379 | { | ||
1380 | return GNUNET_YES; | ||
1381 | } | ||
1382 | return GNUNET_NO; | ||
1383 | } | ||
1384 | |||
1385 | |||
1386 | /** | ||
1387 | * Iterator for determining average size | ||
1388 | * | ||
1389 | * @param cls the union operation `struct Operation *` | ||
1390 | * @param key unused | ||
1391 | * @param value the `struct ElementEntry *` to insert | ||
1392 | * into the key-to-element mapping | ||
1393 | * @return #GNUNET_YES (to continue iterating) | ||
1394 | */ | ||
1395 | static int | ||
1396 | determinate_avg_element_size_iterator (void *cls, | ||
1397 | const struct GNUNET_HashCode *key, | ||
1398 | void *value) | ||
1399 | { | ||
1400 | struct Operation *op = cls; | ||
1401 | struct GNUNET_SETU_Element *element = value; | ||
1402 | op->total_elements_size_local += element->size; | ||
1403 | return GNUNET_YES; | ||
1404 | } | ||
1405 | |||
1406 | |||
1407 | /** | ||
1408 | * Create randomized element hashmap for full sending | ||
1409 | * | ||
1410 | * @param cls the union operation `struct Operation *` | ||
1411 | * @param key unused | ||
1412 | * @param value the `struct ElementEntry *` to insert | ||
1413 | * into the key-to-element mapping | ||
1414 | * @return #GNUNET_YES (to continue iterating) | ||
1415 | */ | ||
1416 | static int | ||
1417 | create_randomized_element_iterator (void *cls, | ||
1418 | const struct GNUNET_HashCode *key, | ||
1419 | void *value) | ||
1420 | { | ||
1421 | struct Operation *op = cls; | ||
1422 | |||
1423 | struct GNUNET_HashContext *hashed_key_context = | ||
1424 | GNUNET_CRYPTO_hash_context_start (); | ||
1425 | struct GNUNET_HashCode new_key; | ||
1426 | |||
1427 | /** | ||
1428 | * Hash element with new salt to randomize hashmap | ||
1429 | */ | ||
1430 | GNUNET_CRYPTO_hash_context_read (hashed_key_context, | ||
1431 | &key, | ||
1432 | sizeof(struct IBF_Key)); | ||
1433 | GNUNET_CRYPTO_hash_context_read (hashed_key_context, | ||
1434 | &op->set->content->elements_randomized_salt, | ||
1435 | sizeof(uint32_t)); | ||
1436 | GNUNET_CRYPTO_hash_context_finish (hashed_key_context, | ||
1437 | &new_key); | ||
1438 | GNUNET_CONTAINER_multihashmap_put (op->set->content->elements_randomized, | ||
1439 | &new_key,value, | ||
1440 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
1441 | return GNUNET_YES; | ||
1442 | } | ||
1443 | |||
1444 | |||
1445 | /** | ||
1446 | * Iterator over hash map entries, called to | ||
1447 | * destroy the linked list of colliding ibf key entries. | ||
1448 | * | ||
1449 | * @param cls closure | ||
1450 | * @param key current key code | ||
1451 | * @param value value in the hash map | ||
1452 | * @return #GNUNET_YES if we should continue to iterate, | ||
1453 | * #GNUNET_NO if not. | ||
1454 | */ | ||
1455 | static int | ||
1456 | destroy_key_to_element_iter (void *cls, | ||
1457 | uint32_t key, | ||
1458 | void *value) | ||
1459 | { | ||
1460 | struct KeyEntry *k = value; | ||
1461 | |||
1462 | GNUNET_assert (NULL != k); | ||
1463 | if (GNUNET_YES == k->element->remote) | ||
1464 | { | ||
1465 | GNUNET_free (k->element); | ||
1466 | k->element = NULL; | ||
1467 | } | ||
1468 | GNUNET_free (k); | ||
1469 | return GNUNET_YES; | ||
1470 | } | ||
1471 | |||
1472 | |||
1473 | /** | ||
1474 | * Signal to the client that the operation has finished and | ||
1475 | * destroy the operation. | ||
1476 | * | ||
1477 | * @param cls operation to destroy | ||
1478 | */ | ||
1479 | static void | ||
1480 | send_client_done (void *cls) | ||
1481 | { | ||
1482 | struct Operation *op = cls; | ||
1483 | struct GNUNET_MQ_Envelope *ev; | ||
1484 | struct GNUNET_SETU_ResultMessage *rm; | ||
1485 | |||
1486 | if (GNUNET_YES == op->client_done_sent) | ||
1487 | return; | ||
1488 | if (PHASE_FINISHED != op->phase) | ||
1489 | { | ||
1490 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1491 | "Union operation failed\n"); | ||
1492 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
1493 | "# Union operations failed", | ||
1494 | 1, | ||
1495 | GNUNET_NO); | ||
1496 | ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SETU_RESULT); | ||
1497 | rm->result_status = htons (GNUNET_SETU_STATUS_FAILURE); | ||
1498 | rm->request_id = htonl (op->client_request_id); | ||
1499 | rm->element_type = htons (0); | ||
1500 | GNUNET_MQ_send (op->set->cs->mq, | ||
1501 | ev); | ||
1502 | return; | ||
1503 | } | ||
1504 | |||
1505 | op->client_done_sent = GNUNET_YES; | ||
1506 | |||
1507 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
1508 | "# Union operations succeeded", | ||
1509 | 1, | ||
1510 | GNUNET_NO); | ||
1511 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1512 | "Signalling client that union operation is done\n"); | ||
1513 | ev = GNUNET_MQ_msg (rm, | ||
1514 | GNUNET_MESSAGE_TYPE_SETU_RESULT); | ||
1515 | rm->request_id = htonl (op->client_request_id); | ||
1516 | rm->result_status = htons (GNUNET_SETU_STATUS_DONE); | ||
1517 | rm->element_type = htons (0); | ||
1518 | rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size ( | ||
1519 | op->key_to_element)); | ||
1520 | GNUNET_MQ_send (op->set->cs->mq, | ||
1521 | ev); | ||
1522 | } | ||
1523 | |||
1524 | |||
1525 | /** | ||
1526 | * Check if all given byzantine parameters are in given boundaries | ||
1527 | * @param op | ||
1528 | * @return indicator if all given byzantine parameters are in given boundaries | ||
1529 | */ | ||
1530 | |||
1531 | static int | ||
1532 | check_byzantine_bounds (struct Operation *op) | ||
1533 | { | ||
1534 | if (op->byzantine != GNUNET_YES) | ||
1535 | return GNUNET_OK; | ||
1536 | |||
1537 | /** | ||
1538 | * Check upper byzantine bounds | ||
1539 | */ | ||
1540 | if (op->remote_element_count + op->remote_set_diff > | ||
1541 | op->byzantine_upper_bound) | ||
1542 | return GNUNET_SYSERR; | ||
1543 | if (op->local_element_count + op->local_set_diff > op->byzantine_upper_bound) | ||
1544 | return GNUNET_SYSERR; | ||
1545 | |||
1546 | /** | ||
1547 | * Check lower byzantine bounds | ||
1548 | */ | ||
1549 | if (op->remote_element_count < op->byzantine_lower_bound) | ||
1550 | return GNUNET_SYSERR; | ||
1551 | return GNUNET_OK; | ||
1552 | } | ||
1553 | |||
1554 | |||
1555 | static enum GNUNET_GenericReturnValue | ||
1556 | free_values_iter(void *cls, | ||
1557 | const struct GNUNET_HashCode *key, | ||
1558 | void *value) | ||
1559 | { | ||
1560 | GNUNET_free (value); | ||
1561 | return GNUNET_YES; | ||
1562 | } | ||
1563 | |||
1564 | |||
1565 | /* FIXME: the destroy logic is a mess and should be cleaned up! */ | ||
1566 | |||
1567 | /** | ||
1568 | * Destroy the given operation. Used for any operation where both | ||
1569 | * peers were known and that thus actually had a vt and channel. Must | ||
1570 | * not be used for operations where 'listener' is still set and we do | ||
1571 | * not know the other peer. | ||
1572 | * | ||
1573 | * Call the implementation-specific cancel function of the operation. | ||
1574 | * Disconnects from the remote peer. Does not disconnect the client, | ||
1575 | * as there may be multiple operations per set. | ||
1576 | * | ||
1577 | * @param op operation to destroy | ||
1578 | */ | ||
1579 | static void | ||
1580 | _GSS_operation_destroy (struct Operation *op) | ||
1581 | { | ||
1582 | struct Set *set = op->set; | ||
1583 | struct GNUNET_CADET_Channel *channel; | ||
1584 | |||
1585 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1586 | "Destroying union operation %p\n", | ||
1587 | op); | ||
1588 | GNUNET_assert (NULL == op->listener); | ||
1589 | /* check if the op was canceled twice */ | ||
1590 | if (NULL != op->remote_ibf) | ||
1591 | { | ||
1592 | ibf_destroy (op->remote_ibf); | ||
1593 | op->remote_ibf = NULL; | ||
1594 | } | ||
1595 | if (NULL != op->demanded_hashes) | ||
1596 | { | ||
1597 | GNUNET_CONTAINER_multihashmap_destroy (op->demanded_hashes); | ||
1598 | op->demanded_hashes = NULL; | ||
1599 | } | ||
1600 | if (NULL != op->local_ibf) | ||
1601 | { | ||
1602 | ibf_destroy (op->local_ibf); | ||
1603 | op->local_ibf = NULL; | ||
1604 | } | ||
1605 | if (NULL != op->se) | ||
1606 | { | ||
1607 | strata_estimator_destroy (op->se); | ||
1608 | op->se = NULL; | ||
1609 | } | ||
1610 | if (NULL != op->key_to_element) | ||
1611 | { | ||
1612 | GNUNET_CONTAINER_multihashmap32_iterate (op->key_to_element, | ||
1613 | &destroy_key_to_element_iter, | ||
1614 | NULL); | ||
1615 | GNUNET_CONTAINER_multihashmap32_destroy (op->key_to_element); | ||
1616 | op->key_to_element = NULL; | ||
1617 | } | ||
1618 | if (NULL != op->message_control_flow) | ||
1619 | { | ||
1620 | GNUNET_CONTAINER_multihashmap_iterate (op->message_control_flow, | ||
1621 | &free_values_iter, | ||
1622 | NULL); | ||
1623 | GNUNET_CONTAINER_multihashmap_destroy (op->message_control_flow); | ||
1624 | op->message_control_flow = NULL; | ||
1625 | } | ||
1626 | if (NULL != op->inquiries_sent) | ||
1627 | { | ||
1628 | GNUNET_CONTAINER_multihashmap_destroy (op->inquiries_sent); | ||
1629 | op->inquiries_sent = NULL; | ||
1630 | } | ||
1631 | if (NULL != set) | ||
1632 | { | ||
1633 | GNUNET_CONTAINER_DLL_remove (set->ops_head, | ||
1634 | set->ops_tail, | ||
1635 | op); | ||
1636 | op->set = NULL; | ||
1637 | } | ||
1638 | if (NULL != op->context_msg) | ||
1639 | { | ||
1640 | GNUNET_free (op->context_msg); | ||
1641 | op->context_msg = NULL; | ||
1642 | } | ||
1643 | if (NULL != (channel = op->channel)) | ||
1644 | { | ||
1645 | /* This will free op; called conditionally as this helper function | ||
1646 | is also called from within the channel disconnect handler. */ | ||
1647 | op->channel = NULL; | ||
1648 | GNUNET_CADET_channel_destroy (channel); | ||
1649 | } | ||
1650 | /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL, | ||
1651 | * there was a channel end handler that will free 'op' on the call stack. */ | ||
1652 | } | ||
1653 | |||
1654 | |||
1655 | /** | ||
1656 | * This function probably should not exist | ||
1657 | * and be replaced by inlining more specific | ||
1658 | * logic in the various places where it is called. | ||
1659 | */ | ||
1660 | static void | ||
1661 | _GSS_operation_destroy2 (struct Operation *op); | ||
1662 | |||
1663 | |||
1664 | /** | ||
1665 | * Destroy an incoming request from a remote peer | ||
1666 | * | ||
1667 | * @param op remote request to destroy | ||
1668 | */ | ||
1669 | static void | ||
1670 | incoming_destroy (struct Operation *op) | ||
1671 | { | ||
1672 | struct Listener *listener; | ||
1673 | |||
1674 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1675 | "Destroying incoming operation %p\n", | ||
1676 | op); | ||
1677 | if (NULL != (listener = op->listener)) | ||
1678 | { | ||
1679 | GNUNET_CONTAINER_DLL_remove (listener->op_head, | ||
1680 | listener->op_tail, | ||
1681 | op); | ||
1682 | op->listener = NULL; | ||
1683 | } | ||
1684 | if (NULL != op->timeout_task) | ||
1685 | { | ||
1686 | GNUNET_SCHEDULER_cancel (op->timeout_task); | ||
1687 | op->timeout_task = NULL; | ||
1688 | } | ||
1689 | _GSS_operation_destroy2 (op); | ||
1690 | } | ||
1691 | |||
1692 | |||
1693 | /** | ||
1694 | * This function probably should not exist | ||
1695 | * and be replaced by inlining more specific | ||
1696 | * logic in the various places where it is called. | ||
1697 | */ | ||
1698 | static void | ||
1699 | _GSS_operation_destroy2 (struct Operation *op) | ||
1700 | { | ||
1701 | struct GNUNET_CADET_Channel *channel; | ||
1702 | |||
1703 | if (NULL != (channel = op->channel)) | ||
1704 | { | ||
1705 | /* This will free op; called conditionally as this helper function | ||
1706 | is also called from within the channel disconnect handler. */ | ||
1707 | op->channel = NULL; | ||
1708 | GNUNET_CADET_channel_destroy (channel); | ||
1709 | } | ||
1710 | if (NULL != op->listener) | ||
1711 | { | ||
1712 | incoming_destroy (op); | ||
1713 | return; | ||
1714 | } | ||
1715 | if (NULL != op->set) | ||
1716 | send_client_done (op); | ||
1717 | _GSS_operation_destroy (op); | ||
1718 | GNUNET_free (op); | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | /** | ||
1723 | * Inform the client that the union operation has failed, | ||
1724 | * and proceed to destroy the evaluate operation. | ||
1725 | * | ||
1726 | * @param op the union operation to fail | ||
1727 | */ | ||
1728 | static void | ||
1729 | fail_union_operation (struct Operation *op) | ||
1730 | { | ||
1731 | struct GNUNET_MQ_Envelope *ev; | ||
1732 | struct GNUNET_SETU_ResultMessage *msg; | ||
1733 | |||
1734 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1735 | "union operation failed\n"); | ||
1736 | ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SETU_RESULT); | ||
1737 | msg->result_status = htons (GNUNET_SETU_STATUS_FAILURE); | ||
1738 | msg->request_id = htonl (op->client_request_id); | ||
1739 | msg->element_type = htons (0); | ||
1740 | GNUNET_MQ_send (op->set->cs->mq, | ||
1741 | ev); | ||
1742 | _GSS_operation_destroy (op); | ||
1743 | } | ||
1744 | |||
1745 | |||
1746 | /** | ||
1747 | * Function that checks if full sync is plausible | ||
1748 | * @param initial_local_elements_in_set | ||
1749 | * @param estimated_set_difference | ||
1750 | * @param repeated_elements | ||
1751 | * @param fresh_elements | ||
1752 | * @param op | ||
1753 | * @return GNUNET_OK if | ||
1754 | */ | ||
1755 | |||
1756 | static void | ||
1757 | full_sync_plausibility_check (struct Operation *op) | ||
1758 | { | ||
1759 | if (GNUNET_YES != op->byzantine) | ||
1760 | return; | ||
1761 | |||
1762 | int security_level_lb = -1 * SECURITY_LEVEL; | ||
1763 | uint64_t duplicates = op->received_fresh - op->received_total; | ||
1764 | |||
1765 | /* | ||
1766 | * Protect full sync from receiving double element when in FULL SENDING | ||
1767 | */ | ||
1768 | if (PHASE_FULL_SENDING == op->phase) | ||
1769 | { | ||
1770 | if (duplicates > 0) | ||
1771 | { | ||
1772 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1773 | "PROTOCOL VIOLATION: Received duplicate element in full receiving " | ||
1774 | "mode of operation this is not allowed! Duplicates: %llu\n", | ||
1775 | (unsigned long long) duplicates); | ||
1776 | GNUNET_break_op (0); | ||
1777 | fail_union_operation (op); | ||
1778 | return; | ||
1779 | } | ||
1780 | |||
1781 | } | ||
1782 | |||
1783 | /* | ||
1784 | * Protect full sync with probabilistic algorithm | ||
1785 | */ | ||
1786 | if (PHASE_FULL_RECEIVING == op->phase) | ||
1787 | { | ||
1788 | if (0 == op->remote_set_diff) | ||
1789 | op->remote_set_diff = 1; | ||
1790 | |||
1791 | long double base = (1 - (long double) (op->remote_set_diff | ||
1792 | / (long double) (op->initial_size | ||
1793 | + op-> | ||
1794 | remote_set_diff))); | ||
1795 | long double exponent = (op->received_total - (op->received_fresh * ((long | ||
1796 | double) | ||
1797 | op-> | ||
1798 | initial_size | ||
1799 | / (long | ||
1800 | double) | ||
1801 | op-> | ||
1802 | remote_set_diff))); | ||
1803 | long double value = exponent * (log2l (base) / log2l (2)); | ||
1804 | if ((value < security_level_lb) || (value > SECURITY_LEVEL) ) | ||
1805 | { | ||
1806 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1807 | "PROTOCOL VIOLATION: Other peer violated probabilistic rule for receiving " | ||
1808 | "to many duplicated full element : %LF\n", | ||
1809 | value); | ||
1810 | GNUNET_break_op (0); | ||
1811 | fail_union_operation (op); | ||
1812 | return; | ||
1813 | } | ||
1814 | } | ||
1815 | } | ||
1816 | |||
1817 | |||
1818 | /** | ||
1819 | * Limit active passive switches in differential sync to configured security level | ||
1820 | * @param op | ||
1821 | */ | ||
1822 | static void | ||
1823 | check_max_differential_rounds (struct Operation *op) | ||
1824 | { | ||
1825 | double probability = op->differential_sync_iterations * (log2l ( | ||
1826 | PROBABILITY_FOR_NEW_ROUND) | ||
1827 | / log2l (2)); | ||
1828 | if ((-1 * SECURITY_LEVEL) > probability) | ||
1829 | { | ||
1830 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1831 | "PROTOCOL VIOLATION: Other peer violated probabilistic rule for to many active passive " | ||
1832 | "switches in differential sync: %u\n", | ||
1833 | op->differential_sync_iterations); | ||
1834 | GNUNET_break_op (0); | ||
1835 | fail_union_operation (op); | ||
1836 | return; | ||
1837 | } | ||
1838 | } | ||
1839 | |||
1840 | |||
1841 | /** | ||
1842 | * Derive the IBF key from a hash code and | ||
1843 | * a salt. | ||
1844 | * | ||
1845 | * @param src the hash code | ||
1846 | * @return the derived IBF key | ||
1847 | */ | ||
1848 | static struct IBF_Key | ||
1849 | get_ibf_key (const struct GNUNET_HashCode *src) | ||
1850 | { | ||
1851 | struct IBF_Key key; | ||
1852 | uint16_t salt = 0; | ||
1853 | |||
1854 | GNUNET_assert (GNUNET_OK == | ||
1855 | GNUNET_CRYPTO_kdf (&key, sizeof(key), | ||
1856 | src, sizeof *src, | ||
1857 | &salt, sizeof(salt), | ||
1858 | NULL, 0)); | ||
1859 | return key; | ||
1860 | } | ||
1861 | |||
1862 | |||
1863 | /** | ||
1864 | * Context for #op_get_element_iterator | ||
1865 | */ | ||
1866 | struct GetElementContext | ||
1867 | { | ||
1868 | /** | ||
1869 | * Gnunet hash code in context | ||
1870 | */ | ||
1871 | struct GNUNET_HashCode hash; | ||
1872 | |||
1873 | /** | ||
1874 | * Pointer to the key entry | ||
1875 | */ | ||
1876 | struct KeyEntry *k; | ||
1877 | }; | ||
1878 | |||
1879 | |||
1880 | /** | ||
1881 | * Iterator over the mapping from IBF keys to element entries. Checks if we | ||
1882 | * have an element with a given GNUNET_HashCode. | ||
1883 | * | ||
1884 | * @param cls closure | ||
1885 | * @param key current key code | ||
1886 | * @param value value in the hash map | ||
1887 | * @return #GNUNET_YES if we should search further, | ||
1888 | * #GNUNET_NO if we've found the element. | ||
1889 | */ | ||
1890 | static int | ||
1891 | op_get_element_iterator (void *cls, | ||
1892 | uint32_t key, | ||
1893 | void *value) | ||
1894 | { | ||
1895 | struct GetElementContext *ctx = cls; | ||
1896 | struct KeyEntry *k = value; | ||
1897 | |||
1898 | GNUNET_assert (NULL != k); | ||
1899 | if (0 == GNUNET_CRYPTO_hash_cmp (&k->element->element_hash, | ||
1900 | &ctx->hash)) | ||
1901 | { | ||
1902 | ctx->k = k; | ||
1903 | return GNUNET_NO; | ||
1904 | } | ||
1905 | return GNUNET_YES; | ||
1906 | } | ||
1907 | |||
1908 | |||
1909 | /** | ||
1910 | * Determine whether the given element is already in the operation's element | ||
1911 | * set. | ||
1912 | * | ||
1913 | * @param op operation that should be tested for 'element_hash' | ||
1914 | * @param element_hash hash of the element to look for | ||
1915 | * @return #GNUNET_YES if the element has been found, #GNUNET_NO otherwise | ||
1916 | */ | ||
1917 | static struct KeyEntry * | ||
1918 | op_get_element (struct Operation *op, | ||
1919 | const struct GNUNET_HashCode *element_hash) | ||
1920 | { | ||
1921 | int ret; | ||
1922 | struct IBF_Key ibf_key; | ||
1923 | struct GetElementContext ctx = { { { 0 } }, 0 }; | ||
1924 | |||
1925 | ctx.hash = *element_hash; | ||
1926 | |||
1927 | ibf_key = get_ibf_key (element_hash); | ||
1928 | ret = GNUNET_CONTAINER_multihashmap32_get_multiple (op->key_to_element, | ||
1929 | (uint32_t) ibf_key.key_val, | ||
1930 | &op_get_element_iterator, | ||
1931 | &ctx); | ||
1932 | |||
1933 | /* was the iteration aborted because we found the element? */ | ||
1934 | if (GNUNET_SYSERR == ret) | ||
1935 | { | ||
1936 | GNUNET_assert (NULL != ctx.k); | ||
1937 | return ctx.k; | ||
1938 | } | ||
1939 | return NULL; | ||
1940 | } | ||
1941 | |||
1942 | |||
1943 | /** | ||
1944 | * Insert an element into the union operation's | ||
1945 | * key-to-element mapping. Takes ownership of 'ee'. | ||
1946 | * Note that this does not insert the element in the set, | ||
1947 | * only in the operation's key-element mapping. | ||
1948 | * This is done to speed up re-tried operations, if some elements | ||
1949 | * were transmitted, and then the IBF fails to decode. | ||
1950 | * | ||
1951 | * XXX: clarify ownership, doesn't sound right. | ||
1952 | * | ||
1953 | * @param op the union operation | ||
1954 | * @param ee the element entry | ||
1955 | * @param received was this element received from the remote peer? | ||
1956 | */ | ||
1957 | static void | ||
1958 | op_register_element (struct Operation *op, | ||
1959 | struct ElementEntry *ee, | ||
1960 | int received) | ||
1961 | { | ||
1962 | struct IBF_Key ibf_key; | ||
1963 | struct KeyEntry *k; | ||
1964 | |||
1965 | ibf_key = get_ibf_key (&ee->element_hash); | ||
1966 | k = GNUNET_new (struct KeyEntry); | ||
1967 | k->element = ee; | ||
1968 | k->ibf_key = ibf_key; | ||
1969 | k->received = received; | ||
1970 | GNUNET_assert (GNUNET_OK == | ||
1971 | GNUNET_CONTAINER_multihashmap32_put (op->key_to_element, | ||
1972 | (uint32_t) ibf_key.key_val, | ||
1973 | k, | ||
1974 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
1975 | } | ||
1976 | |||
1977 | |||
1978 | /** | ||
1979 | * Modify an IBF key @a k_in based on the @a salt, returning a | ||
1980 | * salted key in @a k_out. | ||
1981 | */ | ||
1982 | static void | ||
1983 | salt_key (const struct IBF_Key *k_in, | ||
1984 | uint32_t salt, | ||
1985 | struct IBF_Key *k_out) | ||
1986 | { | ||
1987 | int s = (salt * 7) % 64; | ||
1988 | uint64_t x = k_in->key_val; | ||
1989 | |||
1990 | /* rotate ibf key */ | ||
1991 | x = (x >> s) | (x << (64 - s)); | ||
1992 | k_out->key_val = x; | ||
1993 | } | ||
1994 | |||
1995 | |||
1996 | /** | ||
1997 | * Reverse modification done in the salt_key function | ||
1998 | */ | ||
1999 | static void | ||
2000 | unsalt_key (const struct IBF_Key *k_in, | ||
2001 | uint32_t salt, | ||
2002 | struct IBF_Key *k_out) | ||
2003 | { | ||
2004 | int s = (salt * 7) % 64; | ||
2005 | uint64_t x = k_in->key_val; | ||
2006 | |||
2007 | x = (x << s) | (x >> (64 - s)); | ||
2008 | k_out->key_val = x; | ||
2009 | } | ||
2010 | |||
2011 | |||
2012 | /** | ||
2013 | * Insert a key into an ibf. | ||
2014 | * | ||
2015 | * @param cls the ibf | ||
2016 | * @param key unused | ||
2017 | * @param value the key entry to get the key from | ||
2018 | */ | ||
2019 | static int | ||
2020 | prepare_ibf_iterator (void *cls, | ||
2021 | uint32_t key, | ||
2022 | void *value) | ||
2023 | { | ||
2024 | struct Operation *op = cls; | ||
2025 | struct KeyEntry *ke = value; | ||
2026 | struct IBF_Key salted_key; | ||
2027 | |||
2028 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2029 | "[OP %p] inserting %lx (hash %s) into ibf\n", | ||
2030 | op, | ||
2031 | (unsigned long) ke->ibf_key.key_val, | ||
2032 | GNUNET_h2s (&ke->element->element_hash)); | ||
2033 | salt_key (&ke->ibf_key, | ||
2034 | op->salt_send, | ||
2035 | &salted_key); | ||
2036 | ibf_insert (op->local_ibf, salted_key); | ||
2037 | return GNUNET_YES; | ||
2038 | } | ||
2039 | |||
2040 | |||
2041 | /** | ||
2042 | * Is element @a ee part of the set used by @a op? | ||
2043 | * | ||
2044 | * @param ee element to test | ||
2045 | * @param op operation the defines the set and its generation | ||
2046 | * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not | ||
2047 | */ | ||
2048 | static int | ||
2049 | _GSS_is_element_of_operation (struct ElementEntry *ee, | ||
2050 | struct Operation *op) | ||
2051 | { | ||
2052 | return ee->generation >= op->generation_created; | ||
2053 | } | ||
2054 | |||
2055 | |||
2056 | /** | ||
2057 | * Iterator for initializing the | ||
2058 | * key-to-element mapping of a union operation | ||
2059 | * | ||
2060 | * @param cls the union operation `struct Operation *` | ||
2061 | * @param key unused | ||
2062 | * @param value the `struct ElementEntry *` to insert | ||
2063 | * into the key-to-element mapping | ||
2064 | * @return #GNUNET_YES (to continue iterating) | ||
2065 | */ | ||
2066 | static int | ||
2067 | init_key_to_element_iterator (void *cls, | ||
2068 | const struct GNUNET_HashCode *key, | ||
2069 | void *value) | ||
2070 | { | ||
2071 | struct Operation *op = cls; | ||
2072 | struct ElementEntry *ee = value; | ||
2073 | |||
2074 | /* make sure that the element belongs to the set at the time | ||
2075 | * of creating the operation */ | ||
2076 | if (GNUNET_NO == | ||
2077 | _GSS_is_element_of_operation (ee, | ||
2078 | op)) | ||
2079 | return GNUNET_YES; | ||
2080 | GNUNET_assert (GNUNET_NO == ee->remote); | ||
2081 | op_register_element (op, | ||
2082 | ee, | ||
2083 | GNUNET_NO); | ||
2084 | return GNUNET_YES; | ||
2085 | } | ||
2086 | |||
2087 | |||
2088 | /** | ||
2089 | * Initialize the IBF key to element mapping local to this set operation. | ||
2090 | * | ||
2091 | * @param op the set union operation | ||
2092 | */ | ||
2093 | static void | ||
2094 | initialize_key_to_element (struct Operation *op) | ||
2095 | { | ||
2096 | unsigned int len; | ||
2097 | |||
2098 | GNUNET_assert (NULL == op->key_to_element); | ||
2099 | len = GNUNET_CONTAINER_multihashmap_size (op->set->content->elements); | ||
2100 | op->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); | ||
2101 | GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
2102 | &init_key_to_element_iterator, | ||
2103 | op); | ||
2104 | } | ||
2105 | |||
2106 | |||
2107 | /** | ||
2108 | * Create an ibf with the operation's elements | ||
2109 | * of the specified size | ||
2110 | * | ||
2111 | * @param op the union operation | ||
2112 | * @param size size of the ibf to create | ||
2113 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
2114 | */ | ||
2115 | static int | ||
2116 | prepare_ibf (struct Operation *op, | ||
2117 | uint32_t size) | ||
2118 | { | ||
2119 | GNUNET_assert (NULL != op->key_to_element); | ||
2120 | |||
2121 | if (NULL != op->local_ibf) | ||
2122 | ibf_destroy (op->local_ibf); | ||
2123 | // op->local_ibf = ibf_create (size, SE_IBF_HASH_NUM); | ||
2124 | op->local_ibf = ibf_create (size, | ||
2125 | ((uint8_t) op->ibf_number_buckets_per_element)); | ||
2126 | if (NULL == op->local_ibf) | ||
2127 | { | ||
2128 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2129 | "Failed to allocate local IBF\n"); | ||
2130 | return GNUNET_SYSERR; | ||
2131 | } | ||
2132 | GNUNET_CONTAINER_multihashmap32_iterate (op->key_to_element, | ||
2133 | &prepare_ibf_iterator, | ||
2134 | op); | ||
2135 | return GNUNET_OK; | ||
2136 | } | ||
2137 | |||
2138 | |||
2139 | /** | ||
2140 | * Send an ibf of appropriate size. | ||
2141 | * | ||
2142 | * Fragments the IBF into multiple messages if necessary. | ||
2143 | * | ||
2144 | * @param op the union operation | ||
2145 | * @param ibf_order order of the ibf to send, size=2^order | ||
2146 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
2147 | */ | ||
2148 | static int | ||
2149 | send_ibf (struct Operation *op, | ||
2150 | uint32_t ibf_size) | ||
2151 | { | ||
2152 | uint64_t buckets_sent = 0; | ||
2153 | struct InvertibleBloomFilter *ibf; | ||
2154 | op->differential_sync_iterations++; | ||
2155 | |||
2156 | /** | ||
2157 | * Enforce min size of IBF | ||
2158 | */ | ||
2159 | uint32_t ibf_min_size = IBF_MIN_SIZE; | ||
2160 | |||
2161 | if (ibf_size < ibf_min_size) | ||
2162 | { | ||
2163 | ibf_size = ibf_min_size; | ||
2164 | } | ||
2165 | if (GNUNET_OK != | ||
2166 | prepare_ibf (op, ibf_size)) | ||
2167 | { | ||
2168 | /* allocation failed */ | ||
2169 | return GNUNET_SYSERR; | ||
2170 | } | ||
2171 | |||
2172 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2173 | "sending ibf of size %u\n", | ||
2174 | (unsigned int) ibf_size); | ||
2175 | |||
2176 | { | ||
2177 | char name[64]; | ||
2178 | |||
2179 | GNUNET_snprintf (name, | ||
2180 | sizeof(name), | ||
2181 | "# sent IBF (order %u)", | ||
2182 | ibf_size); | ||
2183 | GNUNET_STATISTICS_update (_GSS_statistics, name, 1, GNUNET_NO); | ||
2184 | } | ||
2185 | |||
2186 | ibf = op->local_ibf; | ||
2187 | |||
2188 | while (buckets_sent < ibf_size) | ||
2189 | { | ||
2190 | unsigned int buckets_in_message; | ||
2191 | struct GNUNET_MQ_Envelope *ev; | ||
2192 | struct IBFMessage *msg; | ||
2193 | |||
2194 | buckets_in_message = ibf_size - buckets_sent; | ||
2195 | /* limit to maximum */ | ||
2196 | if (buckets_in_message > MAX_BUCKETS_PER_MESSAGE) | ||
2197 | buckets_in_message = MAX_BUCKETS_PER_MESSAGE; | ||
2198 | |||
2199 | #if MEASURE_PERFORMANCE | ||
2200 | perf_store.ibf.sent += 1; | ||
2201 | perf_store.ibf.sent_var_bytes += (buckets_in_message * IBF_BUCKET_SIZE); | ||
2202 | #endif | ||
2203 | ev = GNUNET_MQ_msg_extra (msg, | ||
2204 | buckets_in_message * IBF_BUCKET_SIZE, | ||
2205 | GNUNET_MESSAGE_TYPE_SETU_P2P_IBF); | ||
2206 | msg->ibf_size = ibf_size; | ||
2207 | msg->offset = htonl (buckets_sent); | ||
2208 | msg->salt = htonl (op->salt_send); | ||
2209 | msg->ibf_counter_bit_length = ibf_get_max_counter (ibf); | ||
2210 | |||
2211 | |||
2212 | ibf_write_slice (ibf, buckets_sent, | ||
2213 | buckets_in_message, &msg[1], msg->ibf_counter_bit_length); | ||
2214 | buckets_sent += buckets_in_message; | ||
2215 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2216 | "ibf chunk size %u, %llu/%u sent\n", | ||
2217 | (unsigned int) buckets_in_message, | ||
2218 | (unsigned long long) buckets_sent, | ||
2219 | (unsigned int) ibf_size); | ||
2220 | GNUNET_MQ_send (op->mq, ev); | ||
2221 | } | ||
2222 | |||
2223 | /* The other peer must decode the IBF, so | ||
2224 | * we're passive. */ | ||
2225 | op->phase = PHASE_PASSIVE_DECODING; | ||
2226 | return GNUNET_OK; | ||
2227 | } | ||
2228 | |||
2229 | |||
2230 | /** | ||
2231 | * Compute the necessary order of an ibf | ||
2232 | * from the size of the symmetric set difference. | ||
2233 | * | ||
2234 | * @param diff the difference | ||
2235 | * @return the required size of the ibf | ||
2236 | */ | ||
2237 | static unsigned int | ||
2238 | get_size_from_difference (unsigned int diff, int number_buckets_per_element, | ||
2239 | float ibf_bucket_number_factor) | ||
2240 | { | ||
2241 | /** Make ibf estimation size odd reasoning can be found in BSc Thesis of | ||
2242 | * Elias Summermatter (2021) in section 3.11 **/ | ||
2243 | return (((int) (diff * ibf_bucket_number_factor)) | 1); | ||
2244 | |||
2245 | } | ||
2246 | |||
2247 | |||
2248 | static unsigned int | ||
2249 | get_next_ibf_size (float ibf_bucket_number_factor, unsigned int | ||
2250 | decoded_elements, unsigned int last_ibf_size) | ||
2251 | { | ||
2252 | unsigned int next_size = (unsigned int) ((last_ibf_size * 2) | ||
2253 | - (ibf_bucket_number_factor | ||
2254 | * decoded_elements)); | ||
2255 | /** Make ibf estimation size odd reasoning can be found in BSc Thesis of | ||
2256 | * Elias Summermatter (2021) in section 3.11 **/ | ||
2257 | return next_size | 1; | ||
2258 | } | ||
2259 | |||
2260 | |||
2261 | /** | ||
2262 | * Send a set element. | ||
2263 | * | ||
2264 | * @param cls the union operation `struct Operation *` | ||
2265 | * @param key unused | ||
2266 | * @param value the `struct ElementEntry *` to insert | ||
2267 | * into the key-to-element mapping | ||
2268 | * @return #GNUNET_YES (to continue iterating) | ||
2269 | */ | ||
2270 | static int | ||
2271 | send_full_element_iterator (void *cls, | ||
2272 | const struct GNUNET_HashCode *key, | ||
2273 | void *value) | ||
2274 | { | ||
2275 | struct Operation *op = cls; | ||
2276 | struct GNUNET_SETU_ElementMessage *emsg; | ||
2277 | struct ElementEntry *ee = value; | ||
2278 | struct GNUNET_SETU_Element *el = &ee->element; | ||
2279 | struct GNUNET_MQ_Envelope *ev; | ||
2280 | |||
2281 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2282 | "Sending element %s\n", | ||
2283 | GNUNET_h2s (key)); | ||
2284 | #if MEASURE_PERFORMANCE | ||
2285 | perf_store.element_full.received += 1; | ||
2286 | perf_store.element_full.received_var_bytes += el->size; | ||
2287 | #endif | ||
2288 | ev = GNUNET_MQ_msg_extra (emsg, | ||
2289 | el->size, | ||
2290 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_ELEMENT); | ||
2291 | emsg->element_type = htons (el->element_type); | ||
2292 | GNUNET_memcpy (&emsg[1], | ||
2293 | el->data, | ||
2294 | el->size); | ||
2295 | GNUNET_MQ_send (op->mq, | ||
2296 | ev); | ||
2297 | return GNUNET_YES; | ||
2298 | } | ||
2299 | |||
2300 | |||
2301 | /** | ||
2302 | * Switch to full set transmission for @a op. | ||
2303 | * | ||
2304 | * @param op operation to switch to full set transmission. | ||
2305 | */ | ||
2306 | static void | ||
2307 | send_full_set (struct Operation *op) | ||
2308 | { | ||
2309 | struct GNUNET_MQ_Envelope *ev; | ||
2310 | |||
2311 | op->phase = PHASE_FULL_SENDING; | ||
2312 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2313 | "Dedicing to transmit the full set\n"); | ||
2314 | /* FIXME: use a more memory-friendly way of doing this with an | ||
2315 | iterator, just as we do in the non-full case! */ | ||
2316 | |||
2317 | // Randomize Elements to send | ||
2318 | op->set->content->elements_randomized = GNUNET_CONTAINER_multihashmap_create ( | ||
2319 | 32,GNUNET_NO); | ||
2320 | op->set->content->elements_randomized_salt = GNUNET_CRYPTO_random_u64 ( | ||
2321 | GNUNET_CRYPTO_QUALITY_NONCE, | ||
2322 | UINT64_MAX); | ||
2323 | (void) GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
2324 | & | ||
2325 | create_randomized_element_iterator, | ||
2326 | op); | ||
2327 | |||
2328 | (void) GNUNET_CONTAINER_multihashmap_iterate ( | ||
2329 | op->set->content->elements_randomized, | ||
2330 | &send_full_element_iterator, | ||
2331 | op); | ||
2332 | #if MEASURE_PERFORMANCE | ||
2333 | perf_store.full_done.sent += 1; | ||
2334 | #endif | ||
2335 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_DONE); | ||
2336 | GNUNET_MQ_send (op->mq, | ||
2337 | ev); | ||
2338 | } | ||
2339 | |||
2340 | |||
2341 | /** | ||
2342 | * Handle a strata estimator from a remote peer | ||
2343 | * | ||
2344 | * @param cls the union operation | ||
2345 | * @param msg the message | ||
2346 | */ | ||
2347 | static int | ||
2348 | check_union_p2p_strata_estimator (void *cls, | ||
2349 | const struct StrataEstimatorMessage *msg) | ||
2350 | { | ||
2351 | struct Operation *op = cls; | ||
2352 | int is_compressed; | ||
2353 | size_t len; | ||
2354 | |||
2355 | if (op->phase != PHASE_EXPECT_SE) | ||
2356 | { | ||
2357 | GNUNET_break (0); | ||
2358 | return GNUNET_SYSERR; | ||
2359 | } | ||
2360 | is_compressed = (GNUNET_MESSAGE_TYPE_SETU_P2P_SEC == htons ( | ||
2361 | msg->header.type)); | ||
2362 | len = ntohs (msg->header.size) - sizeof(struct StrataEstimatorMessage); | ||
2363 | if ((GNUNET_NO == is_compressed) && | ||
2364 | (len != SE_STRATA_COUNT * SE_IBFS_TOTAL_SIZE * IBF_BUCKET_SIZE)) | ||
2365 | { | ||
2366 | GNUNET_break (0); | ||
2367 | return GNUNET_SYSERR; | ||
2368 | } | ||
2369 | return GNUNET_OK; | ||
2370 | } | ||
2371 | |||
2372 | |||
2373 | /** | ||
2374 | * Handle a strata estimator from a remote peer | ||
2375 | * | ||
2376 | * @param cls the union operation | ||
2377 | * @param msg the message | ||
2378 | */ | ||
2379 | static void | ||
2380 | handle_union_p2p_strata_estimator (void *cls, | ||
2381 | const struct StrataEstimatorMessage *msg) | ||
2382 | { | ||
2383 | #if MEASURE_PERFORMANCE | ||
2384 | perf_store.se.received += 1; | ||
2385 | perf_store.se.received_var_bytes += ntohs (msg->header.size) - sizeof(struct | ||
2386 | StrataEstimatorMessage); | ||
2387 | #endif | ||
2388 | struct Operation *op = cls; | ||
2389 | struct MultiStrataEstimator *remote_se; | ||
2390 | unsigned int diff; | ||
2391 | uint64_t other_size; | ||
2392 | size_t len; | ||
2393 | int is_compressed; | ||
2394 | op->local_element_count = GNUNET_CONTAINER_multihashmap_size ( | ||
2395 | op->set->content->elements); | ||
2396 | // Setting peer site to receiving peer | ||
2397 | op->peer_site = 1; | ||
2398 | |||
2399 | /** | ||
2400 | * Check that the message is received only in supported phase | ||
2401 | */ | ||
2402 | uint8_t allowed_phases[] = {PHASE_EXPECT_SE}; | ||
2403 | if (GNUNET_OK != | ||
2404 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
2405 | { | ||
2406 | GNUNET_break (0); | ||
2407 | fail_union_operation (op); | ||
2408 | return; | ||
2409 | } | ||
2410 | |||
2411 | /** Only allow 1,2,4,8 SEs **/ | ||
2412 | if ((msg->se_count > 8) || (__builtin_popcount ((int) msg->se_count) != 1)) | ||
2413 | { | ||
2414 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2415 | "PROTOCOL VIOLATION: Invalid number of se transmitted by other peer %u\n", | ||
2416 | msg->se_count); | ||
2417 | GNUNET_break_op (0); | ||
2418 | fail_union_operation (op); | ||
2419 | return; | ||
2420 | } | ||
2421 | |||
2422 | is_compressed = (GNUNET_MESSAGE_TYPE_SETU_P2P_SEC == htons ( | ||
2423 | msg->header.type)); | ||
2424 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
2425 | "# bytes of SE received", | ||
2426 | ntohs (msg->header.size), | ||
2427 | GNUNET_NO); | ||
2428 | len = ntohs (msg->header.size) - sizeof(struct StrataEstimatorMessage); | ||
2429 | other_size = GNUNET_ntohll (msg->set_size); | ||
2430 | op->remote_element_count = other_size; | ||
2431 | |||
2432 | if (op->byzantine_upper_bound < op->remote_element_count) | ||
2433 | { | ||
2434 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2435 | "Exceeded configured upper bound <%"PRIu64"> of element: %u\n", | ||
2436 | op->byzantine_upper_bound, | ||
2437 | op->remote_element_count); | ||
2438 | fail_union_operation (op); | ||
2439 | return; | ||
2440 | } | ||
2441 | |||
2442 | remote_se = strata_estimator_create (SE_STRATA_COUNT, | ||
2443 | SE_IBFS_TOTAL_SIZE, | ||
2444 | SE_IBF_HASH_NUM); | ||
2445 | if (NULL == remote_se) | ||
2446 | { | ||
2447 | /* insufficient resources, fail */ | ||
2448 | fail_union_operation (op); | ||
2449 | return; | ||
2450 | } | ||
2451 | if (GNUNET_OK != | ||
2452 | strata_estimator_read (&msg[1], | ||
2453 | len, | ||
2454 | is_compressed, | ||
2455 | msg->se_count, | ||
2456 | SE_IBFS_TOTAL_SIZE, | ||
2457 | remote_se)) | ||
2458 | { | ||
2459 | /* decompression failed */ | ||
2460 | strata_estimator_destroy (remote_se); | ||
2461 | fail_union_operation (op); | ||
2462 | return; | ||
2463 | } | ||
2464 | GNUNET_assert (NULL != op->se); | ||
2465 | strata_estimator_difference (remote_se, | ||
2466 | op->se); | ||
2467 | |||
2468 | /* Calculate remote local diff */ | ||
2469 | long diff_remote = remote_se->stratas[0]->strata[0]->remote_decoded_count; | ||
2470 | long diff_local = remote_se->stratas[0]->strata[0]->local_decoded_count; | ||
2471 | |||
2472 | /* Prevent estimations from overshooting max element */ | ||
2473 | if (diff_remote + op->remote_element_count > op->byzantine_upper_bound) | ||
2474 | diff_remote = op->byzantine_upper_bound - op->remote_element_count; | ||
2475 | if (diff_local + op->local_element_count > op->byzantine_upper_bound) | ||
2476 | diff_local = op->byzantine_upper_bound - op->local_element_count; | ||
2477 | if ((diff_remote < 0) || (diff_local < 0)) | ||
2478 | { | ||
2479 | strata_estimator_destroy (remote_se); | ||
2480 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2481 | "PROTOCOL VIOLATION: More element is set as upper boundary or other peer is " | ||
2482 | "malicious: remote diff %ld, local diff: %ld\n", | ||
2483 | diff_remote, diff_local); | ||
2484 | GNUNET_break_op (0); | ||
2485 | fail_union_operation (op); | ||
2486 | return; | ||
2487 | } | ||
2488 | |||
2489 | /* Make estimation more precise in initial sync cases */ | ||
2490 | if (0 == op->remote_element_count) | ||
2491 | { | ||
2492 | diff_remote = 0; | ||
2493 | diff_local = op->local_element_count; | ||
2494 | } | ||
2495 | if (0 == op->local_element_count) | ||
2496 | { | ||
2497 | diff_local = 0; | ||
2498 | diff_remote = op->remote_element_count; | ||
2499 | } | ||
2500 | |||
2501 | diff = diff_remote + diff_local; | ||
2502 | op->remote_set_diff = diff_remote; | ||
2503 | |||
2504 | /** Calculate avg element size if not initial sync **/ | ||
2505 | uint64_t avg_element_size = 0; | ||
2506 | if (0 < op->local_element_count) | ||
2507 | { | ||
2508 | op->total_elements_size_local = 0; | ||
2509 | GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
2510 | & | ||
2511 | determinate_avg_element_size_iterator, | ||
2512 | op); | ||
2513 | avg_element_size = op->total_elements_size_local / op->local_element_count; | ||
2514 | } | ||
2515 | |||
2516 | op->mode_of_operation = estimate_best_mode_of_operation (avg_element_size, | ||
2517 | GNUNET_CONTAINER_multihashmap_size ( | ||
2518 | op->set->content-> | ||
2519 | elements), | ||
2520 | op-> | ||
2521 | remote_element_count, | ||
2522 | diff_remote, | ||
2523 | diff_local, | ||
2524 | op-> | ||
2525 | rtt_bandwidth_tradeoff, | ||
2526 | op-> | ||
2527 | ibf_bucket_number_factor); | ||
2528 | |||
2529 | #if MEASURE_PERFORMANCE | ||
2530 | perf_store.se_diff_local = diff_local; | ||
2531 | perf_store.se_diff_remote = diff_remote; | ||
2532 | perf_store.se_diff = diff; | ||
2533 | perf_store.mode_of_operation = op->mode_of_operation; | ||
2534 | #endif | ||
2535 | |||
2536 | strata_estimator_destroy (remote_se); | ||
2537 | strata_estimator_destroy (op->se); | ||
2538 | op->se = NULL; | ||
2539 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2540 | "got se diff=%d, using ibf size %d\n", | ||
2541 | diff, | ||
2542 | 1U << get_size_from_difference (diff, op->ibf_number_buckets_per_element, | ||
2543 | op->ibf_bucket_number_factor)); | ||
2544 | |||
2545 | { | ||
2546 | char *set_debug; | ||
2547 | |||
2548 | set_debug = getenv ("GNUNET_SETU_BENCHMARK"); | ||
2549 | if ((NULL != set_debug) && | ||
2550 | (0 == strcmp (set_debug, "1"))) | ||
2551 | { | ||
2552 | FILE *f = fopen ("set.log", "a"); | ||
2553 | fprintf (f, "%llu\n", (unsigned long long) diff); | ||
2554 | fclose (f); | ||
2555 | } | ||
2556 | } | ||
2557 | |||
2558 | if ((GNUNET_YES == op->byzantine) && | ||
2559 | (other_size < op->byzantine_lower_bound)) | ||
2560 | { | ||
2561 | GNUNET_break (0); | ||
2562 | fail_union_operation (op); | ||
2563 | return; | ||
2564 | } | ||
2565 | |||
2566 | if ((GNUNET_YES == op->force_full) || | ||
2567 | (op->mode_of_operation != DIFFERENTIAL_SYNC)) | ||
2568 | { | ||
2569 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2570 | "Deciding to go for full set transmission (diff=%d, own set=%llu)\n", | ||
2571 | diff, | ||
2572 | (unsigned long long) op->initial_size); | ||
2573 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
2574 | "# of full sends", | ||
2575 | 1, | ||
2576 | GNUNET_NO); | ||
2577 | if (FULL_SYNC_LOCAL_SENDING_FIRST == op->mode_of_operation) | ||
2578 | { | ||
2579 | struct TransmitFullMessage *signal_msg; | ||
2580 | struct GNUNET_MQ_Envelope *ev; | ||
2581 | ev = GNUNET_MQ_msg_extra (signal_msg,sizeof(struct TransmitFullMessage), | ||
2582 | GNUNET_MESSAGE_TYPE_SETU_P2P_SEND_FULL); | ||
2583 | signal_msg->remote_set_difference = htonl (diff_local); | ||
2584 | signal_msg->remote_set_size = htonl (op->local_element_count); | ||
2585 | signal_msg->local_set_difference = htonl (diff_remote); | ||
2586 | GNUNET_MQ_send (op->mq, | ||
2587 | ev); | ||
2588 | send_full_set (op); | ||
2589 | } | ||
2590 | else | ||
2591 | { | ||
2592 | struct GNUNET_MQ_Envelope *ev; | ||
2593 | |||
2594 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2595 | "Telling other peer that we expect its full set\n"); | ||
2596 | op->phase = PHASE_FULL_RECEIVING; | ||
2597 | #if MEASURE_PERFORMANCE | ||
2598 | perf_store.request_full.sent += 1; | ||
2599 | #endif | ||
2600 | struct TransmitFullMessage *signal_msg; | ||
2601 | ev = GNUNET_MQ_msg_extra (signal_msg,sizeof(struct TransmitFullMessage), | ||
2602 | GNUNET_MESSAGE_TYPE_SETU_P2P_REQUEST_FULL); | ||
2603 | signal_msg->remote_set_difference = htonl (diff_local); | ||
2604 | signal_msg->remote_set_size = htonl (op->local_element_count); | ||
2605 | signal_msg->local_set_difference = htonl (diff_remote); | ||
2606 | GNUNET_MQ_send (op->mq, | ||
2607 | ev); | ||
2608 | } | ||
2609 | } | ||
2610 | else | ||
2611 | { | ||
2612 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
2613 | "# of ibf sends", | ||
2614 | 1, | ||
2615 | GNUNET_NO); | ||
2616 | if (GNUNET_OK != | ||
2617 | send_ibf (op, | ||
2618 | get_size_from_difference (diff, | ||
2619 | op->ibf_number_buckets_per_element, | ||
2620 | op->ibf_bucket_number_factor))) | ||
2621 | { | ||
2622 | /* Internal error, best we can do is shut the connection */ | ||
2623 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2624 | "Failed to send IBF, closing connection\n"); | ||
2625 | fail_union_operation (op); | ||
2626 | return; | ||
2627 | } | ||
2628 | } | ||
2629 | GNUNET_CADET_receive_done (op->channel); | ||
2630 | } | ||
2631 | |||
2632 | |||
2633 | /** | ||
2634 | * Iterator to send elements to a remote peer | ||
2635 | * | ||
2636 | * @param cls closure with the element key and the union operation | ||
2637 | * @param key ignored | ||
2638 | * @param value the key entry | ||
2639 | */ | ||
2640 | static int | ||
2641 | send_offers_iterator (void *cls, | ||
2642 | uint32_t key, | ||
2643 | void *value) | ||
2644 | { | ||
2645 | struct SendElementClosure *sec = cls; | ||
2646 | struct Operation *op = sec->op; | ||
2647 | struct KeyEntry *ke = value; | ||
2648 | struct GNUNET_MQ_Envelope *ev; | ||
2649 | struct GNUNET_MessageHeader *mh; | ||
2650 | |||
2651 | /* Detect 32-bit key collision for the 64-bit IBF keys. */ | ||
2652 | if (ke->ibf_key.key_val != sec->ibf_key.key_val) | ||
2653 | { | ||
2654 | op->active_passive_switch_required = true; | ||
2655 | return GNUNET_YES; | ||
2656 | } | ||
2657 | |||
2658 | /* Prevent implementation from sending a offer multiple times in case of roll switch */ | ||
2659 | if (GNUNET_YES == | ||
2660 | is_message_in_message_control_flow ( | ||
2661 | op->message_control_flow, | ||
2662 | &ke->element->element_hash, | ||
2663 | OFFER_MESSAGE) | ||
2664 | ) | ||
2665 | { | ||
2666 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2667 | "Skipping already sent processed element offer!\n"); | ||
2668 | return GNUNET_YES; | ||
2669 | } | ||
2670 | |||
2671 | /* Save send offer message for message control */ | ||
2672 | if (GNUNET_YES != | ||
2673 | update_message_control_flow ( | ||
2674 | op->message_control_flow, | ||
2675 | MSG_CFS_SENT, | ||
2676 | &ke->element->element_hash, | ||
2677 | OFFER_MESSAGE) | ||
2678 | ) | ||
2679 | { | ||
2680 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2681 | "Double offer message sent found!\n"); | ||
2682 | GNUNET_break (0); | ||
2683 | fail_union_operation (op); | ||
2684 | return GNUNET_NO; | ||
2685 | } | ||
2686 | ; | ||
2687 | |||
2688 | /* Mark element to be expected to received */ | ||
2689 | if (GNUNET_YES != | ||
2690 | update_message_control_flow ( | ||
2691 | op->message_control_flow, | ||
2692 | MSG_CFS_EXPECTED, | ||
2693 | &ke->element->element_hash, | ||
2694 | DEMAND_MESSAGE) | ||
2695 | ) | ||
2696 | { | ||
2697 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2698 | "Double demand received found!\n"); | ||
2699 | GNUNET_break (0); | ||
2700 | fail_union_operation (op); | ||
2701 | return GNUNET_NO; | ||
2702 | } | ||
2703 | ; | ||
2704 | #if MEASURE_PERFORMANCE | ||
2705 | perf_store.offer.sent += 1; | ||
2706 | perf_store.offer.sent_var_bytes += sizeof(struct GNUNET_HashCode); | ||
2707 | #endif | ||
2708 | ev = GNUNET_MQ_msg_header_extra (mh, | ||
2709 | sizeof(struct GNUNET_HashCode), | ||
2710 | GNUNET_MESSAGE_TYPE_SETU_P2P_OFFER); | ||
2711 | GNUNET_assert (NULL != ev); | ||
2712 | *(struct GNUNET_HashCode *) &mh[1] = ke->element->element_hash; | ||
2713 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2714 | "[OP %p] sending element offer (%s) to peer\n", | ||
2715 | op, | ||
2716 | GNUNET_h2s (&ke->element->element_hash)); | ||
2717 | GNUNET_MQ_send (op->mq, ev); | ||
2718 | return GNUNET_YES; | ||
2719 | } | ||
2720 | |||
2721 | |||
2722 | /** | ||
2723 | * Send offers (in the form of GNUNET_Hash-es) to the remote peer for the given IBF key. | ||
2724 | * | ||
2725 | * @param op union operation | ||
2726 | * @param ibf_key IBF key of interest | ||
2727 | */ | ||
2728 | void | ||
2729 | send_offers_for_key (struct Operation *op, | ||
2730 | struct IBF_Key ibf_key) | ||
2731 | { | ||
2732 | struct SendElementClosure send_cls; | ||
2733 | |||
2734 | send_cls.ibf_key = ibf_key; | ||
2735 | send_cls.op = op; | ||
2736 | (void) GNUNET_CONTAINER_multihashmap32_get_multiple ( | ||
2737 | op->key_to_element, | ||
2738 | (uint32_t) ibf_key. | ||
2739 | key_val, | ||
2740 | &send_offers_iterator, | ||
2741 | &send_cls); | ||
2742 | } | ||
2743 | |||
2744 | |||
2745 | /** | ||
2746 | * Decode which elements are missing on each side, and | ||
2747 | * send the appropriate offers and inquiries. | ||
2748 | * | ||
2749 | * @param op union operation | ||
2750 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
2751 | */ | ||
2752 | static int | ||
2753 | decode_and_send (struct Operation *op) | ||
2754 | { | ||
2755 | struct IBF_Key key; | ||
2756 | struct IBF_Key last_key; | ||
2757 | int side; | ||
2758 | unsigned int num_decoded; | ||
2759 | struct InvertibleBloomFilter *diff_ibf; | ||
2760 | |||
2761 | GNUNET_assert (PHASE_ACTIVE_DECODING == op->phase); | ||
2762 | |||
2763 | if (GNUNET_OK != | ||
2764 | prepare_ibf (op, | ||
2765 | op->remote_ibf->size)) | ||
2766 | { | ||
2767 | GNUNET_break (0); | ||
2768 | /* allocation failed */ | ||
2769 | return GNUNET_SYSERR; | ||
2770 | } | ||
2771 | |||
2772 | diff_ibf = ibf_dup (op->local_ibf); | ||
2773 | ibf_subtract (diff_ibf, | ||
2774 | op->remote_ibf); | ||
2775 | |||
2776 | ibf_destroy (op->remote_ibf); | ||
2777 | op->remote_ibf = NULL; | ||
2778 | |||
2779 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2780 | "decoding IBF (size=%u)\n", | ||
2781 | diff_ibf->size); | ||
2782 | |||
2783 | num_decoded = 0; | ||
2784 | key.key_val = 0; /* just to avoid compiler thinking we use undef'ed variable */ | ||
2785 | |||
2786 | while (1) | ||
2787 | { | ||
2788 | int res; | ||
2789 | int cycle_detected = GNUNET_NO; | ||
2790 | |||
2791 | last_key = key; | ||
2792 | |||
2793 | res = ibf_decode (diff_ibf, | ||
2794 | &side, | ||
2795 | &key); | ||
2796 | if (res == GNUNET_OK) | ||
2797 | { | ||
2798 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2799 | "decoded ibf key %lx\n", | ||
2800 | (unsigned long) key.key_val); | ||
2801 | num_decoded += 1; | ||
2802 | if ((num_decoded > diff_ibf->size) || | ||
2803 | ((num_decoded > 1) && | ||
2804 | (last_key.key_val == key.key_val))) | ||
2805 | { | ||
2806 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2807 | "detected cyclic ibf (decoded %u/%u)\n", | ||
2808 | num_decoded, | ||
2809 | diff_ibf->size); | ||
2810 | cycle_detected = GNUNET_YES; | ||
2811 | } | ||
2812 | } | ||
2813 | if ((GNUNET_SYSERR == res) || | ||
2814 | (GNUNET_YES == cycle_detected)) | ||
2815 | { | ||
2816 | uint32_t next_size; | ||
2817 | /** Enforce odd ibf size **/ | ||
2818 | |||
2819 | next_size = get_next_ibf_size (op->ibf_bucket_number_factor, num_decoded, | ||
2820 | diff_ibf->size); | ||
2821 | /** Make ibf estimation size odd reasoning can be found in BSc Thesis of | ||
2822 | * Elias Summermatter (2021) in section 3.11 **/ | ||
2823 | uint32_t ibf_min_size = IBF_MIN_SIZE | 1; | ||
2824 | |||
2825 | if (next_size<ibf_min_size) | ||
2826 | next_size = ibf_min_size; | ||
2827 | |||
2828 | |||
2829 | if (next_size <= MAX_IBF_SIZE) | ||
2830 | { | ||
2831 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2832 | "decoding failed, sending larger ibf (size %u)\n", | ||
2833 | next_size); | ||
2834 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
2835 | "# of IBF retries", | ||
2836 | 1, | ||
2837 | GNUNET_NO); | ||
2838 | #if MEASURE_PERFORMANCE | ||
2839 | perf_store.active_passive_switches += 1; | ||
2840 | #endif | ||
2841 | |||
2842 | op->salt_send = op->salt_receive++; | ||
2843 | |||
2844 | if (GNUNET_OK != | ||
2845 | send_ibf (op, next_size)) | ||
2846 | { | ||
2847 | /* Internal error, best we can do is shut the connection */ | ||
2848 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2849 | "Failed to send IBF, closing connection\n"); | ||
2850 | fail_union_operation (op); | ||
2851 | ibf_destroy (diff_ibf); | ||
2852 | return GNUNET_SYSERR; | ||
2853 | } | ||
2854 | } | ||
2855 | else | ||
2856 | { | ||
2857 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
2858 | "# of failed union operations (too large)", | ||
2859 | 1, | ||
2860 | GNUNET_NO); | ||
2861 | // XXX: Send the whole set, element-by-element | ||
2862 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2863 | "set union failed: reached ibf limit\n"); | ||
2864 | fail_union_operation (op); | ||
2865 | ibf_destroy (diff_ibf); | ||
2866 | return GNUNET_SYSERR; | ||
2867 | } | ||
2868 | break; | ||
2869 | } | ||
2870 | if (GNUNET_NO == res) | ||
2871 | { | ||
2872 | struct GNUNET_MQ_Envelope *ev; | ||
2873 | |||
2874 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2875 | "transmitted all values, sending DONE\n"); | ||
2876 | |||
2877 | #if MEASURE_PERFORMANCE | ||
2878 | perf_store.done.sent += 1; | ||
2879 | #endif | ||
2880 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SETU_P2P_DONE); | ||
2881 | GNUNET_MQ_send (op->mq, ev); | ||
2882 | /* We now wait until we get a DONE message back | ||
2883 | * and then wait for our MQ to be flushed and all our | ||
2884 | * demands be delivered. */ | ||
2885 | break; | ||
2886 | } | ||
2887 | if (1 == side) | ||
2888 | { | ||
2889 | struct IBF_Key unsalted_key; | ||
2890 | unsalt_key (&key, | ||
2891 | op->salt_receive, | ||
2892 | &unsalted_key); | ||
2893 | send_offers_for_key (op, | ||
2894 | unsalted_key); | ||
2895 | } | ||
2896 | else if (-1 == side) | ||
2897 | { | ||
2898 | struct GNUNET_MQ_Envelope *ev; | ||
2899 | struct InquiryMessage *msg; | ||
2900 | |||
2901 | #if MEASURE_PERFORMANCE | ||
2902 | perf_store.inquery.sent += 1; | ||
2903 | perf_store.inquery.sent_var_bytes += sizeof(struct IBF_Key); | ||
2904 | #endif | ||
2905 | |||
2906 | /** Add sent inquiries to hashmap for flow control **/ | ||
2907 | struct GNUNET_HashContext *hashed_key_context = | ||
2908 | GNUNET_CRYPTO_hash_context_start (); | ||
2909 | struct GNUNET_HashCode *hashed_key = (struct | ||
2910 | GNUNET_HashCode*) GNUNET_malloc ( | ||
2911 | sizeof(struct GNUNET_HashCode)); | ||
2912 | enum MESSAGE_CONTROL_FLOW_STATE mcfs = MSG_CFS_SENT; | ||
2913 | GNUNET_CRYPTO_hash_context_read (hashed_key_context, | ||
2914 | &key, | ||
2915 | sizeof(struct IBF_Key)); | ||
2916 | GNUNET_CRYPTO_hash_context_finish (hashed_key_context, | ||
2917 | hashed_key); | ||
2918 | GNUNET_CONTAINER_multihashmap_put (op->inquiries_sent, | ||
2919 | hashed_key, | ||
2920 | &mcfs, | ||
2921 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE | ||
2922 | ); | ||
2923 | |||
2924 | /* It may be nice to merge multiple requests, but with CADET's corking it is not worth | ||
2925 | * the effort additional complexity. */ | ||
2926 | ev = GNUNET_MQ_msg_extra (msg, | ||
2927 | sizeof(struct IBF_Key), | ||
2928 | GNUNET_MESSAGE_TYPE_SETU_P2P_INQUIRY); | ||
2929 | msg->salt = htonl (op->salt_receive); | ||
2930 | GNUNET_memcpy (&msg[1], | ||
2931 | &key, | ||
2932 | sizeof(struct IBF_Key)); | ||
2933 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2934 | "sending element inquiry for IBF key %lx\n", | ||
2935 | (unsigned long) key.key_val); | ||
2936 | GNUNET_MQ_send (op->mq, ev); | ||
2937 | } | ||
2938 | else | ||
2939 | { | ||
2940 | GNUNET_assert (0); | ||
2941 | } | ||
2942 | } | ||
2943 | ibf_destroy (diff_ibf); | ||
2944 | return GNUNET_OK; | ||
2945 | } | ||
2946 | |||
2947 | |||
2948 | /** | ||
2949 | * Check send full message received from other peer | ||
2950 | * @param cls | ||
2951 | * @param msg | ||
2952 | * @return | ||
2953 | */ | ||
2954 | |||
2955 | static int | ||
2956 | check_union_p2p_send_full (void *cls, | ||
2957 | const struct TransmitFullMessage *msg) | ||
2958 | { | ||
2959 | return GNUNET_OK; | ||
2960 | } | ||
2961 | |||
2962 | |||
2963 | /** | ||
2964 | * Handle send full message received from other peer | ||
2965 | * | ||
2966 | * @param cls | ||
2967 | * @param msg | ||
2968 | */ | ||
2969 | static void | ||
2970 | handle_union_p2p_send_full (void *cls, | ||
2971 | const struct TransmitFullMessage *msg) | ||
2972 | { | ||
2973 | struct Operation *op = cls; | ||
2974 | |||
2975 | /** | ||
2976 | * Check that the message is received only in supported phase | ||
2977 | */ | ||
2978 | uint8_t allowed_phases[] = {PHASE_EXPECT_IBF}; | ||
2979 | if (GNUNET_OK != | ||
2980 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
2981 | { | ||
2982 | GNUNET_break (0); | ||
2983 | fail_union_operation (op); | ||
2984 | return; | ||
2985 | } | ||
2986 | |||
2987 | /** write received values to operator**/ | ||
2988 | op->remote_element_count = ntohl (msg->remote_set_size); | ||
2989 | op->remote_set_diff = ntohl (msg->remote_set_difference); | ||
2990 | op->local_set_diff = ntohl (msg->local_set_difference); | ||
2991 | |||
2992 | /** Check byzantine limits **/ | ||
2993 | if (check_byzantine_bounds (op) != GNUNET_OK) | ||
2994 | { | ||
2995 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2996 | "PROTOCOL VIOLATION: Parameters transmitted from other peer do not satisfie byzantine " | ||
2997 | "criteria\n"); | ||
2998 | GNUNET_break_op (0); | ||
2999 | fail_union_operation (op); | ||
3000 | return; | ||
3001 | } | ||
3002 | |||
3003 | /** Calculate avg element size if not initial sync **/ | ||
3004 | op->local_element_count = GNUNET_CONTAINER_multihashmap_size ( | ||
3005 | op->set->content->elements); | ||
3006 | uint64_t avg_element_size = 0; | ||
3007 | if (0 < op->local_element_count) | ||
3008 | { | ||
3009 | op->total_elements_size_local = 0; | ||
3010 | GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
3011 | & | ||
3012 | determinate_avg_element_size_iterator, | ||
3013 | op); | ||
3014 | avg_element_size = op->total_elements_size_local / op->local_element_count; | ||
3015 | } | ||
3016 | |||
3017 | /** Validate mode of operation **/ | ||
3018 | int mode_of_operation = estimate_best_mode_of_operation (avg_element_size, | ||
3019 | op-> | ||
3020 | remote_element_count, | ||
3021 | op-> | ||
3022 | local_element_count, | ||
3023 | op->local_set_diff, | ||
3024 | op->remote_set_diff, | ||
3025 | op-> | ||
3026 | rtt_bandwidth_tradeoff, | ||
3027 | op-> | ||
3028 | ibf_bucket_number_factor); | ||
3029 | if (FULL_SYNC_LOCAL_SENDING_FIRST != mode_of_operation) | ||
3030 | { | ||
3031 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3032 | "PROTOCOL VIOLATION: Remote peer choose to send his full set first but correct mode would have been" | ||
3033 | " : %d\n", mode_of_operation); | ||
3034 | GNUNET_break_op (0); | ||
3035 | fail_union_operation (op); | ||
3036 | return; | ||
3037 | } | ||
3038 | op->phase = PHASE_FULL_RECEIVING; | ||
3039 | } | ||
3040 | |||
3041 | |||
3042 | /** | ||
3043 | * Check an IBF message from a remote peer. | ||
3044 | * | ||
3045 | * Reassemble the IBF from multiple pieces, and | ||
3046 | * process the whole IBF once possible. | ||
3047 | * | ||
3048 | * @param cls the union operation | ||
3049 | * @param msg the header of the message | ||
3050 | * @return #GNUNET_OK if @a msg is well-formed | ||
3051 | */ | ||
3052 | static int | ||
3053 | check_union_p2p_ibf (void *cls, | ||
3054 | const struct IBFMessage *msg) | ||
3055 | { | ||
3056 | struct Operation *op = cls; | ||
3057 | unsigned int buckets_in_message; | ||
3058 | |||
3059 | buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) | ||
3060 | / IBF_BUCKET_SIZE; | ||
3061 | if (0 == buckets_in_message) | ||
3062 | { | ||
3063 | GNUNET_break_op (0); | ||
3064 | return GNUNET_SYSERR; | ||
3065 | } | ||
3066 | if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message | ||
3067 | * IBF_BUCKET_SIZE) | ||
3068 | { | ||
3069 | GNUNET_break_op (0); | ||
3070 | return GNUNET_SYSERR; | ||
3071 | } | ||
3072 | if (op->phase == PHASE_EXPECT_IBF_LAST) | ||
3073 | { | ||
3074 | if (ntohl (msg->offset) != op->ibf_buckets_received) | ||
3075 | { | ||
3076 | GNUNET_break_op (0); | ||
3077 | return GNUNET_SYSERR; | ||
3078 | } | ||
3079 | |||
3080 | if (msg->ibf_size != op->remote_ibf->size) | ||
3081 | { | ||
3082 | GNUNET_break_op (0); | ||
3083 | return GNUNET_SYSERR; | ||
3084 | } | ||
3085 | if (ntohl (msg->salt) != op->salt_receive) | ||
3086 | { | ||
3087 | GNUNET_break_op (0); | ||
3088 | return GNUNET_SYSERR; | ||
3089 | } | ||
3090 | } | ||
3091 | else if ((op->phase != PHASE_PASSIVE_DECODING) && | ||
3092 | (op->phase != PHASE_EXPECT_IBF)) | ||
3093 | { | ||
3094 | GNUNET_break_op (0); | ||
3095 | return GNUNET_SYSERR; | ||
3096 | } | ||
3097 | |||
3098 | return GNUNET_OK; | ||
3099 | } | ||
3100 | |||
3101 | |||
3102 | /** | ||
3103 | * Handle an IBF message from a remote peer. | ||
3104 | * | ||
3105 | * Reassemble the IBF from multiple pieces, and | ||
3106 | * process the whole IBF once possible. | ||
3107 | * | ||
3108 | * @param cls the union operation | ||
3109 | * @param msg the header of the message | ||
3110 | */ | ||
3111 | static void | ||
3112 | handle_union_p2p_ibf (void *cls, | ||
3113 | const struct IBFMessage *msg) | ||
3114 | { | ||
3115 | struct Operation *op = cls; | ||
3116 | unsigned int buckets_in_message; | ||
3117 | /** | ||
3118 | * Check that the message is received only in supported phase | ||
3119 | */ | ||
3120 | uint8_t allowed_phases[] = {PHASE_EXPECT_IBF, PHASE_EXPECT_IBF_LAST, | ||
3121 | PHASE_PASSIVE_DECODING}; | ||
3122 | if (GNUNET_OK != | ||
3123 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3124 | { | ||
3125 | GNUNET_break (0); | ||
3126 | fail_union_operation (op); | ||
3127 | return; | ||
3128 | } | ||
3129 | op->differential_sync_iterations++; | ||
3130 | check_max_differential_rounds (op); | ||
3131 | op->active_passive_switch_required = false; | ||
3132 | |||
3133 | #if MEASURE_PERFORMANCE | ||
3134 | perf_store.ibf.received += 1; | ||
3135 | perf_store.ibf.received_var_bytes += (ntohs (msg->header.size) - sizeof *msg); | ||
3136 | #endif | ||
3137 | |||
3138 | buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) | ||
3139 | / IBF_BUCKET_SIZE; | ||
3140 | if ((op->phase == PHASE_PASSIVE_DECODING) || | ||
3141 | (op->phase == PHASE_EXPECT_IBF)) | ||
3142 | { | ||
3143 | op->phase = PHASE_EXPECT_IBF_LAST; | ||
3144 | GNUNET_assert (NULL == op->remote_ibf); | ||
3145 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3146 | "Creating new ibf of size %u\n", | ||
3147 | ntohl (msg->ibf_size)); | ||
3148 | // op->remote_ibf = ibf_create (1 << msg->order, SE_IBF_HASH_NUM); | ||
3149 | op->remote_ibf = ibf_create (msg->ibf_size, | ||
3150 | ((uint8_t) op->ibf_number_buckets_per_element)); | ||
3151 | op->salt_receive = ntohl (msg->salt); | ||
3152 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3153 | "Receiving new IBF with salt %u\n", | ||
3154 | op->salt_receive); | ||
3155 | if (NULL == op->remote_ibf) | ||
3156 | { | ||
3157 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3158 | "Failed to parse remote IBF, closing connection\n"); | ||
3159 | fail_union_operation (op); | ||
3160 | return; | ||
3161 | } | ||
3162 | op->ibf_buckets_received = 0; | ||
3163 | if (0 != ntohl (msg->offset)) | ||
3164 | { | ||
3165 | GNUNET_break_op (0); | ||
3166 | fail_union_operation (op); | ||
3167 | return; | ||
3168 | } | ||
3169 | } | ||
3170 | else | ||
3171 | { | ||
3172 | GNUNET_assert (op->phase == PHASE_EXPECT_IBF_LAST); | ||
3173 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3174 | "Received more of IBF\n"); | ||
3175 | } | ||
3176 | GNUNET_assert (NULL != op->remote_ibf); | ||
3177 | |||
3178 | ibf_read_slice (&msg[1], | ||
3179 | op->ibf_buckets_received, | ||
3180 | buckets_in_message, | ||
3181 | op->remote_ibf, msg->ibf_counter_bit_length); | ||
3182 | op->ibf_buckets_received += buckets_in_message; | ||
3183 | |||
3184 | if (op->ibf_buckets_received == op->remote_ibf->size) | ||
3185 | { | ||
3186 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3187 | "received full ibf\n"); | ||
3188 | op->phase = PHASE_ACTIVE_DECODING; | ||
3189 | if (GNUNET_OK != | ||
3190 | decode_and_send (op)) | ||
3191 | { | ||
3192 | /* Internal error, best we can do is shut down */ | ||
3193 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3194 | "Failed to decode IBF, closing connection\n"); | ||
3195 | fail_union_operation (op); | ||
3196 | return; | ||
3197 | } | ||
3198 | } | ||
3199 | GNUNET_CADET_receive_done (op->channel); | ||
3200 | } | ||
3201 | |||
3202 | |||
3203 | /** | ||
3204 | * Send a result message to the client indicating | ||
3205 | * that there is a new element. | ||
3206 | * | ||
3207 | * @param op union operation | ||
3208 | * @param element element to send | ||
3209 | * @param status status to send with the new element | ||
3210 | */ | ||
3211 | static void | ||
3212 | send_client_element (struct Operation *op, | ||
3213 | const struct GNUNET_SETU_Element *element, | ||
3214 | enum GNUNET_SETU_Status status) | ||
3215 | { | ||
3216 | struct GNUNET_MQ_Envelope *ev; | ||
3217 | struct GNUNET_SETU_ResultMessage *rm; | ||
3218 | |||
3219 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3220 | "sending element (size %u) to client\n", | ||
3221 | element->size); | ||
3222 | GNUNET_assert (0 != op->client_request_id); | ||
3223 | ev = GNUNET_MQ_msg_extra (rm, | ||
3224 | element->size, | ||
3225 | GNUNET_MESSAGE_TYPE_SETU_RESULT); | ||
3226 | if (NULL == ev) | ||
3227 | { | ||
3228 | GNUNET_MQ_discard (ev); | ||
3229 | GNUNET_break (0); | ||
3230 | return; | ||
3231 | } | ||
3232 | rm->result_status = htons (status); | ||
3233 | rm->request_id = htonl (op->client_request_id); | ||
3234 | rm->element_type = htons (element->element_type); | ||
3235 | rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size ( | ||
3236 | op->key_to_element)); | ||
3237 | GNUNET_memcpy (&rm[1], | ||
3238 | element->data, | ||
3239 | element->size); | ||
3240 | GNUNET_MQ_send (op->set->cs->mq, | ||
3241 | ev); | ||
3242 | } | ||
3243 | |||
3244 | |||
3245 | /** | ||
3246 | * Tests if the operation is finished, and if so notify. | ||
3247 | * | ||
3248 | * @param op operation to check | ||
3249 | */ | ||
3250 | static void | ||
3251 | maybe_finish (struct Operation *op) | ||
3252 | { | ||
3253 | unsigned int num_demanded; | ||
3254 | |||
3255 | num_demanded = GNUNET_CONTAINER_multihashmap_size ( | ||
3256 | op->demanded_hashes); | ||
3257 | int send_done = GNUNET_CONTAINER_multihashmap_iterate ( | ||
3258 | op->message_control_flow, | ||
3259 | & | ||
3260 | determinate_done_message_iterator, | ||
3261 | op); | ||
3262 | if (PHASE_FINISH_WAITING == op->phase) | ||
3263 | { | ||
3264 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3265 | "In PHASE_FINISH_WAITING, pending %u demands -> %d\n", | ||
3266 | num_demanded, op->peer_site); | ||
3267 | if (-1 != send_done) | ||
3268 | { | ||
3269 | struct GNUNET_MQ_Envelope *ev; | ||
3270 | |||
3271 | op->phase = PHASE_FINISHED; | ||
3272 | #if MEASURE_PERFORMANCE | ||
3273 | perf_store.done.sent += 1; | ||
3274 | #endif | ||
3275 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SETU_P2P_DONE); | ||
3276 | GNUNET_MQ_send (op->mq, | ||
3277 | ev); | ||
3278 | /* We now wait until the other peer sends P2P_OVER | ||
3279 | * after it got all elements from us. */ | ||
3280 | } | ||
3281 | } | ||
3282 | if (PHASE_FINISH_CLOSING == op->phase) | ||
3283 | { | ||
3284 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3285 | "In PHASE_FINISH_CLOSING, pending %u demands %d\n", | ||
3286 | num_demanded, op->peer_site); | ||
3287 | if (-1 != send_done) | ||
3288 | { | ||
3289 | op->phase = PHASE_FINISHED; | ||
3290 | send_client_done (op); | ||
3291 | _GSS_operation_destroy2 (op); | ||
3292 | } | ||
3293 | } | ||
3294 | } | ||
3295 | |||
3296 | |||
3297 | /** | ||
3298 | * Check an element message from a remote peer. | ||
3299 | * | ||
3300 | * @param cls the union operation | ||
3301 | * @param emsg the message | ||
3302 | */ | ||
3303 | static int | ||
3304 | check_union_p2p_elements (void *cls, | ||
3305 | const struct GNUNET_SETU_ElementMessage *emsg) | ||
3306 | { | ||
3307 | struct Operation *op = cls; | ||
3308 | |||
3309 | if (0 == GNUNET_CONTAINER_multihashmap_size (op->demanded_hashes)) | ||
3310 | { | ||
3311 | GNUNET_break_op (0); | ||
3312 | return GNUNET_SYSERR; | ||
3313 | } | ||
3314 | return GNUNET_OK; | ||
3315 | } | ||
3316 | |||
3317 | |||
3318 | /** | ||
3319 | * Handle an element message from a remote peer. | ||
3320 | * Sent by the other peer either because we decoded an IBF and placed a demand, | ||
3321 | * or because the other peer switched to full set transmission. | ||
3322 | * | ||
3323 | * @param cls the union operation | ||
3324 | * @param emsg the message | ||
3325 | */ | ||
3326 | static void | ||
3327 | handle_union_p2p_elements (void *cls, | ||
3328 | const struct GNUNET_SETU_ElementMessage *emsg) | ||
3329 | { | ||
3330 | struct Operation *op = cls; | ||
3331 | struct ElementEntry *ee; | ||
3332 | struct KeyEntry *ke; | ||
3333 | uint16_t element_size; | ||
3334 | |||
3335 | /** | ||
3336 | * Check that the message is received only in supported phase | ||
3337 | */ | ||
3338 | uint8_t allowed_phases[] = {PHASE_ACTIVE_DECODING, PHASE_PASSIVE_DECODING, | ||
3339 | PHASE_FINISH_WAITING, PHASE_FINISH_CLOSING}; | ||
3340 | if (GNUNET_OK != | ||
3341 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3342 | { | ||
3343 | GNUNET_break (0); | ||
3344 | fail_union_operation (op); | ||
3345 | return; | ||
3346 | } | ||
3347 | |||
3348 | element_size = ntohs (emsg->header.size) - sizeof(struct | ||
3349 | GNUNET_SETU_ElementMessage); | ||
3350 | #if MEASURE_PERFORMANCE | ||
3351 | perf_store.element.received += 1; | ||
3352 | perf_store.element.received_var_bytes += element_size; | ||
3353 | #endif | ||
3354 | |||
3355 | ee = GNUNET_malloc (sizeof(struct ElementEntry) + element_size); | ||
3356 | GNUNET_memcpy (&ee[1], | ||
3357 | &emsg[1], | ||
3358 | element_size); | ||
3359 | ee->element.size = element_size; | ||
3360 | ee->element.data = &ee[1]; | ||
3361 | ee->element.element_type = ntohs (emsg->element_type); | ||
3362 | ee->remote = GNUNET_YES; | ||
3363 | GNUNET_SETU_element_hash (&ee->element, | ||
3364 | &ee->element_hash); | ||
3365 | if (GNUNET_NO == | ||
3366 | GNUNET_CONTAINER_multihashmap_remove (op->demanded_hashes, | ||
3367 | &ee->element_hash, | ||
3368 | NULL)) | ||
3369 | { | ||
3370 | /* We got something we didn't demand, since it's not in our map. */ | ||
3371 | GNUNET_break_op (0); | ||
3372 | fail_union_operation (op); | ||
3373 | return; | ||
3374 | } | ||
3375 | |||
3376 | if (GNUNET_OK != | ||
3377 | update_message_control_flow ( | ||
3378 | op->message_control_flow, | ||
3379 | MSG_CFS_RECEIVED, | ||
3380 | &ee->element_hash, | ||
3381 | ELEMENT_MESSAGE) | ||
3382 | ) | ||
3383 | { | ||
3384 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3385 | "An element has been received more than once!\n"); | ||
3386 | GNUNET_break (0); | ||
3387 | fail_union_operation (op); | ||
3388 | return; | ||
3389 | } | ||
3390 | |||
3391 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3392 | "Got element (size %u, hash %s) from peer\n", | ||
3393 | (unsigned int) element_size, | ||
3394 | GNUNET_h2s (&ee->element_hash)); | ||
3395 | |||
3396 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3397 | "# received elements", | ||
3398 | 1, | ||
3399 | GNUNET_NO); | ||
3400 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3401 | "# exchanged elements", | ||
3402 | 1, | ||
3403 | GNUNET_NO); | ||
3404 | |||
3405 | op->received_total++; | ||
3406 | |||
3407 | ke = op_get_element (op, | ||
3408 | &ee->element_hash); | ||
3409 | if (NULL != ke) | ||
3410 | { | ||
3411 | /* Got repeated element. Should not happen since | ||
3412 | * we track demands. */ | ||
3413 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3414 | "# repeated elements", | ||
3415 | 1, | ||
3416 | GNUNET_NO); | ||
3417 | ke->received = GNUNET_YES; | ||
3418 | GNUNET_free (ee); | ||
3419 | } | ||
3420 | else | ||
3421 | { | ||
3422 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3423 | "Registering new element from remote peer\n"); | ||
3424 | op->received_fresh++; | ||
3425 | op_register_element (op, ee, GNUNET_YES); | ||
3426 | /* only send results immediately if the client wants it */ | ||
3427 | send_client_element (op, | ||
3428 | &ee->element, | ||
3429 | GNUNET_SETU_STATUS_ADD_LOCAL); | ||
3430 | } | ||
3431 | |||
3432 | if ((op->received_total > 8) && | ||
3433 | (op->received_fresh < op->received_total / 3)) | ||
3434 | { | ||
3435 | /* The other peer gave us lots of old elements, there's something wrong. */ | ||
3436 | GNUNET_break_op (0); | ||
3437 | fail_union_operation (op); | ||
3438 | return; | ||
3439 | } | ||
3440 | GNUNET_CADET_receive_done (op->channel); | ||
3441 | maybe_finish (op); | ||
3442 | } | ||
3443 | |||
3444 | |||
3445 | /** | ||
3446 | * Check a full element message from a remote peer. | ||
3447 | * | ||
3448 | * @param cls the union operation | ||
3449 | * @param emsg the message | ||
3450 | */ | ||
3451 | static int | ||
3452 | check_union_p2p_full_element (void *cls, | ||
3453 | const struct GNUNET_SETU_ElementMessage *emsg) | ||
3454 | { | ||
3455 | struct Operation *op = cls; | ||
3456 | |||
3457 | (void) op; | ||
3458 | |||
3459 | // FIXME: check that we expect full elements here? | ||
3460 | return GNUNET_OK; | ||
3461 | } | ||
3462 | |||
3463 | |||
3464 | /** | ||
3465 | * Handle an element message from a remote peer. | ||
3466 | * | ||
3467 | * @param cls the union operation | ||
3468 | * @param emsg the message | ||
3469 | */ | ||
3470 | static void | ||
3471 | handle_union_p2p_full_element (void *cls, | ||
3472 | const struct GNUNET_SETU_ElementMessage *emsg) | ||
3473 | { | ||
3474 | struct Operation *op = cls; | ||
3475 | struct ElementEntry *ee; | ||
3476 | struct KeyEntry *ke; | ||
3477 | uint16_t element_size; | ||
3478 | |||
3479 | /** | ||
3480 | * Check that the message is received only in supported phase | ||
3481 | */ | ||
3482 | uint8_t allowed_phases[] = {PHASE_FULL_RECEIVING, PHASE_FULL_SENDING}; | ||
3483 | if (GNUNET_OK != | ||
3484 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3485 | { | ||
3486 | GNUNET_break (0); | ||
3487 | fail_union_operation (op); | ||
3488 | return; | ||
3489 | } | ||
3490 | |||
3491 | element_size = ntohs (emsg->header.size) | ||
3492 | - sizeof(struct GNUNET_SETU_ElementMessage); | ||
3493 | |||
3494 | #if MEASURE_PERFORMANCE | ||
3495 | perf_store.element_full.received += 1; | ||
3496 | perf_store.element_full.received_var_bytes += element_size; | ||
3497 | #endif | ||
3498 | |||
3499 | ee = GNUNET_malloc (sizeof(struct ElementEntry) + element_size); | ||
3500 | GNUNET_memcpy (&ee[1], &emsg[1], element_size); | ||
3501 | ee->element.size = element_size; | ||
3502 | ee->element.data = &ee[1]; | ||
3503 | ee->element.element_type = ntohs (emsg->element_type); | ||
3504 | ee->remote = GNUNET_YES; | ||
3505 | GNUNET_SETU_element_hash (&ee->element, | ||
3506 | &ee->element_hash); | ||
3507 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3508 | "Got element (full diff, size %u, hash %s) from peer\n", | ||
3509 | (unsigned int) element_size, | ||
3510 | GNUNET_h2s (&ee->element_hash)); | ||
3511 | |||
3512 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3513 | "# received elements", | ||
3514 | 1, | ||
3515 | GNUNET_NO); | ||
3516 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3517 | "# exchanged elements", | ||
3518 | 1, | ||
3519 | GNUNET_NO); | ||
3520 | |||
3521 | op->received_total++; | ||
3522 | ke = op_get_element (op, | ||
3523 | &ee->element_hash); | ||
3524 | if (NULL != ke) | ||
3525 | { | ||
3526 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
3527 | "# repeated elements", | ||
3528 | 1, | ||
3529 | GNUNET_NO); | ||
3530 | full_sync_plausibility_check (op); | ||
3531 | ke->received = GNUNET_YES; | ||
3532 | GNUNET_free (ee); | ||
3533 | } | ||
3534 | else | ||
3535 | { | ||
3536 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3537 | "Registering new element from remote peer\n"); | ||
3538 | op->received_fresh++; | ||
3539 | op_register_element (op, ee, GNUNET_YES); | ||
3540 | /* only send results immediately if the client wants it */ | ||
3541 | send_client_element (op, | ||
3542 | &ee->element, | ||
3543 | GNUNET_SETU_STATUS_ADD_LOCAL); | ||
3544 | } | ||
3545 | |||
3546 | |||
3547 | if ((GNUNET_YES == op->byzantine) && | ||
3548 | (op->received_total > op->remote_element_count) ) | ||
3549 | { | ||
3550 | /* The other peer gave us lots of old elements, there's something wrong. */ | ||
3551 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3552 | "Other peer sent %llu elements while pretending to have %llu elements, failing operation\n", | ||
3553 | (unsigned long long) op->received_total, | ||
3554 | (unsigned long long) op->remote_element_count); | ||
3555 | GNUNET_break_op (0); | ||
3556 | fail_union_operation (op); | ||
3557 | return; | ||
3558 | } | ||
3559 | GNUNET_CADET_receive_done (op->channel); | ||
3560 | } | ||
3561 | |||
3562 | |||
3563 | /** | ||
3564 | * Send offers (for GNUNET_Hash-es) in response | ||
3565 | * to inquiries (for IBF_Key-s). | ||
3566 | * | ||
3567 | * @param cls the union operation | ||
3568 | * @param msg the message | ||
3569 | */ | ||
3570 | static int | ||
3571 | check_union_p2p_inquiry (void *cls, | ||
3572 | const struct InquiryMessage *msg) | ||
3573 | { | ||
3574 | struct Operation *op = cls; | ||
3575 | unsigned int num_keys; | ||
3576 | |||
3577 | if (op->phase != PHASE_PASSIVE_DECODING) | ||
3578 | { | ||
3579 | GNUNET_break_op (0); | ||
3580 | return GNUNET_SYSERR; | ||
3581 | } | ||
3582 | num_keys = (ntohs (msg->header.size) - sizeof(struct InquiryMessage)) | ||
3583 | / sizeof(struct IBF_Key); | ||
3584 | if ((ntohs (msg->header.size) - sizeof(struct InquiryMessage)) | ||
3585 | != num_keys * sizeof(struct IBF_Key)) | ||
3586 | { | ||
3587 | GNUNET_break_op (0); | ||
3588 | return GNUNET_SYSERR; | ||
3589 | } | ||
3590 | return GNUNET_OK; | ||
3591 | } | ||
3592 | |||
3593 | |||
3594 | /** | ||
3595 | * Send offers (for GNUNET_Hash-es) in response to inquiries (for IBF_Key-s). | ||
3596 | * | ||
3597 | * @param cls the union operation | ||
3598 | * @param msg the message | ||
3599 | */ | ||
3600 | static void | ||
3601 | handle_union_p2p_inquiry (void *cls, | ||
3602 | const struct InquiryMessage *msg) | ||
3603 | { | ||
3604 | struct Operation *op = cls; | ||
3605 | const struct IBF_Key *ibf_key; | ||
3606 | unsigned int num_keys; | ||
3607 | |||
3608 | /** | ||
3609 | * Check that the message is received only in supported phase | ||
3610 | */ | ||
3611 | uint8_t allowed_phases[] = {PHASE_ACTIVE_DECODING, PHASE_PASSIVE_DECODING}; | ||
3612 | if (GNUNET_OK != | ||
3613 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3614 | { | ||
3615 | GNUNET_break (0); | ||
3616 | fail_union_operation (op); | ||
3617 | return; | ||
3618 | } | ||
3619 | |||
3620 | #if MEASURE_PERFORMANCE | ||
3621 | perf_store.inquery.received += 1; | ||
3622 | perf_store.inquery.received_var_bytes += (ntohs (msg->header.size) | ||
3623 | - sizeof(struct InquiryMessage)); | ||
3624 | #endif | ||
3625 | |||
3626 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3627 | "Received union inquiry\n"); | ||
3628 | num_keys = (ntohs (msg->header.size) - sizeof(struct InquiryMessage)) | ||
3629 | / sizeof(struct IBF_Key); | ||
3630 | ibf_key = (const struct IBF_Key *) &msg[1]; | ||
3631 | |||
3632 | /** Add received inquiries to hashmap for flow control **/ | ||
3633 | struct GNUNET_HashContext *hashed_key_context = | ||
3634 | GNUNET_CRYPTO_hash_context_start (); | ||
3635 | struct GNUNET_HashCode *hashed_key = (struct GNUNET_HashCode*) GNUNET_malloc ( | ||
3636 | sizeof(struct GNUNET_HashCode));; | ||
3637 | enum MESSAGE_CONTROL_FLOW_STATE mcfs = MSG_CFS_RECEIVED; | ||
3638 | GNUNET_CRYPTO_hash_context_read (hashed_key_context, | ||
3639 | &ibf_key, | ||
3640 | sizeof(struct IBF_Key)); | ||
3641 | GNUNET_CRYPTO_hash_context_finish (hashed_key_context, | ||
3642 | hashed_key); | ||
3643 | GNUNET_CONTAINER_multihashmap_put (op->inquiries_sent, | ||
3644 | hashed_key, | ||
3645 | &mcfs, | ||
3646 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE | ||
3647 | ); | ||
3648 | |||
3649 | while (0 != num_keys--) | ||
3650 | { | ||
3651 | struct IBF_Key unsalted_key; | ||
3652 | unsalt_key (ibf_key, | ||
3653 | ntohl (msg->salt), | ||
3654 | &unsalted_key); | ||
3655 | send_offers_for_key (op, | ||
3656 | unsalted_key); | ||
3657 | ibf_key++; | ||
3658 | } | ||
3659 | GNUNET_CADET_receive_done (op->channel); | ||
3660 | } | ||
3661 | |||
3662 | |||
3663 | /** | ||
3664 | * Iterator over hash map entries, called to destroy the linked list of | ||
3665 | * colliding ibf key entries. | ||
3666 | * | ||
3667 | * @param cls closure | ||
3668 | * @param key current key code | ||
3669 | * @param value value in the hash map | ||
3670 | * @return #GNUNET_YES if we should continue to iterate, | ||
3671 | * #GNUNET_NO if not. | ||
3672 | */ | ||
3673 | static int | ||
3674 | send_missing_full_elements_iter (void *cls, | ||
3675 | uint32_t key, | ||
3676 | void *value) | ||
3677 | { | ||
3678 | struct Operation *op = cls; | ||
3679 | struct KeyEntry *ke = value; | ||
3680 | struct GNUNET_MQ_Envelope *ev; | ||
3681 | struct GNUNET_SETU_ElementMessage *emsg; | ||
3682 | struct ElementEntry *ee = ke->element; | ||
3683 | |||
3684 | if (GNUNET_YES == ke->received) | ||
3685 | return GNUNET_YES; | ||
3686 | #if MEASURE_PERFORMANCE | ||
3687 | perf_store.element_full.received += 1; | ||
3688 | #endif | ||
3689 | ev = GNUNET_MQ_msg_extra (emsg, | ||
3690 | ee->element.size, | ||
3691 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_ELEMENT); | ||
3692 | GNUNET_memcpy (&emsg[1], | ||
3693 | ee->element.data, | ||
3694 | ee->element.size); | ||
3695 | emsg->element_type = htons (ee->element.element_type); | ||
3696 | GNUNET_MQ_send (op->mq, | ||
3697 | ev); | ||
3698 | return GNUNET_YES; | ||
3699 | } | ||
3700 | |||
3701 | |||
3702 | /** | ||
3703 | * Handle a request for full set transmission. | ||
3704 | * | ||
3705 | * @param cls closure, a set union operation | ||
3706 | * @param mh the demand message | ||
3707 | */ | ||
3708 | static int | ||
3709 | check_union_p2p_request_full (void *cls, | ||
3710 | const struct TransmitFullMessage *mh) | ||
3711 | { | ||
3712 | return GNUNET_OK; | ||
3713 | } | ||
3714 | |||
3715 | |||
3716 | static void | ||
3717 | handle_union_p2p_request_full (void *cls, | ||
3718 | const struct TransmitFullMessage *msg) | ||
3719 | { | ||
3720 | struct Operation *op = cls; | ||
3721 | |||
3722 | /** | ||
3723 | * Check that the message is received only in supported phase | ||
3724 | */ | ||
3725 | uint8_t allowed_phases[] = {PHASE_EXPECT_IBF}; | ||
3726 | if (GNUNET_OK != | ||
3727 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3728 | { | ||
3729 | GNUNET_break (0); | ||
3730 | fail_union_operation (op); | ||
3731 | return; | ||
3732 | } | ||
3733 | |||
3734 | op->remote_element_count = ntohl (msg->remote_set_size); | ||
3735 | op->remote_set_diff = ntohl (msg->remote_set_difference); | ||
3736 | op->local_set_diff = ntohl (msg->local_set_difference); | ||
3737 | |||
3738 | |||
3739 | if (check_byzantine_bounds (op) != GNUNET_OK) | ||
3740 | { | ||
3741 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3742 | "PROTOCOL VIOLATION: Parameters transmitted from other peer do not satisfie byzantine " | ||
3743 | "criteria\n"); | ||
3744 | GNUNET_break_op (0); | ||
3745 | fail_union_operation (op); | ||
3746 | return; | ||
3747 | } | ||
3748 | |||
3749 | #if MEASURE_PERFORMANCE | ||
3750 | perf_store.request_full.received += 1; | ||
3751 | #endif | ||
3752 | |||
3753 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3754 | "Received request for full set transmission\n"); | ||
3755 | |||
3756 | /** Calculate avg element size if not initial sync **/ | ||
3757 | op->local_element_count = GNUNET_CONTAINER_multihashmap_size ( | ||
3758 | op->set->content->elements); | ||
3759 | uint64_t avg_element_size = 0; | ||
3760 | if (0 < op->local_element_count) | ||
3761 | { | ||
3762 | op->total_elements_size_local = 0; | ||
3763 | GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
3764 | & | ||
3765 | determinate_avg_element_size_iterator, | ||
3766 | op); | ||
3767 | avg_element_size = op->total_elements_size_local / op->local_element_count; | ||
3768 | } | ||
3769 | |||
3770 | int mode_of_operation = estimate_best_mode_of_operation (avg_element_size, | ||
3771 | op-> | ||
3772 | remote_element_count, | ||
3773 | op-> | ||
3774 | local_element_count, | ||
3775 | op->local_set_diff, | ||
3776 | op->remote_set_diff, | ||
3777 | op-> | ||
3778 | rtt_bandwidth_tradeoff, | ||
3779 | op-> | ||
3780 | ibf_bucket_number_factor); | ||
3781 | if (FULL_SYNC_REMOTE_SENDING_FIRST != mode_of_operation) | ||
3782 | { | ||
3783 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3784 | "PROTOCOL VIOLATION: Remote peer choose to request the full set first but correct mode would have been" | ||
3785 | " : %d\n", mode_of_operation); | ||
3786 | GNUNET_break_op (0); | ||
3787 | fail_union_operation (op); | ||
3788 | return; | ||
3789 | } | ||
3790 | |||
3791 | // FIXME: we need to check that our set is larger than the | ||
3792 | // byzantine_lower_bound by some threshold | ||
3793 | send_full_set (op); | ||
3794 | GNUNET_CADET_receive_done (op->channel); | ||
3795 | } | ||
3796 | |||
3797 | |||
3798 | /** | ||
3799 | * Handle a "full done" message. | ||
3800 | * | ||
3801 | * @param cls closure, a set union operation | ||
3802 | * @param mh the demand message | ||
3803 | */ | ||
3804 | static void | ||
3805 | handle_union_p2p_full_done (void *cls, | ||
3806 | const struct GNUNET_MessageHeader *mh) | ||
3807 | { | ||
3808 | struct Operation *op = cls; | ||
3809 | |||
3810 | /** | ||
3811 | * Check that the message is received only in supported phase | ||
3812 | */ | ||
3813 | uint8_t allowed_phases[] = {PHASE_FULL_SENDING, PHASE_FULL_RECEIVING}; | ||
3814 | if (GNUNET_OK != | ||
3815 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3816 | { | ||
3817 | GNUNET_break (0); | ||
3818 | fail_union_operation (op); | ||
3819 | return; | ||
3820 | } | ||
3821 | |||
3822 | #if MEASURE_PERFORMANCE | ||
3823 | perf_store.full_done.received += 1; | ||
3824 | #endif | ||
3825 | |||
3826 | switch (op->phase) | ||
3827 | { | ||
3828 | case PHASE_FULL_RECEIVING: | ||
3829 | { | ||
3830 | struct GNUNET_MQ_Envelope *ev; | ||
3831 | |||
3832 | if ((GNUNET_YES == op->byzantine) && | ||
3833 | (op->received_total != op->remote_element_count) ) | ||
3834 | { | ||
3835 | /* The other peer gave not enough elements before sending full done, there's something wrong. */ | ||
3836 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3837 | "Other peer sent only %llu/%llu fresh elements, failing operation\n", | ||
3838 | (unsigned long long) op->received_total, | ||
3839 | (unsigned long long) op->remote_element_count); | ||
3840 | GNUNET_break_op (0); | ||
3841 | fail_union_operation (op); | ||
3842 | return; | ||
3843 | } | ||
3844 | |||
3845 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3846 | "got FULL DONE, sending elements that other peer is missing\n"); | ||
3847 | |||
3848 | /* send all the elements that did not come from the remote peer */ | ||
3849 | GNUNET_CONTAINER_multihashmap32_iterate (op->key_to_element, | ||
3850 | &send_missing_full_elements_iter, | ||
3851 | op); | ||
3852 | #if MEASURE_PERFORMANCE | ||
3853 | perf_store.full_done.sent += 1; | ||
3854 | #endif | ||
3855 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_DONE); | ||
3856 | GNUNET_MQ_send (op->mq, | ||
3857 | ev); | ||
3858 | op->phase = PHASE_FINISHED; | ||
3859 | /* we now wait until the other peer sends us the OVER message*/ | ||
3860 | } | ||
3861 | break; | ||
3862 | |||
3863 | case PHASE_FULL_SENDING: | ||
3864 | { | ||
3865 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3866 | "got FULL DONE, finishing\n"); | ||
3867 | /* We sent the full set, and got the response for that. We're done. */ | ||
3868 | op->phase = PHASE_FINISHED; | ||
3869 | GNUNET_CADET_receive_done (op->channel); | ||
3870 | send_client_done (op); | ||
3871 | _GSS_operation_destroy2 (op); | ||
3872 | return; | ||
3873 | } | ||
3874 | |||
3875 | default: | ||
3876 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3877 | "Handle full done phase is %u\n", | ||
3878 | (unsigned) op->phase); | ||
3879 | GNUNET_break_op (0); | ||
3880 | fail_union_operation (op); | ||
3881 | return; | ||
3882 | } | ||
3883 | GNUNET_CADET_receive_done (op->channel); | ||
3884 | } | ||
3885 | |||
3886 | |||
3887 | /** | ||
3888 | * Check a demand by the other peer for elements based on a list | ||
3889 | * of `struct GNUNET_HashCode`s. | ||
3890 | * | ||
3891 | * @param cls closure, a set union operation | ||
3892 | * @param mh the demand message | ||
3893 | * @return #GNUNET_OK if @a mh is well-formed | ||
3894 | */ | ||
3895 | static int | ||
3896 | check_union_p2p_demand (void *cls, | ||
3897 | const struct GNUNET_MessageHeader *mh) | ||
3898 | { | ||
3899 | struct Operation *op = cls; | ||
3900 | unsigned int num_hashes; | ||
3901 | |||
3902 | (void) op; | ||
3903 | num_hashes = (ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) | ||
3904 | / sizeof(struct GNUNET_HashCode); | ||
3905 | if ((ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) | ||
3906 | != num_hashes * sizeof(struct GNUNET_HashCode)) | ||
3907 | { | ||
3908 | GNUNET_break_op (0); | ||
3909 | return GNUNET_SYSERR; | ||
3910 | } | ||
3911 | return GNUNET_OK; | ||
3912 | } | ||
3913 | |||
3914 | |||
3915 | /** | ||
3916 | * Handle a demand by the other peer for elements based on a list | ||
3917 | * of `struct GNUNET_HashCode`s. | ||
3918 | * | ||
3919 | * @param cls closure, a set union operation | ||
3920 | * @param mh the demand message | ||
3921 | */ | ||
3922 | static void | ||
3923 | handle_union_p2p_demand (void *cls, | ||
3924 | const struct GNUNET_MessageHeader *mh) | ||
3925 | { | ||
3926 | struct Operation *op = cls; | ||
3927 | struct ElementEntry *ee; | ||
3928 | struct GNUNET_SETU_ElementMessage *emsg; | ||
3929 | const struct GNUNET_HashCode *hash; | ||
3930 | unsigned int num_hashes; | ||
3931 | struct GNUNET_MQ_Envelope *ev; | ||
3932 | |||
3933 | /** | ||
3934 | * Check that the message is received only in supported phase | ||
3935 | */ | ||
3936 | uint8_t allowed_phases[] = {PHASE_ACTIVE_DECODING, PHASE_PASSIVE_DECODING, | ||
3937 | PHASE_FINISH_WAITING}; | ||
3938 | if (GNUNET_OK != | ||
3939 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
3940 | { | ||
3941 | GNUNET_break (0); | ||
3942 | fail_union_operation (op); | ||
3943 | return; | ||
3944 | } | ||
3945 | #if MEASURE_PERFORMANCE | ||
3946 | perf_store.demand.received += 1; | ||
3947 | perf_store.demand.received_var_bytes += (ntohs (mh->size) - sizeof(struct | ||
3948 | GNUNET_MessageHeader)); | ||
3949 | #endif | ||
3950 | |||
3951 | num_hashes = (ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) | ||
3952 | / sizeof(struct GNUNET_HashCode); | ||
3953 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; | ||
3954 | num_hashes > 0; | ||
3955 | hash++, num_hashes--) | ||
3956 | { | ||
3957 | ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements, | ||
3958 | hash); | ||
3959 | if (NULL == ee) | ||
3960 | { | ||
3961 | /* Demand for non-existing element. */ | ||
3962 | GNUNET_break_op (0); | ||
3963 | fail_union_operation (op); | ||
3964 | return; | ||
3965 | } | ||
3966 | |||
3967 | /* Save send demand message for message control */ | ||
3968 | if (GNUNET_YES != | ||
3969 | update_message_control_flow ( | ||
3970 | op->message_control_flow, | ||
3971 | MSG_CFS_RECEIVED, | ||
3972 | &ee->element_hash, | ||
3973 | DEMAND_MESSAGE) | ||
3974 | ) | ||
3975 | { | ||
3976 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3977 | "Double demand message received found!\n"); | ||
3978 | GNUNET_break (0); | ||
3979 | fail_union_operation (op); | ||
3980 | return; | ||
3981 | } | ||
3982 | ; | ||
3983 | |||
3984 | /* Mark element to be expected to received */ | ||
3985 | if (GNUNET_YES != | ||
3986 | update_message_control_flow ( | ||
3987 | op->message_control_flow, | ||
3988 | MSG_CFS_SENT, | ||
3989 | &ee->element_hash, | ||
3990 | ELEMENT_MESSAGE) | ||
3991 | ) | ||
3992 | { | ||
3993 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3994 | "Double element message sent found!\n"); | ||
3995 | GNUNET_break (0); | ||
3996 | fail_union_operation (op); | ||
3997 | return; | ||
3998 | } | ||
3999 | if (GNUNET_NO == _GSS_is_element_of_operation (ee, op)) | ||
4000 | { | ||
4001 | /* Probably confused lazily copied sets. */ | ||
4002 | GNUNET_break_op (0); | ||
4003 | fail_union_operation (op); | ||
4004 | return; | ||
4005 | } | ||
4006 | #if MEASURE_PERFORMANCE | ||
4007 | perf_store.element.sent += 1; | ||
4008 | perf_store.element.sent_var_bytes += ee->element.size; | ||
4009 | #endif | ||
4010 | ev = GNUNET_MQ_msg_extra (emsg, | ||
4011 | ee->element.size, | ||
4012 | GNUNET_MESSAGE_TYPE_SETU_P2P_ELEMENTS); | ||
4013 | GNUNET_memcpy (&emsg[1], | ||
4014 | ee->element.data, | ||
4015 | ee->element.size); | ||
4016 | emsg->reserved = htons (0); | ||
4017 | emsg->element_type = htons (ee->element.element_type); | ||
4018 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
4019 | "[OP %p] Sending demanded element (size %u, hash %s) to peer\n", | ||
4020 | op, | ||
4021 | (unsigned int) ee->element.size, | ||
4022 | GNUNET_h2s (&ee->element_hash)); | ||
4023 | GNUNET_MQ_send (op->mq, ev); | ||
4024 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
4025 | "# exchanged elements", | ||
4026 | 1, | ||
4027 | GNUNET_NO); | ||
4028 | if (op->symmetric) | ||
4029 | send_client_element (op, | ||
4030 | &ee->element, | ||
4031 | GNUNET_SETU_STATUS_ADD_REMOTE); | ||
4032 | } | ||
4033 | GNUNET_CADET_receive_done (op->channel); | ||
4034 | maybe_finish (op); | ||
4035 | } | ||
4036 | |||
4037 | |||
4038 | /** | ||
4039 | * Check offer (of `struct GNUNET_HashCode`s). | ||
4040 | * | ||
4041 | * @param cls the union operation | ||
4042 | * @param mh the message | ||
4043 | * @return #GNUNET_OK if @a mh is well-formed | ||
4044 | */ | ||
4045 | static int | ||
4046 | check_union_p2p_offer (void *cls, | ||
4047 | const struct GNUNET_MessageHeader *mh) | ||
4048 | { | ||
4049 | struct Operation *op = cls; | ||
4050 | unsigned int num_hashes; | ||
4051 | |||
4052 | /* look up elements and send them */ | ||
4053 | if ((op->phase != PHASE_PASSIVE_DECODING) && | ||
4054 | (op->phase != PHASE_ACTIVE_DECODING)) | ||
4055 | { | ||
4056 | GNUNET_break_op (0); | ||
4057 | return GNUNET_SYSERR; | ||
4058 | } | ||
4059 | num_hashes = (ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) | ||
4060 | / sizeof(struct GNUNET_HashCode); | ||
4061 | if ((ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) != | ||
4062 | num_hashes * sizeof(struct GNUNET_HashCode)) | ||
4063 | { | ||
4064 | GNUNET_break_op (0); | ||
4065 | return GNUNET_SYSERR; | ||
4066 | } | ||
4067 | return GNUNET_OK; | ||
4068 | } | ||
4069 | |||
4070 | |||
4071 | /** | ||
4072 | * Handle offers (of `struct GNUNET_HashCode`s) and | ||
4073 | * respond with demands (of `struct GNUNET_HashCode`s). | ||
4074 | * | ||
4075 | * @param cls the union operation | ||
4076 | * @param mh the message | ||
4077 | */ | ||
4078 | static void | ||
4079 | handle_union_p2p_offer (void *cls, | ||
4080 | const struct GNUNET_MessageHeader *mh) | ||
4081 | { | ||
4082 | struct Operation *op = cls; | ||
4083 | const struct GNUNET_HashCode *hash; | ||
4084 | unsigned int num_hashes; | ||
4085 | /** | ||
4086 | * Check that the message is received only in supported phase | ||
4087 | */ | ||
4088 | uint8_t allowed_phases[] = {PHASE_ACTIVE_DECODING, PHASE_PASSIVE_DECODING}; | ||
4089 | if (GNUNET_OK != | ||
4090 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
4091 | { | ||
4092 | GNUNET_break (0); | ||
4093 | fail_union_operation (op); | ||
4094 | return; | ||
4095 | } | ||
4096 | |||
4097 | #if MEASURE_PERFORMANCE | ||
4098 | perf_store.offer.received += 1; | ||
4099 | perf_store.offer.received_var_bytes += (ntohs (mh->size) - sizeof(struct | ||
4100 | GNUNET_MessageHeader)); | ||
4101 | #endif | ||
4102 | |||
4103 | num_hashes = (ntohs (mh->size) - sizeof(struct GNUNET_MessageHeader)) | ||
4104 | / sizeof(struct GNUNET_HashCode); | ||
4105 | for (hash = (const struct GNUNET_HashCode *) &mh[1]; | ||
4106 | num_hashes > 0; | ||
4107 | hash++, num_hashes--) | ||
4108 | { | ||
4109 | struct ElementEntry *ee; | ||
4110 | struct GNUNET_MessageHeader *demands; | ||
4111 | struct GNUNET_MQ_Envelope *ev; | ||
4112 | |||
4113 | ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements, | ||
4114 | hash); | ||
4115 | if (NULL != ee) | ||
4116 | if (GNUNET_YES == _GSS_is_element_of_operation (ee, op)) | ||
4117 | continue; | ||
4118 | |||
4119 | if (GNUNET_YES == | ||
4120 | GNUNET_CONTAINER_multihashmap_contains (op->demanded_hashes, | ||
4121 | hash)) | ||
4122 | { | ||
4123 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
4124 | "Skipped sending duplicate demand\n"); | ||
4125 | continue; | ||
4126 | } | ||
4127 | |||
4128 | GNUNET_assert (GNUNET_OK == | ||
4129 | GNUNET_CONTAINER_multihashmap_put ( | ||
4130 | op->demanded_hashes, | ||
4131 | hash, | ||
4132 | NULL, | ||
4133 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); | ||
4134 | |||
4135 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
4136 | "[OP %p] Requesting element (hash %s)\n", | ||
4137 | op, GNUNET_h2s (hash)); | ||
4138 | |||
4139 | #if MEASURE_PERFORMANCE | ||
4140 | perf_store.demand.sent += 1; | ||
4141 | perf_store.demand.sent_var_bytes += sizeof(struct GNUNET_HashCode); | ||
4142 | #endif | ||
4143 | /* Save send demand message for message control */ | ||
4144 | if (GNUNET_YES != | ||
4145 | update_message_control_flow ( | ||
4146 | op->message_control_flow, | ||
4147 | MSG_CFS_SENT, | ||
4148 | hash, | ||
4149 | DEMAND_MESSAGE)) | ||
4150 | { | ||
4151 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
4152 | "Double demand message sent found!\n"); | ||
4153 | GNUNET_break (0); | ||
4154 | fail_union_operation (op); | ||
4155 | return; | ||
4156 | } | ||
4157 | |||
4158 | /* Mark offer as received received */ | ||
4159 | if (GNUNET_YES != | ||
4160 | update_message_control_flow ( | ||
4161 | op->message_control_flow, | ||
4162 | MSG_CFS_RECEIVED, | ||
4163 | hash, | ||
4164 | OFFER_MESSAGE)) | ||
4165 | { | ||
4166 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
4167 | "Double offer message received found!\n"); | ||
4168 | GNUNET_break (0); | ||
4169 | fail_union_operation (op); | ||
4170 | return; | ||
4171 | } | ||
4172 | /* Mark element to be expected to received */ | ||
4173 | if (GNUNET_YES != | ||
4174 | update_message_control_flow ( | ||
4175 | op->message_control_flow, | ||
4176 | MSG_CFS_EXPECTED, | ||
4177 | hash, | ||
4178 | ELEMENT_MESSAGE)) | ||
4179 | { | ||
4180 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
4181 | "Element already expected!\n"); | ||
4182 | GNUNET_break (0); | ||
4183 | fail_union_operation (op); | ||
4184 | return; | ||
4185 | } | ||
4186 | ev = GNUNET_MQ_msg_header_extra (demands, | ||
4187 | sizeof(struct GNUNET_HashCode), | ||
4188 | GNUNET_MESSAGE_TYPE_SETU_P2P_DEMAND); | ||
4189 | GNUNET_memcpy (&demands[1], | ||
4190 | hash, | ||
4191 | sizeof(struct GNUNET_HashCode)); | ||
4192 | GNUNET_MQ_send (op->mq, ev); | ||
4193 | } | ||
4194 | GNUNET_CADET_receive_done (op->channel); | ||
4195 | } | ||
4196 | |||
4197 | |||
4198 | /** | ||
4199 | * Handle a done message from a remote peer | ||
4200 | * | ||
4201 | * @param cls the union operation | ||
4202 | * @param mh the message | ||
4203 | */ | ||
4204 | static void | ||
4205 | handle_union_p2p_done (void *cls, | ||
4206 | const struct GNUNET_MessageHeader *mh) | ||
4207 | { | ||
4208 | struct Operation *op = cls; | ||
4209 | |||
4210 | /** | ||
4211 | * Check that the message is received only in supported phase | ||
4212 | */ | ||
4213 | uint8_t allowed_phases[] = {PHASE_ACTIVE_DECODING, PHASE_PASSIVE_DECODING}; | ||
4214 | if (GNUNET_OK != | ||
4215 | check_valid_phase (allowed_phases,sizeof(allowed_phases),op)) | ||
4216 | { | ||
4217 | GNUNET_break (0); | ||
4218 | fail_union_operation (op); | ||
4219 | return; | ||
4220 | } | ||
4221 | |||
4222 | if (op->active_passive_switch_required) | ||
4223 | { | ||
4224 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
4225 | "PROTOCOL VIOLATION: Received done but role change is necessary\n"); | ||
4226 | GNUNET_break (0); | ||
4227 | fail_union_operation (op); | ||
4228 | return; | ||
4229 | } | ||
4230 | |||
4231 | #if MEASURE_PERFORMANCE | ||
4232 | perf_store.done.received += 1; | ||
4233 | #endif | ||
4234 | switch (op->phase) | ||
4235 | { | ||
4236 | case PHASE_PASSIVE_DECODING: | ||
4237 | /* We got all requests, but still have to send our elements in response. */ | ||
4238 | op->phase = PHASE_FINISH_WAITING; | ||
4239 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
4240 | "got DONE (as passive partner), waiting for our demands to be satisfied\n"); | ||
4241 | /* The active peer is done sending offers | ||
4242 | * and inquiries. This means that all | ||
4243 | * our responses to that (demands and offers) | ||
4244 | * must be in flight (queued or in mesh). | ||
4245 | * | ||
4246 | * We should notify the active peer once | ||
4247 | * all our demands are satisfied, so that the active | ||
4248 | * peer can quit if we gave it everything. | ||
4249 | */GNUNET_CADET_receive_done (op->channel); | ||
4250 | maybe_finish (op); | ||
4251 | return; | ||
4252 | case PHASE_ACTIVE_DECODING: | ||
4253 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
4254 | "got DONE (as active partner), waiting to finish\n"); | ||
4255 | /* All demands of the other peer are satisfied, | ||
4256 | * and we processed all offers, thus we know | ||
4257 | * exactly what our demands must be. | ||
4258 | * | ||
4259 | * We'll close the channel | ||
4260 | * to the other peer once our demands are met. | ||
4261 | */op->phase = PHASE_FINISH_CLOSING; | ||
4262 | GNUNET_CADET_receive_done (op->channel); | ||
4263 | maybe_finish (op); | ||
4264 | return; | ||
4265 | default: | ||
4266 | GNUNET_break_op (0); | ||
4267 | fail_union_operation (op); | ||
4268 | return; | ||
4269 | } | ||
4270 | } | ||
4271 | |||
4272 | |||
4273 | /** | ||
4274 | * Handle a over message from a remote peer | ||
4275 | * | ||
4276 | * @param cls the union operation | ||
4277 | * @param mh the message | ||
4278 | */ | ||
4279 | static void | ||
4280 | handle_union_p2p_over (void *cls, | ||
4281 | const struct GNUNET_MessageHeader *mh) | ||
4282 | { | ||
4283 | #if MEASURE_PERFORMANCE | ||
4284 | perf_store.over.received += 1; | ||
4285 | #endif | ||
4286 | send_client_done (cls); | ||
4287 | } | ||
4288 | |||
4289 | |||
4290 | /** | ||
4291 | * Get the incoming socket associated with the given id. | ||
4292 | * | ||
4293 | * @param listener the listener to look in | ||
4294 | * @param id id to look for | ||
4295 | * @return the incoming socket associated with the id, | ||
4296 | * or NULL if there is none | ||
4297 | */ | ||
4298 | static struct Operation * | ||
4299 | get_incoming (uint32_t id) | ||
4300 | { | ||
4301 | for (struct Listener *listener = listener_head; | ||
4302 | NULL != listener; | ||
4303 | listener = listener->next) | ||
4304 | { | ||
4305 | for (struct Operation *op = listener->op_head; | ||
4306 | NULL != op; | ||
4307 | op = op->next) | ||
4308 | if (op->suggest_id == id) | ||
4309 | return op; | ||
4310 | } | ||
4311 | return NULL; | ||
4312 | } | ||
4313 | |||
4314 | |||
4315 | /** | ||
4316 | * Callback called when a client connects to the service. | ||
4317 | * | ||
4318 | * @param cls closure for the service | ||
4319 | * @param c the new client that connected to the service | ||
4320 | * @param mq the message queue used to send messages to the client | ||
4321 | * @return @a `struct ClientState` | ||
4322 | */ | ||
4323 | static void * | ||
4324 | client_connect_cb (void *cls, | ||
4325 | struct GNUNET_SERVICE_Client *c, | ||
4326 | struct GNUNET_MQ_Handle *mq) | ||
4327 | { | ||
4328 | struct ClientState *cs; | ||
4329 | |||
4330 | num_clients++; | ||
4331 | cs = GNUNET_new (struct ClientState); | ||
4332 | cs->client = c; | ||
4333 | cs->mq = mq; | ||
4334 | return cs; | ||
4335 | } | ||
4336 | |||
4337 | |||
4338 | /** | ||
4339 | * Iterator over hash map entries to free element entries. | ||
4340 | * | ||
4341 | * @param cls closure | ||
4342 | * @param key current key code | ||
4343 | * @param value a `struct ElementEntry *` to be free'd | ||
4344 | * @return #GNUNET_YES (continue to iterate) | ||
4345 | */ | ||
4346 | static int | ||
4347 | destroy_elements_iterator (void *cls, | ||
4348 | const struct GNUNET_HashCode *key, | ||
4349 | void *value) | ||
4350 | { | ||
4351 | struct ElementEntry *ee = value; | ||
4352 | |||
4353 | GNUNET_free (ee); | ||
4354 | return GNUNET_YES; | ||
4355 | } | ||
4356 | |||
4357 | |||
4358 | /** | ||
4359 | * Clean up after a client has disconnected | ||
4360 | * | ||
4361 | * @param cls closure, unused | ||
4362 | * @param client the client to clean up after | ||
4363 | * @param internal_cls the `struct ClientState` | ||
4364 | */ | ||
4365 | static void | ||
4366 | client_disconnect_cb (void *cls, | ||
4367 | struct GNUNET_SERVICE_Client *client, | ||
4368 | void *internal_cls) | ||
4369 | { | ||
4370 | struct ClientState *cs = internal_cls; | ||
4371 | struct Operation *op; | ||
4372 | struct Listener *listener; | ||
4373 | struct Set *set; | ||
4374 | |||
4375 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4376 | "Client disconnected, cleaning up\n"); | ||
4377 | if (NULL != (set = cs->set)) | ||
4378 | { | ||
4379 | struct SetContent *content = set->content; | ||
4380 | |||
4381 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4382 | "Destroying client's set\n"); | ||
4383 | /* Destroy pending set operations */ | ||
4384 | while (NULL != set->ops_head) | ||
4385 | _GSS_operation_destroy (set->ops_head); | ||
4386 | |||
4387 | /* Destroy operation-specific state */ | ||
4388 | if (NULL != set->se) | ||
4389 | { | ||
4390 | strata_estimator_destroy (set->se); | ||
4391 | set->se = NULL; | ||
4392 | } | ||
4393 | /* free set content (or at least decrement RC) */ | ||
4394 | set->content = NULL; | ||
4395 | GNUNET_assert (0 != content->refcount); | ||
4396 | content->refcount--; | ||
4397 | if (0 == content->refcount) | ||
4398 | { | ||
4399 | GNUNET_assert (NULL != content->elements); | ||
4400 | GNUNET_CONTAINER_multihashmap_iterate (content->elements, | ||
4401 | &destroy_elements_iterator, | ||
4402 | NULL); | ||
4403 | GNUNET_CONTAINER_multihashmap_destroy (content->elements); | ||
4404 | content->elements = NULL; | ||
4405 | GNUNET_free (content); | ||
4406 | } | ||
4407 | GNUNET_free (set); | ||
4408 | } | ||
4409 | |||
4410 | if (NULL != (listener = cs->listener)) | ||
4411 | { | ||
4412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4413 | "Destroying client's listener\n"); | ||
4414 | GNUNET_CADET_close_port (listener->open_port); | ||
4415 | listener->open_port = NULL; | ||
4416 | while (NULL != (op = listener->op_head)) | ||
4417 | { | ||
4418 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
4419 | "Destroying incoming operation `%u' from peer `%s'\n", | ||
4420 | (unsigned int) op->client_request_id, | ||
4421 | GNUNET_i2s (&op->peer)); | ||
4422 | incoming_destroy (op); | ||
4423 | } | ||
4424 | GNUNET_CONTAINER_DLL_remove (listener_head, | ||
4425 | listener_tail, | ||
4426 | listener); | ||
4427 | GNUNET_free (listener); | ||
4428 | } | ||
4429 | GNUNET_free (cs); | ||
4430 | num_clients--; | ||
4431 | if ( (GNUNET_YES == in_shutdown) && | ||
4432 | (0 == num_clients) ) | ||
4433 | { | ||
4434 | if (NULL != cadet) | ||
4435 | { | ||
4436 | GNUNET_CADET_disconnect (cadet); | ||
4437 | cadet = NULL; | ||
4438 | } | ||
4439 | } | ||
4440 | } | ||
4441 | |||
4442 | |||
4443 | /** | ||
4444 | * Check a request for a set operation from another peer. | ||
4445 | * | ||
4446 | * @param cls the operation state | ||
4447 | * @param msg the received message | ||
4448 | * @return #GNUNET_OK if the channel should be kept alive, | ||
4449 | * #GNUNET_SYSERR to destroy the channel | ||
4450 | */ | ||
4451 | static int | ||
4452 | check_incoming_msg (void *cls, | ||
4453 | const struct OperationRequestMessage *msg) | ||
4454 | { | ||
4455 | struct Operation *op = cls; | ||
4456 | struct Listener *listener = op->listener; | ||
4457 | const struct GNUNET_MessageHeader *nested_context; | ||
4458 | |||
4459 | /* double operation request */ | ||
4460 | if (0 != op->suggest_id) | ||
4461 | { | ||
4462 | GNUNET_break_op (0); | ||
4463 | return GNUNET_SYSERR; | ||
4464 | } | ||
4465 | /* This should be equivalent to the previous condition, but can't hurt to check twice */ | ||
4466 | if (NULL == listener) | ||
4467 | { | ||
4468 | GNUNET_break (0); | ||
4469 | return GNUNET_SYSERR; | ||
4470 | } | ||
4471 | nested_context = GNUNET_MQ_extract_nested_mh (msg); | ||
4472 | if ((NULL != nested_context) && | ||
4473 | (ntohs (nested_context->size) > GNUNET_SETU_CONTEXT_MESSAGE_MAX_SIZE)) | ||
4474 | { | ||
4475 | GNUNET_break_op (0); | ||
4476 | return GNUNET_SYSERR; | ||
4477 | } | ||
4478 | return GNUNET_OK; | ||
4479 | } | ||
4480 | |||
4481 | |||
4482 | /** | ||
4483 | * Handle a request for a set operation from another peer. Checks if we | ||
4484 | * have a listener waiting for such a request (and in that case initiates | ||
4485 | * asking the listener about accepting the connection). If no listener | ||
4486 | * is waiting, we queue the operation request in hope that a listener | ||
4487 | * shows up soon (before timeout). | ||
4488 | * | ||
4489 | * This msg is expected as the first and only msg handled through the | ||
4490 | * non-operation bound virtual table, acceptance of this operation replaces | ||
4491 | * our virtual table and subsequent msgs would be routed differently (as | ||
4492 | * we then know what type of operation this is). | ||
4493 | * | ||
4494 | * @param cls the operation state | ||
4495 | * @param msg the received message | ||
4496 | */ | ||
4497 | static void | ||
4498 | handle_incoming_msg (void *cls, | ||
4499 | const struct OperationRequestMessage *msg) | ||
4500 | { | ||
4501 | struct Operation *op = cls; | ||
4502 | struct Listener *listener = op->listener; | ||
4503 | const struct GNUNET_MessageHeader *nested_context; | ||
4504 | struct GNUNET_MQ_Envelope *env; | ||
4505 | struct GNUNET_SETU_RequestMessage *cmsg; | ||
4506 | |||
4507 | nested_context = GNUNET_MQ_extract_nested_mh (msg); | ||
4508 | /* Make a copy of the nested_context (application-specific context | ||
4509 | information that is opaque to set) so we can pass it to the | ||
4510 | listener later on */ | ||
4511 | if (NULL != nested_context) | ||
4512 | op->context_msg = GNUNET_copy_message (nested_context); | ||
4513 | op->remote_element_count = ntohl (msg->element_count); | ||
4514 | GNUNET_log ( | ||
4515 | GNUNET_ERROR_TYPE_DEBUG, | ||
4516 | "Received P2P operation request (port %s) for active listener\n", | ||
4517 | GNUNET_h2s (&op->listener->app_id)); | ||
4518 | GNUNET_assert (0 == op->suggest_id); | ||
4519 | if (0 == suggest_id) | ||
4520 | suggest_id++; | ||
4521 | op->suggest_id = suggest_id++; | ||
4522 | GNUNET_assert (NULL != op->timeout_task); | ||
4523 | GNUNET_SCHEDULER_cancel (op->timeout_task); | ||
4524 | op->timeout_task = NULL; | ||
4525 | env = GNUNET_MQ_msg_nested_mh (cmsg, | ||
4526 | GNUNET_MESSAGE_TYPE_SETU_REQUEST, | ||
4527 | op->context_msg); | ||
4528 | GNUNET_log ( | ||
4529 | GNUNET_ERROR_TYPE_DEBUG, | ||
4530 | "Suggesting incoming request with accept id %u to listener %p of client %p\n", | ||
4531 | op->suggest_id, | ||
4532 | listener, | ||
4533 | listener->cs); | ||
4534 | cmsg->accept_id = htonl (op->suggest_id); | ||
4535 | cmsg->peer_id = op->peer; | ||
4536 | GNUNET_MQ_send (listener->cs->mq, | ||
4537 | env); | ||
4538 | /* NOTE: GNUNET_CADET_receive_done() will be called in | ||
4539 | #handle_client_accept() */ | ||
4540 | } | ||
4541 | |||
4542 | |||
4543 | /** | ||
4544 | * Called when a client wants to create a new set. This is typically | ||
4545 | * the first request from a client, and includes the type of set | ||
4546 | * operation to be performed. | ||
4547 | * | ||
4548 | * @param cls client that sent the message | ||
4549 | * @param m message sent by the client | ||
4550 | */ | ||
4551 | static void | ||
4552 | handle_client_create_set (void *cls, | ||
4553 | const struct GNUNET_SETU_CreateMessage *msg) | ||
4554 | { | ||
4555 | struct ClientState *cs = cls; | ||
4556 | struct Set *set; | ||
4557 | |||
4558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4559 | "Client created new set for union operation\n"); | ||
4560 | if (NULL != cs->set) | ||
4561 | { | ||
4562 | /* There can only be one set per client */ | ||
4563 | GNUNET_break (0); | ||
4564 | GNUNET_SERVICE_client_drop (cs->client); | ||
4565 | return; | ||
4566 | } | ||
4567 | set = GNUNET_new (struct Set); | ||
4568 | { | ||
4569 | struct MultiStrataEstimator *se; | ||
4570 | |||
4571 | se = strata_estimator_create (SE_STRATA_COUNT, | ||
4572 | SE_IBFS_TOTAL_SIZE, | ||
4573 | SE_IBF_HASH_NUM); | ||
4574 | if (NULL == se) | ||
4575 | { | ||
4576 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
4577 | "Failed to allocate strata estimator\n"); | ||
4578 | GNUNET_free (set); | ||
4579 | GNUNET_SERVICE_client_drop (cs->client); | ||
4580 | return; | ||
4581 | } | ||
4582 | set->se = se; | ||
4583 | } | ||
4584 | set->content = GNUNET_new (struct SetContent); | ||
4585 | set->content->refcount = 1; | ||
4586 | set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, | ||
4587 | GNUNET_YES); | ||
4588 | set->cs = cs; | ||
4589 | cs->set = set; | ||
4590 | GNUNET_SERVICE_client_continue (cs->client); | ||
4591 | } | ||
4592 | |||
4593 | |||
4594 | /** | ||
4595 | * Timeout happens iff: | ||
4596 | * - we suggested an operation to our listener, | ||
4597 | * but did not receive a response in time | ||
4598 | * - we got the channel from a peer but no #GNUNET_MESSAGE_TYPE_SETU_P2P_OPERATION_REQUEST | ||
4599 | * | ||
4600 | * @param cls channel context | ||
4601 | * @param tc context information (why was this task triggered now) | ||
4602 | */ | ||
4603 | static void | ||
4604 | incoming_timeout_cb (void *cls) | ||
4605 | { | ||
4606 | struct Operation *op = cls; | ||
4607 | |||
4608 | op->timeout_task = NULL; | ||
4609 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4610 | "Remote peer's incoming request timed out\n"); | ||
4611 | incoming_destroy (op); | ||
4612 | } | ||
4613 | |||
4614 | |||
4615 | /** | ||
4616 | * Method called whenever another peer has added us to a channel the | ||
4617 | * other peer initiated. Only called (once) upon reception of data | ||
4618 | * from a channel we listen on. | ||
4619 | * | ||
4620 | * The channel context represents the operation itself and gets added | ||
4621 | * to a DLL, from where it gets looked up when our local listener | ||
4622 | * client responds to a proposed/suggested operation or connects and | ||
4623 | * associates with this operation. | ||
4624 | * | ||
4625 | * @param cls closure | ||
4626 | * @param channel new handle to the channel | ||
4627 | * @param source peer that started the channel | ||
4628 | * @return initial channel context for the channel | ||
4629 | * returns NULL on error | ||
4630 | */ | ||
4631 | static void * | ||
4632 | channel_new_cb (void *cls, | ||
4633 | struct GNUNET_CADET_Channel *channel, | ||
4634 | const struct GNUNET_PeerIdentity *source) | ||
4635 | { | ||
4636 | struct Listener *listener = cls; | ||
4637 | struct Operation *op; | ||
4638 | |||
4639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4640 | "New incoming channel\n"); | ||
4641 | op = GNUNET_new (struct Operation); | ||
4642 | op->listener = listener; | ||
4643 | op->peer = *source; | ||
4644 | op->channel = channel; | ||
4645 | op->mq = GNUNET_CADET_get_mq (op->channel); | ||
4646 | op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
4647 | UINT32_MAX); | ||
4648 | op->timeout_task = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT, | ||
4649 | &incoming_timeout_cb, | ||
4650 | op); | ||
4651 | GNUNET_CONTAINER_DLL_insert (listener->op_head, | ||
4652 | listener->op_tail, | ||
4653 | op); | ||
4654 | return op; | ||
4655 | } | ||
4656 | |||
4657 | |||
4658 | /** | ||
4659 | * Function called whenever a channel is destroyed. Should clean up | ||
4660 | * any associated state. It must NOT call | ||
4661 | * GNUNET_CADET_channel_destroy() on the channel. | ||
4662 | * | ||
4663 | * The peer_disconnect function is part of a a virtual table set initially either | ||
4664 | * when a peer creates a new channel with us, or once we create | ||
4665 | * a new channel ourselves (evaluate). | ||
4666 | * | ||
4667 | * Once we know the exact type of operation (union/intersection), the vt is | ||
4668 | * replaced with an operation specific instance (_GSS_[op]_vt). | ||
4669 | * | ||
4670 | * @param channel_ctx place where local state associated | ||
4671 | * with the channel is stored | ||
4672 | * @param channel connection to the other end (henceforth invalid) | ||
4673 | */ | ||
4674 | static void | ||
4675 | channel_end_cb (void *channel_ctx, | ||
4676 | const struct GNUNET_CADET_Channel *channel) | ||
4677 | { | ||
4678 | struct Operation *op = channel_ctx; | ||
4679 | |||
4680 | op->channel = NULL; | ||
4681 | _GSS_operation_destroy2 (op); | ||
4682 | } | ||
4683 | |||
4684 | |||
4685 | /** | ||
4686 | * Function called whenever an MQ-channel's transmission window size changes. | ||
4687 | * | ||
4688 | * The first callback in an outgoing channel will be with a non-zero value | ||
4689 | * and will mean the channel is connected to the destination. | ||
4690 | * | ||
4691 | * For an incoming channel it will be called immediately after the | ||
4692 | * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value. | ||
4693 | * | ||
4694 | * @param cls Channel closure. | ||
4695 | * @param channel Connection to the other end (henceforth invalid). | ||
4696 | * @param window_size New window size. If the is more messages than buffer size | ||
4697 | * this value will be negative.. | ||
4698 | */ | ||
4699 | static void | ||
4700 | channel_window_cb (void *cls, | ||
4701 | const struct GNUNET_CADET_Channel *channel, | ||
4702 | int window_size) | ||
4703 | { | ||
4704 | /* FIXME: not implemented, we could do flow control here... */ | ||
4705 | } | ||
4706 | |||
4707 | |||
4708 | /** | ||
4709 | * Called when a client wants to create a new listener. | ||
4710 | * | ||
4711 | * @param cls client that sent the message | ||
4712 | * @param msg message sent by the client | ||
4713 | */ | ||
4714 | |||
4715 | static void | ||
4716 | handle_client_listen (void *cls, | ||
4717 | const struct GNUNET_SETU_ListenMessage *msg) | ||
4718 | { | ||
4719 | struct ClientState *cs = cls; | ||
4720 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
4721 | GNUNET_MQ_hd_var_size (incoming_msg, | ||
4722 | GNUNET_MESSAGE_TYPE_SETU_P2P_OPERATION_REQUEST, | ||
4723 | struct OperationRequestMessage, | ||
4724 | NULL), | ||
4725 | GNUNET_MQ_hd_var_size (union_p2p_ibf, | ||
4726 | GNUNET_MESSAGE_TYPE_SETU_P2P_IBF, | ||
4727 | struct IBFMessage, | ||
4728 | NULL), | ||
4729 | GNUNET_MQ_hd_var_size (union_p2p_elements, | ||
4730 | GNUNET_MESSAGE_TYPE_SETU_P2P_ELEMENTS, | ||
4731 | struct GNUNET_SETU_ElementMessage, | ||
4732 | NULL), | ||
4733 | GNUNET_MQ_hd_var_size (union_p2p_offer, | ||
4734 | GNUNET_MESSAGE_TYPE_SETU_P2P_OFFER, | ||
4735 | struct GNUNET_MessageHeader, | ||
4736 | NULL), | ||
4737 | GNUNET_MQ_hd_var_size (union_p2p_inquiry, | ||
4738 | GNUNET_MESSAGE_TYPE_SETU_P2P_INQUIRY, | ||
4739 | struct InquiryMessage, | ||
4740 | NULL), | ||
4741 | GNUNET_MQ_hd_var_size (union_p2p_demand, | ||
4742 | GNUNET_MESSAGE_TYPE_SETU_P2P_DEMAND, | ||
4743 | struct GNUNET_MessageHeader, | ||
4744 | NULL), | ||
4745 | GNUNET_MQ_hd_fixed_size (union_p2p_done, | ||
4746 | GNUNET_MESSAGE_TYPE_SETU_P2P_DONE, | ||
4747 | struct GNUNET_MessageHeader, | ||
4748 | NULL), | ||
4749 | GNUNET_MQ_hd_fixed_size (union_p2p_over, | ||
4750 | GNUNET_MESSAGE_TYPE_SETU_P2P_OVER, | ||
4751 | struct GNUNET_MessageHeader, | ||
4752 | NULL), | ||
4753 | GNUNET_MQ_hd_fixed_size (union_p2p_full_done, | ||
4754 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_DONE, | ||
4755 | struct GNUNET_MessageHeader, | ||
4756 | NULL), | ||
4757 | GNUNET_MQ_hd_var_size (union_p2p_request_full, | ||
4758 | GNUNET_MESSAGE_TYPE_SETU_P2P_REQUEST_FULL, | ||
4759 | struct TransmitFullMessage, | ||
4760 | NULL), | ||
4761 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, | ||
4762 | GNUNET_MESSAGE_TYPE_SETU_P2P_SE, | ||
4763 | struct StrataEstimatorMessage, | ||
4764 | NULL), | ||
4765 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, | ||
4766 | GNUNET_MESSAGE_TYPE_SETU_P2P_SEC, | ||
4767 | struct StrataEstimatorMessage, | ||
4768 | NULL), | ||
4769 | GNUNET_MQ_hd_var_size (union_p2p_full_element, | ||
4770 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_ELEMENT, | ||
4771 | struct GNUNET_SETU_ElementMessage, | ||
4772 | NULL), | ||
4773 | GNUNET_MQ_hd_var_size (union_p2p_send_full, | ||
4774 | GNUNET_MESSAGE_TYPE_SETU_P2P_SEND_FULL, | ||
4775 | struct TransmitFullMessage, | ||
4776 | NULL), | ||
4777 | GNUNET_MQ_handler_end () | ||
4778 | }; | ||
4779 | struct Listener *listener; | ||
4780 | |||
4781 | if (NULL != cs->listener) | ||
4782 | { | ||
4783 | /* max. one active listener per client! */ | ||
4784 | GNUNET_break (0); | ||
4785 | GNUNET_SERVICE_client_drop (cs->client); | ||
4786 | return; | ||
4787 | } | ||
4788 | listener = GNUNET_new (struct Listener); | ||
4789 | listener->cs = cs; | ||
4790 | cs->listener = listener; | ||
4791 | listener->app_id = msg->app_id; | ||
4792 | GNUNET_CONTAINER_DLL_insert (listener_head, | ||
4793 | listener_tail, | ||
4794 | listener); | ||
4795 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4796 | "New listener created (port %s)\n", | ||
4797 | GNUNET_h2s (&listener->app_id)); | ||
4798 | listener->open_port = GNUNET_CADET_open_port (cadet, | ||
4799 | &msg->app_id, | ||
4800 | &channel_new_cb, | ||
4801 | listener, | ||
4802 | &channel_window_cb, | ||
4803 | &channel_end_cb, | ||
4804 | cadet_handlers); | ||
4805 | GNUNET_SERVICE_client_continue (cs->client); | ||
4806 | } | ||
4807 | |||
4808 | |||
4809 | /** | ||
4810 | * Called when the listening client rejects an operation | ||
4811 | * request by another peer. | ||
4812 | * | ||
4813 | * @param cls client that sent the message | ||
4814 | * @param msg message sent by the client | ||
4815 | */ | ||
4816 | static void | ||
4817 | handle_client_reject (void *cls, | ||
4818 | const struct GNUNET_SETU_RejectMessage *msg) | ||
4819 | { | ||
4820 | struct ClientState *cs = cls; | ||
4821 | struct Operation *op; | ||
4822 | |||
4823 | op = get_incoming (ntohl (msg->accept_reject_id)); | ||
4824 | if (NULL == op) | ||
4825 | { | ||
4826 | /* no matching incoming operation for this reject; | ||
4827 | could be that the other peer already disconnected... */ | ||
4828 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
4829 | "Client rejected unknown operation %u\n", | ||
4830 | (unsigned int) ntohl (msg->accept_reject_id)); | ||
4831 | GNUNET_SERVICE_client_continue (cs->client); | ||
4832 | return; | ||
4833 | } | ||
4834 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4835 | "Peer request (app %s) rejected by client\n", | ||
4836 | GNUNET_h2s (&cs->listener->app_id)); | ||
4837 | _GSS_operation_destroy2 (op); | ||
4838 | GNUNET_SERVICE_client_continue (cs->client); | ||
4839 | } | ||
4840 | |||
4841 | |||
4842 | /** | ||
4843 | * Called when a client wants to add or remove an element to a set it inhabits. | ||
4844 | * | ||
4845 | * @param cls client that sent the message | ||
4846 | * @param msg message sent by the client | ||
4847 | */ | ||
4848 | static int | ||
4849 | check_client_set_add (void *cls, | ||
4850 | const struct GNUNET_SETU_ElementMessage *msg) | ||
4851 | { | ||
4852 | /* NOTE: Technically, we should probably check with the | ||
4853 | block library whether the element we are given is well-formed */ | ||
4854 | return GNUNET_OK; | ||
4855 | } | ||
4856 | |||
4857 | |||
4858 | /** | ||
4859 | * Called when a client wants to add or remove an element to a set it inhabits. | ||
4860 | * | ||
4861 | * @param cls client that sent the message | ||
4862 | * @param msg message sent by the client | ||
4863 | */ | ||
4864 | static void | ||
4865 | handle_client_set_add (void *cls, | ||
4866 | const struct GNUNET_SETU_ElementMessage *msg) | ||
4867 | { | ||
4868 | struct ClientState *cs = cls; | ||
4869 | struct Set *set; | ||
4870 | struct GNUNET_SETU_Element el; | ||
4871 | struct ElementEntry *ee; | ||
4872 | struct GNUNET_HashCode hash; | ||
4873 | |||
4874 | if (NULL == (set = cs->set)) | ||
4875 | { | ||
4876 | /* client without a set requested an operation */ | ||
4877 | GNUNET_break (0); | ||
4878 | GNUNET_SERVICE_client_drop (cs->client); | ||
4879 | return; | ||
4880 | } | ||
4881 | GNUNET_SERVICE_client_continue (cs->client); | ||
4882 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing mutation on set\n"); | ||
4883 | el.size = ntohs (msg->header.size) - sizeof(*msg); | ||
4884 | el.data = &msg[1]; | ||
4885 | el.element_type = ntohs (msg->element_type); | ||
4886 | GNUNET_SETU_element_hash (&el, | ||
4887 | &hash); | ||
4888 | ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, | ||
4889 | &hash); | ||
4890 | if (NULL == ee) | ||
4891 | { | ||
4892 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4893 | "Client inserts element %s of size %u\n", | ||
4894 | GNUNET_h2s (&hash), | ||
4895 | el.size); | ||
4896 | ee = GNUNET_malloc (el.size + sizeof(*ee)); | ||
4897 | ee->element.size = el.size; | ||
4898 | GNUNET_memcpy (&ee[1], el.data, el.size); | ||
4899 | ee->element.data = &ee[1]; | ||
4900 | ee->element.element_type = el.element_type; | ||
4901 | ee->remote = GNUNET_NO; | ||
4902 | ee->generation = set->current_generation; | ||
4903 | ee->element_hash = hash; | ||
4904 | GNUNET_break (GNUNET_YES == | ||
4905 | GNUNET_CONTAINER_multihashmap_put ( | ||
4906 | set->content->elements, | ||
4907 | &ee->element_hash, | ||
4908 | ee, | ||
4909 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4910 | } | ||
4911 | else | ||
4912 | { | ||
4913 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4914 | "Client inserted element %s of size %u twice (ignored)\n", | ||
4915 | GNUNET_h2s (&hash), | ||
4916 | el.size); | ||
4917 | /* same element inserted twice */ | ||
4918 | return; | ||
4919 | } | ||
4920 | strata_estimator_insert (set->se, | ||
4921 | get_ibf_key (&ee->element_hash)); | ||
4922 | } | ||
4923 | |||
4924 | |||
4925 | /** | ||
4926 | * Advance the current generation of a set, | ||
4927 | * adding exclusion ranges if necessary. | ||
4928 | * | ||
4929 | * @param set the set where we want to advance the generation | ||
4930 | */ | ||
4931 | static void | ||
4932 | advance_generation (struct Set *set) | ||
4933 | { | ||
4934 | set->content->latest_generation++; | ||
4935 | set->current_generation++; | ||
4936 | } | ||
4937 | |||
4938 | |||
4939 | /** | ||
4940 | * Called when a client wants to initiate a set operation with another | ||
4941 | * peer. Initiates the CADET connection to the listener and sends the | ||
4942 | * request. | ||
4943 | * | ||
4944 | * @param cls client that sent the message | ||
4945 | * @param msg message sent by the client | ||
4946 | * @return #GNUNET_OK if the message is well-formed | ||
4947 | */ | ||
4948 | static int | ||
4949 | check_client_evaluate (void *cls, | ||
4950 | const struct GNUNET_SETU_EvaluateMessage *msg) | ||
4951 | { | ||
4952 | /* FIXME: suboptimal, even if the context below could be NULL, | ||
4953 | there are malformed messages this does not check for... */ | ||
4954 | return GNUNET_OK; | ||
4955 | } | ||
4956 | |||
4957 | |||
4958 | /** | ||
4959 | * Called when a client wants to initiate a set operation with another | ||
4960 | * peer. Initiates the CADET connection to the listener and sends the | ||
4961 | * request. | ||
4962 | * | ||
4963 | * @param cls client that sent the message | ||
4964 | * @param msg message sent by the client | ||
4965 | */ | ||
4966 | static void | ||
4967 | handle_client_evaluate (void *cls, | ||
4968 | const struct GNUNET_SETU_EvaluateMessage *msg) | ||
4969 | { | ||
4970 | struct ClientState *cs = cls; | ||
4971 | struct Operation *op = GNUNET_new (struct Operation); | ||
4972 | |||
4973 | const struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
4974 | GNUNET_MQ_hd_var_size (incoming_msg, | ||
4975 | GNUNET_MESSAGE_TYPE_SETU_P2P_OPERATION_REQUEST, | ||
4976 | struct OperationRequestMessage, | ||
4977 | op), | ||
4978 | GNUNET_MQ_hd_var_size (union_p2p_ibf, | ||
4979 | GNUNET_MESSAGE_TYPE_SETU_P2P_IBF, | ||
4980 | struct IBFMessage, | ||
4981 | op), | ||
4982 | GNUNET_MQ_hd_var_size (union_p2p_elements, | ||
4983 | GNUNET_MESSAGE_TYPE_SETU_P2P_ELEMENTS, | ||
4984 | struct GNUNET_SETU_ElementMessage, | ||
4985 | op), | ||
4986 | GNUNET_MQ_hd_var_size (union_p2p_offer, | ||
4987 | GNUNET_MESSAGE_TYPE_SETU_P2P_OFFER, | ||
4988 | struct GNUNET_MessageHeader, | ||
4989 | op), | ||
4990 | GNUNET_MQ_hd_var_size (union_p2p_inquiry, | ||
4991 | GNUNET_MESSAGE_TYPE_SETU_P2P_INQUIRY, | ||
4992 | struct InquiryMessage, | ||
4993 | op), | ||
4994 | GNUNET_MQ_hd_var_size (union_p2p_demand, | ||
4995 | GNUNET_MESSAGE_TYPE_SETU_P2P_DEMAND, | ||
4996 | struct GNUNET_MessageHeader, | ||
4997 | op), | ||
4998 | GNUNET_MQ_hd_fixed_size (union_p2p_done, | ||
4999 | GNUNET_MESSAGE_TYPE_SETU_P2P_DONE, | ||
5000 | struct GNUNET_MessageHeader, | ||
5001 | op), | ||
5002 | GNUNET_MQ_hd_fixed_size (union_p2p_over, | ||
5003 | GNUNET_MESSAGE_TYPE_SETU_P2P_OVER, | ||
5004 | struct GNUNET_MessageHeader, | ||
5005 | op), | ||
5006 | GNUNET_MQ_hd_fixed_size (union_p2p_full_done, | ||
5007 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_DONE, | ||
5008 | struct GNUNET_MessageHeader, | ||
5009 | op), | ||
5010 | GNUNET_MQ_hd_var_size (union_p2p_request_full, | ||
5011 | GNUNET_MESSAGE_TYPE_SETU_P2P_REQUEST_FULL, | ||
5012 | struct TransmitFullMessage, | ||
5013 | op), | ||
5014 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, | ||
5015 | GNUNET_MESSAGE_TYPE_SETU_P2P_SE, | ||
5016 | struct StrataEstimatorMessage, | ||
5017 | op), | ||
5018 | GNUNET_MQ_hd_var_size (union_p2p_strata_estimator, | ||
5019 | GNUNET_MESSAGE_TYPE_SETU_P2P_SEC, | ||
5020 | struct StrataEstimatorMessage, | ||
5021 | op), | ||
5022 | GNUNET_MQ_hd_var_size (union_p2p_full_element, | ||
5023 | GNUNET_MESSAGE_TYPE_SETU_P2P_FULL_ELEMENT, | ||
5024 | struct GNUNET_SETU_ElementMessage, | ||
5025 | op), | ||
5026 | GNUNET_MQ_hd_var_size (union_p2p_send_full, | ||
5027 | GNUNET_MESSAGE_TYPE_SETU_P2P_SEND_FULL, | ||
5028 | struct TransmitFullMessage, | ||
5029 | NULL), | ||
5030 | GNUNET_MQ_handler_end () | ||
5031 | }; | ||
5032 | struct Set *set; | ||
5033 | const struct GNUNET_MessageHeader *context; | ||
5034 | |||
5035 | if (NULL == (set = cs->set)) | ||
5036 | { | ||
5037 | GNUNET_break (0); | ||
5038 | GNUNET_free (op); | ||
5039 | GNUNET_SERVICE_client_drop (cs->client); | ||
5040 | return; | ||
5041 | } | ||
5042 | op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
5043 | UINT32_MAX); | ||
5044 | op->peer = msg->target_peer; | ||
5045 | op->client_request_id = ntohl (msg->request_id); | ||
5046 | op->byzantine = msg->byzantine; | ||
5047 | op->byzantine_lower_bound = ntohl (msg->byzantine_lower_bound); | ||
5048 | op->force_full = msg->force_full; | ||
5049 | op->force_delta = msg->force_delta; | ||
5050 | op->symmetric = msg->symmetric; | ||
5051 | op->rtt_bandwidth_tradeoff = msg->bandwidth_latency_tradeoff; | ||
5052 | op->ibf_bucket_number_factor = msg->ibf_bucket_number_factor; | ||
5053 | op->ibf_number_buckets_per_element = msg->ibf_number_of_buckets_per_element; | ||
5054 | op->byzantine_upper_bound = msg->byzantine_upper_bond; | ||
5055 | op->active_passive_switch_required = false; | ||
5056 | context = GNUNET_MQ_extract_nested_mh (msg); | ||
5057 | |||
5058 | /* create hashmap for message control */ | ||
5059 | op->message_control_flow = GNUNET_CONTAINER_multihashmap_create (32, | ||
5060 | GNUNET_NO); | ||
5061 | op->inquiries_sent = GNUNET_CONTAINER_multihashmap_create (32,GNUNET_NO); | ||
5062 | |||
5063 | #if MEASURE_PERFORMANCE | ||
5064 | /* load config */ | ||
5065 | load_config (op); | ||
5066 | #endif | ||
5067 | |||
5068 | /* Advance generation values, so that | ||
5069 | mutations won't interfere with the running operation. */ | ||
5070 | op->set = set; | ||
5071 | op->generation_created = set->current_generation; | ||
5072 | advance_generation (set); | ||
5073 | GNUNET_CONTAINER_DLL_insert (set->ops_head, | ||
5074 | set->ops_tail, | ||
5075 | op); | ||
5076 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5077 | "Creating new CADET channel to port %s for set union\n", | ||
5078 | GNUNET_h2s (&msg->app_id)); | ||
5079 | op->channel = GNUNET_CADET_channel_create (cadet, | ||
5080 | op, | ||
5081 | &msg->target_peer, | ||
5082 | &msg->app_id, | ||
5083 | &channel_window_cb, | ||
5084 | &channel_end_cb, | ||
5085 | cadet_handlers); | ||
5086 | op->mq = GNUNET_CADET_get_mq (op->channel); | ||
5087 | { | ||
5088 | struct GNUNET_MQ_Envelope *ev; | ||
5089 | struct OperationRequestMessage *msg; | ||
5090 | |||
5091 | #if MEASURE_PERFORMANCE | ||
5092 | perf_store.operation_request.sent += 1; | ||
5093 | #endif | ||
5094 | ev = GNUNET_MQ_msg_nested_mh (msg, | ||
5095 | GNUNET_MESSAGE_TYPE_SETU_P2P_OPERATION_REQUEST, | ||
5096 | context); | ||
5097 | if (NULL == ev) | ||
5098 | { | ||
5099 | /* the context message is too large */ | ||
5100 | GNUNET_break (0); | ||
5101 | GNUNET_SERVICE_client_drop (cs->client); | ||
5102 | return; | ||
5103 | } | ||
5104 | op->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, | ||
5105 | GNUNET_NO); | ||
5106 | /* copy the current generation's strata estimator for this operation */ | ||
5107 | op->se = strata_estimator_dup (op->set->se); | ||
5108 | /* we started the operation, thus we have to send the operation request */ | ||
5109 | op->phase = PHASE_EXPECT_SE; | ||
5110 | |||
5111 | op->salt_receive = (op->peer_site + 1) % 2; | ||
5112 | op->salt_send = op->peer_site; // FIXME????? | ||
5113 | |||
5114 | |||
5115 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
5116 | "Initiating union operation evaluation\n"); | ||
5117 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
5118 | "# of total union operations", | ||
5119 | 1, | ||
5120 | GNUNET_NO); | ||
5121 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
5122 | "# of initiated union operations", | ||
5123 | 1, | ||
5124 | GNUNET_NO); | ||
5125 | GNUNET_MQ_send (op->mq, | ||
5126 | ev); | ||
5127 | if (NULL != context) | ||
5128 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
5129 | "sent op request with context message\n"); | ||
5130 | else | ||
5131 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
5132 | "sent op request without context message\n"); | ||
5133 | initialize_key_to_element (op); | ||
5134 | op->initial_size = GNUNET_CONTAINER_multihashmap32_size ( | ||
5135 | op->key_to_element); | ||
5136 | |||
5137 | } | ||
5138 | GNUNET_SERVICE_client_continue (cs->client); | ||
5139 | } | ||
5140 | |||
5141 | |||
5142 | /** | ||
5143 | * Handle a request from the client to cancel a running set operation. | ||
5144 | * | ||
5145 | * @param cls the client | ||
5146 | * @param msg the message | ||
5147 | */ | ||
5148 | static void | ||
5149 | handle_client_cancel (void *cls, | ||
5150 | const struct GNUNET_SETU_CancelMessage *msg) | ||
5151 | { | ||
5152 | struct ClientState *cs = cls; | ||
5153 | struct Set *set; | ||
5154 | struct Operation *op; | ||
5155 | int found; | ||
5156 | |||
5157 | if (NULL == (set = cs->set)) | ||
5158 | { | ||
5159 | /* client without a set requested an operation */ | ||
5160 | GNUNET_break (0); | ||
5161 | GNUNET_SERVICE_client_drop (cs->client); | ||
5162 | return; | ||
5163 | } | ||
5164 | found = GNUNET_NO; | ||
5165 | for (op = set->ops_head; NULL != op; op = op->next) | ||
5166 | { | ||
5167 | if (op->client_request_id == ntohl (msg->request_id)) | ||
5168 | { | ||
5169 | found = GNUNET_YES; | ||
5170 | break; | ||
5171 | } | ||
5172 | } | ||
5173 | if (GNUNET_NO == found) | ||
5174 | { | ||
5175 | /* It may happen that the operation was already destroyed due to | ||
5176 | * the other peer disconnecting. The client may not know about this | ||
5177 | * yet and try to cancel the (just barely non-existent) operation. | ||
5178 | * So this is not a hard error. | ||
5179 | */// | ||
5180 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
5181 | "Client canceled non-existent op %u\n", | ||
5182 | (uint32_t) ntohl (msg->request_id)); | ||
5183 | } | ||
5184 | else | ||
5185 | { | ||
5186 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5187 | "Client requested cancel for op %u\n", | ||
5188 | (uint32_t) ntohl (msg->request_id)); | ||
5189 | _GSS_operation_destroy (op); | ||
5190 | } | ||
5191 | GNUNET_SERVICE_client_continue (cs->client); | ||
5192 | } | ||
5193 | |||
5194 | |||
5195 | /** | ||
5196 | * Handle a request from the client to accept a set operation that | ||
5197 | * came from a remote peer. We forward the accept to the associated | ||
5198 | * operation for handling | ||
5199 | * | ||
5200 | * @param cls the client | ||
5201 | * @param msg the message | ||
5202 | */ | ||
5203 | static void | ||
5204 | handle_client_accept (void *cls, | ||
5205 | const struct GNUNET_SETU_AcceptMessage *msg) | ||
5206 | { | ||
5207 | struct ClientState *cs = cls; | ||
5208 | struct Set *set; | ||
5209 | struct Operation *op; | ||
5210 | struct GNUNET_SETU_ResultMessage *result_message; | ||
5211 | struct GNUNET_MQ_Envelope *ev; | ||
5212 | struct Listener *listener; | ||
5213 | |||
5214 | if (NULL == (set = cs->set)) | ||
5215 | { | ||
5216 | /* client without a set requested to accept */ | ||
5217 | GNUNET_break (0); | ||
5218 | GNUNET_SERVICE_client_drop (cs->client); | ||
5219 | return; | ||
5220 | } | ||
5221 | op = get_incoming (ntohl (msg->accept_reject_id)); | ||
5222 | if (NULL == op) | ||
5223 | { | ||
5224 | /* It is not an error if the set op does not exist -- it may | ||
5225 | * have been destroyed when the partner peer disconnected. */ | ||
5226 | GNUNET_log ( | ||
5227 | GNUNET_ERROR_TYPE_INFO, | ||
5228 | "Client %p accepted request %u of listener %p that is no longer active\n", | ||
5229 | cs, | ||
5230 | ntohl (msg->accept_reject_id), | ||
5231 | cs->listener); | ||
5232 | ev = GNUNET_MQ_msg (result_message, | ||
5233 | GNUNET_MESSAGE_TYPE_SETU_RESULT); | ||
5234 | result_message->request_id = msg->request_id; | ||
5235 | result_message->result_status = htons (GNUNET_SETU_STATUS_FAILURE); | ||
5236 | GNUNET_MQ_send (set->cs->mq, ev); | ||
5237 | GNUNET_SERVICE_client_continue (cs->client); | ||
5238 | return; | ||
5239 | } | ||
5240 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5241 | "Client accepting request %u\n", | ||
5242 | (uint32_t) ntohl (msg->accept_reject_id)); | ||
5243 | listener = op->listener; | ||
5244 | op->listener = NULL; | ||
5245 | GNUNET_CONTAINER_DLL_remove (listener->op_head, | ||
5246 | listener->op_tail, | ||
5247 | op); | ||
5248 | op->set = set; | ||
5249 | GNUNET_CONTAINER_DLL_insert (set->ops_head, | ||
5250 | set->ops_tail, | ||
5251 | op); | ||
5252 | op->client_request_id = ntohl (msg->request_id); | ||
5253 | op->byzantine = msg->byzantine; | ||
5254 | op->byzantine_lower_bound = ntohl (msg->byzantine_lower_bound); | ||
5255 | op->force_full = msg->force_full; | ||
5256 | op->force_delta = msg->force_delta; | ||
5257 | op->symmetric = msg->symmetric; | ||
5258 | op->rtt_bandwidth_tradeoff = msg->bandwidth_latency_tradeoff; | ||
5259 | op->ibf_bucket_number_factor = msg->ibf_bucket_number_factor; | ||
5260 | op->ibf_number_buckets_per_element = msg->ibf_number_of_buckets_per_element; | ||
5261 | op->byzantine_upper_bound = msg->byzantine_upper_bond; | ||
5262 | op->active_passive_switch_required = false; | ||
5263 | /* create hashmap for message control */ | ||
5264 | op->message_control_flow = GNUNET_CONTAINER_multihashmap_create (32, | ||
5265 | GNUNET_NO); | ||
5266 | op->inquiries_sent = GNUNET_CONTAINER_multihashmap_create (32,GNUNET_NO); | ||
5267 | |||
5268 | #if MEASURE_PERFORMANCE | ||
5269 | /* load config */ | ||
5270 | load_config (op); | ||
5271 | #endif | ||
5272 | |||
5273 | /* Advance generation values, so that future mutations do not | ||
5274 | interfer with the running operation. */ | ||
5275 | op->generation_created = set->current_generation; | ||
5276 | advance_generation (set); | ||
5277 | GNUNET_assert (NULL == op->se); | ||
5278 | |||
5279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
5280 | "accepting set union operation\n"); | ||
5281 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
5282 | "# of accepted union operations", | ||
5283 | 1, | ||
5284 | GNUNET_NO); | ||
5285 | GNUNET_STATISTICS_update (_GSS_statistics, | ||
5286 | "# of total union operations", | ||
5287 | 1, | ||
5288 | GNUNET_NO); | ||
5289 | { | ||
5290 | struct MultiStrataEstimator *se; | ||
5291 | struct GNUNET_MQ_Envelope *ev; | ||
5292 | struct StrataEstimatorMessage *strata_msg; | ||
5293 | char *buf; | ||
5294 | size_t len; | ||
5295 | uint16_t type; | ||
5296 | |||
5297 | op->se = strata_estimator_dup (op->set->se); | ||
5298 | op->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, | ||
5299 | GNUNET_NO); | ||
5300 | op->salt_receive = (op->peer_site + 1) % 2; | ||
5301 | op->salt_send = op->peer_site; // FIXME????? | ||
5302 | initialize_key_to_element (op); | ||
5303 | op->initial_size = GNUNET_CONTAINER_multihashmap32_size ( | ||
5304 | op->key_to_element); | ||
5305 | |||
5306 | /* kick off the operation */ | ||
5307 | se = op->se; | ||
5308 | |||
5309 | uint8_t se_count = 1; | ||
5310 | if (op->initial_size > 0) | ||
5311 | { | ||
5312 | op->total_elements_size_local = 0; | ||
5313 | GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements, | ||
5314 | & | ||
5315 | determinate_avg_element_size_iterator, | ||
5316 | op); | ||
5317 | se_count = determine_strata_count ( | ||
5318 | op->total_elements_size_local / op->initial_size, | ||
5319 | op->initial_size); | ||
5320 | } | ||
5321 | buf = GNUNET_malloc (se->stratas[0]->strata_count * IBF_BUCKET_SIZE | ||
5322 | * ((SE_IBFS_TOTAL_SIZE / 8) * se_count)); | ||
5323 | len = strata_estimator_write (se, | ||
5324 | SE_IBFS_TOTAL_SIZE, | ||
5325 | se_count, | ||
5326 | buf); | ||
5327 | #if MEASURE_PERFORMANCE | ||
5328 | perf_store.se.sent += 1; | ||
5329 | perf_store.se.sent_var_bytes += len; | ||
5330 | #endif | ||
5331 | |||
5332 | if (len < se->stratas[0]->strata_count * IBF_BUCKET_SIZE | ||
5333 | * SE_IBFS_TOTAL_SIZE) | ||
5334 | type = GNUNET_MESSAGE_TYPE_SETU_P2P_SEC; | ||
5335 | else | ||
5336 | type = GNUNET_MESSAGE_TYPE_SETU_P2P_SE; | ||
5337 | ev = GNUNET_MQ_msg_extra (strata_msg, | ||
5338 | len, | ||
5339 | type); | ||
5340 | GNUNET_memcpy (&strata_msg[1], | ||
5341 | buf, | ||
5342 | len); | ||
5343 | GNUNET_free (buf); | ||
5344 | strata_msg->set_size | ||
5345 | = GNUNET_htonll (GNUNET_CONTAINER_multihashmap_size ( | ||
5346 | op->set->content->elements)); | ||
5347 | strata_msg->se_count = se_count; | ||
5348 | GNUNET_MQ_send (op->mq, | ||
5349 | ev); | ||
5350 | op->phase = PHASE_EXPECT_IBF; | ||
5351 | } | ||
5352 | /* Now allow CADET to continue, as we did not do this in | ||
5353 | #handle_incoming_msg (as we wanted to first see if the | ||
5354 | local client would accept the request). */ | ||
5355 | GNUNET_CADET_receive_done (op->channel); | ||
5356 | GNUNET_SERVICE_client_continue (cs->client); | ||
5357 | } | ||
5358 | |||
5359 | |||
5360 | /** | ||
5361 | * Called to clean up, after a shutdown has been requested. | ||
5362 | * | ||
5363 | * @param cls closure, NULL | ||
5364 | */ | ||
5365 | static void | ||
5366 | shutdown_task (void *cls) | ||
5367 | { | ||
5368 | /* Delay actual shutdown to allow service to disconnect clients */ | ||
5369 | in_shutdown = GNUNET_YES; | ||
5370 | if (0 == num_clients) | ||
5371 | { | ||
5372 | if (NULL != cadet) | ||
5373 | { | ||
5374 | GNUNET_CADET_disconnect (cadet); | ||
5375 | cadet = NULL; | ||
5376 | } | ||
5377 | } | ||
5378 | GNUNET_STATISTICS_destroy (_GSS_statistics, | ||
5379 | GNUNET_YES); | ||
5380 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5381 | "handled shutdown request\n"); | ||
5382 | #if MEASURE_PERFORMANCE | ||
5383 | calculate_perf_store (); | ||
5384 | #endif | ||
5385 | } | ||
5386 | |||
5387 | |||
5388 | /** | ||
5389 | * Function called by the service's run | ||
5390 | * method to run service-specific setup code. | ||
5391 | * | ||
5392 | * @param cls closure | ||
5393 | * @param cfg configuration to use | ||
5394 | * @param service the initialized service | ||
5395 | */ | ||
5396 | static void | ||
5397 | run (void *cls, | ||
5398 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
5399 | struct GNUNET_SERVICE_Handle *service) | ||
5400 | { | ||
5401 | /* FIXME: need to modify SERVICE (!) API to allow | ||
5402 | us to run a shutdown task *after* clients were | ||
5403 | forcefully disconnected! */ | ||
5404 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
5405 | NULL); | ||
5406 | _GSS_statistics = GNUNET_STATISTICS_create ("setu", | ||
5407 | cfg); | ||
5408 | cadet = GNUNET_CADET_connect (cfg); | ||
5409 | if (NULL == cadet) | ||
5410 | { | ||
5411 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
5412 | _ ("Could not connect to CADET service\n")); | ||
5413 | GNUNET_SCHEDULER_shutdown (); | ||
5414 | return; | ||
5415 | } | ||
5416 | } | ||
5417 | |||
5418 | |||
5419 | /** | ||
5420 | * Define "main" method using service macro. | ||
5421 | */ | ||
5422 | GNUNET_SERVICE_MAIN ( | ||
5423 | "set", | ||
5424 | GNUNET_SERVICE_OPTION_NONE, | ||
5425 | &run, | ||
5426 | &client_connect_cb, | ||
5427 | &client_disconnect_cb, | ||
5428 | NULL, | ||
5429 | GNUNET_MQ_hd_fixed_size (client_accept, | ||
5430 | GNUNET_MESSAGE_TYPE_SETU_ACCEPT, | ||
5431 | struct GNUNET_SETU_AcceptMessage, | ||
5432 | NULL), | ||
5433 | GNUNET_MQ_hd_var_size (client_set_add, | ||
5434 | GNUNET_MESSAGE_TYPE_SETU_ADD, | ||
5435 | struct GNUNET_SETU_ElementMessage, | ||
5436 | NULL), | ||
5437 | GNUNET_MQ_hd_fixed_size (client_create_set, | ||
5438 | GNUNET_MESSAGE_TYPE_SETU_CREATE, | ||
5439 | struct GNUNET_SETU_CreateMessage, | ||
5440 | NULL), | ||
5441 | GNUNET_MQ_hd_var_size (client_evaluate, | ||
5442 | GNUNET_MESSAGE_TYPE_SETU_EVALUATE, | ||
5443 | struct GNUNET_SETU_EvaluateMessage, | ||
5444 | NULL), | ||
5445 | GNUNET_MQ_hd_fixed_size (client_listen, | ||
5446 | GNUNET_MESSAGE_TYPE_SETU_LISTEN, | ||
5447 | struct GNUNET_SETU_ListenMessage, | ||
5448 | NULL), | ||
5449 | GNUNET_MQ_hd_fixed_size (client_reject, | ||
5450 | GNUNET_MESSAGE_TYPE_SETU_REJECT, | ||
5451 | struct GNUNET_SETU_RejectMessage, | ||
5452 | NULL), | ||
5453 | GNUNET_MQ_hd_fixed_size (client_cancel, | ||
5454 | GNUNET_MESSAGE_TYPE_SETU_CANCEL, | ||
5455 | struct GNUNET_SETU_CancelMessage, | ||
5456 | NULL), | ||
5457 | GNUNET_MQ_handler_end ()); | ||
5458 | |||
5459 | |||
5460 | /* end of gnunet-service-setu.c */ | ||
diff --git a/src/setu/gnunet-service-setu_protocol.h b/src/setu/gnunet-service-setu_protocol.h deleted file mode 100644 index c896166ce..000000000 --- a/src/setu/gnunet-service-setu_protocol.h +++ /dev/null | |||
@@ -1,256 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @author Florian Dold | ||
22 | * @author Christian Grothoff | ||
23 | * @file set/gnunet-service-set_protocol.h | ||
24 | * @brief Peer-to-Peer messages for gnunet set | ||
25 | */ | ||
26 | #ifndef SET_PROTOCOL_H | ||
27 | #define SET_PROTOCOL_H | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_common.h" | ||
31 | |||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | struct OperationRequestMessage | ||
36 | { | ||
37 | /** | ||
38 | * Type: #GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * For Intersection: my element count | ||
44 | */ | ||
45 | uint32_t element_count GNUNET_PACKED; | ||
46 | |||
47 | /** | ||
48 | * Application-specific identifier of the request. | ||
49 | */ | ||
50 | struct GNUNET_HashCode app_idX; | ||
51 | |||
52 | /* rest: optional message */ | ||
53 | }; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Message containing buckets of an invertible bloom filter. | ||
58 | * | ||
59 | * If an IBF has too many buckets for an IBF message, | ||
60 | * it is split into multiple messages. | ||
61 | */ | ||
62 | struct IBFMessage | ||
63 | { | ||
64 | /** | ||
65 | * Type: #GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF | ||
66 | */ | ||
67 | struct GNUNET_MessageHeader header; | ||
68 | |||
69 | /** | ||
70 | * Size of the whole ibf (number of buckets) | ||
71 | */ | ||
72 | uint32_t ibf_size; | ||
73 | |||
74 | /** | ||
75 | * Offset of the strata in the rest of the message | ||
76 | */ | ||
77 | uint32_t offset GNUNET_PACKED; | ||
78 | |||
79 | /** | ||
80 | * Salt used when hashing elements for this IBF. | ||
81 | */ | ||
82 | uint16_t salt GNUNET_PACKED; | ||
83 | |||
84 | /** | ||
85 | * The bit length of the counter | ||
86 | */ | ||
87 | uint16_t ibf_counter_bit_length; | ||
88 | /* rest: buckets */ | ||
89 | }; | ||
90 | |||
91 | |||
92 | /** | ||
93 | estimate_best_mode_of_operation (uint64_t avg_element_size, | ||
94 | uint64_t local_set_size, | ||
95 | uint64_t remote_set_size, | ||
96 | uint64_t est_set_diff_remote, | ||
97 | uint64_t est_set_diff_local,) | ||
98 | **/ | ||
99 | |||
100 | |||
101 | struct InquiryMessage | ||
102 | { | ||
103 | /** | ||
104 | * Type: #GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF | ||
105 | */ | ||
106 | struct GNUNET_MessageHeader header; | ||
107 | |||
108 | /** | ||
109 | * Salt used when hashing elements for this inquiry. | ||
110 | */ | ||
111 | uint32_t salt GNUNET_PACKED; | ||
112 | |||
113 | /* rest: inquiry IBF keys */ | ||
114 | }; | ||
115 | |||
116 | |||
117 | /** | ||
118 | * During intersection, the first (and possibly second) message | ||
119 | * send it the number of elements in the set, to allow the peers | ||
120 | * to decide who should start with the Bloom filter. | ||
121 | */ | ||
122 | struct IntersectionElementInfoMessage | ||
123 | { | ||
124 | /** | ||
125 | * Type: #GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO | ||
126 | */ | ||
127 | struct GNUNET_MessageHeader header; | ||
128 | |||
129 | /** | ||
130 | * mutator used with this bloomfilter. | ||
131 | */ | ||
132 | uint32_t sender_element_count GNUNET_PACKED; | ||
133 | }; | ||
134 | |||
135 | |||
136 | /** | ||
137 | * Bloom filter messages exchanged for set intersection calculation. | ||
138 | */ | ||
139 | struct BFMessage | ||
140 | { | ||
141 | /** | ||
142 | * Type: #GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF | ||
143 | */ | ||
144 | struct GNUNET_MessageHeader header; | ||
145 | |||
146 | /** | ||
147 | * Number of elements the sender still has in the set. | ||
148 | */ | ||
149 | uint32_t sender_element_count GNUNET_PACKED; | ||
150 | |||
151 | /** | ||
152 | * XOR of all hashes over all elements remaining in the set. | ||
153 | * Used to determine termination. | ||
154 | */ | ||
155 | struct GNUNET_HashCode element_xor_hash; | ||
156 | |||
157 | /** | ||
158 | * Mutator used with this bloomfilter. | ||
159 | */ | ||
160 | uint32_t sender_mutator GNUNET_PACKED; | ||
161 | |||
162 | /** | ||
163 | * Total length of the bloomfilter data. | ||
164 | */ | ||
165 | uint32_t bloomfilter_total_length GNUNET_PACKED; | ||
166 | |||
167 | /** | ||
168 | * Number of bits (k-value) used in encoding the bloomfilter. | ||
169 | */ | ||
170 | uint32_t bits_per_element GNUNET_PACKED; | ||
171 | |||
172 | /** | ||
173 | * rest: the sender's bloomfilter | ||
174 | */ | ||
175 | }; | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Last message, send to confirm the final set. Contains the element | ||
180 | * count as it is possible that the peer determined that we were done | ||
181 | * by getting the empty set, which in that case also needs to be | ||
182 | * communicated. | ||
183 | */ | ||
184 | struct IntersectionDoneMessage | ||
185 | { | ||
186 | /** | ||
187 | * Type: #GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE | ||
188 | */ | ||
189 | struct GNUNET_MessageHeader header; | ||
190 | |||
191 | /** | ||
192 | * Final number of elements in intersection. | ||
193 | */ | ||
194 | uint32_t final_element_count GNUNET_PACKED; | ||
195 | |||
196 | /** | ||
197 | * XOR of all hashes over all elements remaining in the set. | ||
198 | */ | ||
199 | struct GNUNET_HashCode element_xor_hash; | ||
200 | }; | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Strata estimator together with the peer's overall set size. | ||
205 | */ | ||
206 | struct StrataEstimatorMessage | ||
207 | { | ||
208 | /** | ||
209 | * Type: #GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE(C) | ||
210 | */ | ||
211 | struct GNUNET_MessageHeader header; | ||
212 | |||
213 | /** | ||
214 | * The number of ses transmitted | ||
215 | */ | ||
216 | uint8_t se_count; | ||
217 | |||
218 | /** | ||
219 | * Size of the local set | ||
220 | */ | ||
221 | uint64_t set_size GNUNET_PACKED; | ||
222 | }; | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Message which signals to other peer that we are sending full set | ||
227 | * | ||
228 | */ | ||
229 | struct TransmitFullMessage | ||
230 | { | ||
231 | /** | ||
232 | * Type: #GNUNET_MESSAGE_TYPE_SETU_P2P_SEND_FULL | ||
233 | */ | ||
234 | struct GNUNET_MessageHeader header; | ||
235 | |||
236 | /** | ||
237 | * Remote set difference calculated with strata estimator | ||
238 | */ | ||
239 | uint32_t remote_set_difference; | ||
240 | |||
241 | /** | ||
242 | * Total remote set size | ||
243 | */ | ||
244 | uint32_t remote_set_size; | ||
245 | |||
246 | /** | ||
247 | * Local set difference calculated with strata estimator | ||
248 | */ | ||
249 | uint32_t local_set_difference; | ||
250 | |||
251 | }; | ||
252 | |||
253 | |||
254 | GNUNET_NETWORK_STRUCT_END | ||
255 | |||
256 | #endif | ||
diff --git a/src/setu/gnunet-service-setu_strata_estimator.c b/src/setu/gnunet-service-setu_strata_estimator.c deleted file mode 100644 index 43ccf3afd..000000000 --- a/src/setu/gnunet-service-setu_strata_estimator.c +++ /dev/null | |||
@@ -1,468 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file set/gnunet-service-setu_strata_estimator.c | ||
22 | * @brief invertible bloom filter | ||
23 | * @author Florian Dold | ||
24 | * @author Christian Grothoff | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "ibf.h" | ||
30 | #include "gnunet-service-setu_strata_estimator.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Should we try compressing the strata estimator? This will | ||
35 | * break compatibility with the 0.10.1-network. | ||
36 | */ | ||
37 | #define FAIL_10_1_COMPATIBILTIY 1 | ||
38 | |||
39 | /** | ||
40 | * Number of strata estimators in memory NOT transmitted | ||
41 | */ | ||
42 | |||
43 | #define MULTI_SE_BASE_COUNT 8 | ||
44 | |||
45 | /** | ||
46 | * The avg size of 1 se | ||
47 | * Based on the bsc thesis of Elias Summermatter (2021) | ||
48 | */ | ||
49 | |||
50 | #define AVG_BYTE_SIZE_SE 4221 | ||
51 | |||
52 | /** | ||
53 | * Calculates the optimal number of strata Estimators to send | ||
54 | * @param avg_element_size | ||
55 | * @param element_count | ||
56 | * @return | ||
57 | */ | ||
58 | uint8_t | ||
59 | determine_strata_count (uint64_t avg_element_size, uint64_t element_count) | ||
60 | { | ||
61 | uint64_t base_size = avg_element_size * element_count; | ||
62 | /* >67kb total size of elements in set */ | ||
63 | if (base_size < AVG_BYTE_SIZE_SE * 16) | ||
64 | return 1; | ||
65 | /* >270kb total size of elements in set */ | ||
66 | if (base_size < AVG_BYTE_SIZE_SE * 64) | ||
67 | return 2; | ||
68 | /* >1mb total size of elements in set */ | ||
69 | if (base_size < AVG_BYTE_SIZE_SE * 256) | ||
70 | return 4; | ||
71 | return 8; | ||
72 | } | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Modify an IBF key @a k_in based on the @a salt, returning a | ||
77 | * salted key in @a k_out. | ||
78 | */ | ||
79 | static void | ||
80 | salt_key (const struct IBF_Key *k_in, | ||
81 | uint32_t salt, | ||
82 | struct IBF_Key *k_out) | ||
83 | { | ||
84 | int s = (salt * 7) % 64; | ||
85 | uint64_t x = k_in->key_val; | ||
86 | |||
87 | /* rotate ibf key */ | ||
88 | if (s > 0) | ||
89 | x = (x >> s) | (x << (64 - s)); | ||
90 | k_out->key_val = x; | ||
91 | } | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Reverse modification done in the salt_key function | ||
96 | */ | ||
97 | static void | ||
98 | unsalt_key (const struct IBF_Key *k_in, | ||
99 | uint32_t salt, | ||
100 | struct IBF_Key *k_out) | ||
101 | { | ||
102 | int s = (salt * 7) % 64; | ||
103 | uint64_t x = k_in->key_val; | ||
104 | |||
105 | x = (x << s) | (x >> (64 - s)); | ||
106 | k_out->key_val = x; | ||
107 | } | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Write the given strata estimator to the buffer. | ||
112 | * | ||
113 | * @param se strata estimator to serialize | ||
114 | * @param[out] buf buffer to write to, must be of appropriate size | ||
115 | * @return number of bytes written to @a buf | ||
116 | */ | ||
117 | size_t | ||
118 | strata_estimator_write (struct MultiStrataEstimator *se, | ||
119 | uint16_t se_ibf_total_size, | ||
120 | uint8_t number_se_send, | ||
121 | void *buf) | ||
122 | { | ||
123 | char *sbuf = buf; | ||
124 | unsigned int i; | ||
125 | size_t osize; | ||
126 | uint64_t sbuf_offset = 0; | ||
127 | se->size = number_se_send; | ||
128 | |||
129 | GNUNET_assert (NULL != se); | ||
130 | for (uint8_t strata_ctr = 0; strata_ctr < number_se_send; strata_ctr++) | ||
131 | { | ||
132 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
133 | { | ||
134 | ibf_write_slice (se->stratas[strata_ctr]->strata[i], | ||
135 | 0, | ||
136 | se->stratas[strata_ctr]->ibf_size, | ||
137 | &sbuf[sbuf_offset], | ||
138 | 8); | ||
139 | sbuf_offset += se->stratas[strata_ctr]->ibf_size * IBF_BUCKET_SIZE; | ||
140 | } | ||
141 | } | ||
142 | osize = ((se_ibf_total_size / 8) * number_se_send) * IBF_BUCKET_SIZE | ||
143 | * se->stratas[0]->strata_count; | ||
144 | #if FAIL_10_1_COMPATIBILTIY | ||
145 | { | ||
146 | char *cbuf; | ||
147 | size_t nsize; | ||
148 | |||
149 | if (GNUNET_YES == | ||
150 | GNUNET_try_compression (buf, | ||
151 | osize, | ||
152 | &cbuf, | ||
153 | &nsize)) | ||
154 | { | ||
155 | GNUNET_memcpy (buf, cbuf, nsize); | ||
156 | osize = nsize; | ||
157 | GNUNET_free (cbuf); | ||
158 | } | ||
159 | } | ||
160 | #endif | ||
161 | return osize; | ||
162 | } | ||
163 | |||
164 | |||
165 | /** | ||
166 | * Read strata from the buffer into the given strata | ||
167 | * estimator. The strata estimator must already be allocated. | ||
168 | * | ||
169 | * @param buf buffer to read from | ||
170 | * @param buf_len number of bytes in @a buf | ||
171 | * @param is_compressed is the data compressed? | ||
172 | * @param[out] se strata estimator to write to | ||
173 | * @return #GNUNET_OK on success | ||
174 | */ | ||
175 | int | ||
176 | strata_estimator_read (const void *buf, | ||
177 | size_t buf_len, | ||
178 | int is_compressed, | ||
179 | uint8_t number_se_received, | ||
180 | uint16_t se_ibf_total_size, | ||
181 | struct MultiStrataEstimator *se) | ||
182 | { | ||
183 | unsigned int i; | ||
184 | size_t osize; | ||
185 | char *dbuf; | ||
186 | |||
187 | dbuf = NULL; | ||
188 | if (GNUNET_YES == is_compressed) | ||
189 | { | ||
190 | osize = ((se_ibf_total_size / 8) * number_se_received) * IBF_BUCKET_SIZE | ||
191 | * se->stratas[0]->strata_count; | ||
192 | dbuf = GNUNET_decompress (buf, | ||
193 | buf_len, | ||
194 | osize); | ||
195 | if (NULL == dbuf) | ||
196 | { | ||
197 | GNUNET_break_op (0); /* bad compressed input data */ | ||
198 | return GNUNET_SYSERR; | ||
199 | } | ||
200 | buf = dbuf; | ||
201 | buf_len = osize; | ||
202 | } | ||
203 | |||
204 | if (buf_len != se->stratas[0]->strata_count * ((se_ibf_total_size / 8) | ||
205 | * number_se_received) | ||
206 | * IBF_BUCKET_SIZE) | ||
207 | { | ||
208 | GNUNET_break (0); /* very odd error */ | ||
209 | GNUNET_free (dbuf); | ||
210 | return GNUNET_SYSERR; | ||
211 | } | ||
212 | |||
213 | for (uint8_t strata_ctr = 0; strata_ctr < number_se_received; strata_ctr++) | ||
214 | { | ||
215 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
216 | { | ||
217 | ibf_read_slice (buf, 0, se->stratas[strata_ctr]->ibf_size, | ||
218 | se->stratas[strata_ctr]->strata[i], 8); | ||
219 | buf += se->stratas[strata_ctr]->ibf_size * IBF_BUCKET_SIZE; | ||
220 | } | ||
221 | } | ||
222 | se->size = number_se_received; | ||
223 | GNUNET_free (dbuf); | ||
224 | return GNUNET_OK; | ||
225 | } | ||
226 | |||
227 | |||
228 | /** | ||
229 | * Add a key to the strata estimator. | ||
230 | * | ||
231 | * @param se strata estimator to add the key to | ||
232 | * @param key key to add | ||
233 | */ | ||
234 | void | ||
235 | strata_estimator_insert (struct MultiStrataEstimator *se, | ||
236 | struct IBF_Key key) | ||
237 | { | ||
238 | |||
239 | |||
240 | /* count trailing '1'-bits of v */ | ||
241 | for (int strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) | ||
242 | { | ||
243 | unsigned int i; | ||
244 | uint64_t v; | ||
245 | |||
246 | struct IBF_Key salted_key; | ||
247 | salt_key (&key, | ||
248 | strata_ctr * (64 / MULTI_SE_BASE_COUNT), | ||
249 | &salted_key); | ||
250 | v = salted_key.key_val; | ||
251 | for (i = 0; v & 1; v >>= 1, i++) | ||
252 | { | ||
253 | ibf_insert (se->stratas[strata_ctr]->strata[i], salted_key); | ||
254 | } | ||
255 | } | ||
256 | /* empty */; | ||
257 | |||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Remove a key from the strata estimator. (NOT USED) | ||
263 | * | ||
264 | * @param se strata estimator to remove the key from | ||
265 | * @param key key to remove | ||
266 | */ | ||
267 | void | ||
268 | strata_estimator_remove (struct MultiStrataEstimator *se, | ||
269 | struct IBF_Key key) | ||
270 | { | ||
271 | |||
272 | /* count trailing '1'-bits of v */ | ||
273 | for (int strata_ctr = 0; strata_ctr < se->size; strata_ctr++) | ||
274 | { | ||
275 | uint64_t v; | ||
276 | unsigned int i; | ||
277 | |||
278 | struct IBF_Key unsalted_key; | ||
279 | unsalt_key (&key, | ||
280 | strata_ctr * (64 / MULTI_SE_BASE_COUNT), | ||
281 | &unsalted_key); | ||
282 | |||
283 | v = unsalted_key.key_val; | ||
284 | for (i = 0; v & 1; v >>= 1, i++) | ||
285 | { | ||
286 | /* empty */; | ||
287 | ibf_remove (se->stratas[strata_ctr]->strata[i], unsalted_key); | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | |||
292 | |||
293 | /** | ||
294 | * Create a new strata estimator with the given parameters. | ||
295 | * | ||
296 | * @param strata_count number of stratas, that is, number of ibfs in the estimator | ||
297 | * @param ibf_size size of each ibf stratum | ||
298 | * @param ibf_hashnum hashnum parameter of each ibf | ||
299 | * @return a freshly allocated, empty strata estimator, NULL on error | ||
300 | */ | ||
301 | struct MultiStrataEstimator * | ||
302 | strata_estimator_create (unsigned int strata_count, | ||
303 | uint32_t ibf_size, | ||
304 | uint8_t ibf_hashnum) | ||
305 | { | ||
306 | struct MultiStrataEstimator *se; | ||
307 | unsigned int i; | ||
308 | unsigned int j; | ||
309 | se = GNUNET_new (struct MultiStrataEstimator); | ||
310 | |||
311 | se->size = MULTI_SE_BASE_COUNT; | ||
312 | se->stratas = GNUNET_new_array (MULTI_SE_BASE_COUNT,struct StrataEstimator *); | ||
313 | |||
314 | uint8_t ibf_prime_sizes[] = {79,79,79,79,79,79,79,79}; | ||
315 | |||
316 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) | ||
317 | { | ||
318 | se->stratas[strata_ctr] = GNUNET_new (struct StrataEstimator); | ||
319 | se->stratas[strata_ctr]->strata_count = strata_count; | ||
320 | se->stratas[strata_ctr]->ibf_size = ibf_prime_sizes[strata_ctr]; | ||
321 | se->stratas[strata_ctr]->strata = GNUNET_new_array (strata_count * 4, | ||
322 | struct | ||
323 | InvertibleBloomFilter *); | ||
324 | for (i = 0; i < strata_count; i++) | ||
325 | { | ||
326 | se->stratas[strata_ctr]->strata[i] = ibf_create ( | ||
327 | ibf_prime_sizes[strata_ctr], ibf_hashnum); | ||
328 | if (NULL == se->stratas[strata_ctr]->strata[i]) | ||
329 | { | ||
330 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
331 | "Failed to allocate memory for strata estimator\n"); | ||
332 | for (j = 0; j < i; j++) | ||
333 | ibf_destroy (se->stratas[strata_ctr]->strata[i]); | ||
334 | GNUNET_free (se); | ||
335 | return NULL; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | return se; | ||
340 | } | ||
341 | |||
342 | |||
343 | /** | ||
344 | * Estimate set difference with two strata estimators, | ||
345 | * i.e. arrays of IBFs. | ||
346 | * Does not not modify its arguments. | ||
347 | * | ||
348 | * @param se1 first strata estimator | ||
349 | * @param se2 second strata estimator | ||
350 | * @return the estimated difference | ||
351 | */ | ||
352 | void | ||
353 | strata_estimator_difference (const struct MultiStrataEstimator *se1, | ||
354 | const struct MultiStrataEstimator *se2) | ||
355 | { | ||
356 | int avg_local_diff = 0; | ||
357 | int avg_remote_diff = 0; | ||
358 | uint8_t number_of_estimators = se1->size; | ||
359 | |||
360 | for (uint8_t strata_ctr = 0; strata_ctr < number_of_estimators; strata_ctr++) | ||
361 | { | ||
362 | GNUNET_assert (se1->stratas[strata_ctr]->strata_count == | ||
363 | se2->stratas[strata_ctr]->strata_count); | ||
364 | |||
365 | |||
366 | for (int i = se1->stratas[strata_ctr]->strata_count - 1; i >= 0; i--) | ||
367 | { | ||
368 | struct InvertibleBloomFilter *diff; | ||
369 | /* number of keys decoded from the ibf */ | ||
370 | |||
371 | /* FIXME: implement this without always allocating new IBFs */ | ||
372 | diff = ibf_dup (se1->stratas[strata_ctr]->strata[i]); | ||
373 | diff->local_decoded_count = 0; | ||
374 | diff->remote_decoded_count = 0; | ||
375 | |||
376 | ibf_subtract (diff, se2->stratas[strata_ctr]->strata[i]); | ||
377 | |||
378 | for (int ibf_count = 0; GNUNET_YES; ibf_count++) | ||
379 | { | ||
380 | int more; | ||
381 | |||
382 | more = ibf_decode (diff, NULL, NULL); | ||
383 | if (GNUNET_NO == more) | ||
384 | { | ||
385 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count += | ||
386 | diff->local_decoded_count; | ||
387 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count += | ||
388 | diff->remote_decoded_count; | ||
389 | break; | ||
390 | } | ||
391 | /* Estimate if decoding fails or would not terminate */ | ||
392 | if ((GNUNET_SYSERR == more) || (ibf_count > diff->size)) | ||
393 | { | ||
394 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count = | ||
395 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count * (1 << (i | ||
396 | + | ||
397 | 1)); | ||
398 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count = | ||
399 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count * (1 << (i | ||
400 | + | ||
401 | 1)); | ||
402 | ibf_destroy (diff); | ||
403 | goto break_all_counting_loops; | ||
404 | } | ||
405 | } | ||
406 | ibf_destroy (diff); | ||
407 | } | ||
408 | break_all_counting_loops:; | ||
409 | avg_local_diff += se1->stratas[strata_ctr]->strata[0]->local_decoded_count; | ||
410 | avg_remote_diff += | ||
411 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count; | ||
412 | } | ||
413 | se1->stratas[0]->strata[0]->local_decoded_count = avg_local_diff | ||
414 | / number_of_estimators; | ||
415 | se1->stratas[0]->strata[0]->remote_decoded_count = avg_remote_diff | ||
416 | / number_of_estimators; | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Make a copy of a strata estimator. | ||
422 | * | ||
423 | * @param se the strata estimator to copy | ||
424 | * @return the copy | ||
425 | */ | ||
426 | struct MultiStrataEstimator * | ||
427 | strata_estimator_dup (struct MultiStrataEstimator *se) | ||
428 | { | ||
429 | struct MultiStrataEstimator *c; | ||
430 | unsigned int i; | ||
431 | |||
432 | c = GNUNET_new (struct MultiStrataEstimator); | ||
433 | c->stratas = GNUNET_new_array (MULTI_SE_BASE_COUNT,struct StrataEstimator *); | ||
434 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) | ||
435 | { | ||
436 | c->stratas[strata_ctr] = GNUNET_new (struct StrataEstimator); | ||
437 | c->stratas[strata_ctr]->strata_count = | ||
438 | se->stratas[strata_ctr]->strata_count; | ||
439 | c->stratas[strata_ctr]->ibf_size = se->stratas[strata_ctr]->ibf_size; | ||
440 | c->stratas[strata_ctr]->strata = GNUNET_new_array ( | ||
441 | se->stratas[strata_ctr]->strata_count, | ||
442 | struct | ||
443 | InvertibleBloomFilter *); | ||
444 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
445 | c->stratas[strata_ctr]->strata[i] = ibf_dup ( | ||
446 | se->stratas[strata_ctr]->strata[i]); | ||
447 | } | ||
448 | return c; | ||
449 | } | ||
450 | |||
451 | |||
452 | /** | ||
453 | * Destroy a strata estimator, free all of its resources. | ||
454 | * | ||
455 | * @param se strata estimator to destroy. | ||
456 | */ | ||
457 | void | ||
458 | strata_estimator_destroy (struct MultiStrataEstimator *se) | ||
459 | { | ||
460 | unsigned int i; | ||
461 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) | ||
462 | { | ||
463 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
464 | ibf_destroy (se->stratas[strata_ctr]->strata[i]); | ||
465 | GNUNET_free (se->stratas[strata_ctr]->strata); | ||
466 | } | ||
467 | GNUNET_free (se); | ||
468 | } | ||
diff --git a/src/setu/gnunet-service-setu_strata_estimator.h b/src/setu/gnunet-service-setu_strata_estimator.h deleted file mode 100644 index 4871a7fcd..000000000 --- a/src/setu/gnunet-service-setu_strata_estimator.h +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/gnunet-service-setu_strata_estimator.h | ||
23 | * @brief estimator of set difference | ||
24 | * @author Florian Dold | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | |||
28 | #ifndef GNUNET_SERVICE_SETU_STRATA_ESTIMATOR_H | ||
29 | #define GNUNET_SERVICE_SETU_STRATA_ESTIMATOR_H | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_common.h" | ||
33 | #include "gnunet_util_lib.h" | ||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" | ||
37 | { | ||
38 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
39 | } | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
43 | |||
44 | /** | ||
45 | * A handle to a strata estimator. | ||
46 | */ | ||
47 | struct StrataEstimator | ||
48 | { | ||
49 | /** | ||
50 | * The IBFs of this strata estimator. | ||
51 | */ | ||
52 | struct InvertibleBloomFilter **strata; | ||
53 | |||
54 | /** | ||
55 | * Size of the IBF array in @e strata | ||
56 | */ | ||
57 | unsigned int strata_count; | ||
58 | |||
59 | /** | ||
60 | * Size of each IBF stratum (in bytes) | ||
61 | */ | ||
62 | unsigned int ibf_size; | ||
63 | }; | ||
64 | |||
65 | struct MultiStrataEstimator | ||
66 | { | ||
67 | /** | ||
68 | * Array of strata estimators | ||
69 | */ | ||
70 | struct StrataEstimator **stratas; | ||
71 | |||
72 | /** | ||
73 | * Number of strata estimators in struct | ||
74 | */ | ||
75 | uint8_t size; | ||
76 | |||
77 | }; | ||
78 | |||
79 | /** | ||
80 | * Deteminate how many strata estimators in the message are necessary | ||
81 | * @param avg_element_size | ||
82 | * @param element_count | ||
83 | * @return number of strata's | ||
84 | */ | ||
85 | |||
86 | uint8_t | ||
87 | determine_strata_count (uint64_t avg_element_size, | ||
88 | uint64_t element_count); | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Write the given strata estimator to the buffer. | ||
93 | * | ||
94 | * @param se strata estimator to serialize | ||
95 | * @param[out] buf buffer to write to, must be of appropriate size | ||
96 | * @return number of bytes written to @a buf | ||
97 | */ | ||
98 | size_t | ||
99 | strata_estimator_write (struct MultiStrataEstimator *se, | ||
100 | uint16_t se_ibf_total_size, | ||
101 | uint8_t number_se_send, | ||
102 | void *buf); | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Read strata from the buffer into the given strata | ||
107 | * estimator. The strata estimator must already be allocated. | ||
108 | * | ||
109 | * @param buf buffer to read from | ||
110 | * @param buf_len number of bytes in @a buf | ||
111 | * @param is_compressed is the data compressed? | ||
112 | * @param[out] se strata estimator to write to | ||
113 | * @return #GNUNET_OK on success | ||
114 | */ | ||
115 | int | ||
116 | strata_estimator_read (const void *buf, | ||
117 | size_t buf_len, | ||
118 | int is_compressed, | ||
119 | uint8_t number_se_received, | ||
120 | uint16_t se_ibf_total_size, | ||
121 | struct MultiStrataEstimator *se); | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Create a new strata estimator with the given parameters. | ||
126 | * | ||
127 | * @param strata_count number of stratas, that is, number of ibfs in the estimator | ||
128 | * @param ibf_size size of each ibf stratum | ||
129 | * @param ibf_hashnum hashnum parameter of each ibf | ||
130 | * @return a freshly allocated, empty strata estimator, NULL on error | ||
131 | */ | ||
132 | struct MultiStrataEstimator * | ||
133 | strata_estimator_create (unsigned int strata_count, | ||
134 | uint32_t ibf_size, | ||
135 | uint8_t ibf_hashnum); | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Get an estimation of the symmetric difference of the elements | ||
140 | * contained in both strata estimators. | ||
141 | * | ||
142 | * @param se1 first strata estimator | ||
143 | * @param se2 second strata estimator | ||
144 | * @return nothing | ||
145 | */ | ||
146 | void | ||
147 | strata_estimator_difference (const struct MultiStrataEstimator *se1, | ||
148 | const struct MultiStrataEstimator *se2); | ||
149 | |||
150 | |||
151 | /** | ||
152 | * Add a key to the strata estimator. | ||
153 | * | ||
154 | * @param se strata estimator to add the key to | ||
155 | * @param key key to add | ||
156 | */ | ||
157 | void | ||
158 | strata_estimator_insert (struct MultiStrataEstimator *se, | ||
159 | struct IBF_Key key); | ||
160 | |||
161 | |||
162 | /** | ||
163 | * Remove a key from the strata estimator. | ||
164 | * | ||
165 | * @param se strata estimator to remove the key from | ||
166 | * @param key key to remove | ||
167 | */ | ||
168 | void | ||
169 | strata_estimator_remove (struct MultiStrataEstimator *se, | ||
170 | struct IBF_Key key); | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Destroy a strata estimator, free all of its resources. | ||
175 | * | ||
176 | * @param se strata estimator to destroy. | ||
177 | */ | ||
178 | void | ||
179 | strata_estimator_destroy (struct MultiStrataEstimator *se); | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Make a copy of a strata estimator. | ||
184 | * | ||
185 | * @param se the strata estimator to copy | ||
186 | * @return the copy | ||
187 | */ | ||
188 | struct MultiStrataEstimator * | ||
189 | strata_estimator_dup (struct MultiStrataEstimator *se); | ||
190 | |||
191 | |||
192 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
193 | { | ||
194 | #endif | ||
195 | #ifdef __cplusplus | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | #endif | ||
diff --git a/src/setu/gnunet-setu-ibf-profiler.c b/src/setu/gnunet-setu-ibf-profiler.c deleted file mode 100644 index 6465b15b8..000000000 --- a/src/setu/gnunet-setu-ibf-profiler.c +++ /dev/null | |||
@@ -1,308 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/gnunet-set-ibf-profiler.c | ||
23 | * @brief tool for profiling the invertible bloom filter implementation | ||
24 | * @author Florian Dold | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | |||
30 | #include "ibf.h" | ||
31 | |||
32 | static unsigned int asize = 10; | ||
33 | static unsigned int bsize = 10; | ||
34 | static unsigned int csize = 10; | ||
35 | static unsigned int hash_num = 4; | ||
36 | static unsigned int ibf_size = 80; | ||
37 | |||
38 | /* FIXME: add parameter for this */ | ||
39 | static enum GNUNET_CRYPTO_Quality random_quality = GNUNET_CRYPTO_QUALITY_WEAK; | ||
40 | |||
41 | static struct GNUNET_CONTAINER_MultiHashMap *set_a; | ||
42 | static struct GNUNET_CONTAINER_MultiHashMap *set_b; | ||
43 | /* common elements in a and b */ | ||
44 | static struct GNUNET_CONTAINER_MultiHashMap *set_c; | ||
45 | |||
46 | static struct GNUNET_CONTAINER_MultiHashMap *key_to_hashcode; | ||
47 | |||
48 | static struct InvertibleBloomFilter *ibf_a; | ||
49 | static struct InvertibleBloomFilter *ibf_b; | ||
50 | |||
51 | |||
52 | static void | ||
53 | register_hashcode (struct GNUNET_HashCode *hash) | ||
54 | { | ||
55 | struct GNUNET_HashCode replicated; | ||
56 | struct IBF_Key key; | ||
57 | |||
58 | key = ibf_key_from_hashcode (hash); | ||
59 | ibf_hashcode_from_key (key, &replicated); | ||
60 | (void) GNUNET_CONTAINER_multihashmap_put ( | ||
61 | key_to_hashcode, | ||
62 | &replicated, | ||
63 | GNUNET_memdup (hash, sizeof *hash), | ||
64 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
65 | } | ||
66 | |||
67 | |||
68 | static void | ||
69 | iter_hashcodes (struct IBF_Key key, | ||
70 | GNUNET_CONTAINER_MultiHashMapIteratorCallback iter, | ||
71 | void *cls) | ||
72 | { | ||
73 | struct GNUNET_HashCode replicated; | ||
74 | |||
75 | ibf_hashcode_from_key (key, &replicated); | ||
76 | GNUNET_CONTAINER_multihashmap_get_multiple (key_to_hashcode, | ||
77 | &replicated, | ||
78 | iter, | ||
79 | cls); | ||
80 | } | ||
81 | |||
82 | |||
83 | static int | ||
84 | insert_iterator (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
85 | { | ||
86 | struct InvertibleBloomFilter *ibf = cls; | ||
87 | |||
88 | ibf_insert (ibf, ibf_key_from_hashcode (key)); | ||
89 | return GNUNET_YES; | ||
90 | } | ||
91 | |||
92 | |||
93 | static int | ||
94 | remove_iterator (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
95 | { | ||
96 | struct GNUNET_CONTAINER_MultiHashMap *hashmap = cls; | ||
97 | |||
98 | /* if remove fails, there just was a collision with another key */ | ||
99 | (void) GNUNET_CONTAINER_multihashmap_remove (hashmap, value, NULL); | ||
100 | return GNUNET_YES; | ||
101 | } | ||
102 | |||
103 | |||
104 | static void | ||
105 | run (void *cls, | ||
106 | char *const *args, | ||
107 | const char *cfgfile, | ||
108 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
109 | { | ||
110 | struct GNUNET_HashCode id; | ||
111 | struct IBF_Key ibf_key; | ||
112 | int i; | ||
113 | int side; | ||
114 | int res; | ||
115 | struct GNUNET_TIME_Absolute start_time; | ||
116 | struct GNUNET_TIME_Relative delta_time; | ||
117 | |||
118 | set_a = | ||
119 | GNUNET_CONTAINER_multihashmap_create (((asize == 0) ? 1 : (asize + csize)), | ||
120 | GNUNET_NO); | ||
121 | set_b = | ||
122 | GNUNET_CONTAINER_multihashmap_create (((bsize == 0) ? 1 : (bsize + csize)), | ||
123 | GNUNET_NO); | ||
124 | set_c = GNUNET_CONTAINER_multihashmap_create (((csize == 0) ? 1 : csize), | ||
125 | GNUNET_NO); | ||
126 | |||
127 | key_to_hashcode = | ||
128 | GNUNET_CONTAINER_multihashmap_create (((asize + bsize + csize == 0) | ||
129 | ? 1 | ||
130 | : (asize + bsize + csize)), | ||
131 | GNUNET_NO); | ||
132 | |||
133 | printf ("hash-num=%u, size=%u, #(A-B)=%u, #(B-A)=%u, #(A&B)=%u\n", | ||
134 | hash_num, | ||
135 | ibf_size, | ||
136 | asize, | ||
137 | bsize, | ||
138 | csize); | ||
139 | |||
140 | i = 0; | ||
141 | while (i < asize) | ||
142 | { | ||
143 | GNUNET_CRYPTO_hash_create_random (random_quality, &id); | ||
144 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id)) | ||
145 | continue; | ||
146 | GNUNET_break (GNUNET_OK == | ||
147 | GNUNET_CONTAINER_multihashmap_put ( | ||
148 | set_a, | ||
149 | &id, | ||
150 | NULL, | ||
151 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
152 | register_hashcode (&id); | ||
153 | i++; | ||
154 | } | ||
155 | i = 0; | ||
156 | while (i < bsize) | ||
157 | { | ||
158 | GNUNET_CRYPTO_hash_create_random (random_quality, &id); | ||
159 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id)) | ||
160 | continue; | ||
161 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id)) | ||
162 | continue; | ||
163 | GNUNET_break (GNUNET_OK == | ||
164 | GNUNET_CONTAINER_multihashmap_put ( | ||
165 | set_b, | ||
166 | &id, | ||
167 | NULL, | ||
168 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
169 | register_hashcode (&id); | ||
170 | i++; | ||
171 | } | ||
172 | i = 0; | ||
173 | while (i < csize) | ||
174 | { | ||
175 | GNUNET_CRYPTO_hash_create_random (random_quality, &id); | ||
176 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id)) | ||
177 | continue; | ||
178 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id)) | ||
179 | continue; | ||
180 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_c, &id)) | ||
181 | continue; | ||
182 | GNUNET_break (GNUNET_OK == | ||
183 | GNUNET_CONTAINER_multihashmap_put ( | ||
184 | set_c, | ||
185 | &id, | ||
186 | NULL, | ||
187 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
188 | register_hashcode (&id); | ||
189 | i++; | ||
190 | } | ||
191 | |||
192 | ibf_a = ibf_create (ibf_size, hash_num); | ||
193 | ibf_b = ibf_create (ibf_size, hash_num); | ||
194 | if ((NULL == ibf_a) || (NULL == ibf_b)) | ||
195 | { | ||
196 | /* insufficient memory */ | ||
197 | GNUNET_break (0); | ||
198 | GNUNET_SCHEDULER_shutdown (); | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | |||
203 | printf ("generated sets\n"); | ||
204 | |||
205 | start_time = GNUNET_TIME_absolute_get (); | ||
206 | |||
207 | GNUNET_CONTAINER_multihashmap_iterate (set_a, &insert_iterator, ibf_a); | ||
208 | GNUNET_CONTAINER_multihashmap_iterate (set_b, &insert_iterator, ibf_b); | ||
209 | GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_a); | ||
210 | GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_b); | ||
211 | |||
212 | delta_time = GNUNET_TIME_absolute_get_duration (start_time); | ||
213 | |||
214 | printf ("encoded in: %s\n", | ||
215 | GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO)); | ||
216 | |||
217 | ibf_subtract (ibf_a, ibf_b); | ||
218 | |||
219 | |||
220 | start_time = GNUNET_TIME_absolute_get (); | ||
221 | |||
222 | for (i = 0; i <= asize + bsize; i++) | ||
223 | { | ||
224 | res = ibf_decode (ibf_a, &side, &ibf_key); | ||
225 | if (GNUNET_SYSERR == res) | ||
226 | { | ||
227 | printf ("decode failed, %u/%u elements left\n", | ||
228 | GNUNET_CONTAINER_multihashmap_size (set_a) | ||
229 | + GNUNET_CONTAINER_multihashmap_size (set_b), | ||
230 | asize + bsize); | ||
231 | return; | ||
232 | } | ||
233 | if (GNUNET_NO == res) | ||
234 | { | ||
235 | if ((0 == GNUNET_CONTAINER_multihashmap_size (set_b)) && | ||
236 | (0 == GNUNET_CONTAINER_multihashmap_size (set_a))) | ||
237 | { | ||
238 | delta_time = GNUNET_TIME_absolute_get_duration (start_time); | ||
239 | printf ("decoded successfully in: %s\n", | ||
240 | GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO)); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | printf ("decode missed elements (should never happen)\n"); | ||
245 | } | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | if (side == 1) | ||
250 | iter_hashcodes (ibf_key, remove_iterator, set_a); | ||
251 | if (side == -1) | ||
252 | iter_hashcodes (ibf_key, remove_iterator, set_b); | ||
253 | } | ||
254 | printf ("cyclic IBF, %u/%u elements left\n", | ||
255 | GNUNET_CONTAINER_multihashmap_size (set_a) | ||
256 | + GNUNET_CONTAINER_multihashmap_size (set_b), | ||
257 | asize + bsize); | ||
258 | } | ||
259 | |||
260 | |||
261 | int | ||
262 | main (int argc, char **argv) | ||
263 | { | ||
264 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
265 | GNUNET_GETOPT_option_uint ('A', | ||
266 | "asize", | ||
267 | NULL, | ||
268 | gettext_noop ("number of element in set A-B"), | ||
269 | &asize), | ||
270 | |||
271 | GNUNET_GETOPT_option_uint ('B', | ||
272 | "bsize", | ||
273 | NULL, | ||
274 | gettext_noop ("number of element in set B-A"), | ||
275 | &bsize), | ||
276 | |||
277 | GNUNET_GETOPT_option_uint ('C', | ||
278 | "csize", | ||
279 | NULL, | ||
280 | gettext_noop ( | ||
281 | "number of common elements in A and B"), | ||
282 | &csize), | ||
283 | |||
284 | GNUNET_GETOPT_option_uint ('k', | ||
285 | "hash-num", | ||
286 | NULL, | ||
287 | gettext_noop ("hash num"), | ||
288 | &hash_num), | ||
289 | |||
290 | GNUNET_GETOPT_option_uint ('s', | ||
291 | "ibf-size", | ||
292 | NULL, | ||
293 | gettext_noop ("ibf size"), | ||
294 | &ibf_size), | ||
295 | |||
296 | GNUNET_GETOPT_OPTION_END | ||
297 | }; | ||
298 | |||
299 | GNUNET_PROGRAM_run2 (argc, | ||
300 | argv, | ||
301 | "gnunet-consensus-ibf", | ||
302 | "help", | ||
303 | options, | ||
304 | &run, | ||
305 | NULL, | ||
306 | GNUNET_YES); | ||
307 | return 0; | ||
308 | } | ||
diff --git a/src/setu/gnunet-setu-profiler.c b/src/setu/gnunet-setu-profiler.c deleted file mode 100644 index 8d6a2dc8c..000000000 --- a/src/setu/gnunet-setu-profiler.c +++ /dev/null | |||
@@ -1,499 +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 it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file setu/gnunet-setu-profiler.c | ||
23 | * @brief profiling tool for set | ||
24 | * @author Florian Dold | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_statistics_service.h" | ||
29 | #include "gnunet_setu_service.h" | ||
30 | #include "gnunet_testbed_service.h" | ||
31 | |||
32 | |||
33 | static int ret; | ||
34 | |||
35 | static unsigned int num_a = 5; | ||
36 | static unsigned int num_b = 5; | ||
37 | static unsigned int num_c = 20; | ||
38 | |||
39 | static char *op_str = "union"; | ||
40 | |||
41 | const static struct GNUNET_CONFIGURATION_Handle *config; | ||
42 | |||
43 | struct SetInfo | ||
44 | { | ||
45 | char *id; | ||
46 | struct GNUNET_SETU_Handle *set; | ||
47 | struct GNUNET_SETU_OperationHandle *oh; | ||
48 | struct GNUNET_CONTAINER_MultiHashMap *sent; | ||
49 | struct GNUNET_CONTAINER_MultiHashMap *received; | ||
50 | int done; | ||
51 | } info1, info2; | ||
52 | |||
53 | static struct GNUNET_CONTAINER_MultiHashMap *common_sent; | ||
54 | |||
55 | static struct GNUNET_HashCode app_id; | ||
56 | |||
57 | static struct GNUNET_PeerIdentity local_peer; | ||
58 | |||
59 | static struct GNUNET_SETU_ListenHandle *set_listener; | ||
60 | |||
61 | static int byzantine; | ||
62 | static unsigned int force_delta; | ||
63 | static unsigned int force_full; | ||
64 | static unsigned int element_size = 32; | ||
65 | |||
66 | /** | ||
67 | * Handle to the statistics service. | ||
68 | */ | ||
69 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
70 | |||
71 | /** | ||
72 | * The profiler will write statistics | ||
73 | * for all peers to the file with this name. | ||
74 | */ | ||
75 | static char *statistics_filename; | ||
76 | |||
77 | /** | ||
78 | * The profiler will write statistics | ||
79 | * for all peers to this file. | ||
80 | */ | ||
81 | static FILE *statistics_file; | ||
82 | |||
83 | |||
84 | static int | ||
85 | map_remove_iterator (void *cls, | ||
86 | const struct GNUNET_HashCode *key, | ||
87 | void *value) | ||
88 | { | ||
89 | struct GNUNET_CONTAINER_MultiHashMap *m = cls; | ||
90 | int ret; | ||
91 | |||
92 | GNUNET_assert (NULL != key); | ||
93 | |||
94 | ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key); | ||
95 | if (GNUNET_OK != ret) | ||
96 | printf ("spurious element\n"); | ||
97 | return GNUNET_YES; | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Callback function to process statistic values. | ||
103 | * | ||
104 | * @param cls closure | ||
105 | * @param subsystem name of subsystem that created the statistic | ||
106 | * @param name the name of the datum | ||
107 | * @param value the current value | ||
108 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not | ||
109 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | ||
110 | */ | ||
111 | static int | ||
112 | statistics_result (void *cls, | ||
113 | const char *subsystem, | ||
114 | const char *name, | ||
115 | uint64_t value, | ||
116 | int is_persistent) | ||
117 | { | ||
118 | if (NULL != statistics_file) | ||
119 | { | ||
120 | fprintf (statistics_file, "%s\t%s\t%lu\n", subsystem, name, (unsigned | ||
121 | long) value); | ||
122 | } | ||
123 | return GNUNET_OK; | ||
124 | } | ||
125 | |||
126 | |||
127 | static void | ||
128 | statistics_done (void *cls, | ||
129 | int success) | ||
130 | { | ||
131 | GNUNET_assert (GNUNET_YES == success); | ||
132 | if (NULL != statistics_file) | ||
133 | fclose (statistics_file); | ||
134 | GNUNET_SCHEDULER_shutdown (); | ||
135 | } | ||
136 | |||
137 | |||
138 | static void | ||
139 | check_all_done (void) | ||
140 | { | ||
141 | if ((info1.done == GNUNET_NO) || (info2.done == GNUNET_NO)) | ||
142 | return; | ||
143 | |||
144 | GNUNET_CONTAINER_multihashmap_iterate (info1.received, map_remove_iterator, | ||
145 | info2.sent); | ||
146 | GNUNET_CONTAINER_multihashmap_iterate (info2.received, map_remove_iterator, | ||
147 | info1.sent); | ||
148 | |||
149 | printf ("set a: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size ( | ||
150 | info1.sent)); | ||
151 | printf ("set b: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size ( | ||
152 | info2.sent)); | ||
153 | |||
154 | if (NULL == statistics_filename) | ||
155 | { | ||
156 | GNUNET_SCHEDULER_shutdown (); | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | statistics_file = fopen (statistics_filename, "w"); | ||
161 | GNUNET_STATISTICS_get (statistics, NULL, NULL, | ||
162 | &statistics_done, | ||
163 | &statistics_result, NULL); | ||
164 | } | ||
165 | |||
166 | |||
167 | static void | ||
168 | set_result_cb (void *cls, | ||
169 | const struct GNUNET_SETU_Element *element, | ||
170 | uint64_t current_size, | ||
171 | enum GNUNET_SETU_Status status) | ||
172 | { | ||
173 | struct SetInfo *info = cls; | ||
174 | |||
175 | GNUNET_assert (GNUNET_NO == info->done); | ||
176 | switch (status) | ||
177 | { | ||
178 | case GNUNET_SETU_STATUS_DONE: | ||
179 | info->done = GNUNET_YES; | ||
180 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s done\n", info->id); | ||
181 | check_all_done (); | ||
182 | info->oh = NULL; | ||
183 | return; | ||
184 | |||
185 | case GNUNET_SETU_STATUS_FAILURE: | ||
186 | info->oh = NULL; | ||
187 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failure\n"); | ||
188 | GNUNET_SCHEDULER_shutdown (); | ||
189 | return; | ||
190 | |||
191 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
192 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: local element\n", info->id); | ||
193 | break; | ||
194 | default: | ||
195 | GNUNET_assert (0); | ||
196 | } | ||
197 | |||
198 | if (element->size != element_size) | ||
199 | { | ||
200 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
201 | "wrong element size: %u, expected %u\n", | ||
202 | element->size, | ||
203 | (unsigned int) sizeof(struct GNUNET_HashCode)); | ||
204 | GNUNET_assert (0); | ||
205 | } | ||
206 | |||
207 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n", | ||
208 | info->id, GNUNET_h2s (element->data)); | ||
209 | GNUNET_assert (NULL != element->data); | ||
210 | struct GNUNET_HashCode data_hash; | ||
211 | GNUNET_CRYPTO_hash (element->data, element_size, &data_hash); | ||
212 | GNUNET_CONTAINER_multihashmap_put (info->received, | ||
213 | &data_hash, NULL, | ||
214 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
215 | } | ||
216 | |||
217 | |||
218 | static void | ||
219 | set_listen_cb (void *cls, | ||
220 | const struct GNUNET_PeerIdentity *other_peer, | ||
221 | const struct GNUNET_MessageHeader *context_msg, | ||
222 | struct GNUNET_SETU_Request *request) | ||
223 | { | ||
224 | /* max. 2 options plus terminator */ | ||
225 | struct GNUNET_SETU_Option opts[3] = { { 0 } }; | ||
226 | unsigned int n_opts = 0; | ||
227 | |||
228 | if (NULL == request) | ||
229 | { | ||
230 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
231 | "listener failed\n"); | ||
232 | return; | ||
233 | } | ||
234 | GNUNET_assert (NULL == info2.oh); | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
236 | "set listen cb called\n"); | ||
237 | if (byzantine) | ||
238 | { | ||
239 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
240 | GNUNET_SETU_OPTION_BYZANTINE }; | ||
241 | } | ||
242 | GNUNET_assert (! (force_full && force_delta)); | ||
243 | if (force_full) | ||
244 | { | ||
245 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
246 | GNUNET_SETU_OPTION_FORCE_FULL }; | ||
247 | } | ||
248 | if (force_delta) | ||
249 | { | ||
250 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
251 | GNUNET_SETU_OPTION_FORCE_DELTA }; | ||
252 | } | ||
253 | |||
254 | opts[n_opts].type = 0; | ||
255 | info2.oh = GNUNET_SETU_accept (request, | ||
256 | opts, | ||
257 | set_result_cb, &info2); | ||
258 | GNUNET_SETU_commit (info2.oh, info2.set); | ||
259 | } | ||
260 | |||
261 | |||
262 | static int | ||
263 | set_insert_iterator (void *cls, | ||
264 | const struct GNUNET_HashCode *key, | ||
265 | void *value) | ||
266 | { | ||
267 | struct GNUNET_SETU_Handle *set = cls; | ||
268 | struct GNUNET_SETU_Element el; | ||
269 | |||
270 | el.element_type = 0; | ||
271 | el.data = value; | ||
272 | el.size = element_size; | ||
273 | GNUNET_SETU_add_element (set, &el, NULL, NULL); | ||
274 | return GNUNET_YES; | ||
275 | } | ||
276 | |||
277 | |||
278 | static void | ||
279 | handle_shutdown (void *cls) | ||
280 | { | ||
281 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
282 | "Shutting down set profiler\n"); | ||
283 | if (NULL != set_listener) | ||
284 | { | ||
285 | GNUNET_SETU_listen_cancel (set_listener); | ||
286 | set_listener = NULL; | ||
287 | } | ||
288 | if (NULL != info1.oh) | ||
289 | { | ||
290 | GNUNET_SETU_operation_cancel (info1.oh); | ||
291 | info1.oh = NULL; | ||
292 | } | ||
293 | if (NULL != info2.oh) | ||
294 | { | ||
295 | GNUNET_SETU_operation_cancel (info2.oh); | ||
296 | info2.oh = NULL; | ||
297 | } | ||
298 | if (NULL != info1.set) | ||
299 | { | ||
300 | GNUNET_SETU_destroy (info1.set); | ||
301 | info1.set = NULL; | ||
302 | } | ||
303 | if (NULL != info2.set) | ||
304 | { | ||
305 | GNUNET_SETU_destroy (info2.set); | ||
306 | info2.set = NULL; | ||
307 | } | ||
308 | GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); | ||
309 | } | ||
310 | |||
311 | |||
312 | static void | ||
313 | run (void *cls, | ||
314 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
315 | struct GNUNET_TESTING_Peer *peer) | ||
316 | { | ||
317 | unsigned int i; | ||
318 | struct GNUNET_HashCode hash; | ||
319 | /* max. 2 options plus terminator */ | ||
320 | struct GNUNET_SETU_Option opts[3] = { { 0 } }; | ||
321 | unsigned int n_opts = 0; | ||
322 | |||
323 | config = cfg; | ||
324 | |||
325 | GNUNET_assert (element_size > 0); | ||
326 | |||
327 | if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer)) | ||
328 | { | ||
329 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n"); | ||
330 | ret = 0; | ||
331 | return; | ||
332 | } | ||
333 | |||
334 | statistics = GNUNET_STATISTICS_create ("set-profiler", cfg); | ||
335 | |||
336 | GNUNET_SCHEDULER_add_shutdown (&handle_shutdown, NULL); | ||
337 | |||
338 | info1.id = "a"; | ||
339 | info2.id = "b"; | ||
340 | |||
341 | info1.sent = GNUNET_CONTAINER_multihashmap_create (num_a + 1, GNUNET_NO); | ||
342 | info2.sent = GNUNET_CONTAINER_multihashmap_create (num_b + 1, GNUNET_NO); | ||
343 | common_sent = GNUNET_CONTAINER_multihashmap_create (num_c + 1, GNUNET_NO); | ||
344 | |||
345 | info1.received = GNUNET_CONTAINER_multihashmap_create (num_a + 1, GNUNET_NO); | ||
346 | info2.received = GNUNET_CONTAINER_multihashmap_create (num_b + 1, GNUNET_NO); | ||
347 | |||
348 | for (i = 0; i < num_a; i++) | ||
349 | { | ||
350 | char *data = GNUNET_malloc (element_size); | ||
351 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size); | ||
352 | GNUNET_CRYPTO_hash (data, element_size, &hash); | ||
353 | GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, data, | ||
354 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
355 | } | ||
356 | |||
357 | for (i = 0; i < num_b; i++) | ||
358 | { | ||
359 | char *data = GNUNET_malloc (element_size); | ||
360 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size); | ||
361 | GNUNET_CRYPTO_hash (data, element_size, &hash); | ||
362 | GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, data, | ||
363 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
364 | } | ||
365 | |||
366 | for (i = 0; i < num_c; i++) | ||
367 | { | ||
368 | char *data = GNUNET_malloc (element_size); | ||
369 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size); | ||
370 | GNUNET_CRYPTO_hash (data, element_size, &hash); | ||
371 | GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, data, | ||
372 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
373 | } | ||
374 | |||
375 | GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &app_id); | ||
376 | |||
377 | /* FIXME: also implement intersection etc. */ | ||
378 | info1.set = GNUNET_SETU_create (config); | ||
379 | info2.set = GNUNET_SETU_create (config); | ||
380 | |||
381 | GNUNET_CONTAINER_multihashmap_iterate (info1.sent, set_insert_iterator, | ||
382 | info1.set); | ||
383 | GNUNET_CONTAINER_multihashmap_iterate (info2.sent, set_insert_iterator, | ||
384 | info2.set); | ||
385 | GNUNET_CONTAINER_multihashmap_iterate (common_sent, set_insert_iterator, | ||
386 | info1.set); | ||
387 | GNUNET_CONTAINER_multihashmap_iterate (common_sent, set_insert_iterator, | ||
388 | info2.set); | ||
389 | |||
390 | set_listener = GNUNET_SETU_listen (config, | ||
391 | &app_id, | ||
392 | &set_listen_cb, | ||
393 | NULL); | ||
394 | |||
395 | |||
396 | if (byzantine) | ||
397 | { | ||
398 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
399 | GNUNET_SETU_OPTION_BYZANTINE }; | ||
400 | } | ||
401 | GNUNET_assert (! (force_full && force_delta)); | ||
402 | if (force_full) | ||
403 | { | ||
404 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
405 | GNUNET_SETU_OPTION_FORCE_FULL }; | ||
406 | } | ||
407 | if (force_delta) | ||
408 | { | ||
409 | opts[n_opts++] = (struct GNUNET_SETU_Option) { .type = | ||
410 | GNUNET_SETU_OPTION_FORCE_DELTA }; | ||
411 | } | ||
412 | |||
413 | opts[n_opts].type = 0; | ||
414 | |||
415 | info1.oh = GNUNET_SETU_prepare (&local_peer, &app_id, NULL, | ||
416 | opts, | ||
417 | set_result_cb, &info1); | ||
418 | GNUNET_SETU_commit (info1.oh, info1.set); | ||
419 | GNUNET_SETU_destroy (info1.set); | ||
420 | info1.set = NULL; | ||
421 | } | ||
422 | |||
423 | |||
424 | static void | ||
425 | pre_run (void *cls, char *const *args, const char *cfgfile, | ||
426 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
427 | { | ||
428 | if (0 != GNUNET_TESTING_peer_run ("set-profiler", | ||
429 | cfgfile, | ||
430 | &run, NULL)) | ||
431 | ret = 2; | ||
432 | } | ||
433 | |||
434 | |||
435 | int | ||
436 | main (int argc, char **argv) | ||
437 | { | ||
438 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
439 | GNUNET_GETOPT_option_uint ('A', | ||
440 | "num-first", | ||
441 | NULL, | ||
442 | gettext_noop ("number of values"), | ||
443 | &num_a), | ||
444 | |||
445 | GNUNET_GETOPT_option_uint ('B', | ||
446 | "num-second", | ||
447 | NULL, | ||
448 | gettext_noop ("number of values"), | ||
449 | &num_b), | ||
450 | |||
451 | GNUNET_GETOPT_option_flag ('b', | ||
452 | "byzantine", | ||
453 | gettext_noop ("use byzantine mode"), | ||
454 | &byzantine), | ||
455 | |||
456 | GNUNET_GETOPT_option_uint ('f', | ||
457 | "force-full", | ||
458 | NULL, | ||
459 | gettext_noop ("force sending full set"), | ||
460 | &force_full), | ||
461 | |||
462 | GNUNET_GETOPT_option_uint ('d', | ||
463 | "force-delta", | ||
464 | NULL, | ||
465 | gettext_noop ("number delta operation"), | ||
466 | &force_delta), | ||
467 | |||
468 | GNUNET_GETOPT_option_uint ('C', | ||
469 | "num-common", | ||
470 | NULL, | ||
471 | gettext_noop ("number of values"), | ||
472 | &num_c), | ||
473 | |||
474 | GNUNET_GETOPT_option_string ('x', | ||
475 | "operation", | ||
476 | NULL, | ||
477 | gettext_noop ("operation to execute"), | ||
478 | &op_str), | ||
479 | |||
480 | GNUNET_GETOPT_option_uint ('w', | ||
481 | "element-size", | ||
482 | NULL, | ||
483 | gettext_noop ("element size"), | ||
484 | &element_size), | ||
485 | |||
486 | GNUNET_GETOPT_option_filename ('s', | ||
487 | "statistics", | ||
488 | "FILENAME", | ||
489 | gettext_noop ("write statistics to file"), | ||
490 | &statistics_filename), | ||
491 | |||
492 | GNUNET_GETOPT_OPTION_END | ||
493 | }; | ||
494 | |||
495 | GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler", | ||
496 | "help", | ||
497 | options, &pre_run, NULL, GNUNET_YES); | ||
498 | return ret; | ||
499 | } | ||
diff --git a/src/setu/ibf.c b/src/setu/ibf.c deleted file mode 100644 index a55e21764..000000000 --- a/src/setu/ibf.c +++ /dev/null | |||
@@ -1,585 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/ibf.c | ||
23 | * @brief implementation of the invertible bloom filter | ||
24 | * @author Florian Dold | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "ibf.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #define LOG(kind, ...) GNUNET_log_from (kind, "setu", __VA_ARGS__) | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Compute the key's hash from the key. | ||
36 | * Redefine to use a different hash function. | ||
37 | */ | ||
38 | #define IBF_KEY_HASH_VAL(k) (GNUNET_CRYPTO_crc32_n (&(k), sizeof(struct \ | ||
39 | IBF_KeyHash))) | ||
40 | |||
41 | /** | ||
42 | * Create a key from a hashcode. | ||
43 | * | ||
44 | * @param hash the hashcode | ||
45 | * @return a key | ||
46 | */ | ||
47 | struct IBF_Key | ||
48 | ibf_key_from_hashcode (const struct GNUNET_HashCode *hash) | ||
49 | { | ||
50 | return *(struct IBF_Key *) hash; | ||
51 | } | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Create a hashcode from a key, by replicating the key | ||
56 | * until the hascode is filled | ||
57 | * | ||
58 | * @param key the key | ||
59 | * @param dst hashcode to store the result in | ||
60 | */ | ||
61 | void | ||
62 | ibf_hashcode_from_key (struct IBF_Key key, | ||
63 | struct GNUNET_HashCode *dst) | ||
64 | { | ||
65 | struct IBF_Key *p; | ||
66 | unsigned int i; | ||
67 | const unsigned int keys_per_hashcode = sizeof(struct GNUNET_HashCode) | ||
68 | / sizeof(struct IBF_Key); | ||
69 | |||
70 | p = (struct IBF_Key *) dst; | ||
71 | for (i = 0; i < keys_per_hashcode; i++) | ||
72 | *p++ = key; | ||
73 | } | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Create an invertible bloom filter. | ||
78 | * | ||
79 | * @param size number of IBF buckets | ||
80 | * @param hash_num number of buckets one element is hashed in | ||
81 | * @return the newly created invertible bloom filter, NULL on error | ||
82 | */ | ||
83 | struct InvertibleBloomFilter * | ||
84 | ibf_create (uint32_t size, uint8_t hash_num) | ||
85 | { | ||
86 | struct InvertibleBloomFilter *ibf; | ||
87 | |||
88 | GNUNET_assert (0 != size); | ||
89 | |||
90 | ibf = GNUNET_new (struct InvertibleBloomFilter); | ||
91 | ibf->count = GNUNET_malloc_large (size * sizeof(uint64_t)); | ||
92 | if (NULL == ibf->count) | ||
93 | { | ||
94 | GNUNET_free (ibf); | ||
95 | return NULL; | ||
96 | } | ||
97 | ibf->key_sum = GNUNET_malloc_large (size * sizeof(struct IBF_Key)); | ||
98 | if (NULL == ibf->key_sum) | ||
99 | { | ||
100 | GNUNET_free (ibf->count); | ||
101 | GNUNET_free (ibf); | ||
102 | return NULL; | ||
103 | } | ||
104 | ibf->key_hash_sum = GNUNET_malloc_large (size * sizeof(struct IBF_KeyHash)); | ||
105 | if (NULL == ibf->key_hash_sum) | ||
106 | { | ||
107 | GNUNET_free (ibf->key_sum); | ||
108 | GNUNET_free (ibf->count); | ||
109 | GNUNET_free (ibf); | ||
110 | return NULL; | ||
111 | } | ||
112 | ibf->size = size; | ||
113 | ibf->hash_num = hash_num; | ||
114 | |||
115 | return ibf; | ||
116 | } | ||
117 | |||
118 | |||
119 | /** | ||
120 | * Store unique bucket indices for the specified @a key in @a dst. | ||
121 | */ | ||
122 | static void | ||
123 | ibf_get_indices (const struct InvertibleBloomFilter *ibf, | ||
124 | struct IBF_Key key, | ||
125 | int *dst) | ||
126 | { | ||
127 | uint32_t filled; | ||
128 | uint32_t i; | ||
129 | uint32_t bucket; | ||
130 | |||
131 | bucket = GNUNET_CRYPTO_crc32_n (&key, sizeof key); | ||
132 | for (i = 0, filled = 0; filled < ibf->hash_num; i++) | ||
133 | { | ||
134 | uint64_t x; | ||
135 | |||
136 | for (unsigned int j = 0; j < filled; j++) | ||
137 | if (dst[j] == bucket % ibf->size) | ||
138 | goto try_next; | ||
139 | dst[filled++] = bucket % ibf->size; | ||
140 | try_next: | ||
141 | x = ((uint64_t) bucket << 32) | i; | ||
142 | bucket = GNUNET_CRYPTO_crc32_n (&x, sizeof x); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | |||
147 | static void | ||
148 | ibf_insert_into (struct InvertibleBloomFilter *ibf, | ||
149 | struct IBF_Key key, | ||
150 | const int *buckets, | ||
151 | int side) | ||
152 | { | ||
153 | for (unsigned int i = 0; i < ibf->hash_num; i++) | ||
154 | { | ||
155 | const int bucket = buckets[i]; | ||
156 | |||
157 | ibf->count[bucket].count_val += side; | ||
158 | ibf->key_sum[bucket].key_val ^= key.key_val; | ||
159 | ibf->key_hash_sum[bucket].key_hash_val | ||
160 | ^= IBF_KEY_HASH_VAL (key); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | /** | ||
166 | * Insert a key into an IBF. | ||
167 | * | ||
168 | * @param ibf the IBF | ||
169 | * @param key the element's hash code | ||
170 | */ | ||
171 | void | ||
172 | ibf_insert (struct InvertibleBloomFilter *ibf, | ||
173 | struct IBF_Key key) | ||
174 | { | ||
175 | int buckets[ibf->hash_num]; | ||
176 | |||
177 | GNUNET_assert (ibf->hash_num <= ibf->size); | ||
178 | ibf_get_indices (ibf, key, buckets); | ||
179 | ibf_insert_into (ibf, key, buckets, 1); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Remove a key from an IBF. | ||
185 | * | ||
186 | * @param ibf the IBF | ||
187 | * @param key the element's hash code | ||
188 | */ | ||
189 | void | ||
190 | ibf_remove (struct InvertibleBloomFilter *ibf, | ||
191 | struct IBF_Key key) | ||
192 | { | ||
193 | int buckets[ibf->hash_num]; | ||
194 | |||
195 | GNUNET_assert (ibf->hash_num <= ibf->size); | ||
196 | ibf_get_indices (ibf, key, buckets); | ||
197 | ibf_insert_into (ibf, key, buckets, -1); | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Test is the IBF is empty, i.e. all counts, keys and key hashes are zero. | ||
203 | */ | ||
204 | static int | ||
205 | ibf_is_empty (struct InvertibleBloomFilter *ibf) | ||
206 | { | ||
207 | for (uint32_t i = 0; i < ibf->size; i++) | ||
208 | { | ||
209 | if (0 != ibf->count[i].count_val) | ||
210 | return GNUNET_NO; | ||
211 | if (0 != ibf->key_hash_sum[i].key_hash_val) | ||
212 | return GNUNET_NO; | ||
213 | if (0 != ibf->key_sum[i].key_val) | ||
214 | return GNUNET_NO; | ||
215 | } | ||
216 | return GNUNET_YES; | ||
217 | } | ||
218 | |||
219 | |||
220 | int | ||
221 | ibf_decode (struct InvertibleBloomFilter *ibf, | ||
222 | int *ret_side, | ||
223 | struct IBF_Key *ret_id) | ||
224 | { | ||
225 | struct IBF_KeyHash hash; | ||
226 | int buckets[ibf->hash_num]; | ||
227 | |||
228 | for (uint32_t i = 0; i < ibf->size; i++) | ||
229 | { | ||
230 | int hit; | ||
231 | |||
232 | /* we can only decode from pure buckets */ | ||
233 | if ( (1 != ibf->count[i].count_val) && | ||
234 | (-1 != ibf->count[i].count_val) ) | ||
235 | continue; | ||
236 | |||
237 | hash.key_hash_val = IBF_KEY_HASH_VAL (ibf->key_sum[i]); | ||
238 | |||
239 | /* test if the hash matches the key */ | ||
240 | if (hash.key_hash_val != ibf->key_hash_sum[i].key_hash_val) | ||
241 | continue; | ||
242 | |||
243 | /* test if key in bucket hits its own location, | ||
244 | * if not, the key hash was subject to collision */ | ||
245 | hit = GNUNET_NO; | ||
246 | ibf_get_indices (ibf, ibf->key_sum[i], buckets); | ||
247 | for (int j = 0; j < ibf->hash_num; j++) | ||
248 | if (buckets[j] == i) | ||
249 | hit = GNUNET_YES; | ||
250 | |||
251 | if (GNUNET_NO == hit) | ||
252 | continue; | ||
253 | |||
254 | if (1 == ibf->count[i].count_val) | ||
255 | { | ||
256 | ibf->remote_decoded_count++; | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | ibf->local_decoded_count++; | ||
261 | } | ||
262 | |||
263 | |||
264 | if (NULL != ret_side) | ||
265 | *ret_side = ibf->count[i].count_val; | ||
266 | if (NULL != ret_id) | ||
267 | *ret_id = ibf->key_sum[i]; | ||
268 | |||
269 | /* insert on the opposite side, effectively removing the element */ | ||
270 | ibf_insert_into (ibf, ibf->key_sum[i], buckets, -ibf->count[i].count_val); | ||
271 | |||
272 | return GNUNET_YES; | ||
273 | } | ||
274 | |||
275 | if (GNUNET_YES == ibf_is_empty (ibf)) | ||
276 | return GNUNET_NO; | ||
277 | return GNUNET_SYSERR; | ||
278 | } | ||
279 | |||
280 | |||
281 | /** | ||
282 | * Returns the minimal bytes needed to store the counter of the IBF | ||
283 | * | ||
284 | * @param ibf the IBF | ||
285 | */ | ||
286 | uint8_t | ||
287 | ibf_get_max_counter (struct InvertibleBloomFilter *ibf) | ||
288 | { | ||
289 | long long max_counter = 0; | ||
290 | for (uint64_t i = 0; i < ibf->size; i++) | ||
291 | { | ||
292 | if (ibf->count[i].count_val > max_counter) | ||
293 | { | ||
294 | max_counter = ibf->count[i].count_val; | ||
295 | } | ||
296 | } | ||
297 | return 64 - __builtin_clzll (max_counter); | ||
298 | } | ||
299 | |||
300 | |||
301 | /** | ||
302 | * Write buckets from an ibf to a buffer. | ||
303 | * Exactly (IBF_BUCKET_SIZE*ibf->size) bytes are written to buf. | ||
304 | * | ||
305 | * @param ibf the ibf to write | ||
306 | * @param start with which bucket to start | ||
307 | * @param count how many buckets to write | ||
308 | * @param buf buffer to write the data to | ||
309 | * @param max bit length of a counter for unpacking | ||
310 | */ | ||
311 | void | ||
312 | ibf_write_slice (const struct InvertibleBloomFilter *ibf, | ||
313 | uint32_t start, | ||
314 | uint64_t count, | ||
315 | void *buf, | ||
316 | uint8_t counter_max_length) | ||
317 | { | ||
318 | struct IBF_Key *key_dst; | ||
319 | struct IBF_KeyHash *key_hash_dst; | ||
320 | |||
321 | GNUNET_assert (start + count <= ibf->size); | ||
322 | |||
323 | /* copy keys */ | ||
324 | key_dst = (struct IBF_Key *) buf; | ||
325 | GNUNET_memcpy (key_dst, | ||
326 | ibf->key_sum + start, | ||
327 | count * sizeof(*key_dst)); | ||
328 | key_dst += count; | ||
329 | /* copy key hashes */ | ||
330 | key_hash_dst = (struct IBF_KeyHash *) key_dst; | ||
331 | GNUNET_memcpy (key_hash_dst, | ||
332 | ibf->key_hash_sum + start, | ||
333 | count * sizeof(*key_hash_dst)); | ||
334 | key_hash_dst += count; | ||
335 | |||
336 | /* pack and copy counter */ | ||
337 | pack_counter (ibf, | ||
338 | start, | ||
339 | count, | ||
340 | (uint8_t *) key_hash_dst, | ||
341 | counter_max_length); | ||
342 | |||
343 | |||
344 | } | ||
345 | |||
346 | |||
347 | |||
348 | void | ||
349 | pack_counter (const struct InvertibleBloomFilter *ibf, | ||
350 | uint32_t start, | ||
351 | uint64_t count, | ||
352 | uint8_t *buf, | ||
353 | uint8_t counter_max_length) | ||
354 | { | ||
355 | uint8_t store_size = 0; | ||
356 | uint8_t store = 0; | ||
357 | uint16_t byte_ctr = 0; | ||
358 | |||
359 | /** | ||
360 | * Iterate over IBF bucket | ||
361 | */ | ||
362 | for (uint64_t i = start; i< (count + start);) | ||
363 | { | ||
364 | uint64_t count_val_to_write = ibf->count[i].count_val; | ||
365 | uint8_t count_len_to_write = counter_max_length; | ||
366 | |||
367 | /** | ||
368 | * Pack and compose counters to byte values | ||
369 | */ | ||
370 | while ((count_len_to_write + store_size) >= 8) | ||
371 | { | ||
372 | uint8_t bit_shift = 0; | ||
373 | |||
374 | /** | ||
375 | * Shift bits if more than a byte has to be written | ||
376 | * or the store size is not empty | ||
377 | */ | ||
378 | if ((store_size > 0) || (count_len_to_write > 8)) | ||
379 | { | ||
380 | uint8_t bit_unused = 8 - store_size; | ||
381 | bit_shift = count_len_to_write - bit_unused; | ||
382 | store = store << bit_unused; | ||
383 | } | ||
384 | |||
385 | buf[byte_ctr] = ((count_val_to_write >> bit_shift) | store) & 0xFF; | ||
386 | byte_ctr++; | ||
387 | count_len_to_write -= (8 - store_size); | ||
388 | count_val_to_write = count_val_to_write & ((1ULL << | ||
389 | count_len_to_write) - 1); | ||
390 | store = 0; | ||
391 | store_size = 0; | ||
392 | } | ||
393 | store = (store << count_len_to_write) | count_val_to_write; | ||
394 | store_size = store_size + count_len_to_write; | ||
395 | count_len_to_write = 0; | ||
396 | i++; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * Pack data left in story before finishing | ||
401 | */ | ||
402 | if (store_size > 0) | ||
403 | { | ||
404 | buf[byte_ctr] = store << (8 - store_size); | ||
405 | byte_ctr++; | ||
406 | } | ||
407 | |||
408 | } | ||
409 | |||
410 | |||
411 | |||
412 | void | ||
413 | unpack_counter (const struct InvertibleBloomFilter *ibf, | ||
414 | uint32_t start, | ||
415 | uint64_t count, | ||
416 | uint8_t *buf, | ||
417 | uint8_t counter_max_length) | ||
418 | { | ||
419 | uint64_t ibf_counter_ctr = 0; | ||
420 | uint64_t store = 0; | ||
421 | uint64_t store_bit_ctr = 0; | ||
422 | uint64_t byte_ctr = 0; | ||
423 | |||
424 | /** | ||
425 | * Iterate over received bytes | ||
426 | */ | ||
427 | while (true) | ||
428 | { | ||
429 | uint8_t byte_read = buf[byte_ctr]; | ||
430 | uint8_t bit_to_read_left = 8; | ||
431 | byte_ctr++; | ||
432 | |||
433 | /** | ||
434 | * Pack data left in story before finishing | ||
435 | */ | ||
436 | while (true) | ||
437 | { | ||
438 | /** | ||
439 | * Stop decoding when end is reached | ||
440 | */ | ||
441 | if (ibf_counter_ctr > (count - 1)) | ||
442 | return; | ||
443 | |||
444 | /* | ||
445 | * Unpack the counter | ||
446 | */ | ||
447 | if ((store_bit_ctr + bit_to_read_left) >= counter_max_length) | ||
448 | { | ||
449 | uint8_t bytes_used = counter_max_length - store_bit_ctr; | ||
450 | if (store_bit_ctr > 0) | ||
451 | { | ||
452 | store = store << bytes_used; | ||
453 | } | ||
454 | |||
455 | uint8_t bytes_to_shift = bit_to_read_left - bytes_used; | ||
456 | uint64_t counter_part = byte_read >> bytes_to_shift; | ||
457 | store = store | counter_part; | ||
458 | ibf->count[ibf_counter_ctr + start].count_val = store; | ||
459 | byte_read = byte_read & ((1 << bytes_to_shift) - 1); | ||
460 | bit_to_read_left -= bytes_used; | ||
461 | ibf_counter_ctr++; | ||
462 | store = 0; | ||
463 | store_bit_ctr = 0; | ||
464 | } | ||
465 | else | ||
466 | { | ||
467 | store_bit_ctr += bit_to_read_left; | ||
468 | if (0 == store) | ||
469 | { | ||
470 | store = byte_read; | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | store = store << bit_to_read_left; | ||
475 | store = store | byte_read; | ||
476 | } | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | |||
483 | |||
484 | /** | ||
485 | * Read buckets from a buffer into an ibf. | ||
486 | * | ||
487 | * @param buf pointer to the buffer to read from | ||
488 | * @param start which bucket to start at | ||
489 | * @param count how many buckets to read | ||
490 | * @param ibf the ibf to read from | ||
491 | * @param max bit length of a counter for unpacking | ||
492 | */ | ||
493 | void | ||
494 | ibf_read_slice (const void *buf, | ||
495 | uint32_t start, | ||
496 | uint64_t count, | ||
497 | struct InvertibleBloomFilter *ibf, | ||
498 | uint8_t counter_max_length) | ||
499 | { | ||
500 | struct IBF_Key *key_src; | ||
501 | struct IBF_KeyHash *key_hash_src; | ||
502 | struct IBF_Count *count_src; | ||
503 | |||
504 | GNUNET_assert (count > 0); | ||
505 | GNUNET_assert (start + count <= ibf->size); | ||
506 | |||
507 | /* copy keys */ | ||
508 | key_src = (struct IBF_Key *) buf; | ||
509 | GNUNET_memcpy (ibf->key_sum + start, | ||
510 | key_src, | ||
511 | count * sizeof *key_src); | ||
512 | key_src += count; | ||
513 | /* copy key hashes */ | ||
514 | key_hash_src = (struct IBF_KeyHash *) key_src; | ||
515 | GNUNET_memcpy (ibf->key_hash_sum + start, | ||
516 | key_hash_src, | ||
517 | count * sizeof *key_hash_src); | ||
518 | key_hash_src += count; | ||
519 | |||
520 | /* copy and unpack counts */ | ||
521 | count_src = (struct IBF_Count *) key_hash_src; | ||
522 | unpack_counter (ibf,start,count,(uint8_t *) count_src,counter_max_length); | ||
523 | } | ||
524 | |||
525 | |||
526 | /** | ||
527 | * Subtract ibf2 from ibf1, storing the result in ibf1. | ||
528 | * The two IBF's must have the same parameters size and hash_num. | ||
529 | * | ||
530 | * @param ibf1 IBF that is subtracted from | ||
531 | * @param ibf2 IBF that will be subtracted from ibf1 | ||
532 | */ | ||
533 | void | ||
534 | ibf_subtract (struct InvertibleBloomFilter *ibf1, | ||
535 | const struct InvertibleBloomFilter *ibf2) | ||
536 | { | ||
537 | GNUNET_assert (ibf1->size == ibf2->size); | ||
538 | GNUNET_assert (ibf1->hash_num == ibf2->hash_num); | ||
539 | |||
540 | for (uint32_t i = 0; i < ibf1->size; i++) | ||
541 | { | ||
542 | ibf1->count[i].count_val -= ibf2->count[i].count_val; | ||
543 | ibf1->key_hash_sum[i].key_hash_val ^= ibf2->key_hash_sum[i].key_hash_val; | ||
544 | ibf1->key_sum[i].key_val ^= ibf2->key_sum[i].key_val; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * Create a copy of an IBF, the copy has to be destroyed properly. | ||
551 | * | ||
552 | * @param ibf the IBF to copy | ||
553 | */ | ||
554 | struct InvertibleBloomFilter * | ||
555 | ibf_dup (const struct InvertibleBloomFilter *ibf) | ||
556 | { | ||
557 | struct InvertibleBloomFilter *copy; | ||
558 | |||
559 | copy = GNUNET_malloc (sizeof *copy); | ||
560 | copy->hash_num = ibf->hash_num; | ||
561 | copy->size = ibf->size; | ||
562 | copy->key_hash_sum = GNUNET_memdup (ibf->key_hash_sum, | ||
563 | ibf->size * sizeof(struct IBF_KeyHash)); | ||
564 | copy->key_sum = GNUNET_memdup (ibf->key_sum, | ||
565 | ibf->size * sizeof(struct IBF_Key)); | ||
566 | copy->count = GNUNET_memdup (ibf->count, | ||
567 | ibf->size * sizeof(struct IBF_Count)); | ||
568 | return copy; | ||
569 | } | ||
570 | |||
571 | |||
572 | /** | ||
573 | * Destroy all resources associated with the invertible bloom filter. | ||
574 | * No more ibf_*-functions may be called on ibf after calling destroy. | ||
575 | * | ||
576 | * @param ibf the intertible bloom filter to destroy | ||
577 | */ | ||
578 | void | ||
579 | ibf_destroy (struct InvertibleBloomFilter *ibf) | ||
580 | { | ||
581 | GNUNET_free (ibf->key_sum); | ||
582 | GNUNET_free (ibf->key_hash_sum); | ||
583 | GNUNET_free (ibf->count); | ||
584 | GNUNET_free (ibf); | ||
585 | } | ||
diff --git a/src/setu/ibf.h b/src/setu/ibf.h deleted file mode 100644 index 5628405dc..000000000 --- a/src/setu/ibf.h +++ /dev/null | |||
@@ -1,310 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/ibf.h | ||
23 | * @brief invertible bloom filter | ||
24 | * @author Florian Dold | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | |||
28 | #ifndef GNUNET_CONSENSUS_IBF_H | ||
29 | #define GNUNET_CONSENSUS_IBF_H | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | |||
34 | #ifdef __cplusplus | ||
35 | extern "C" | ||
36 | { | ||
37 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
38 | } | ||
39 | #endif | ||
40 | #endif | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Keys that can be inserted into and removed from an IBF. | ||
45 | */ | ||
46 | struct IBF_Key | ||
47 | { | ||
48 | uint64_t key_val; | ||
49 | }; | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Hash of an IBF key. | ||
54 | */ | ||
55 | struct IBF_KeyHash | ||
56 | { | ||
57 | uint32_t key_hash_val; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Type of the count field of IBF buckets. | ||
63 | */ | ||
64 | struct IBF_Count | ||
65 | { | ||
66 | int64_t count_val; | ||
67 | }; | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Size of one ibf bucket in bytes | ||
72 | */ | ||
73 | #define IBF_BUCKET_SIZE (sizeof(struct IBF_Count) + sizeof(struct IBF_Key) \ | ||
74 | + sizeof(struct IBF_KeyHash)) | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Invertible bloom filter (IBF). | ||
79 | * | ||
80 | * An IBF is a counting bloom filter that has the ability to restore | ||
81 | * the hashes of its stored elements with high probability. | ||
82 | */ | ||
83 | struct InvertibleBloomFilter | ||
84 | { | ||
85 | /** | ||
86 | * How many cells does this IBF have? | ||
87 | */ | ||
88 | uint32_t size; | ||
89 | |||
90 | /** | ||
91 | * In how many cells do we hash one element? | ||
92 | * Usually 4 or 3. | ||
93 | */ | ||
94 | uint8_t hash_num; | ||
95 | |||
96 | /** | ||
97 | * If an IBF is decoded this count stores how many | ||
98 | * elements are on the local site. This is used | ||
99 | * to estimate the set difference on a site | ||
100 | */ | ||
101 | int local_decoded_count; | ||
102 | |||
103 | /** | ||
104 | * If an IBF is decoded this count stores how many | ||
105 | * elements are on the remote site. This is used | ||
106 | * to estimate the set difference on a site | ||
107 | */ | ||
108 | int remote_decoded_count; | ||
109 | |||
110 | /** | ||
111 | * Xor sums of the elements' keys, used to identify the elements. | ||
112 | * Array of 'size' elements. | ||
113 | */ | ||
114 | struct IBF_Key *key_sum; | ||
115 | |||
116 | /** | ||
117 | * Xor sums of the hashes of the keys of inserted elements. | ||
118 | * Array of 'size' elements. | ||
119 | */ | ||
120 | struct IBF_KeyHash *key_hash_sum; | ||
121 | |||
122 | /** | ||
123 | * How many times has a bucket been hit? | ||
124 | * Can be negative, as a result of IBF subtraction. | ||
125 | * Array of 'size' elements. | ||
126 | */ | ||
127 | struct IBF_Count *count; | ||
128 | }; | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Write buckets from an ibf to a buffer. | ||
133 | * Exactly (IBF_BUCKET_SIZE*ibf->size) bytes are written to buf. | ||
134 | * | ||
135 | * @param ibf the ibf to write | ||
136 | * @param start with which bucket to start | ||
137 | * @param count how many buckets to write | ||
138 | * @param buf buffer to write the data to | ||
139 | */ | ||
140 | void | ||
141 | ibf_write_slice (const struct InvertibleBloomFilter *ibf, | ||
142 | uint32_t start, | ||
143 | uint64_t count, | ||
144 | void *buf, | ||
145 | uint8_t counter_max_length); | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Read buckets from a buffer into an ibf. | ||
150 | * | ||
151 | * @param buf pointer to the buffer to read from | ||
152 | * @param start which bucket to start at | ||
153 | * @param count how many buckets to read | ||
154 | * @param ibf the ibf to write to | ||
155 | */ | ||
156 | void | ||
157 | ibf_read_slice (const void *buf, | ||
158 | uint32_t start, | ||
159 | uint64_t count, | ||
160 | struct InvertibleBloomFilter *ibf, | ||
161 | uint8_t counter_max_length); | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Create a key from a hashcode. | ||
166 | * | ||
167 | * @param hash the hashcode | ||
168 | * @return a key | ||
169 | */ | ||
170 | struct IBF_Key | ||
171 | ibf_key_from_hashcode (const struct GNUNET_HashCode *hash); | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Create a hashcode from a key, by replicating the key | ||
176 | * until the hascode is filled | ||
177 | * | ||
178 | * @param key the key | ||
179 | * @param dst hashcode to store the result in | ||
180 | */ | ||
181 | void | ||
182 | ibf_hashcode_from_key (struct IBF_Key key, struct GNUNET_HashCode *dst); | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Create an invertible bloom filter. | ||
187 | * | ||
188 | * @param size number of IBF buckets | ||
189 | * @param hash_num number of buckets one element is hashed in, usually 3 or 4 | ||
190 | * @return the newly created invertible bloom filter, NULL on error | ||
191 | */ | ||
192 | struct InvertibleBloomFilter * | ||
193 | ibf_create (uint32_t size, uint8_t hash_num); | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Insert a key into an IBF. | ||
198 | * | ||
199 | * @param ibf the IBF | ||
200 | * @param key the element's hash code | ||
201 | */ | ||
202 | void | ||
203 | ibf_insert (struct InvertibleBloomFilter *ibf, struct IBF_Key key); | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Remove a key from an IBF. | ||
208 | * | ||
209 | * @param ibf the IBF | ||
210 | * @param key the element's hash code | ||
211 | */ | ||
212 | void | ||
213 | ibf_remove (struct InvertibleBloomFilter *ibf, struct IBF_Key key); | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Subtract ibf2 from ibf1, storing the result in ibf1. | ||
218 | * The two IBF's must have the same parameters size and hash_num. | ||
219 | * | ||
220 | * @param ibf1 IBF that is subtracted from | ||
221 | * @param ibf2 IBF that will be subtracted from ibf1 | ||
222 | */ | ||
223 | void | ||
224 | ibf_subtract (struct InvertibleBloomFilter *ibf1, | ||
225 | const struct InvertibleBloomFilter *ibf2); | ||
226 | |||
227 | |||
228 | /** | ||
229 | * Decode and remove an element from the IBF, if possible. | ||
230 | * | ||
231 | * @param ibf the invertible bloom filter to decode | ||
232 | * @param ret_side sign of the cell's count where the decoded element came from. | ||
233 | * A negative sign indicates that the element was recovered | ||
234 | * resides in an IBF that was previously subtracted from. | ||
235 | * @param ret_id receives the hash code of the decoded element, if successful | ||
236 | * @return #GNUNET_YES if decoding an element was successful, | ||
237 | * #GNUNET_NO if the IBF is empty, | ||
238 | * #GNUNET_SYSERR if the decoding has failed | ||
239 | */ | ||
240 | int | ||
241 | ibf_decode (struct InvertibleBloomFilter *ibf, | ||
242 | int *ret_side, | ||
243 | struct IBF_Key *ret_id); | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Create a copy of an IBF, the copy has to be destroyed properly. | ||
248 | * | ||
249 | * @param ibf the IBF to copy | ||
250 | */ | ||
251 | struct InvertibleBloomFilter * | ||
252 | ibf_dup (const struct InvertibleBloomFilter *ibf); | ||
253 | |||
254 | |||
255 | /** | ||
256 | * Destroy all resources associated with the invertible bloom filter. | ||
257 | * No more ibf_*-functions may be called on ibf after calling destroy. | ||
258 | * | ||
259 | * @param ibf the intertible bloom filter to destroy | ||
260 | */ | ||
261 | void | ||
262 | ibf_destroy (struct InvertibleBloomFilter *ibf); | ||
263 | |||
264 | uint8_t | ||
265 | ibf_get_max_counter (struct InvertibleBloomFilter *ibf); | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Packs the counter to transmit only the smallest possible amount of bytes and | ||
270 | * preventing overflow of the counter | ||
271 | * @param ibf the ibf to write | ||
272 | * @param start with which bucket to start | ||
273 | * @param count how many buckets to write | ||
274 | * @param buf buffer to write the data to | ||
275 | * @param max bit length of a counter for unpacking | ||
276 | */ | ||
277 | |||
278 | void | ||
279 | pack_counter (const struct InvertibleBloomFilter *ibf, | ||
280 | uint32_t start, | ||
281 | uint64_t count, | ||
282 | uint8_t *buf, | ||
283 | uint8_t counter_max_length); | ||
284 | |||
285 | /** | ||
286 | * Unpacks the counter to transmit only the smallest possible amount of bytes and | ||
287 | * preventing overflow of the counter | ||
288 | * @param ibf the ibf to write | ||
289 | * @param start with which bucket to start | ||
290 | * @param count how many buckets to write | ||
291 | * @param buf buffer to write the data to | ||
292 | * @param max bit length of a counter for unpacking | ||
293 | */ | ||
294 | |||
295 | void | ||
296 | unpack_counter (const struct InvertibleBloomFilter *ibf, | ||
297 | uint32_t start, | ||
298 | uint64_t count, | ||
299 | uint8_t *buf, | ||
300 | uint8_t counter_max_length); | ||
301 | |||
302 | |||
303 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
304 | { | ||
305 | #endif | ||
306 | #ifdef __cplusplus | ||
307 | } | ||
308 | #endif | ||
309 | |||
310 | #endif | ||
diff --git a/src/setu/ibf_sim.c b/src/setu/ibf_sim.c deleted file mode 100644 index 563ed0fb8..000000000 --- a/src/setu/ibf_sim.c +++ /dev/null | |||
@@ -1,143 +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 it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/ibf_sim.c | ||
23 | * @brief implementation of simulation for invertible bloom filter | ||
24 | * @author Florian Dold | ||
25 | * | ||
26 | * This code was used for some internal experiments, it is not | ||
27 | * build or shipped as part of the GNUnet system. | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include <stdlib.h> | ||
31 | #include <stdio.h> | ||
32 | #include <string.h> | ||
33 | |||
34 | #define MAX_IBF_DECODE 16 | ||
35 | |||
36 | /* report average over how many rounds? */ | ||
37 | #define ROUNDS 100000 | ||
38 | |||
39 | /* enable one of the three below */ | ||
40 | // simple fix | ||
41 | #define FIX1 0 | ||
42 | // possibly slightly better fix for large IBF_DECODE values | ||
43 | #define FIX2 1 | ||
44 | |||
45 | // SIGCOMM algorithm | ||
46 | #define STRATA 0 | ||
47 | |||
48 | // print each value? | ||
49 | #define VERBOSE 0 | ||
50 | // avoid assembly? (ASM is about 50% faster) | ||
51 | #define SLOW 0 | ||
52 | |||
53 | int | ||
54 | main (int argc, char **argv) | ||
55 | { | ||
56 | unsigned int round; | ||
57 | unsigned int buckets[31]; // max is 2^31 as 'random' returns only between 0 and 2^31 | ||
58 | unsigned int i; | ||
59 | int j; | ||
60 | unsigned int r; | ||
61 | unsigned int ret; | ||
62 | unsigned long long total; | ||
63 | unsigned int want; | ||
64 | double predict; | ||
65 | |||
66 | srandom (time (NULL)); | ||
67 | total = 0; | ||
68 | want = atoi (argv[1]); | ||
69 | for (round = 0; round < ROUNDS; round++) | ||
70 | { | ||
71 | memset (buckets, 0, sizeof(buckets)); | ||
72 | for (i = 0; i < want; i++) | ||
73 | { | ||
74 | /* FIXME: might want to use 'better' PRNG to avoid | ||
75 | PRNG-induced biases */ | ||
76 | r = random (); | ||
77 | if (0 == r) | ||
78 | continue; | ||
79 | #if SLOW | ||
80 | for (j = 0; (j < 31) && (0 == (r & (1 << j))); j++) | ||
81 | ; | ||
82 | #else | ||
83 | /* use assembly / gcc */ | ||
84 | j = __builtin_ffs (r) - 1; | ||
85 | #endif | ||
86 | buckets[j]++; | ||
87 | } | ||
88 | ret = 0; | ||
89 | predict = 0.0; | ||
90 | for (j = 31; j >= 0; j--) | ||
91 | { | ||
92 | #if FIX1 | ||
93 | /* improved algorithm, for 1000 elements with IBF-DECODE 8, I | ||
94 | get 990/1000 elements on average over 1 million runs; key | ||
95 | idea being to stop short of the 'last' possible IBF as | ||
96 | otherwise a "lowball" per-chance would unduely influence the | ||
97 | result */if ((j > 0) && | ||
98 | (buckets[j - 1] > MAX_IBF_DECODE)) | ||
99 | { | ||
100 | ret *= (1 << (j + 1)); | ||
101 | break; | ||
102 | } | ||
103 | #endif | ||
104 | #if FIX2 | ||
105 | /* another improvement: don't just always cut off the last one, | ||
106 | but rather try to predict based on all previous values where | ||
107 | that "last" one is; additional prediction can only really | ||
108 | work if MAX_IBF_DECODE is sufficiently high */ | ||
109 | if ((j > 0) && | ||
110 | ((buckets[j - 1] > MAX_IBF_DECODE) || | ||
111 | (predict > MAX_IBF_DECODE))) | ||
112 | { | ||
113 | ret *= (1 << (j + 1)); | ||
114 | break; | ||
115 | } | ||
116 | #endif | ||
117 | #if STRATA | ||
118 | /* original algorithm, for 1000 elements with IBF-DECODE 8, | ||
119 | I get 920/1000 elements on average over 1 million runs */ | ||
120 | if (buckets[j] > MAX_IBF_DECODE) | ||
121 | { | ||
122 | ret *= (1 << (j + 1)); | ||
123 | break; | ||
124 | } | ||
125 | #endif | ||
126 | ret += buckets[j]; | ||
127 | predict = (buckets[j] + 2.0 * predict) / 2.0; | ||
128 | } | ||
129 | #if VERBOSE | ||
130 | fprintf (stderr, "%u ", ret); | ||
131 | #endif | ||
132 | total += ret; | ||
133 | } | ||
134 | fprintf (stderr, "\n"); | ||
135 | fprintf (stdout, "average %llu\n", total / ROUNDS); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | |||
140 | /* TODO: should calculate stddev of the results to also be able to | ||
141 | say something about the stability of the results, outside of | ||
142 | large-scale averages -- gaining 8% precision at the expense of | ||
143 | 50% additional variance might not be worth it... */ | ||
diff --git a/src/setu/meson.build b/src/setu/meson.build deleted file mode 100644 index fe5611fd2..000000000 --- a/src/setu/meson.build +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | libgnunetsetu_src = ['setu_api.c'] | ||
2 | |||
3 | gnunetservicesetu_src = ['gnunet-service-setu.c', | ||
4 | 'ibf.c', | ||
5 | 'gnunet-service-setu_strata_estimator.c'] | ||
6 | |||
7 | configure_file(input : 'setu.conf.in', | ||
8 | output : 'setu.conf', | ||
9 | configuration : cdata, | ||
10 | install: true, | ||
11 | install_dir: pkgcfgdir) | ||
12 | |||
13 | |||
14 | if get_option('monolith') | ||
15 | foreach p : libgnunetsetu_src + gnunetservicesetu_src | ||
16 | gnunet_src += 'setu/' + p | ||
17 | endforeach | ||
18 | subdir_done() | ||
19 | endif | ||
20 | |||
21 | libgnunetsetu = library('gnunetsetu', | ||
22 | libgnunetsetu_src, | ||
23 | soversion: '0', | ||
24 | version: '0.0.0', | ||
25 | dependencies: libgnunetutil_dep, | ||
26 | include_directories: [incdir, configuration_inc], | ||
27 | install: true, | ||
28 | install_dir: get_option('libdir')) | ||
29 | pkg.generate(libgnunetsetu, url: 'https://www.gnunet.org', | ||
30 | description : 'Provides API for accessing the set union service') | ||
31 | libgnunetsetu_dep = declare_dependency(link_with : libgnunetsetu) | ||
32 | shared_module('gnunet_plugin_block_setu_test', | ||
33 | ['plugin_block_setu_test.c'], | ||
34 | dependencies: libgnunetutil_dep, | ||
35 | include_directories: [incdir, configuration_inc], | ||
36 | install:true, | ||
37 | install_dir: get_option('libdir')/'gnunet') | ||
38 | executable ('gnunet-service-setu', | ||
39 | gnunetservicesetu_src, | ||
40 | dependencies: [libgnunetsetu_dep, | ||
41 | libgnunetutil_dep, | ||
42 | m_dep, | ||
43 | libgnunetstatistics_dep, | ||
44 | libgnunetcore_dep, | ||
45 | libgnunetcadet_dep, | ||
46 | libgnunetblock_dep], | ||
47 | include_directories: [incdir, configuration_inc], | ||
48 | install: true, | ||
49 | install_dir: get_option('libdir') / 'gnunet' / 'libexec') | ||
50 | |||
diff --git a/src/setu/perf_setu_api.c b/src/setu/perf_setu_api.c deleted file mode 100644 index 7f4d64f74..000000000 --- a/src/setu/perf_setu_api.c +++ /dev/null | |||
@@ -1,473 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/test_setu_api.c | ||
23 | * @brief testcase for setu_api.c | ||
24 | * @author Florian Dold | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_testing_lib.h" | ||
30 | #include "gnunet_setu_service.h" | ||
31 | #include <sys/sysinfo.h> | ||
32 | #include <pthread.h> | ||
33 | |||
34 | |||
35 | static struct GNUNET_PeerIdentity local_id; | ||
36 | |||
37 | static struct GNUNET_HashCode app_id; | ||
38 | |||
39 | static struct GNUNET_SETU_Handle *set1; | ||
40 | |||
41 | static struct GNUNET_SETU_Handle *set2; | ||
42 | |||
43 | static struct GNUNET_SETU_ListenHandle *listen_handle; | ||
44 | |||
45 | static struct GNUNET_SETU_OperationHandle *oh1; | ||
46 | |||
47 | static struct GNUNET_SETU_OperationHandle *oh2; | ||
48 | |||
49 | static const struct GNUNET_CONFIGURATION_Handle *config; | ||
50 | |||
51 | static int ret; | ||
52 | |||
53 | static struct GNUNET_SCHEDULER_Task *tt; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Handles configuration file for setu performance test | ||
58 | * | ||
59 | */ | ||
60 | static struct GNUNET_CONFIGURATION_Handle *setu_cfg; | ||
61 | |||
62 | |||
63 | static void | ||
64 | result_cb_set1 (void *cls, | ||
65 | const struct GNUNET_SETU_Element *element, | ||
66 | uint64_t size, | ||
67 | enum GNUNET_SETU_Status status) | ||
68 | { | ||
69 | switch (status) | ||
70 | { | ||
71 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
72 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 1: got element\n"); | ||
73 | break; | ||
74 | |||
75 | case GNUNET_SETU_STATUS_FAILURE: | ||
76 | GNUNET_break (0); | ||
77 | oh1 = NULL; | ||
78 | fprintf (stderr, "set 1: received failure status!\n"); | ||
79 | ret = 1; | ||
80 | if (NULL != tt) | ||
81 | { | ||
82 | GNUNET_SCHEDULER_cancel (tt); | ||
83 | tt = NULL; | ||
84 | } | ||
85 | GNUNET_SCHEDULER_shutdown (); | ||
86 | break; | ||
87 | |||
88 | case GNUNET_SETU_STATUS_DONE: | ||
89 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 1: done\n"); | ||
90 | oh1 = NULL; | ||
91 | if (NULL != set1) | ||
92 | { | ||
93 | GNUNET_SETU_destroy (set1); | ||
94 | set1 = NULL; | ||
95 | } | ||
96 | if (NULL == set2) | ||
97 | { | ||
98 | GNUNET_SCHEDULER_cancel (tt); | ||
99 | tt = NULL; | ||
100 | GNUNET_SCHEDULER_shutdown (); | ||
101 | } | ||
102 | break; | ||
103 | |||
104 | default: | ||
105 | GNUNET_assert (0); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | |||
110 | static void | ||
111 | result_cb_set2 (void *cls, | ||
112 | const struct GNUNET_SETU_Element *element, | ||
113 | uint64_t size, | ||
114 | enum GNUNET_SETU_Status status) | ||
115 | { | ||
116 | switch (status) | ||
117 | { | ||
118 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
119 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 2: got element\n"); | ||
120 | break; | ||
121 | |||
122 | case GNUNET_SETU_STATUS_FAILURE: | ||
123 | GNUNET_break (0); | ||
124 | oh2 = NULL; | ||
125 | fprintf (stderr, "set 2: received failure status\n"); | ||
126 | GNUNET_SCHEDULER_shutdown (); | ||
127 | ret = 1; | ||
128 | break; | ||
129 | |||
130 | case GNUNET_SETU_STATUS_DONE: | ||
131 | oh2 = NULL; | ||
132 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 2: done\n"); | ||
133 | GNUNET_SETU_destroy (set2); | ||
134 | set2 = NULL; | ||
135 | if (NULL == set1) | ||
136 | { | ||
137 | GNUNET_SCHEDULER_cancel (tt); | ||
138 | tt = NULL; | ||
139 | GNUNET_SCHEDULER_shutdown (); | ||
140 | } | ||
141 | break; | ||
142 | |||
143 | default: | ||
144 | GNUNET_assert (0); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | |||
149 | static void | ||
150 | listen_cb (void *cls, | ||
151 | const struct GNUNET_PeerIdentity *other_peer, | ||
152 | const struct GNUNET_MessageHeader *context_msg, | ||
153 | struct GNUNET_SETU_Request *request) | ||
154 | { | ||
155 | GNUNET_assert (NULL != context_msg); | ||
156 | GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY); | ||
157 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "listen cb called\n"); | ||
158 | oh2 = GNUNET_SETU_accept (request, | ||
159 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
160 | &result_cb_set2, | ||
161 | NULL); | ||
162 | GNUNET_SETU_commit (oh2, set2); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Start the set operation. | ||
168 | * | ||
169 | * @param cls closure, unused | ||
170 | */ | ||
171 | static void | ||
172 | start (void *cls) | ||
173 | { | ||
174 | struct GNUNET_MessageHeader context_msg; | ||
175 | |||
176 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting reconciliation\n"); | ||
177 | context_msg.size = htons (sizeof context_msg); | ||
178 | context_msg.type = htons (GNUNET_MESSAGE_TYPE_DUMMY); | ||
179 | listen_handle = GNUNET_SETU_listen (config, | ||
180 | &app_id, | ||
181 | &listen_cb, | ||
182 | NULL); | ||
183 | oh1 = GNUNET_SETU_prepare (&local_id, | ||
184 | &app_id, | ||
185 | &context_msg, | ||
186 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
187 | &result_cb_set1, | ||
188 | NULL); | ||
189 | GNUNET_SETU_commit (oh1, set1); | ||
190 | } | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Generate random byte stream | ||
195 | */ | ||
196 | |||
197 | unsigned char * | ||
198 | gen_rdm_bytestream (size_t num_bytes) | ||
199 | { | ||
200 | unsigned char *stream = GNUNET_malloc (num_bytes); | ||
201 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, stream, num_bytes); | ||
202 | return stream; | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Generate random sets | ||
208 | */ | ||
209 | |||
210 | static void | ||
211 | initRandomSets (int overlap, int set1_size, int set2_size, int | ||
212 | element_size_in_bytes) | ||
213 | { | ||
214 | struct GNUNET_SETU_Element element; | ||
215 | element.element_type = 0; | ||
216 | |||
217 | // Add elements to both sets | ||
218 | for (int i = 0; i < overlap; i++) | ||
219 | { | ||
220 | element.data = gen_rdm_bytestream (element_size_in_bytes); | ||
221 | element.size = element_size_in_bytes; | ||
222 | GNUNET_SETU_add_element (set1, &element, NULL, NULL); | ||
223 | GNUNET_SETU_add_element (set2, &element, NULL, NULL); | ||
224 | set1_size--; | ||
225 | set2_size--; | ||
226 | } | ||
227 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initialized elements in both sets\n"); | ||
228 | |||
229 | // Add other elements to set 1 | ||
230 | while (set1_size>0) | ||
231 | { | ||
232 | element.data = gen_rdm_bytestream (element_size_in_bytes); | ||
233 | element.size = element_size_in_bytes; | ||
234 | GNUNET_SETU_add_element (set1, &element, NULL, NULL); | ||
235 | set1_size--; | ||
236 | } | ||
237 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initialized elements in set1\n"); | ||
238 | |||
239 | // Add other elements to set 2 | ||
240 | while (set2_size > 0) | ||
241 | { | ||
242 | element.data = gen_rdm_bytestream (element_size_in_bytes); | ||
243 | element.size = element_size_in_bytes; | ||
244 | |||
245 | if (set2_size != 1) | ||
246 | { | ||
247 | GNUNET_SETU_add_element (set2, &element,NULL, NULL); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | GNUNET_SETU_add_element (set2, &element,&start, NULL); | ||
252 | } | ||
253 | |||
254 | set2_size--; | ||
255 | } | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initialized elements in set2\n"); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Function run on timeout. | ||
262 | * | ||
263 | * @param cls closure | ||
264 | */ | ||
265 | static void | ||
266 | timeout_fail (void *cls) | ||
267 | { | ||
268 | tt = NULL; | ||
269 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Testcase failed with timeout\n"); | ||
270 | GNUNET_SCHEDULER_shutdown (); | ||
271 | ret = 1; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Function run on shutdown. | ||
277 | * | ||
278 | * @param cls closure | ||
279 | */ | ||
280 | static void | ||
281 | do_shutdown (void *cls) | ||
282 | { | ||
283 | if (NULL != tt) | ||
284 | { | ||
285 | GNUNET_SCHEDULER_cancel (tt); | ||
286 | tt = NULL; | ||
287 | } | ||
288 | if (NULL != oh1) | ||
289 | { | ||
290 | GNUNET_SETU_operation_cancel (oh1); | ||
291 | oh1 = NULL; | ||
292 | } | ||
293 | if (NULL != oh2) | ||
294 | { | ||
295 | GNUNET_SETU_operation_cancel (oh2); | ||
296 | oh2 = NULL; | ||
297 | } | ||
298 | if (NULL != set1) | ||
299 | { | ||
300 | GNUNET_SETU_destroy (set1); | ||
301 | set1 = NULL; | ||
302 | } | ||
303 | if (NULL != set2) | ||
304 | { | ||
305 | GNUNET_SETU_destroy (set2); | ||
306 | set2 = NULL; | ||
307 | } | ||
308 | if (NULL != listen_handle) | ||
309 | { | ||
310 | GNUNET_SETU_listen_cancel (listen_handle); | ||
311 | listen_handle = NULL; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * Signature of the 'main' function for a (single-peer) testcase that | ||
318 | * is run using 'GNUNET_TESTING_peer_run'. | ||
319 | * | ||
320 | * @param cls closure | ||
321 | * @param cfg configuration of the peer that was started | ||
322 | * @param peer identity of the peer that was created | ||
323 | */ | ||
324 | static void | ||
325 | run (void *cls, | ||
326 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
327 | struct GNUNET_TESTING_Peer *peer) | ||
328 | { | ||
329 | struct GNUNET_SETU_OperationHandle *my_oh; | ||
330 | |||
331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "Running preparatory tests\n"); | ||
333 | tt = GNUNET_SCHEDULER_add_delayed ( | ||
334 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), | ||
335 | &timeout_fail, | ||
336 | NULL); | ||
337 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
338 | |||
339 | config = cfg; | ||
340 | GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_get_peer_identity (cfg, | ||
341 | &local_id)); | ||
342 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
343 | "my id (from CRYPTO): %s\n", | ||
344 | GNUNET_i2s (&local_id)); | ||
345 | GNUNET_TESTING_peer_get_identity (peer, | ||
346 | &local_id); | ||
347 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
348 | "my id (from TESTING): %s\n", | ||
349 | GNUNET_i2s (&local_id)); | ||
350 | set1 = GNUNET_SETU_create (cfg); | ||
351 | set2 = GNUNET_SETU_create (cfg); | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
353 | "Created sets %p and %p for union operation\n", | ||
354 | set1, | ||
355 | set2); | ||
356 | GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id); | ||
357 | |||
358 | /* test if canceling an uncommitted request works! */ | ||
359 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
360 | "Launching and instantly stopping set operation\n"); | ||
361 | my_oh = GNUNET_SETU_prepare (&local_id, | ||
362 | &app_id, | ||
363 | NULL, | ||
364 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
365 | NULL, | ||
366 | NULL); | ||
367 | GNUNET_SETU_operation_cancel (my_oh); | ||
368 | |||
369 | /* test the real set reconciliation */ | ||
370 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
371 | "Running real set-reconciliation\n"); | ||
372 | // init_set1 (); | ||
373 | // limit ~23800 element total | ||
374 | initRandomSets (490, 500,500,32); | ||
375 | } | ||
376 | |||
377 | |||
378 | void | ||
379 | perf_thread () | ||
380 | { | ||
381 | GNUNET_TESTING_service_run ("perf_setu_api", | ||
382 | "arm", | ||
383 | "test_setu.conf", | ||
384 | &run, | ||
385 | NULL); | ||
386 | |||
387 | } | ||
388 | |||
389 | |||
390 | static void | ||
391 | run_petf_thread (int total_runs) | ||
392 | { | ||
393 | int core_count = get_nprocs_conf (); | ||
394 | pid_t child_pid, wpid; | ||
395 | int status = 0; | ||
396 | |||
397 | // Father code (before child processes start) | ||
398 | for (int processed = 0; processed < total_runs;) | ||
399 | { | ||
400 | for (int id = 0; id < core_count; id++) | ||
401 | { | ||
402 | if (processed >= total_runs) | ||
403 | break; | ||
404 | |||
405 | if ((child_pid = fork ()) == 0) | ||
406 | { | ||
407 | perf_thread (); | ||
408 | exit (0); | ||
409 | } | ||
410 | processed += 1; | ||
411 | } | ||
412 | while ((wpid = wait (&status)) > 0) | ||
413 | ; | ||
414 | |||
415 | } | ||
416 | } | ||
417 | |||
418 | |||
419 | static void | ||
420 | execute_perf () | ||
421 | { | ||
422 | |||
423 | /** | ||
424 | * Erase statfile | ||
425 | */ | ||
426 | remove ("perf_stats.csv"); | ||
427 | remove ("perf_failure_bucket_number_factor.csv"); | ||
428 | for (int out_out_ctr = 3; out_out_ctr <= 3; out_out_ctr++) | ||
429 | { | ||
430 | |||
431 | for (int out_ctr = 20; out_ctr <= 20; out_ctr++) | ||
432 | { | ||
433 | float base = 0.1; | ||
434 | float x = out_ctr * base; | ||
435 | char factor[10]; | ||
436 | char *buffer = gcvt (x, 4, factor); | ||
437 | setu_cfg = GNUNET_CONFIGURATION_create (); | ||
438 | GNUNET_CONFIGURATION_set_value_string (setu_cfg, "IBF", | ||
439 | "BUCKET_NUMBER_FACTOR", | ||
440 | buffer); // Factor default=4 | ||
441 | GNUNET_CONFIGURATION_set_value_number (setu_cfg, "IBF", | ||
442 | "NUMBER_PER_BUCKET", 3); // K default=4 | ||
443 | GNUNET_CONFIGURATION_set_value_string (setu_cfg, "PERFORMANCE", | ||
444 | "TRADEOFF", "2"); // default=0.25 | ||
445 | GNUNET_CONFIGURATION_set_value_string (setu_cfg, "PERFORMANCE", | ||
446 | "MAX_SET_DIFF_FACTOR_DIFFERENTIAL", | ||
447 | "20000"); // default=0.25 | ||
448 | GNUNET_CONFIGURATION_set_value_number (setu_cfg, "BOUNDARIES", | ||
449 | "UPPER_ELEMENT", 5000); | ||
450 | |||
451 | |||
452 | if (GNUNET_OK != GNUNET_CONFIGURATION_write (setu_cfg, "perf_setu.conf")) | ||
453 | GNUNET_log ( | ||
454 | GNUNET_ERROR_TYPE_ERROR, | ||
455 | _ ("Failed to write subsystem default identifier map'.\n")); | ||
456 | run_petf_thread (100); | ||
457 | } | ||
458 | |||
459 | } | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | |||
464 | int | ||
465 | main (int argc, char **argv) | ||
466 | { | ||
467 | |||
468 | GNUNET_log_setup ("perf_setu_api", | ||
469 | "WARNING", | ||
470 | NULL); | ||
471 | execute_perf (); | ||
472 | return 0; | ||
473 | } | ||
diff --git a/src/setu/plugin_block_setu_test.c b/src/setu/plugin_block_setu_test.c deleted file mode 100644 index 178ad3314..000000000 --- a/src/setu/plugin_block_setu_test.c +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file setu/plugin_block_setu_test.c | ||
23 | * @brief set test block, recognizes elements with non-zero first byte as invalid | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_block_plugin.h" | ||
28 | #include "gnunet_block_group_lib.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Function called to validate a query. | ||
33 | * | ||
34 | * @param cls closure | ||
35 | * @param ctx block context | ||
36 | * @param type block type | ||
37 | * @param query original query (hash) | ||
38 | * @param xquery extrended query data (can be NULL, depending on type) | ||
39 | * @param xquery_size number of bytes in @a xquery | ||
40 | * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not | ||
41 | */ | ||
42 | static enum GNUNET_GenericReturnValue | ||
43 | block_plugin_setu_test_check_query (void *cls, | ||
44 | enum GNUNET_BLOCK_Type type, | ||
45 | const struct GNUNET_HashCode *query, | ||
46 | const void *xquery, | ||
47 | size_t xquery_size) | ||
48 | { | ||
49 | if (GNUNET_BLOCK_TYPE_SETU_TEST != type) | ||
50 | { | ||
51 | GNUNET_break (0); | ||
52 | return GNUNET_SYSERR; | ||
53 | } | ||
54 | if (0 != xquery_size) | ||
55 | { | ||
56 | GNUNET_break_op (0); | ||
57 | return GNUNET_NO; | ||
58 | } | ||
59 | return GNUNET_OK; | ||
60 | } | ||
61 | |||
62 | |||
63 | /** | ||
64 | * Function called to validate a block for storage. | ||
65 | * | ||
66 | * @param cls closure | ||
67 | * @param type block type | ||
68 | * @param block block data to validate | ||
69 | * @param block_size number of bytes in @a block | ||
70 | * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not | ||
71 | */ | ||
72 | static enum GNUNET_GenericReturnValue | ||
73 | block_plugin_setu_test_check_block (void *cls, | ||
74 | enum GNUNET_BLOCK_Type type, | ||
75 | const void *block, | ||
76 | size_t block_size) | ||
77 | { | ||
78 | if (GNUNET_BLOCK_TYPE_SETU_TEST != type) | ||
79 | { | ||
80 | GNUNET_break (0); | ||
81 | return GNUNET_SYSERR; | ||
82 | } | ||
83 | if ( (NULL == block) || | ||
84 | (0 == block_size) || | ||
85 | (0 != ((char *) block)[0]) ) | ||
86 | return GNUNET_NO; | ||
87 | return GNUNET_OK; | ||
88 | } | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Function called to validate a reply to a request. Note that it is assumed | ||
93 | * that the reply has already been matched to the key (and signatures checked) | ||
94 | * as it would be done with the GetKeyFunction and the | ||
95 | * BlockEvaluationFunction. | ||
96 | * | ||
97 | * @param cls closure | ||
98 | * @param type block type | ||
99 | * @param group which block group to use for evaluation | ||
100 | * @param query original query (hash) | ||
101 | * @param xquery extrended query data (can be NULL, depending on type) | ||
102 | * @param xquery_size number of bytes in @a xquery | ||
103 | * @param reply_block response to validate | ||
104 | * @param reply_block_size number of bytes in @a reply_block | ||
105 | * @return characterization of result | ||
106 | */ | ||
107 | static enum GNUNET_BLOCK_ReplyEvaluationResult | ||
108 | block_plugin_setu_test_check_reply (void *cls, | ||
109 | enum GNUNET_BLOCK_Type type, | ||
110 | struct GNUNET_BLOCK_Group *group, | ||
111 | const struct GNUNET_HashCode *query, | ||
112 | const void *xquery, | ||
113 | size_t xquery_size, | ||
114 | const void *reply_block, | ||
115 | size_t reply_block_size) | ||
116 | { | ||
117 | (void) cls; | ||
118 | (void) xquery; | ||
119 | (void) xquery_size; | ||
120 | if (GNUNET_BLOCK_TYPE_SETU_TEST != type) | ||
121 | { | ||
122 | GNUNET_break (0); | ||
123 | return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED; | ||
124 | } | ||
125 | if ( (NULL == reply_block) || | ||
126 | (0 == reply_block_size) || | ||
127 | (0 != ((char *) reply_block)[0]) ) | ||
128 | GNUNET_assert (0); | ||
129 | return GNUNET_BLOCK_REPLY_OK_MORE; | ||
130 | } | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Function called to obtain the key for a block. | ||
135 | * | ||
136 | * @param cls closure | ||
137 | * @param type block type | ||
138 | * @param block block to get the key for | ||
139 | * @param block_size number of bytes in block | ||
140 | * @param key set to the key (query) for the given block | ||
141 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported | ||
142 | * (or if extracting a key from a block of this type does not work) | ||
143 | */ | ||
144 | static enum GNUNET_GenericReturnValue | ||
145 | block_plugin_setu_test_get_key (void *cls, | ||
146 | enum GNUNET_BLOCK_Type type, | ||
147 | const void *block, | ||
148 | size_t block_size, | ||
149 | struct GNUNET_HashCode *key) | ||
150 | { | ||
151 | if (GNUNET_BLOCK_TYPE_SETU_TEST != type) | ||
152 | { | ||
153 | GNUNET_break (0); | ||
154 | return GNUNET_SYSERR; | ||
155 | } | ||
156 | return GNUNET_NO; | ||
157 | } | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Entry point for the plugin. | ||
162 | */ | ||
163 | void * | ||
164 | libgnunet_plugin_block_setu_test_init (void *cls) | ||
165 | { | ||
166 | static enum GNUNET_BLOCK_Type types[] = { | ||
167 | GNUNET_BLOCK_TYPE_SETU_TEST, | ||
168 | GNUNET_BLOCK_TYPE_ANY /* end of list */ | ||
169 | }; | ||
170 | struct GNUNET_BLOCK_PluginFunctions *api; | ||
171 | |||
172 | api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); | ||
173 | api->get_key = &block_plugin_setu_test_get_key; | ||
174 | api->check_query = &block_plugin_setu_test_check_query; | ||
175 | api->check_block = &block_plugin_setu_test_check_block; | ||
176 | api->check_reply = &block_plugin_setu_test_check_reply; | ||
177 | api->types = types; | ||
178 | return api; | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Exit point from the plugin. | ||
184 | */ | ||
185 | void * | ||
186 | libgnunet_plugin_block_setu_test_done (void *cls) | ||
187 | { | ||
188 | struct GNUNET_BLOCK_PluginFunctions *api = cls; | ||
189 | |||
190 | GNUNET_free (api); | ||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | |||
195 | /* end of plugin_block_setu_test.c */ | ||
diff --git a/src/setu/setu.conf.in b/src/setu/setu.conf.in deleted file mode 100644 index 6c48f6156..000000000 --- a/src/setu/setu.conf.in +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | [setu] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | @UNIXONLY@PORT = 2106 | ||
4 | HOSTNAME = localhost | ||
5 | BINARY = gnunet-service-setu | ||
6 | ACCEPT_FROM = 127.0.0.1; | ||
7 | ACCEPT_FROM6 = ::1; | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-setu.sock | ||
9 | UNIX_MATCH_UID = YES | ||
10 | UNIX_MATCH_GID = YES | ||
11 | |||
12 | #PREFIX = valgrind | ||
diff --git a/src/setu/setu.h b/src/setu/setu.h deleted file mode 100644 index 7b606f12c..000000000 --- a/src/setu/setu.h +++ /dev/null | |||
@@ -1,365 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012-2014, 2020 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file set/set.h | ||
22 | * @brief messages used for the set union api | ||
23 | * @author Florian Dold | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef SET_H | ||
27 | #define SET_H | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_common.h" | ||
31 | #include "gnunet_set_service.h" | ||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | /** | ||
36 | * Message sent by the client to the service to ask starting | ||
37 | * a new set to perform operations with. Includes the desired | ||
38 | * set operation type. | ||
39 | */ | ||
40 | struct GNUNET_SETU_CreateMessage | ||
41 | { | ||
42 | /** | ||
43 | * Type: #GNUNET_MESSAGE_TYPE_SETU_CREATE | ||
44 | */ | ||
45 | struct GNUNET_MessageHeader header; | ||
46 | |||
47 | }; | ||
48 | |||
49 | |||
50 | /** | ||
51 | * Message sent by the client to the service to start listening for | ||
52 | * incoming requests to perform a certain type of set operation for a | ||
53 | * certain type of application. | ||
54 | */ | ||
55 | struct GNUNET_SETU_ListenMessage | ||
56 | { | ||
57 | /** | ||
58 | * Type: #GNUNET_MESSAGE_TYPE_SETU_LISTEN | ||
59 | */ | ||
60 | struct GNUNET_MessageHeader header; | ||
61 | |||
62 | /** | ||
63 | * Always zero. | ||
64 | */ | ||
65 | uint32_t reserved GNUNET_PACKED; | ||
66 | |||
67 | /** | ||
68 | * application id | ||
69 | */ | ||
70 | struct GNUNET_HashCode app_id; | ||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Message sent by a listening client to the service to accept | ||
76 | * performing the operation with the other peer. | ||
77 | */ | ||
78 | struct GNUNET_SETU_AcceptMessage | ||
79 | { | ||
80 | /** | ||
81 | * Type: #GNUNET_MESSAGE_TYPE_SETU_ACCEPT | ||
82 | */ | ||
83 | struct GNUNET_MessageHeader header; | ||
84 | |||
85 | /** | ||
86 | * ID of the incoming request we want to accept. | ||
87 | */ | ||
88 | uint32_t accept_reject_id GNUNET_PACKED; | ||
89 | |||
90 | /** | ||
91 | * Request ID to identify responses. | ||
92 | */ | ||
93 | uint32_t request_id GNUNET_PACKED; | ||
94 | |||
95 | /** | ||
96 | * Always use delta operation instead of sending full sets, | ||
97 | * even it it's less efficient. | ||
98 | */ | ||
99 | uint8_t force_delta; | ||
100 | |||
101 | /** | ||
102 | * Always send full sets, even if delta operations would | ||
103 | * be more efficient. | ||
104 | */ | ||
105 | uint8_t force_full; | ||
106 | |||
107 | /** | ||
108 | * #GNUNET_YES to fail operations where Byzantine faults | ||
109 | * are suspected | ||
110 | */ | ||
111 | uint8_t byzantine; | ||
112 | |||
113 | /** | ||
114 | * #GNUNET_YES to also send back set elements we are sending to | ||
115 | * the remote peer. | ||
116 | */ | ||
117 | uint8_t symmetric; | ||
118 | |||
119 | /** | ||
120 | * Lower bound for the set size, used only when | ||
121 | * byzantine mode is enabled. | ||
122 | */ | ||
123 | uint32_t byzantine_lower_bound; | ||
124 | |||
125 | |||
126 | /** | ||
127 | * Upper bound for the set size, used only when | ||
128 | * byzantine mode is enabled. | ||
129 | */ | ||
130 | uint64_t byzantine_upper_bond; | ||
131 | |||
132 | /** | ||
133 | * Bandwidth latency tradeoff determines how much bytes a single RTT is | ||
134 | * worth, which is a performance setting | ||
135 | */ | ||
136 | uint64_t bandwidth_latency_tradeoff; | ||
137 | |||
138 | /** | ||
139 | * The factor determines the number of buckets an IBF has which is | ||
140 | * multiplied by the estimated setsize default: 2 | ||
141 | */ | ||
142 | uint64_t ibf_bucket_number_factor; | ||
143 | |||
144 | /** | ||
145 | * This setting determines to how many IBF buckets an single elements | ||
146 | * is mapped to. | ||
147 | */ | ||
148 | uint64_t ibf_number_of_buckets_per_element; | ||
149 | |||
150 | }; | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Message sent by a listening client to the service to reject | ||
155 | * performing the operation with the other peer. | ||
156 | */ | ||
157 | struct GNUNET_SETU_RejectMessage | ||
158 | { | ||
159 | /** | ||
160 | * Type: #GNUNET_MESSAGE_TYPE_SETU_REJECT | ||
161 | */ | ||
162 | struct GNUNET_MessageHeader header; | ||
163 | |||
164 | /** | ||
165 | * ID of the incoming request we want to reject. | ||
166 | */ | ||
167 | uint32_t accept_reject_id GNUNET_PACKED; | ||
168 | }; | ||
169 | |||
170 | |||
171 | /** | ||
172 | * A request for an operation with another client. | ||
173 | */ | ||
174 | struct GNUNET_SETU_RequestMessage | ||
175 | { | ||
176 | /** | ||
177 | * Type: #GNUNET_MESSAGE_TYPE_SETU_REQUEST. | ||
178 | */ | ||
179 | struct GNUNET_MessageHeader header; | ||
180 | |||
181 | /** | ||
182 | * ID of the to identify the request when accepting or | ||
183 | * rejecting it. | ||
184 | */ | ||
185 | uint32_t accept_id GNUNET_PACKED; | ||
186 | |||
187 | /** | ||
188 | * Identity of the requesting peer. | ||
189 | */ | ||
190 | struct GNUNET_PeerIdentity peer_id; | ||
191 | |||
192 | /* rest: context message, that is, application-specific | ||
193 | message to convince listener to pick up */ | ||
194 | }; | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Message sent by client to service to initiate a set operation as a | ||
199 | * client (not as listener). A set (which determines the operation | ||
200 | * type) must already exist in association with this client. | ||
201 | */ | ||
202 | struct GNUNET_SETU_EvaluateMessage | ||
203 | { | ||
204 | /** | ||
205 | * Type: #GNUNET_MESSAGE_TYPE_SETU_EVALUATE | ||
206 | */ | ||
207 | struct GNUNET_MessageHeader header; | ||
208 | |||
209 | /** | ||
210 | * Id of our set to evaluate, chosen implicitly by the client when it | ||
211 | * calls #GNUNET_SETU_commit(). | ||
212 | */ | ||
213 | uint32_t request_id GNUNET_PACKED; | ||
214 | |||
215 | /** | ||
216 | * Peer to evaluate the operation with | ||
217 | */ | ||
218 | struct GNUNET_PeerIdentity target_peer; | ||
219 | |||
220 | /** | ||
221 | * Application id | ||
222 | */ | ||
223 | struct GNUNET_HashCode app_id; | ||
224 | |||
225 | /** | ||
226 | * Always use delta operation instead of sending full sets, | ||
227 | * even it it's less efficient. | ||
228 | */ | ||
229 | uint8_t force_delta; | ||
230 | |||
231 | /** | ||
232 | * Always send full sets, even if delta operations would | ||
233 | * be more efficient. | ||
234 | */ | ||
235 | uint8_t force_full; | ||
236 | |||
237 | /** | ||
238 | * #GNUNET_YES to fail operations where Byzantine faults | ||
239 | * are suspected | ||
240 | */ | ||
241 | uint8_t byzantine; | ||
242 | |||
243 | /** | ||
244 | * Also return set elements we are sending to the remote peer. | ||
245 | */ | ||
246 | uint8_t symmetric; | ||
247 | |||
248 | /** | ||
249 | * Lower bound for the set size, used only when | ||
250 | * byzantine mode is enabled. | ||
251 | */ | ||
252 | uint32_t byzantine_lower_bound; | ||
253 | |||
254 | /** | ||
255 | * Upper bound for the set size, used only when | ||
256 | * byzantine mode is enabled. | ||
257 | */ | ||
258 | uint64_t byzantine_upper_bond; | ||
259 | |||
260 | /** | ||
261 | * Bandwidth latency tradeoff determines how much bytes a single RTT is | ||
262 | * worth, which is a performance setting | ||
263 | */ | ||
264 | uint64_t bandwidth_latency_tradeoff; | ||
265 | |||
266 | /** | ||
267 | * The factor determines the number of buckets an IBF has which is | ||
268 | * multiplied by the estimated setsize default: 2 | ||
269 | */ | ||
270 | uint64_t ibf_bucket_number_factor; | ||
271 | |||
272 | /** | ||
273 | * This setting determines to how many IBF buckets an single elements | ||
274 | * is mapped to. | ||
275 | */ | ||
276 | uint64_t ibf_number_of_buckets_per_element; | ||
277 | |||
278 | /* rest: context message, that is, application-specific | ||
279 | message to convince listener to pick up */ | ||
280 | }; | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Message sent by the service to the client to indicate an | ||
285 | * element that is removed (set intersection) or added | ||
286 | * (set union) or part of the final result, depending on | ||
287 | * options specified for the operation. | ||
288 | */ | ||
289 | struct GNUNET_SETU_ResultMessage | ||
290 | { | ||
291 | /** | ||
292 | * Type: #GNUNET_MESSAGE_TYPE_SETU_RESULT | ||
293 | */ | ||
294 | struct GNUNET_MessageHeader header; | ||
295 | |||
296 | /** | ||
297 | * Current set size. | ||
298 | */ | ||
299 | uint64_t current_size; | ||
300 | |||
301 | /** | ||
302 | * id the result belongs to | ||
303 | */ | ||
304 | uint32_t request_id GNUNET_PACKED; | ||
305 | |||
306 | /** | ||
307 | * Was the evaluation successful? Contains | ||
308 | * an `enum GNUNET_SETU_Status` in NBO. | ||
309 | */ | ||
310 | uint16_t result_status GNUNET_PACKED; | ||
311 | |||
312 | /** | ||
313 | * Type of the element attached to the message, if any. | ||
314 | */ | ||
315 | uint16_t element_type GNUNET_PACKED; | ||
316 | |||
317 | /* rest: the actual element */ | ||
318 | }; | ||
319 | |||
320 | |||
321 | /** | ||
322 | * Message sent by client to the service to add | ||
323 | * an element to the set. | ||
324 | */ | ||
325 | struct GNUNET_SETU_ElementMessage | ||
326 | { | ||
327 | /** | ||
328 | * Type: #GNUNET_MESSAGE_TYPE_SETU_ADD | ||
329 | */ | ||
330 | struct GNUNET_MessageHeader header; | ||
331 | |||
332 | /** | ||
333 | * Type of the element to add or remove. | ||
334 | */ | ||
335 | uint16_t element_type GNUNET_PACKED; | ||
336 | |||
337 | /** | ||
338 | * For alignment, always zero. | ||
339 | */ | ||
340 | uint16_t reserved GNUNET_PACKED; | ||
341 | |||
342 | /* rest: the actual element */ | ||
343 | }; | ||
344 | |||
345 | |||
346 | /** | ||
347 | * Sent to the service by the client in order to cancel a set operation. | ||
348 | */ | ||
349 | struct GNUNET_SETU_CancelMessage | ||
350 | { | ||
351 | /** | ||
352 | * Type: #GNUNET_MESSAGE_TYPE_SETU_CANCEL | ||
353 | */ | ||
354 | struct GNUNET_MessageHeader header; | ||
355 | |||
356 | /** | ||
357 | * ID of the request we want to cancel. | ||
358 | */ | ||
359 | uint32_t request_id GNUNET_PACKED; | ||
360 | }; | ||
361 | |||
362 | |||
363 | GNUNET_NETWORK_STRUCT_END | ||
364 | |||
365 | #endif | ||
diff --git a/src/setu/setu_api.c b/src/setu/setu_api.c deleted file mode 100644 index 7fa144590..000000000 --- a/src/setu/setu_api.c +++ /dev/null | |||
@@ -1,911 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012-2016, 2020 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file set/setu_api.c | ||
22 | * @brief api for the set union service | ||
23 | * @author Florian Dold | ||
24 | * @author Christian Grothoff | ||
25 | * @author Elias Summermatter | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | #include "gnunet_setu_service.h" | ||
31 | #include "setu.h" | ||
32 | |||
33 | |||
34 | #define LOG(kind, ...) GNUNET_log_from (kind, "set-api", __VA_ARGS__) | ||
35 | |||
36 | /** | ||
37 | * Opaque handle to a set. | ||
38 | */ | ||
39 | struct GNUNET_SETU_Handle | ||
40 | { | ||
41 | /** | ||
42 | * Message queue for @e client. | ||
43 | */ | ||
44 | struct GNUNET_MQ_Handle *mq; | ||
45 | |||
46 | /** | ||
47 | * Linked list of operations on the set. | ||
48 | */ | ||
49 | struct GNUNET_SETU_OperationHandle *ops_head; | ||
50 | |||
51 | /** | ||
52 | * Linked list of operations on the set. | ||
53 | */ | ||
54 | struct GNUNET_SETU_OperationHandle *ops_tail; | ||
55 | |||
56 | /** | ||
57 | * Should the set be destroyed once all operations are gone? | ||
58 | * #GNUNET_SYSERR if #GNUNET_SETU_destroy() must raise this flag, | ||
59 | * #GNUNET_YES if #GNUNET_SETU_destroy() did raise this flag. | ||
60 | */ | ||
61 | int destroy_requested; | ||
62 | |||
63 | /** | ||
64 | * Has the set become invalid (e.g. service died)? | ||
65 | */ | ||
66 | int invalid; | ||
67 | |||
68 | }; | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Handle for a set operation request from another peer. | ||
73 | */ | ||
74 | struct GNUNET_SETU_Request | ||
75 | { | ||
76 | /** | ||
77 | * Id of the request, used to identify the request when | ||
78 | * accepting/rejecting it. | ||
79 | */ | ||
80 | uint32_t accept_id; | ||
81 | |||
82 | /** | ||
83 | * Has the request been accepted already? | ||
84 | * #GNUNET_YES/#GNUNET_NO | ||
85 | */ | ||
86 | int accepted; | ||
87 | }; | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Handle to an operation. Only known to the service after committing | ||
92 | * the handle with a set. | ||
93 | */ | ||
94 | struct GNUNET_SETU_OperationHandle | ||
95 | { | ||
96 | /** | ||
97 | * Function to be called when we have a result, | ||
98 | * or an error. | ||
99 | */ | ||
100 | GNUNET_SETU_ResultIterator result_cb; | ||
101 | |||
102 | /** | ||
103 | * Closure for @e result_cb. | ||
104 | */ | ||
105 | void *result_cls; | ||
106 | |||
107 | /** | ||
108 | * Local set used for the operation, | ||
109 | * NULL if no set has been provided by conclude yet. | ||
110 | */ | ||
111 | struct GNUNET_SETU_Handle *set; | ||
112 | |||
113 | /** | ||
114 | * Message sent to the server on calling conclude, | ||
115 | * NULL if conclude has been called. | ||
116 | */ | ||
117 | struct GNUNET_MQ_Envelope *conclude_mqm; | ||
118 | |||
119 | /** | ||
120 | * Address of the request if in the conclude message, | ||
121 | * used to patch the request id into the message when the set is known. | ||
122 | */ | ||
123 | uint32_t *request_id_addr; | ||
124 | |||
125 | /** | ||
126 | * Handles are kept in a linked list. | ||
127 | */ | ||
128 | struct GNUNET_SETU_OperationHandle *prev; | ||
129 | |||
130 | /** | ||
131 | * Handles are kept in a linked list. | ||
132 | */ | ||
133 | struct GNUNET_SETU_OperationHandle *next; | ||
134 | |||
135 | /** | ||
136 | * Request ID to identify the operation within the set. | ||
137 | */ | ||
138 | uint32_t request_id; | ||
139 | }; | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Opaque handle to a listen operation. | ||
144 | */ | ||
145 | struct GNUNET_SETU_ListenHandle | ||
146 | { | ||
147 | /** | ||
148 | * Message queue for the client. | ||
149 | */ | ||
150 | struct GNUNET_MQ_Handle*mq; | ||
151 | |||
152 | /** | ||
153 | * Configuration handle for the listener, stored | ||
154 | * here to be able to reconnect transparently on | ||
155 | * connection failure. | ||
156 | */ | ||
157 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
158 | |||
159 | /** | ||
160 | * Function to call on a new incoming request, | ||
161 | * or on error. | ||
162 | */ | ||
163 | GNUNET_SETU_ListenCallback listen_cb; | ||
164 | |||
165 | /** | ||
166 | * Closure for @e listen_cb. | ||
167 | */ | ||
168 | void *listen_cls; | ||
169 | |||
170 | /** | ||
171 | * Application ID we listen for. | ||
172 | */ | ||
173 | struct GNUNET_HashCode app_id; | ||
174 | |||
175 | /** | ||
176 | * Time to wait until we try to reconnect on failure. | ||
177 | */ | ||
178 | struct GNUNET_TIME_Relative reconnect_backoff; | ||
179 | |||
180 | /** | ||
181 | * Task for reconnecting when the listener fails. | ||
182 | */ | ||
183 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
184 | |||
185 | }; | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Check that the given @a msg is well-formed. | ||
190 | * | ||
191 | * @param cls closure | ||
192 | * @param msg message to check | ||
193 | * @return #GNUNET_OK if message is well-formed | ||
194 | */ | ||
195 | static int | ||
196 | check_result (void *cls, | ||
197 | const struct GNUNET_SETU_ResultMessage *msg) | ||
198 | { | ||
199 | /* minimum size was already checked, everything else is OK! */ | ||
200 | return GNUNET_OK; | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * Handle result message for a set operation. | ||
206 | * | ||
207 | * @param cls the set | ||
208 | * @param mh the message | ||
209 | */ | ||
210 | static void | ||
211 | handle_result (void *cls, | ||
212 | const struct GNUNET_SETU_ResultMessage *msg) | ||
213 | { | ||
214 | struct GNUNET_SETU_Handle *set = cls; | ||
215 | struct GNUNET_SETU_OperationHandle *oh; | ||
216 | struct GNUNET_SETU_Element e; | ||
217 | enum GNUNET_SETU_Status result_status; | ||
218 | int destroy_set; | ||
219 | |||
220 | GNUNET_assert (NULL != set->mq); | ||
221 | result_status = (enum GNUNET_SETU_Status) ntohs (msg->result_status); | ||
222 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
223 | "Got result message with status %d\n", | ||
224 | result_status); | ||
225 | oh = GNUNET_MQ_assoc_get (set->mq, | ||
226 | ntohl (msg->request_id)); | ||
227 | if (NULL == oh) | ||
228 | { | ||
229 | /* 'oh' can be NULL if we canceled the operation, but the service | ||
230 | did not get the cancel message yet. */ | ||
231 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
232 | "Ignoring result from canceled operation\n"); | ||
233 | return; | ||
234 | } | ||
235 | |||
236 | switch (result_status) | ||
237 | { | ||
238 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
239 | case GNUNET_SETU_STATUS_ADD_REMOTE: | ||
240 | e.data = &msg[1]; | ||
241 | e.size = ntohs (msg->header.size) | ||
242 | - sizeof(struct GNUNET_SETU_ResultMessage); | ||
243 | e.element_type = ntohs (msg->element_type); | ||
244 | if (NULL != oh->result_cb) | ||
245 | oh->result_cb (oh->result_cls, | ||
246 | &e, | ||
247 | GNUNET_ntohll (msg->current_size), | ||
248 | result_status); | ||
249 | return; | ||
250 | case GNUNET_SETU_STATUS_FAILURE: | ||
251 | case GNUNET_SETU_STATUS_DONE: | ||
252 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
253 | "Treating result as final status\n"); | ||
254 | GNUNET_MQ_assoc_remove (set->mq, | ||
255 | ntohl (msg->request_id)); | ||
256 | GNUNET_CONTAINER_DLL_remove (set->ops_head, | ||
257 | set->ops_tail, | ||
258 | oh); | ||
259 | /* Need to do this calculation _before_ the result callback, | ||
260 | as IF the application still has a valid set handle, it | ||
261 | may trigger destruction of the set during the callback. */ | ||
262 | destroy_set = (GNUNET_YES == set->destroy_requested) && | ||
263 | (NULL == set->ops_head); | ||
264 | if (NULL != oh->result_cb) | ||
265 | { | ||
266 | oh->result_cb (oh->result_cls, | ||
267 | NULL, | ||
268 | GNUNET_ntohll (msg->current_size), | ||
269 | result_status); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
274 | "No callback for final status\n"); | ||
275 | } | ||
276 | if (destroy_set) | ||
277 | GNUNET_SETU_destroy (set); | ||
278 | GNUNET_free (oh); | ||
279 | return; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | |||
284 | /** | ||
285 | * Destroy the given set operation. | ||
286 | * | ||
287 | * @param oh set operation to destroy | ||
288 | */ | ||
289 | static void | ||
290 | set_operation_destroy (struct GNUNET_SETU_OperationHandle *oh) | ||
291 | { | ||
292 | struct GNUNET_SETU_Handle *set = oh->set; | ||
293 | struct GNUNET_SETU_OperationHandle *h_assoc; | ||
294 | |||
295 | if (NULL != oh->conclude_mqm) | ||
296 | GNUNET_MQ_discard (oh->conclude_mqm); | ||
297 | /* is the operation already committed? */ | ||
298 | if (NULL != set) | ||
299 | { | ||
300 | GNUNET_CONTAINER_DLL_remove (set->ops_head, | ||
301 | set->ops_tail, | ||
302 | oh); | ||
303 | h_assoc = GNUNET_MQ_assoc_remove (set->mq, | ||
304 | oh->request_id); | ||
305 | GNUNET_assert ((NULL == h_assoc) || | ||
306 | (h_assoc == oh)); | ||
307 | } | ||
308 | GNUNET_free (oh); | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Cancel the given set operation. We need to send an explicit cancel | ||
314 | * message, as all operations one one set communicate using one | ||
315 | * handle. | ||
316 | * | ||
317 | * @param oh set operation to cancel | ||
318 | */ | ||
319 | void | ||
320 | GNUNET_SETU_operation_cancel (struct GNUNET_SETU_OperationHandle *oh) | ||
321 | { | ||
322 | struct GNUNET_SETU_Handle *set = oh->set; | ||
323 | struct GNUNET_SETU_CancelMessage *m; | ||
324 | struct GNUNET_MQ_Envelope *mqm; | ||
325 | |||
326 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
327 | "Cancelling SET operation\n"); | ||
328 | if (NULL != set) | ||
329 | { | ||
330 | mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SETU_CANCEL); | ||
331 | m->request_id = htonl (oh->request_id); | ||
332 | GNUNET_MQ_send (set->mq, mqm); | ||
333 | } | ||
334 | set_operation_destroy (oh); | ||
335 | if ((NULL != set) && | ||
336 | (GNUNET_YES == set->destroy_requested) && | ||
337 | (NULL == set->ops_head)) | ||
338 | { | ||
339 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
340 | "Destroying set after operation cancel\n"); | ||
341 | GNUNET_SETU_destroy (set); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||
346 | /** | ||
347 | * We encountered an error communicating with the set service while | ||
348 | * performing a set operation. Report to the application. | ||
349 | * | ||
350 | * @param cls the `struct GNUNET_SETU_Handle` | ||
351 | * @param error error code | ||
352 | */ | ||
353 | static void | ||
354 | handle_client_set_error (void *cls, | ||
355 | enum GNUNET_MQ_Error error) | ||
356 | { | ||
357 | struct GNUNET_SETU_Handle *set = cls; | ||
358 | |||
359 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
360 | "Handling client set error %d\n", | ||
361 | error); | ||
362 | while (NULL != set->ops_head) | ||
363 | { | ||
364 | if ((NULL != set->ops_head->result_cb) && | ||
365 | (GNUNET_NO == set->destroy_requested)) | ||
366 | set->ops_head->result_cb (set->ops_head->result_cls, | ||
367 | NULL, | ||
368 | 0, | ||
369 | GNUNET_SETU_STATUS_FAILURE); | ||
370 | set_operation_destroy (set->ops_head); | ||
371 | } | ||
372 | set->invalid = GNUNET_YES; | ||
373 | } | ||
374 | |||
375 | |||
376 | /** | ||
377 | * Create an empty set, supporting the specified operation. | ||
378 | * | ||
379 | * @param cfg configuration to use for connecting to the | ||
380 | * set service | ||
381 | * @return a handle to the set | ||
382 | */ | ||
383 | struct GNUNET_SETU_Handle * | ||
384 | GNUNET_SETU_create (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
385 | { | ||
386 | struct GNUNET_SETU_Handle *set = GNUNET_new (struct GNUNET_SETU_Handle); | ||
387 | struct GNUNET_MQ_MessageHandler mq_handlers[] = { | ||
388 | GNUNET_MQ_hd_var_size (result, | ||
389 | GNUNET_MESSAGE_TYPE_SETU_RESULT, | ||
390 | struct GNUNET_SETU_ResultMessage, | ||
391 | set), | ||
392 | GNUNET_MQ_handler_end () | ||
393 | }; | ||
394 | struct GNUNET_MQ_Envelope *mqm; | ||
395 | struct GNUNET_SETU_CreateMessage *create_msg; | ||
396 | |||
397 | set->mq = GNUNET_CLIENT_connect (cfg, | ||
398 | "setu", | ||
399 | mq_handlers, | ||
400 | &handle_client_set_error, | ||
401 | set); | ||
402 | if (NULL == set->mq) | ||
403 | { | ||
404 | GNUNET_free (set); | ||
405 | return NULL; | ||
406 | } | ||
407 | mqm = GNUNET_MQ_msg (create_msg, | ||
408 | GNUNET_MESSAGE_TYPE_SETU_CREATE); | ||
409 | GNUNET_MQ_send (set->mq, | ||
410 | mqm); | ||
411 | return set; | ||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * Add an element to the given set. After the element has been added | ||
417 | * (in the sense of being transmitted to the set service), @a cont | ||
418 | * will be called. Multiple calls to GNUNET_SETU_add_element() can be | ||
419 | * queued. | ||
420 | * | ||
421 | * @param set set to add element to | ||
422 | * @param element element to add to the set | ||
423 | * @param cb continuation called after the element has been added | ||
424 | * @param cb_cls closure for @a cb | ||
425 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the | ||
426 | * set is invalid (e.g. the set service crashed) | ||
427 | */ | ||
428 | int | ||
429 | GNUNET_SETU_add_element (struct GNUNET_SETU_Handle *set, | ||
430 | const struct GNUNET_SETU_Element *element, | ||
431 | GNUNET_SCHEDULER_TaskCallback cb, | ||
432 | void *cb_cls) | ||
433 | { | ||
434 | struct GNUNET_MQ_Envelope *mqm; | ||
435 | struct GNUNET_SETU_ElementMessage *msg; | ||
436 | |||
437 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
438 | "adding element of type %u to set %p\n", | ||
439 | (unsigned int) element->element_type, | ||
440 | set); | ||
441 | GNUNET_assert (NULL != set); | ||
442 | if (GNUNET_YES == set->invalid) | ||
443 | { | ||
444 | if (NULL != cb) | ||
445 | cb (cb_cls); | ||
446 | return GNUNET_SYSERR; | ||
447 | } | ||
448 | mqm = GNUNET_MQ_msg_extra (msg, | ||
449 | element->size, | ||
450 | GNUNET_MESSAGE_TYPE_SETU_ADD); | ||
451 | msg->element_type = htons (element->element_type); | ||
452 | GNUNET_memcpy (&msg[1], | ||
453 | element->data, | ||
454 | element->size); | ||
455 | GNUNET_MQ_notify_sent (mqm, | ||
456 | cb, | ||
457 | cb_cls); | ||
458 | GNUNET_MQ_send (set->mq, | ||
459 | mqm); | ||
460 | return GNUNET_OK; | ||
461 | } | ||
462 | |||
463 | |||
464 | /** | ||
465 | * Destroy the set handle if no operations are left, mark the set | ||
466 | * for destruction otherwise. | ||
467 | * | ||
468 | * @param set set handle to destroy | ||
469 | */ | ||
470 | void | ||
471 | GNUNET_SETU_destroy (struct GNUNET_SETU_Handle *set) | ||
472 | { | ||
473 | /* destroying set while iterator is active is currently | ||
474 | not supported; we should expand the API to allow | ||
475 | clients to explicitly cancel the iteration! */ | ||
476 | GNUNET_assert (NULL != set); | ||
477 | if ((NULL != set->ops_head) || | ||
478 | (GNUNET_SYSERR == set->destroy_requested)) | ||
479 | { | ||
480 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
481 | "Set operations are pending, delaying set destruction\n"); | ||
482 | set->destroy_requested = GNUNET_YES; | ||
483 | return; | ||
484 | } | ||
485 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
486 | "Really destroying set\n"); | ||
487 | if (NULL != set->mq) | ||
488 | { | ||
489 | GNUNET_MQ_destroy (set->mq); | ||
490 | set->mq = NULL; | ||
491 | } | ||
492 | GNUNET_free (set); | ||
493 | } | ||
494 | |||
495 | |||
496 | struct GNUNET_SETU_OperationHandle * | ||
497 | GNUNET_SETU_prepare (const struct GNUNET_PeerIdentity *other_peer, | ||
498 | const struct GNUNET_HashCode *app_id, | ||
499 | const struct GNUNET_MessageHeader *context_msg, | ||
500 | const struct GNUNET_SETU_Option options[], | ||
501 | GNUNET_SETU_ResultIterator result_cb, | ||
502 | void *result_cls) | ||
503 | { | ||
504 | struct GNUNET_MQ_Envelope *mqm; | ||
505 | struct GNUNET_SETU_OperationHandle *oh; | ||
506 | struct GNUNET_SETU_EvaluateMessage *msg; | ||
507 | |||
508 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
509 | "Client prepares set union operation\n"); | ||
510 | oh = GNUNET_new (struct GNUNET_SETU_OperationHandle); | ||
511 | oh->result_cb = result_cb; | ||
512 | oh->result_cls = result_cls; | ||
513 | mqm = GNUNET_MQ_msg_nested_mh (msg, | ||
514 | GNUNET_MESSAGE_TYPE_SETU_EVALUATE, | ||
515 | context_msg); | ||
516 | msg->app_id = *app_id; | ||
517 | msg->target_peer = *other_peer; | ||
518 | |||
519 | /* Set default values */ | ||
520 | msg->byzantine_upper_bond = UINT64_MAX; | ||
521 | msg->bandwidth_latency_tradeoff = 0; | ||
522 | msg->ibf_bucket_number_factor = 2; | ||
523 | msg->ibf_number_of_buckets_per_element = 3; | ||
524 | |||
525 | |||
526 | for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++) | ||
527 | { | ||
528 | switch (opt->type) | ||
529 | { | ||
530 | case GNUNET_SETU_OPTION_BYZANTINE: | ||
531 | msg->byzantine = GNUNET_YES; | ||
532 | msg->byzantine_lower_bound = htonl (opt->v.num); | ||
533 | break; | ||
534 | case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND: | ||
535 | msg->byzantine_upper_bond = htonl (opt->v.num); | ||
536 | break; | ||
537 | case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF: | ||
538 | msg->bandwidth_latency_tradeoff = htonl (opt->v.num); | ||
539 | break; | ||
540 | case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR: | ||
541 | msg->ibf_bucket_number_factor = htonl (opt->v.num); | ||
542 | break; | ||
543 | case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT: | ||
544 | msg->ibf_number_of_buckets_per_element = htonl (opt->v.num); | ||
545 | break; | ||
546 | case GNUNET_SETU_OPTION_FORCE_FULL: | ||
547 | msg->force_full = GNUNET_YES; | ||
548 | break; | ||
549 | case GNUNET_SETU_OPTION_FORCE_DELTA: | ||
550 | msg->force_delta = GNUNET_YES; | ||
551 | break; | ||
552 | case GNUNET_SETU_OPTION_SYMMETRIC: | ||
553 | msg->symmetric = GNUNET_YES; | ||
554 | break; | ||
555 | default: | ||
556 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
557 | "Option with type %d not recognized\n", | ||
558 | (int) opt->type); | ||
559 | } | ||
560 | } | ||
561 | oh->conclude_mqm = mqm; | ||
562 | oh->request_id_addr = &msg->request_id; | ||
563 | return oh; | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * Connect to the set service in order to listen for requests. | ||
569 | * | ||
570 | * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect | ||
571 | */ | ||
572 | static void | ||
573 | listen_connect (void *cls); | ||
574 | |||
575 | |||
576 | /** | ||
577 | * Check validity of request message for a listen operation | ||
578 | * | ||
579 | * @param cls the listen handle | ||
580 | * @param msg the message | ||
581 | * @return #GNUNET_OK if the message is well-formed | ||
582 | */ | ||
583 | static int | ||
584 | check_request (void *cls, | ||
585 | const struct GNUNET_SETU_RequestMessage *msg) | ||
586 | { | ||
587 | const struct GNUNET_MessageHeader *context_msg; | ||
588 | |||
589 | if (ntohs (msg->header.size) == sizeof(*msg)) | ||
590 | return GNUNET_OK; /* no context message is OK */ | ||
591 | context_msg = GNUNET_MQ_extract_nested_mh (msg); | ||
592 | if (NULL == context_msg) | ||
593 | { | ||
594 | /* malformed context message is NOT ok */ | ||
595 | GNUNET_break_op (0); | ||
596 | return GNUNET_SYSERR; | ||
597 | } | ||
598 | return GNUNET_OK; | ||
599 | } | ||
600 | |||
601 | |||
602 | /** | ||
603 | * Handle request message for a listen operation | ||
604 | * | ||
605 | * @param cls the listen handle | ||
606 | * @param msg the message | ||
607 | */ | ||
608 | static void | ||
609 | handle_request (void *cls, | ||
610 | const struct GNUNET_SETU_RequestMessage *msg) | ||
611 | { | ||
612 | struct GNUNET_SETU_ListenHandle *lh = cls; | ||
613 | struct GNUNET_SETU_Request req; | ||
614 | const struct GNUNET_MessageHeader *context_msg; | ||
615 | struct GNUNET_MQ_Envelope *mqm; | ||
616 | struct GNUNET_SETU_RejectMessage *rmsg; | ||
617 | |||
618 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
619 | "Processing incoming operation request with id %u\n", | ||
620 | ntohl (msg->accept_id)); | ||
621 | /* we got another valid request => reset the backoff */ | ||
622 | lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
623 | req.accept_id = ntohl (msg->accept_id); | ||
624 | req.accepted = GNUNET_NO; | ||
625 | context_msg = GNUNET_MQ_extract_nested_mh (msg); | ||
626 | /* calling #GNUNET_SETU_accept() in the listen cb will set req->accepted */ | ||
627 | lh->listen_cb (lh->listen_cls, | ||
628 | &msg->peer_id, | ||
629 | context_msg, | ||
630 | &req); | ||
631 | if (GNUNET_YES == req.accepted) | ||
632 | return; /* the accept-case is handled in #GNUNET_SETU_accept() */ | ||
633 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
634 | "Rejected request %u\n", | ||
635 | ntohl (msg->accept_id)); | ||
636 | mqm = GNUNET_MQ_msg (rmsg, | ||
637 | GNUNET_MESSAGE_TYPE_SETU_REJECT); | ||
638 | rmsg->accept_reject_id = msg->accept_id; | ||
639 | GNUNET_MQ_send (lh->mq, | ||
640 | mqm); | ||
641 | } | ||
642 | |||
643 | |||
644 | /** | ||
645 | * Our connection with the set service encountered an error, | ||
646 | * re-initialize with exponential back-off. | ||
647 | * | ||
648 | * @param cls the `struct GNUNET_SETU_ListenHandle *` | ||
649 | * @param error reason for the disconnect | ||
650 | */ | ||
651 | static void | ||
652 | handle_client_listener_error (void *cls, | ||
653 | enum GNUNET_MQ_Error error) | ||
654 | { | ||
655 | struct GNUNET_SETU_ListenHandle *lh = cls; | ||
656 | |||
657 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
658 | "Listener broke down (%d), re-connecting\n", | ||
659 | (int) error); | ||
660 | GNUNET_MQ_destroy (lh->mq); | ||
661 | lh->mq = NULL; | ||
662 | lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff, | ||
663 | &listen_connect, | ||
664 | lh); | ||
665 | lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff); | ||
666 | } | ||
667 | |||
668 | |||
669 | /** | ||
670 | * Connect to the set service in order to listen for requests. | ||
671 | * | ||
672 | * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect | ||
673 | */ | ||
674 | static void | ||
675 | listen_connect (void *cls) | ||
676 | { | ||
677 | struct GNUNET_SETU_ListenHandle *lh = cls; | ||
678 | struct GNUNET_MQ_MessageHandler mq_handlers[] = { | ||
679 | GNUNET_MQ_hd_var_size (request, | ||
680 | GNUNET_MESSAGE_TYPE_SETU_REQUEST, | ||
681 | struct GNUNET_SETU_RequestMessage, | ||
682 | lh), | ||
683 | GNUNET_MQ_handler_end () | ||
684 | }; | ||
685 | struct GNUNET_MQ_Envelope *mqm; | ||
686 | struct GNUNET_SETU_ListenMessage *msg; | ||
687 | |||
688 | lh->reconnect_task = NULL; | ||
689 | GNUNET_assert (NULL == lh->mq); | ||
690 | lh->mq = GNUNET_CLIENT_connect (lh->cfg, | ||
691 | "setu", | ||
692 | mq_handlers, | ||
693 | &handle_client_listener_error, | ||
694 | lh); | ||
695 | if (NULL == lh->mq) | ||
696 | return; | ||
697 | mqm = GNUNET_MQ_msg (msg, | ||
698 | GNUNET_MESSAGE_TYPE_SETU_LISTEN); | ||
699 | msg->app_id = lh->app_id; | ||
700 | GNUNET_MQ_send (lh->mq, | ||
701 | mqm); | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Wait for set operation requests for the given application id | ||
707 | * | ||
708 | * @param cfg configuration to use for connecting to | ||
709 | * the set service, needs to be valid for the lifetime of the listen handle | ||
710 | * @param app_id id of the application that handles set operation requests | ||
711 | * @param listen_cb called for each incoming request matching the operation | ||
712 | * and application id | ||
713 | * @param listen_cls handle for @a listen_cb | ||
714 | * @return a handle that can be used to cancel the listen operation | ||
715 | */ | ||
716 | struct GNUNET_SETU_ListenHandle * | ||
717 | GNUNET_SETU_listen (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
718 | const struct GNUNET_HashCode *app_id, | ||
719 | GNUNET_SETU_ListenCallback listen_cb, | ||
720 | void *listen_cls) | ||
721 | { | ||
722 | struct GNUNET_SETU_ListenHandle *lh; | ||
723 | |||
724 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
725 | "Starting listener for app %s\n", | ||
726 | GNUNET_h2s (app_id)); | ||
727 | lh = GNUNET_new (struct GNUNET_SETU_ListenHandle); | ||
728 | lh->listen_cb = listen_cb; | ||
729 | lh->listen_cls = listen_cls; | ||
730 | lh->cfg = cfg; | ||
731 | lh->app_id = *app_id; | ||
732 | lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
733 | listen_connect (lh); | ||
734 | if (NULL == lh->mq) | ||
735 | { | ||
736 | GNUNET_free (lh); | ||
737 | return NULL; | ||
738 | } | ||
739 | return lh; | ||
740 | } | ||
741 | |||
742 | |||
743 | /** | ||
744 | * Cancel the given listen operation. | ||
745 | * | ||
746 | * @param lh handle for the listen operation | ||
747 | */ | ||
748 | void | ||
749 | GNUNET_SETU_listen_cancel (struct GNUNET_SETU_ListenHandle *lh) | ||
750 | { | ||
751 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
752 | "Canceling listener %s\n", | ||
753 | GNUNET_h2s (&lh->app_id)); | ||
754 | if (NULL != lh->mq) | ||
755 | { | ||
756 | GNUNET_MQ_destroy (lh->mq); | ||
757 | lh->mq = NULL; | ||
758 | } | ||
759 | if (NULL != lh->reconnect_task) | ||
760 | { | ||
761 | GNUNET_SCHEDULER_cancel (lh->reconnect_task); | ||
762 | lh->reconnect_task = NULL; | ||
763 | } | ||
764 | GNUNET_free (lh); | ||
765 | } | ||
766 | |||
767 | |||
768 | struct GNUNET_SETU_OperationHandle * | ||
769 | GNUNET_SETU_accept (struct GNUNET_SETU_Request *request, | ||
770 | const struct GNUNET_SETU_Option options[], | ||
771 | GNUNET_SETU_ResultIterator result_cb, | ||
772 | void *result_cls) | ||
773 | { | ||
774 | struct GNUNET_MQ_Envelope *mqm; | ||
775 | struct GNUNET_SETU_OperationHandle *oh; | ||
776 | struct GNUNET_SETU_AcceptMessage *msg; | ||
777 | |||
778 | GNUNET_assert (GNUNET_NO == request->accepted); | ||
779 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
780 | "Client accepts set union operation with id %u\n", | ||
781 | request->accept_id); | ||
782 | request->accepted = GNUNET_YES; | ||
783 | mqm = GNUNET_MQ_msg (msg, | ||
784 | GNUNET_MESSAGE_TYPE_SETU_ACCEPT); | ||
785 | msg->accept_reject_id = htonl (request->accept_id); | ||
786 | |||
787 | /* Set default values */ | ||
788 | msg->byzantine_upper_bond = UINT64_MAX; | ||
789 | msg->bandwidth_latency_tradeoff = 0; | ||
790 | msg->ibf_bucket_number_factor = 2; | ||
791 | msg->ibf_number_of_buckets_per_element = 3; | ||
792 | |||
793 | for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++) | ||
794 | { | ||
795 | switch (opt->type) | ||
796 | { | ||
797 | case GNUNET_SETU_OPTION_BYZANTINE: | ||
798 | msg->byzantine = GNUNET_YES; | ||
799 | msg->byzantine_lower_bound = htonl (opt->v.num); | ||
800 | break; | ||
801 | case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND: | ||
802 | msg->byzantine_upper_bond = htonl (opt->v.num); | ||
803 | break; | ||
804 | case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF: | ||
805 | msg->bandwidth_latency_tradeoff = htonl (opt->v.num); | ||
806 | break; | ||
807 | case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR: | ||
808 | msg->ibf_bucket_number_factor = htonl (opt->v.num); | ||
809 | break; | ||
810 | case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT: | ||
811 | msg->ibf_number_of_buckets_per_element = htonl (opt->v.num); | ||
812 | break; | ||
813 | case GNUNET_SETU_OPTION_FORCE_FULL: | ||
814 | msg->force_full = GNUNET_YES; | ||
815 | break; | ||
816 | case GNUNET_SETU_OPTION_FORCE_DELTA: | ||
817 | msg->force_delta = GNUNET_YES; | ||
818 | break; | ||
819 | case GNUNET_SETU_OPTION_SYMMETRIC: | ||
820 | msg->symmetric = GNUNET_YES; | ||
821 | break; | ||
822 | default: | ||
823 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
824 | "Option with type %d not recognized\n", | ||
825 | (int) opt->type); | ||
826 | } | ||
827 | } | ||
828 | oh = GNUNET_new (struct GNUNET_SETU_OperationHandle); | ||
829 | oh->result_cb = result_cb; | ||
830 | oh->result_cls = result_cls; | ||
831 | oh->conclude_mqm = mqm; | ||
832 | oh->request_id_addr = &msg->request_id; | ||
833 | return oh; | ||
834 | } | ||
835 | |||
836 | |||
837 | /** | ||
838 | * Commit a set to be used with a set operation. | ||
839 | * This function is called once we have fully constructed | ||
840 | * the set that we want to use for the operation. At this | ||
841 | * time, the P2P protocol can then begin to exchange the | ||
842 | * set information and call the result callback with the | ||
843 | * result information. | ||
844 | * | ||
845 | * @param oh handle to the set operation | ||
846 | * @param set the set to use for the operation | ||
847 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the | ||
848 | * set is invalid (e.g. the set service crashed) | ||
849 | */ | ||
850 | int | ||
851 | GNUNET_SETU_commit (struct GNUNET_SETU_OperationHandle *oh, | ||
852 | struct GNUNET_SETU_Handle *set) | ||
853 | { | ||
854 | if (NULL != oh->set) | ||
855 | { | ||
856 | /* Some other set was already committed for this | ||
857 | * operation, there is a logic bug in the client of this API */ | ||
858 | GNUNET_break (0); | ||
859 | return GNUNET_OK; | ||
860 | } | ||
861 | GNUNET_assert (NULL != set); | ||
862 | if (GNUNET_YES == set->invalid) | ||
863 | return GNUNET_SYSERR; | ||
864 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | "Client commits to SET\n"); | ||
866 | GNUNET_assert (NULL != oh->conclude_mqm); | ||
867 | oh->set = set; | ||
868 | GNUNET_CONTAINER_DLL_insert (set->ops_head, | ||
869 | set->ops_tail, | ||
870 | oh); | ||
871 | oh->request_id = GNUNET_MQ_assoc_add (set->mq, | ||
872 | oh); | ||
873 | *oh->request_id_addr = htonl (oh->request_id); | ||
874 | GNUNET_MQ_send (set->mq, | ||
875 | oh->conclude_mqm); | ||
876 | oh->conclude_mqm = NULL; | ||
877 | oh->request_id_addr = NULL; | ||
878 | return GNUNET_OK; | ||
879 | } | ||
880 | |||
881 | |||
882 | /** | ||
883 | * Hash a set element. | ||
884 | * | ||
885 | * @param element the element that should be hashed | ||
886 | * @param[out] ret_hash a pointer to where the hash of @a element | ||
887 | * should be stored | ||
888 | */ | ||
889 | void | ||
890 | GNUNET_SETU_element_hash (const struct GNUNET_SETU_Element *element, | ||
891 | struct GNUNET_HashCode *ret_hash) | ||
892 | { | ||
893 | struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start (); | ||
894 | |||
895 | /* It's not guaranteed that the element data is always after the element header, | ||
896 | so we need to hash the chunks separately. */ | ||
897 | GNUNET_CRYPTO_hash_context_read (ctx, | ||
898 | &element->size, | ||
899 | sizeof(uint16_t)); | ||
900 | GNUNET_CRYPTO_hash_context_read (ctx, | ||
901 | &element->element_type, | ||
902 | sizeof(uint16_t)); | ||
903 | GNUNET_CRYPTO_hash_context_read (ctx, | ||
904 | element->data, | ||
905 | element->size); | ||
906 | GNUNET_CRYPTO_hash_context_finish (ctx, | ||
907 | ret_hash); | ||
908 | } | ||
909 | |||
910 | |||
911 | /* end of setu_api.c */ | ||
diff --git a/src/setu/test_setu.conf b/src/setu/test_setu.conf deleted file mode 100644 index 6d132fc1f..000000000 --- a/src/setu/test_setu.conf +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-set/ | ||
5 | |||
6 | [setu] | ||
7 | START_ON_DEMAND = YES | ||
8 | #PREFIX = valgrind --leak-check=full | ||
9 | #PREFIX = gdbserver :1234 | ||
10 | OPTIONS = -L INFO | ||
11 | |||
12 | [transport] | ||
13 | PLUGINS = unix | ||
14 | OPTIONS = -LERROR | ||
15 | |||
16 | [nat] | ||
17 | RETURN_LOCAL_ADDRESSES = YES | ||
18 | DISABLEV6 = YES | ||
19 | USE_LOCALADDR = YES | ||
20 | |||
21 | [peerinfo] | ||
22 | NO_IO = YES | ||
23 | |||
24 | [nat] | ||
25 | # Use addresses from the local network interfaces (including loopback, but also others) | ||
26 | USE_LOCALADDR = YES | ||
27 | |||
28 | # Disable IPv6 support | ||
29 | DISABLEV6 = NO | ||
30 | |||
31 | # Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8) | ||
32 | RETURN_LOCAL_ADDRESSES = YES | ||
diff --git a/src/setu/test_setu_api.c b/src/setu/test_setu_api.c deleted file mode 100644 index 5a0c9d70d..000000000 --- a/src/setu/test_setu_api.c +++ /dev/null | |||
@@ -1,360 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file set/test_setu_api.c | ||
23 | * @brief testcase for setu_api.c | ||
24 | * @author Florian Dold | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | #include "gnunet_setu_service.h" | ||
30 | |||
31 | |||
32 | static struct GNUNET_PeerIdentity local_id; | ||
33 | |||
34 | static struct GNUNET_HashCode app_id; | ||
35 | |||
36 | static struct GNUNET_SETU_Handle *set1; | ||
37 | |||
38 | static struct GNUNET_SETU_Handle *set2; | ||
39 | |||
40 | static struct GNUNET_SETU_ListenHandle *listen_handle; | ||
41 | |||
42 | static struct GNUNET_SETU_OperationHandle *oh1; | ||
43 | |||
44 | static struct GNUNET_SETU_OperationHandle *oh2; | ||
45 | |||
46 | static const struct GNUNET_CONFIGURATION_Handle *config; | ||
47 | |||
48 | static int ret; | ||
49 | |||
50 | static struct GNUNET_SCHEDULER_Task *tt; | ||
51 | |||
52 | |||
53 | static void | ||
54 | result_cb_set1 (void *cls, | ||
55 | const struct GNUNET_SETU_Element *element, | ||
56 | uint64_t size, | ||
57 | enum GNUNET_SETU_Status status) | ||
58 | { | ||
59 | switch (status) | ||
60 | { | ||
61 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
62 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 1: got element\n"); | ||
63 | break; | ||
64 | |||
65 | case GNUNET_SETU_STATUS_FAILURE: | ||
66 | GNUNET_break (0); | ||
67 | oh1 = NULL; | ||
68 | fprintf (stderr, "set 1: received failure status!\n"); | ||
69 | ret = 1; | ||
70 | if (NULL != tt) | ||
71 | { | ||
72 | GNUNET_SCHEDULER_cancel (tt); | ||
73 | tt = NULL; | ||
74 | } | ||
75 | GNUNET_SCHEDULER_shutdown (); | ||
76 | break; | ||
77 | |||
78 | case GNUNET_SETU_STATUS_DONE: | ||
79 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 1: done\n"); | ||
80 | oh1 = NULL; | ||
81 | if (NULL != set1) | ||
82 | { | ||
83 | GNUNET_SETU_destroy (set1); | ||
84 | set1 = NULL; | ||
85 | } | ||
86 | if (NULL == set2) | ||
87 | { | ||
88 | GNUNET_SCHEDULER_cancel (tt); | ||
89 | tt = NULL; | ||
90 | GNUNET_SCHEDULER_shutdown (); | ||
91 | } | ||
92 | break; | ||
93 | |||
94 | default: | ||
95 | GNUNET_assert (0); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | static void | ||
101 | result_cb_set2 (void *cls, | ||
102 | const struct GNUNET_SETU_Element *element, | ||
103 | uint64_t size, | ||
104 | enum GNUNET_SETU_Status status) | ||
105 | { | ||
106 | switch (status) | ||
107 | { | ||
108 | case GNUNET_SETU_STATUS_ADD_LOCAL: | ||
109 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 2: got element\n"); | ||
110 | break; | ||
111 | |||
112 | case GNUNET_SETU_STATUS_FAILURE: | ||
113 | GNUNET_break (0); | ||
114 | oh2 = NULL; | ||
115 | fprintf (stderr, "set 2: received failure status\n"); | ||
116 | GNUNET_SCHEDULER_shutdown (); | ||
117 | ret = 1; | ||
118 | break; | ||
119 | |||
120 | case GNUNET_SETU_STATUS_DONE: | ||
121 | oh2 = NULL; | ||
122 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "set 2: done\n"); | ||
123 | GNUNET_SETU_destroy (set2); | ||
124 | set2 = NULL; | ||
125 | if (NULL == set1) | ||
126 | { | ||
127 | GNUNET_SCHEDULER_cancel (tt); | ||
128 | tt = NULL; | ||
129 | GNUNET_SCHEDULER_shutdown (); | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | default: | ||
134 | GNUNET_assert (0); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | |||
139 | static void | ||
140 | listen_cb (void *cls, | ||
141 | const struct GNUNET_PeerIdentity *other_peer, | ||
142 | const struct GNUNET_MessageHeader *context_msg, | ||
143 | struct GNUNET_SETU_Request *request) | ||
144 | { | ||
145 | GNUNET_assert (NULL != context_msg); | ||
146 | GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY); | ||
147 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "listen cb called\n"); | ||
148 | oh2 = GNUNET_SETU_accept (request, | ||
149 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
150 | &result_cb_set2, | ||
151 | NULL); | ||
152 | GNUNET_SETU_commit (oh2, set2); | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Start the set operation. | ||
158 | * | ||
159 | * @param cls closure, unused | ||
160 | */ | ||
161 | static void | ||
162 | start (void *cls) | ||
163 | { | ||
164 | struct GNUNET_MessageHeader context_msg; | ||
165 | |||
166 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting reconciliation\n"); | ||
167 | context_msg.size = htons (sizeof context_msg); | ||
168 | context_msg.type = htons (GNUNET_MESSAGE_TYPE_DUMMY); | ||
169 | listen_handle = GNUNET_SETU_listen (config, | ||
170 | &app_id, | ||
171 | &listen_cb, | ||
172 | NULL); | ||
173 | oh1 = GNUNET_SETU_prepare (&local_id, | ||
174 | &app_id, | ||
175 | &context_msg, | ||
176 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
177 | &result_cb_set1, | ||
178 | NULL); | ||
179 | GNUNET_SETU_commit (oh1, set1); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Initialize the second set, continue | ||
185 | * | ||
186 | * @param cls closure, unused | ||
187 | */ | ||
188 | static void | ||
189 | init_set2 (void *cls) | ||
190 | { | ||
191 | struct GNUNET_SETU_Element element; | ||
192 | |||
193 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initializing set 2\n"); | ||
194 | |||
195 | element.element_type = 0; | ||
196 | element.data = "hello1"; | ||
197 | element.size = strlen (element.data); | ||
198 | GNUNET_SETU_add_element (set2, &element, NULL, NULL); | ||
199 | element.data = "quux"; | ||
200 | element.size = strlen (element.data); | ||
201 | GNUNET_SETU_add_element (set2, &element, NULL, NULL); | ||
202 | element.data = "baz"; | ||
203 | element.size = strlen (element.data); | ||
204 | GNUNET_SETU_add_element (set2, &element, &start, NULL); | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Initialize the first set, continue. | ||
210 | */ | ||
211 | static void | ||
212 | init_set1 (void) | ||
213 | { | ||
214 | struct GNUNET_SETU_Element element; | ||
215 | |||
216 | element.element_type = 0; | ||
217 | element.data = "hello"; | ||
218 | element.size = strlen (element.data); | ||
219 | GNUNET_SETU_add_element (set1, &element, NULL, NULL); | ||
220 | element.data = "bar"; | ||
221 | element.size = strlen (element.data); | ||
222 | GNUNET_SETU_add_element (set1, &element, &init_set2, NULL); | ||
223 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initialized set 1\n"); | ||
224 | } | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Function run on timeout. | ||
229 | * | ||
230 | * @param cls closure | ||
231 | */ | ||
232 | static void | ||
233 | timeout_fail (void *cls) | ||
234 | { | ||
235 | tt = NULL; | ||
236 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Testcase failed with timeout\n"); | ||
237 | GNUNET_SCHEDULER_shutdown (); | ||
238 | ret = 1; | ||
239 | } | ||
240 | |||
241 | |||
242 | /** | ||
243 | * Function run on shutdown. | ||
244 | * | ||
245 | * @param cls closure | ||
246 | */ | ||
247 | static void | ||
248 | do_shutdown (void *cls) | ||
249 | { | ||
250 | if (NULL != tt) | ||
251 | { | ||
252 | GNUNET_SCHEDULER_cancel (tt); | ||
253 | tt = NULL; | ||
254 | } | ||
255 | if (NULL != oh1) | ||
256 | { | ||
257 | GNUNET_SETU_operation_cancel (oh1); | ||
258 | oh1 = NULL; | ||
259 | } | ||
260 | if (NULL != oh2) | ||
261 | { | ||
262 | GNUNET_SETU_operation_cancel (oh2); | ||
263 | oh2 = NULL; | ||
264 | } | ||
265 | if (NULL != set1) | ||
266 | { | ||
267 | GNUNET_SETU_destroy (set1); | ||
268 | set1 = NULL; | ||
269 | } | ||
270 | if (NULL != set2) | ||
271 | { | ||
272 | GNUNET_SETU_destroy (set2); | ||
273 | set2 = NULL; | ||
274 | } | ||
275 | if (NULL != listen_handle) | ||
276 | { | ||
277 | GNUNET_SETU_listen_cancel (listen_handle); | ||
278 | listen_handle = NULL; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Signature of the 'main' function for a (single-peer) testcase that | ||
285 | * is run using 'GNUNET_TESTING_peer_run'. | ||
286 | * | ||
287 | * @param cls closure | ||
288 | * @param cfg configuration of the peer that was started | ||
289 | * @param peer identity of the peer that was created | ||
290 | */ | ||
291 | static void | ||
292 | run (void *cls, | ||
293 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
294 | struct GNUNET_TESTING_Peer *peer) | ||
295 | { | ||
296 | struct GNUNET_SETU_OperationHandle *my_oh; | ||
297 | |||
298 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
299 | "Running preparatory tests\n"); | ||
300 | tt = GNUNET_SCHEDULER_add_delayed ( | ||
301 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), | ||
302 | &timeout_fail, | ||
303 | NULL); | ||
304 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
305 | |||
306 | config = cfg; | ||
307 | GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_get_peer_identity (cfg, | ||
308 | &local_id)); | ||
309 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
310 | "my id (from CRYPTO): %s\n", | ||
311 | GNUNET_i2s (&local_id)); | ||
312 | GNUNET_TESTING_peer_get_identity (peer, | ||
313 | &local_id); | ||
314 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
315 | "my id (from TESTING): %s\n", | ||
316 | GNUNET_i2s (&local_id)); | ||
317 | set1 = GNUNET_SETU_create (cfg); | ||
318 | set2 = GNUNET_SETU_create (cfg); | ||
319 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
320 | "Created sets %p and %p for union operation\n", | ||
321 | set1, | ||
322 | set2); | ||
323 | GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id); | ||
324 | |||
325 | /* test if canceling an uncommitted request works! */ | ||
326 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
327 | "Launching and instantly stopping set operation\n"); | ||
328 | my_oh = GNUNET_SETU_prepare (&local_id, | ||
329 | &app_id, | ||
330 | NULL, | ||
331 | (struct GNUNET_SETU_Option[]){ 0 }, | ||
332 | NULL, | ||
333 | NULL); | ||
334 | GNUNET_SETU_operation_cancel (my_oh); | ||
335 | |||
336 | /* test the real set reconciliation */ | ||
337 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
338 | "Running real set-reconciliation\n"); | ||
339 | init_set1 (); | ||
340 | } | ||
341 | |||
342 | |||
343 | int | ||
344 | main (int argc, char **argv) | ||
345 | { | ||
346 | GNUNET_log_setup ("test_setu_api", | ||
347 | "WARNING", | ||
348 | NULL); | ||
349 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
350 | "Launching peer\n"); | ||
351 | if (0 != | ||
352 | GNUNET_TESTING_peer_run ("test_setu_api", | ||
353 | "test_setu.conf", | ||
354 | &run, | ||
355 | NULL)) | ||
356 | { | ||
357 | return 1; | ||
358 | } | ||
359 | return ret; | ||
360 | } | ||