aboutsummaryrefslogtreecommitdiff
path: root/src/dht
diff options
context:
space:
mode:
Diffstat (limited to 'src/dht')
-rw-r--r--src/dht/.gitignore12
-rw-r--r--src/dht/Makefile.am222
-rw-r--r--src/dht/dht.conf.in35
-rw-r--r--src/dht/dht.h408
-rw-r--r--src/dht/dht_api.c1253
-rw-r--r--src/dht/dht_test_lib.c202
-rw-r--r--src/dht/dht_test_lib.h95
-rw-r--r--src/dht/gnunet-dht-get.c310
-rw-r--r--src/dht/gnunet-dht-monitor.c345
-rw-r--r--src/dht/gnunet-dht-put.c250
-rw-r--r--src/dht/gnunet-service-dht.c164
-rw-r--r--src/dht/gnunet-service-dht.h131
-rw-r--r--src/dht/gnunet-service-dht_clients.c1531
-rw-r--r--src/dht/gnunet-service-dht_datacache.c365
-rw-r--r--src/dht/gnunet-service-dht_datacache.h147
-rw-r--r--src/dht/gnunet-service-dht_hello.c154
-rw-r--r--src/dht/gnunet-service-dht_hello.h55
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c2532
-rw-r--r--src/dht/gnunet-service-dht_neighbours.h164
-rw-r--r--src/dht/gnunet-service-dht_nse.c121
-rw-r--r--src/dht/gnunet-service-dht_nse.h52
-rw-r--r--src/dht/gnunet-service-dht_routing.c419
-rw-r--r--src/dht/gnunet-service-dht_routing.h87
-rw-r--r--src/dht/gnunet_dht_profiler.c1029
-rw-r--r--src/dht/plugin_block_dht.c393
-rw-r--r--src/dht/test_dht_2dtorus.conf37
-rw-r--r--src/dht/test_dht_api.c193
-rw-r--r--src/dht/test_dht_api_data.conf44
-rw-r--r--src/dht/test_dht_api_peer1.conf41
-rw-r--r--src/dht/test_dht_line.conf38
-rw-r--r--src/dht/test_dht_monitor.c435
-rw-r--r--src/dht/test_dht_monitor.conf39
-rw-r--r--src/dht/test_dht_multipeer.conf40
-rw-r--r--src/dht/test_dht_multipeer_topology.dat11
-rw-r--r--src/dht/test_dht_tools.conf157
-rw-r--r--src/dht/test_dht_tools.py.in149
-rwxr-xr-xsrc/dht/test_dht_tools.sh64
-rw-r--r--src/dht/test_dht_topo.c624
38 files changed, 0 insertions, 12348 deletions
diff --git a/src/dht/.gitignore b/src/dht/.gitignore
deleted file mode 100644
index 25b1daf28..000000000
--- a/src/dht/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
1gnunet-dht-get
2gnunet-dht-monitor
3gnunet-dht-profiler
4gnunet-dht-put
5gnunet-service-dht
6test_dht_2dtorus
7test_dht_api
8test_dht_line
9test_dht_monitor
10test_dht_multipeer
11test_dht_tools.py
12test_dht_twopeer
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
deleted file mode 100644
index be48fab02..000000000
--- a/src/dht/Makefile.am
+++ /dev/null
@@ -1,222 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 dht.conf
12
13if USE_COVERAGE
14 AM_CFLAGS = --coverage -O0
15 XLIB = -lgcov
16endif
17
18lib_LTLIBRARIES = \
19 libgnunetdht.la
20
21libgnunetdht_la_SOURCES = \
22 dht_api.c dht.h
23libgnunetdht_la_LIBADD = \
24 $(top_builddir)/src/util/libgnunetutil.la \
25 $(XLIB) \
26 $(LTLIBINTL)
27libgnunetdht_la_LDFLAGS = \
28 $(GN_LIB_LDFLAGS) \
29 -version-info 3:0:0
30
31
32plugin_LTLIBRARIES = \
33 libgnunet_plugin_block_dht.la
34
35libgnunet_plugin_block_dht_la_SOURCES = \
36 plugin_block_dht.c
37libgnunet_plugin_block_dht_la_LIBADD = \
38 $(top_builddir)/src/hello/libgnunethello.la \
39 $(top_builddir)/src/block/libgnunetblock.la \
40 $(top_builddir)/src/block/libgnunetblockgroup.la \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(LTLIBINTL)
43libgnunet_plugin_block_dht_la_LDFLAGS = \
44 $(GN_PLUGIN_LDFLAGS)
45
46
47libexec_PROGRAMS = \
48 gnunet-service-dht
49
50bin_PROGRAMS = \
51 gnunet-dht-monitor \
52 gnunet-dht-get \
53 gnunet-dht-put
54
55noinst_PROGRAMS = \
56 gnunet-dht-profiler
57
58gnunet_service_dht_SOURCES = \
59 gnunet-service-dht.c gnunet-service-dht.h \
60 gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \
61 gnunet-service-dht_hello.c gnunet-service-dht_hello.h \
62 gnunet-service-dht_nse.c gnunet-service-dht_nse.h \
63 gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \
64 gnunet-service-dht_routing.c gnunet-service-dht_routing.h
65gnunet_service_dht_LDADD = \
66 libgnunetdht.la \
67 $(top_builddir)/src/statistics/libgnunetstatistics.la \
68 $(top_builddir)/src/core/libgnunetcore.la \
69 $(top_builddir)/src/nse/libgnunetnse.la \
70 $(top_builddir)/src/ats/libgnunetats.la \
71 $(top_builddir)/src/transport/libgnunettransport.la \
72 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
73 $(top_builddir)/src/hello/libgnunethello.la \
74 $(top_builddir)/src/block/libgnunetblock.la \
75 $(top_builddir)/src/datacache/libgnunetdatacache.la \
76 $(top_builddir)/src/util/libgnunetutil.la \
77 -lm
78gnunet_service_dht_LDFLAGS = \
79 $(GN_LIBINTL)
80
81gnunet_dht_get_SOURCES = \
82 gnunet-dht-get.c
83gnunet_dht_get_LDADD = \
84 libgnunetdht.la \
85 $(top_builddir)/src/core/libgnunetcore.la \
86 $(top_builddir)/src/util/libgnunetutil.la
87gnunet_dht_get_LDFLAGS = \
88 $(GN_LIBINTL)
89
90gnunet_dht_put_SOURCES = \
91 gnunet-dht-put.c
92gnunet_dht_put_LDADD = \
93 libgnunetdht.la \
94 $(top_builddir)/src/core/libgnunetcore.la \
95 $(top_builddir)/src/util/libgnunetutil.la
96gnunet_dht_put_LDFLAGS = \
97 $(GN_LIBINTL)
98
99gnunet_dht_monitor_SOURCES = \
100 gnunet-dht-monitor.c
101gnunet_dht_monitor_LDADD = \
102 libgnunetdht.la \
103 $(top_builddir)/src/core/libgnunetcore.la \
104 $(top_builddir)/src/util/libgnunetutil.la
105gnunet_dht_monitor_LDFLAGS = \
106 $(GN_LIBINTL)
107
108gnunet_dht_profiler_SOURCES = \
109 gnunet_dht_profiler.c
110gnunet_dht_profiler_LDADD = \
111 libgnunetdht.la \
112 $(top_builddir)/src/core/libgnunetcore.la \
113 $(top_builddir)/src/util/libgnunetutil.la \
114 $(top_builddir)/src/testing/libgnunettesting.la \
115 $(top_builddir)/src/testbed/libgnunettestbed.la
116gnunet_dht_profiler_LDFLAGS = \
117 $(GN_LIBINTL)
118
119noinst_LIBRARIES = libgnunetdhttest.a
120
121libgnunetdhttest_a_SOURCES = \
122 dht_test_lib.c dht_test_lib.h
123libgnunetdhttest_a_LIBADD = \
124 $(top_builddir)/src/util/libgnunetutil.la \
125 $(top_builddir)/src/testbed/libgnunettestbed.la \
126 libgnunetdht.la
127
128check_PROGRAMS = \
129 test_dht_api \
130 test_dht_twopeer \
131 test_dht_multipeer \
132 test_dht_line \
133 test_dht_2dtorus \
134 test_dht_monitor
135
136if HAVE_EXPERIMENTAL
137# These tests still do not work as testbed does
138# not support the respective topology op
139 NEW_TESTS = test_dht_2dtorus test_dht_multipeer
140endif
141
142if ENABLE_TEST_RUN
143AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
144TESTS = test_dht_api $(check_SCRIPTS) \
145 test_dht_twopeer \
146 test_dht_line \
147 test_dht_monitor \
148 $(NEW_TESTS)
149endif
150
151test_dht_api_SOURCES = \
152 test_dht_api.c
153test_dht_api_LDADD = \
154 $(top_builddir)/src/util/libgnunetutil.la \
155 $(top_builddir)/src/testing/libgnunettesting.la \
156 $(top_builddir)/src/hello/libgnunethello.la \
157 libgnunetdht.la
158
159test_dht_twopeer_SOURCES = \
160 test_dht_topo.c
161test_dht_twopeer_LDADD = \
162 libgnunetdhttest.a \
163 $(top_builddir)/src/util/libgnunetutil.la \
164 libgnunetdhttest.a \
165 $(top_builddir)/src/testbed/libgnunettestbed.la \
166 libgnunetdht.la
167
168test_dht_2dtorus_SOURCES = \
169 test_dht_topo.c
170test_dht_2dtorus_LDADD = \
171 libgnunetdhttest.a \
172 $(top_builddir)/src/util/libgnunetutil.la \
173 $(top_builddir)/src/testbed/libgnunettestbed.la \
174 libgnunetdht.la
175
176test_dht_line_SOURCES = \
177 test_dht_topo.c
178test_dht_line_LDADD = \
179 libgnunetdhttest.a \
180 $(top_builddir)/src/util/libgnunetutil.la \
181 $(top_builddir)/src/testbed/libgnunettestbed.la \
182 libgnunetdht.la
183
184test_dht_multipeer_SOURCES = \
185 test_dht_topo.c
186test_dht_multipeer_LDADD = \
187 libgnunetdhttest.a \
188 $(top_builddir)/src/util/libgnunetutil.la \
189 $(top_builddir)/src/statistics/libgnunetstatistics.la \
190 $(top_builddir)/src/testbed/libgnunettestbed.la \
191 libgnunetdht.la
192
193test_dht_monitor_SOURCES = \
194 test_dht_monitor.c
195test_dht_monitor_LDADD = \
196 libgnunetdhttest.a \
197 $(top_builddir)/src/util/libgnunetutil.la \
198 $(top_builddir)/src/testbed/libgnunettestbed.la \
199 libgnunetdht.la
200
201EXTRA_DIST = \
202 $(check_SCRIPTS) \
203 gnunet-service-dht_clients.c \
204 test_dht_api_data.conf \
205 test_dht_api_peer1.conf \
206 test_dht_monitor.conf \
207 test_dht_multipeer.conf \
208 test_dht_2dtorus.conf \
209 test_dht_line.conf \
210 test_dht_tools.conf \
211 test_dht_tools.py.in \
212 test_dht_multipeer_topology.dat
213
214if HAVE_PYTHON
215check_SCRIPTS = \
216 test_dht_tools.py
217endif
218
219SUFFIXES = .py.in .py
220.py.in.py:
221 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/$< > $@
222 chmod +x $@
diff --git a/src/dht/dht.conf.in b/src/dht/dht.conf.in
deleted file mode 100644
index 405ef1917..000000000
--- a/src/dht/dht.conf.in
+++ /dev/null
@@ -1,35 +0,0 @@
1[dht]
2IMMEDIATE_START = YES
3START_ON_DEMAND = @START_ON_DEMAND@
4@JAVAPORT@PORT = 2095
5HOSTNAME = localhost
6BINARY = gnunet-service-dht
7ACCEPT_FROM = 127.0.0.1;
8ACCEPT_FROM6 = ::1;
9BUCKET_SIZE = 4
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-dht.sock
11UNIX_MATCH_UID = NO
12UNIX_MATCH_GID = YES
13# DISABLE_SOCKET_FORWARDING = NO
14# USERNAME =
15# MAXBUF =
16# TIMEOUT =
17# DISABLEV6 =
18# BINDTO =
19# REJECT_FROM =
20# REJECT_FROM6 =
21# PREFIX =
22
23# Should the DHT cache results that we are routing in the DATACACHE as well?
24CACHE_RESULTS = YES
25
26# Special option to disable DHT calling 'try_connect' (for testing)
27DISABLE_TRY_CONNECT = NO
28
29
30[dhtcache]
31DATABASE = heap
32QUOTA = 50 MB
33
34# Disable RC-file for Bloom filter? (for benchmarking with limited IO availability)
35DISABLE_BF_RC = NO
diff --git a/src/dht/dht.h b/src/dht/dht.h
deleted file mode 100644
index c69b69f07..000000000
--- a/src/dht/dht.h
+++ /dev/null
@@ -1,408 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2009, 2011, 2021 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 * @author Christian Grothoff
23 * @author Nathan Evans
24 * @file dht/dht.h
25 */
26
27#ifndef DHT_H
28#define DHT_H
29
30
31/**
32 * Size of the bloom filter the DHT uses to filter peers.
33 */
34#define DHT_BLOOM_SIZE 128
35
36
37GNUNET_NETWORK_STRUCT_BEGIN
38
39/**
40 * Message which indicates the DHT should cancel outstanding
41 * requests and discard any state.
42 */
43struct GNUNET_DHT_ClientGetStopMessage
44{
45 /**
46 * Type: #GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP
47 */
48 struct GNUNET_MessageHeader header;
49
50 /**
51 * Always zero.
52 */
53 uint32_t reserved GNUNET_PACKED;
54
55 /**
56 * Unique ID identifying this request
57 */
58 uint64_t unique_id GNUNET_PACKED;
59
60 /**
61 * Key of this request
62 */
63 struct GNUNET_HashCode key;
64};
65
66
67/**
68 * DHT GET message sent from clients to service. Indicates that a GET
69 * request should be issued.
70 */
71struct GNUNET_DHT_ClientGetMessage
72{
73 /**
74 * Type: #GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
80 */
81 uint32_t options GNUNET_PACKED;
82
83 /**
84 * Replication level for this message
85 */
86 uint32_t desired_replication_level GNUNET_PACKED;
87
88 /**
89 * The type for the data for the GET request; actually an 'enum
90 * GNUNET_BLOCK_Type'.
91 */
92 uint32_t type GNUNET_PACKED;
93
94 /**
95 * The key to search for
96 */
97 struct GNUNET_HashCode key GNUNET_PACKED;
98
99 /**
100 * Unique ID identifying this request, if 0 then
101 * the client will not expect a response
102 */
103 uint64_t unique_id GNUNET_PACKED;
104
105 /* Possibly followed by xquery, copied to end of this dealy do */
106};
107
108
109/**
110 * DHT GET RESULTS KNOWN message sent from clients to service. Indicates that a GET
111 * request should exclude certain results which are already known.
112 */
113struct GNUNET_DHT_ClientGetResultSeenMessage
114{
115 /**
116 * Type: #GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN
117 */
118 struct GNUNET_MessageHeader header;
119
120 /**
121 * Reserved, always 0.
122 */
123 uint32_t reserved GNUNET_PACKED;
124
125 /**
126 * The key we are searching for (to make it easy to find the corresponding
127 * GET inside the service).
128 */
129 struct GNUNET_HashCode key GNUNET_PACKED;
130
131 /**
132 * Unique ID identifying this request.
133 */
134 uint64_t unique_id GNUNET_PACKED;
135
136 /* Followed by an array of the hash codes of known results */
137};
138
139
140/**
141 * Reply to a GET send from the service to a client.
142 */
143struct GNUNET_DHT_ClientResultMessage
144{
145 /**
146 * Type: #GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT
147 */
148 struct GNUNET_MessageHeader header;
149
150 /**
151 * The type for the data.
152 */
153 uint32_t type GNUNET_PACKED;
154
155 /**
156 * Number of peers recorded in the outgoing path from source to the
157 * storgage location of this message.
158 */
159 uint32_t put_path_length GNUNET_PACKED;
160
161 /**
162 * The number of peer identities recorded from the storage location
163 * to this peer.
164 */
165 uint32_t get_path_length GNUNET_PACKED;
166
167 /**
168 * Unique ID of the matching GET request.
169 */
170 uint64_t unique_id GNUNET_PACKED;
171
172 /**
173 * When does this entry expire?
174 */
175 struct GNUNET_TIME_AbsoluteNBO expiration;
176
177 /**
178 * The key that was searched for
179 */
180 struct GNUNET_HashCode key GNUNET_PACKED;
181
182 /* put path, get path and actual data are copied to end of this dealy do */
183};
184
185
186/**
187 * Message to insert data into the DHT, sent from clients to DHT service.
188 */
189struct GNUNET_DHT_ClientPutMessage
190{
191 /**
192 * Type: #GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT
193 */
194 struct GNUNET_MessageHeader header;
195
196 /**
197 * The type of data to insert.
198 */
199 uint32_t type GNUNET_PACKED;
200
201 /**
202 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
203 */
204 uint32_t options GNUNET_PACKED;
205
206 /**
207 * Replication level for this message
208 */
209 uint32_t desired_replication_level GNUNET_PACKED;
210
211 /**
212 * How long should this data persist?
213 */
214 struct GNUNET_TIME_AbsoluteNBO expiration;
215
216 /**
217 * The key to store the value under.
218 */
219 struct GNUNET_HashCode key GNUNET_PACKED;
220
221 /* DATA copied to end of this message */
222};
223
224
225/**
226 * Message to monitor put requests going through peer, DHT service -> clients.
227 */
228struct GNUNET_DHT_MonitorPutMessage
229{
230 /**
231 * Type: #GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT
232 */
233 struct GNUNET_MessageHeader header;
234
235 /**
236 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
237 */
238 uint32_t options GNUNET_PACKED;
239
240 /**
241 * The type of data in the request.
242 */
243 uint32_t type GNUNET_PACKED;
244
245 /**
246 * Hop count so far.
247 */
248 uint32_t hop_count GNUNET_PACKED;
249
250 /**
251 * Replication level for this message
252 */
253 uint32_t desired_replication_level GNUNET_PACKED;
254
255 /**
256 * Number of peers recorded in the outgoing path from source to the
257 * storage location of this message.
258 */
259 uint32_t put_path_length GNUNET_PACKED;
260
261 /**
262 * How long should this data persist?
263 */
264 struct GNUNET_TIME_AbsoluteNBO expiration_time;
265
266 /**
267 * The key to store the value under.
268 */
269 struct GNUNET_HashCode key GNUNET_PACKED;
270
271 /* put path (if tracked) */
272
273 /* Payload */
274};
275
276
277/**
278 * Message to request monitoring messages, clients -> DHT service.
279 */
280struct GNUNET_DHT_MonitorStartStopMessage
281{
282 /**
283 * Type: #GNUNET_MESSAGE_TYPE_DHT_MONITOR_START or
284 * #GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP
285 */
286 struct GNUNET_MessageHeader header;
287
288 /**
289 * The type of data desired, GNUNET_BLOCK_TYPE_ANY for all.
290 */
291 uint32_t type GNUNET_PACKED;
292
293 /**
294 * Flag whether to notify about GET messages.
295 */
296 int16_t get GNUNET_PACKED;
297
298 /**
299 * Flag whether to notify about GET_REPONSE messages.
300 */
301 int16_t get_resp GNUNET_PACKED;
302
303 /**
304 * Flag whether to notify about PUT messages.
305 */
306 int16_t put GNUNET_PACKED;
307
308 /**
309 * Flag whether to use the provided key to filter messages.
310 */
311 int16_t filter_key GNUNET_PACKED;
312
313 /**
314 * The key to filter messages by.
315 */
316 struct GNUNET_HashCode key GNUNET_PACKED;
317};
318
319
320/**
321 * Message to monitor get requests going through peer, DHT service -> clients.
322 */
323struct GNUNET_DHT_MonitorGetMessage
324{
325 /**
326 * Type: #GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET
327 */
328 struct GNUNET_MessageHeader header;
329
330 /**
331 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
332 */
333 uint32_t options GNUNET_PACKED;
334
335 /**
336 * The type of data in the request.
337 */
338 uint32_t type GNUNET_PACKED;
339
340 /**
341 * Hop count
342 */
343 uint32_t hop_count GNUNET_PACKED;
344
345 /**
346 * Replication level for this message
347 */
348 uint32_t desired_replication_level GNUNET_PACKED;
349
350 /**
351 * Number of peers recorded in the outgoing path from source to the
352 * storage location of this message.
353 */
354 uint32_t get_path_length GNUNET_PACKED;
355
356 /**
357 * The key to store the value under.
358 */
359 struct GNUNET_HashCode key GNUNET_PACKED;
360
361 /* get path (if tracked) */
362};
363
364/**
365 * Message to monitor get results going through peer, DHT service -> clients.
366 */
367struct GNUNET_DHT_MonitorGetRespMessage
368{
369 /**
370 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
371 */
372 struct GNUNET_MessageHeader header;
373
374 /**
375 * Content type.
376 */
377 uint32_t type GNUNET_PACKED;
378
379 /**
380 * Length of the PUT path that follows (if tracked).
381 */
382 uint32_t put_path_length GNUNET_PACKED;
383
384 /**
385 * Length of the GET path that follows (if tracked).
386 */
387 uint32_t get_path_length GNUNET_PACKED;
388
389 /**
390 * When does the content expire?
391 */
392 struct GNUNET_TIME_AbsoluteNBO expiration_time;
393
394 /**
395 * The key of the corresponding GET request.
396 */
397 struct GNUNET_HashCode key GNUNET_PACKED;
398
399 /* put path (if tracked) */
400
401 /* get path (if tracked) */
402
403 /* Payload */
404};
405
406GNUNET_NETWORK_STRUCT_END
407
408#endif
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
deleted file mode 100644
index 8389bbb95..000000000
--- a/src/dht/dht_api.c
+++ /dev/null
@@ -1,1253 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2012, 2016, 2018 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 dht/dht_api.c
23 * @brief library to access the DHT service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_constants.h"
31#include "gnunet_signatures.h"
32#include "gnunet_arm_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_dht_service.h"
36#include "dht.h"
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "dht-api", __VA_ARGS__)
39
40
41/**
42 * Handle to a PUT request.
43 */
44struct GNUNET_DHT_PutHandle
45{
46 /**
47 * Kept in a DLL.
48 */
49 struct GNUNET_DHT_PutHandle *next;
50
51 /**
52 * Kept in a DLL.
53 */
54 struct GNUNET_DHT_PutHandle *prev;
55
56 /**
57 * Continuation to call when done.
58 */
59 GNUNET_SCHEDULER_TaskCallback cont;
60
61 /**
62 * Main handle to this DHT api
63 */
64 struct GNUNET_DHT_Handle *dht_handle;
65
66 /**
67 * Closure for @e cont.
68 */
69 void *cont_cls;
70
71 /**
72 * Envelope from the PUT operation.
73 */
74 struct GNUNET_MQ_Envelope *env;
75};
76
77/**
78 * Handle to a GET request
79 */
80struct GNUNET_DHT_GetHandle
81{
82 /**
83 * Iterator to call on data receipt
84 */
85 GNUNET_DHT_GetIterator iter;
86
87 /**
88 * Closure for @e iter.
89 */
90 void *iter_cls;
91
92 /**
93 * Main handle to this DHT api
94 */
95 struct GNUNET_DHT_Handle *dht_handle;
96
97 /**
98 * Array of hash codes over the results that we have already
99 * seen.
100 */
101 struct GNUNET_HashCode *seen_results;
102
103 /**
104 * Key that this get request is for
105 */
106 struct GNUNET_HashCode key;
107
108 /**
109 * Unique identifier for this request (for key collisions).
110 */
111 uint64_t unique_id;
112
113 /**
114 * Size of the extended query, allocated at the end of this struct.
115 */
116 size_t xquery_size;
117
118 /**
119 * Desired replication level.
120 */
121 uint32_t desired_replication_level;
122
123 /**
124 * Type of the block we are looking for.
125 */
126 enum GNUNET_BLOCK_Type type;
127
128 /**
129 * Routing options.
130 */
131 enum GNUNET_DHT_RouteOption options;
132
133 /**
134 * Size of the @e seen_results array. Note that not
135 * all positions might be used (as we over-allocate).
136 */
137 unsigned int seen_results_size;
138
139 /**
140 * Offset into the @e seen_results array marking the
141 * end of the positions that are actually used.
142 */
143 unsigned int seen_results_end;
144};
145
146
147/**
148 * Handle to a monitoring request.
149 */
150struct GNUNET_DHT_MonitorHandle
151{
152 /**
153 * DLL.
154 */
155 struct GNUNET_DHT_MonitorHandle *next;
156
157 /**
158 * DLL.
159 */
160 struct GNUNET_DHT_MonitorHandle *prev;
161
162 /**
163 * Main handle to this DHT api.
164 */
165 struct GNUNET_DHT_Handle *dht_handle;
166
167 /**
168 * Type of block looked for.
169 */
170 enum GNUNET_BLOCK_Type type;
171
172 /**
173 * Key being looked for, NULL == all.
174 */
175 struct GNUNET_HashCode *key;
176
177 /**
178 * Callback for each received message of type get.
179 */
180 GNUNET_DHT_MonitorGetCB get_cb;
181
182 /**
183 * Callback for each received message of type get response.
184 */
185 GNUNET_DHT_MonitorGetRespCB get_resp_cb;
186
187 /**
188 * Callback for each received message of type put.
189 */
190 GNUNET_DHT_MonitorPutCB put_cb;
191
192 /**
193 * Closure for @e get_cb, @e put_cb and @e get_resp_cb.
194 */
195 void *cb_cls;
196};
197
198
199/**
200 * Connection to the DHT service.
201 */
202struct GNUNET_DHT_Handle
203{
204 /**
205 * Configuration to use.
206 */
207 const struct GNUNET_CONFIGURATION_Handle *cfg;
208
209 /**
210 * Connection to DHT service.
211 */
212 struct GNUNET_MQ_Handle *mq;
213
214 /**
215 * Head of linked list of messages we would like to monitor.
216 */
217 struct GNUNET_DHT_MonitorHandle *monitor_head;
218
219 /**
220 * Tail of linked list of messages we would like to monitor.
221 */
222 struct GNUNET_DHT_MonitorHandle *monitor_tail;
223
224 /**
225 * Head of active PUT requests.
226 */
227 struct GNUNET_DHT_PutHandle *put_head;
228
229 /**
230 * Tail of active PUT requests.
231 */
232 struct GNUNET_DHT_PutHandle *put_tail;
233
234 /**
235 * Hash map containing the current outstanding unique GET requests
236 * (values are of type `struct GNUNET_DHT_GetHandle`).
237 */
238 struct GNUNET_CONTAINER_MultiHashMap *active_requests;
239
240 /**
241 * Task for trying to reconnect.
242 */
243 struct GNUNET_SCHEDULER_Task *reconnect_task;
244
245 /**
246 * How quickly should we retry? Used for exponential back-off on
247 * connect-errors.
248 */
249 struct GNUNET_TIME_Relative retry_time;
250
251 /**
252 * Generator for unique ids.
253 */
254 uint64_t uid_gen;
255};
256
257
258/**
259 * Try to (re)connect to the DHT service.
260 *
261 * @param h DHT handle to reconnect
262 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
263 */
264static enum GNUNET_GenericReturnValue
265try_connect (struct GNUNET_DHT_Handle *h);
266
267
268/**
269 * Send GET message for a @a get_handle to DHT.
270 *
271 * @param gh GET to generate messages for.
272 */
273static void
274send_get (struct GNUNET_DHT_GetHandle *gh)
275{
276 struct GNUNET_DHT_Handle *h = gh->dht_handle;
277 struct GNUNET_MQ_Envelope *env;
278 struct GNUNET_DHT_ClientGetMessage *get_msg;
279
280 env = GNUNET_MQ_msg_extra (get_msg,
281 gh->xquery_size,
282 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET);
283 get_msg->options = htonl ((uint32_t) gh->options);
284 get_msg->desired_replication_level = htonl (gh->desired_replication_level);
285 get_msg->type = htonl (gh->type);
286 get_msg->key = gh->key;
287 get_msg->unique_id = gh->unique_id;
288 GNUNET_memcpy (&get_msg[1],
289 &gh[1],
290 gh->xquery_size);
291 GNUNET_MQ_send (h->mq,
292 env);
293}
294
295
296/**
297 * Send GET message(s) for indicating which results are already known
298 * for a @a get_handle to DHT. Complex as we need to send the list of
299 * known results, which means we may need multiple messages to block
300 * known results from the result set.
301 *
302 * @param gh GET to generate messages for
303 * @param transmission_offset_start at which offset should we start?
304 */
305static void
306send_get_known_results (struct GNUNET_DHT_GetHandle *gh,
307 unsigned int transmission_offset_start)
308{
309 struct GNUNET_DHT_Handle *h = gh->dht_handle;
310 struct GNUNET_MQ_Envelope *env;
311 struct GNUNET_DHT_ClientGetResultSeenMessage *msg;
312 unsigned int delta;
313 unsigned int max;
314 unsigned int transmission_offset;
315
316 max = (GNUNET_MAX_MESSAGE_SIZE - sizeof(*msg))
317 / sizeof(struct GNUNET_HashCode);
318 transmission_offset = transmission_offset_start;
319 while (transmission_offset < gh->seen_results_end)
320 {
321 delta = gh->seen_results_end - transmission_offset;
322 if (delta > max)
323 delta = max;
324 env = GNUNET_MQ_msg_extra (msg,
325 delta * sizeof(struct GNUNET_HashCode),
326 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN);
327 msg->key = gh->key;
328 msg->unique_id = gh->unique_id;
329 GNUNET_memcpy (&msg[1],
330 &gh->seen_results[transmission_offset],
331 sizeof(struct GNUNET_HashCode) * delta);
332 GNUNET_MQ_send (h->mq,
333 env);
334 transmission_offset += delta;
335 }
336}
337
338
339/**
340 * Add the GET request corresponding to the given route handle
341 * to the pending queue (if it is not already in there).
342 *
343 * @param cls the `struct GNUNET_DHT_Handle *`
344 * @param key key for the request (not used)
345 * @param value the `struct GNUNET_DHT_GetHandle *`
346 * @return #GNUNET_YES (always)
347 */
348static enum GNUNET_GenericReturnValue
349add_get_request_to_pending (void *cls,
350 const struct GNUNET_HashCode *key,
351 void *value)
352{
353 struct GNUNET_DHT_Handle *handle = cls;
354 struct GNUNET_DHT_GetHandle *gh = value;
355
356 LOG (GNUNET_ERROR_TYPE_DEBUG,
357 "Retransmitting request related to %s to DHT %p\n",
358 GNUNET_h2s (key),
359 handle);
360 send_get (gh);
361 send_get_known_results (gh, 0);
362 return GNUNET_YES;
363}
364
365
366/**
367 * Send #GNUNET_MESSAGE_TYPE_DHT_MONITOR_START message.
368 *
369 * @param mh monitor handle to generate start message for
370 */
371static void
372send_monitor_start (struct GNUNET_DHT_MonitorHandle *mh)
373{
374 struct GNUNET_DHT_Handle *h = mh->dht_handle;
375 struct GNUNET_MQ_Envelope *env;
376 struct GNUNET_DHT_MonitorStartStopMessage *m;
377
378 env = GNUNET_MQ_msg (m,
379 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START);
380 m->type = htonl (mh->type);
381 m->get = htons (NULL != mh->get_cb);
382 m->get_resp = htons (NULL != mh->get_resp_cb);
383 m->put = htons (NULL != mh->put_cb);
384 if (NULL != mh->key)
385 {
386 m->filter_key = htons (1);
387 m->key = *mh->key;
388 }
389 GNUNET_MQ_send (h->mq,
390 env);
391}
392
393
394/**
395 * Try reconnecting to the dht service.
396 *
397 * @param cls a `struct GNUNET_DHT_Handle`
398 */
399static void
400try_reconnect (void *cls)
401{
402 struct GNUNET_DHT_Handle *h = cls;
403 struct GNUNET_DHT_MonitorHandle *mh;
404
405 LOG (GNUNET_ERROR_TYPE_DEBUG,
406 "Reconnecting with DHT %p\n",
407 h);
408 h->retry_time = GNUNET_TIME_STD_BACKOFF (h->retry_time);
409 h->reconnect_task = NULL;
410 if (GNUNET_YES != try_connect (h))
411 {
412 LOG (GNUNET_ERROR_TYPE_WARNING,
413 "DHT reconnect failed!\n");
414 h->reconnect_task
415 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
416 &try_reconnect,
417 h);
418 return;
419 }
420 GNUNET_CONTAINER_multihashmap_iterate (h->active_requests,
421 &add_get_request_to_pending,
422 h);
423 for (mh = h->monitor_head; NULL != mh; mh = mh->next)
424 send_monitor_start (mh);
425}
426
427
428/**
429 * Try reconnecting to the DHT service.
430 *
431 * @param h handle to dht to (possibly) disconnect and reconnect
432 */
433static void
434do_disconnect (struct GNUNET_DHT_Handle *h)
435{
436 struct GNUNET_DHT_PutHandle *ph;
437 GNUNET_SCHEDULER_TaskCallback cont;
438 void *cont_cls;
439
440 if (NULL == h->mq)
441 return;
442 GNUNET_MQ_destroy (h->mq);
443 h->mq = NULL;
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Disconnecting from DHT service, will try to reconnect in %s\n",
446 GNUNET_STRINGS_relative_time_to_string (h->retry_time,
447 GNUNET_YES));
448 /* notify client about all PUTs that (may) have failed due to disconnect */
449 while (NULL != (ph = h->put_head))
450 {
451 cont = ph->cont;
452 cont_cls = ph->cont_cls;
453 ph->env = NULL;
454 GNUNET_DHT_put_cancel (ph);
455 if (NULL != cont)
456 cont (cont_cls);
457 }
458 GNUNET_assert (NULL == h->reconnect_task);
459 h->reconnect_task
460 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
461 &try_reconnect,
462 h);
463}
464
465
466/**
467 * Generic error handler, called with the appropriate error code and
468 * the same closure specified at the creation of the message queue.
469 * Not every message queue implementation supports an error handler.
470 *
471 * @param cls closure with the `struct GNUNET_DHT_Handle *`
472 * @param error error code
473 */
474static void
475mq_error_handler (void *cls,
476 enum GNUNET_MQ_Error error)
477{
478 struct GNUNET_DHT_Handle *h = cls;
479
480 do_disconnect (h);
481}
482
483
484/**
485 * Verify integrity of a get monitor message from the service.
486 *
487 * @param cls The DHT handle.
488 * @param msg Monitor get message from the service.
489 * @return #GNUNET_OK if everything went fine,
490 * #GNUNET_SYSERR if the message is malformed.
491 */
492static enum GNUNET_GenericReturnValue
493check_monitor_get (void *cls,
494 const struct GNUNET_DHT_MonitorGetMessage *msg)
495{
496 uint32_t plen = ntohl (msg->get_path_length);
497 uint16_t msize = ntohs (msg->header.size) - sizeof(*msg);
498
499 if ((plen > UINT16_MAX) ||
500 (plen * sizeof(struct GNUNET_DHT_PathElement) != msize))
501 {
502 GNUNET_break (0);
503 return GNUNET_SYSERR;
504 }
505 return GNUNET_OK;
506}
507
508
509/**
510 * Process a get monitor message from the service.
511 *
512 * @param cls The DHT handle.
513 * @param msg Monitor get message from the service.
514 */
515static void
516handle_monitor_get (void *cls,
517 const struct GNUNET_DHT_MonitorGetMessage *msg)
518{
519 struct GNUNET_DHT_Handle *handle = cls;
520 struct GNUNET_DHT_MonitorHandle *mh;
521
522 for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
523 {
524 if (NULL == mh->get_cb)
525 continue;
526 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
527 (mh->type == ntohl (msg->type))) &&
528 ((NULL == mh->key) ||
529 (0 == memcmp (mh->key,
530 &msg->key,
531 sizeof(struct GNUNET_HashCode)))))
532 mh->get_cb (mh->cb_cls,
533 ntohl (msg->options),
534 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
535 ntohl (msg->hop_count),
536 ntohl (msg->desired_replication_level),
537 ntohl (msg->get_path_length),
538 (struct GNUNET_DHT_PathElement *) &msg[1],
539 &msg->key);
540 }
541}
542
543
544/**
545 * Validate a get response monitor message from the service.
546 *
547 * @param cls The DHT handle.
548 * @param msg monitor get response message from the service
549 * @return #GNUNET_OK if everything went fine,
550 * #GNUNET_SYSERR if the message is malformed.
551 */
552static enum GNUNET_GenericReturnValue
553check_monitor_get_resp (void *cls,
554 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
555{
556 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
557 uint32_t getl = ntohl (msg->get_path_length);
558 uint32_t putl = ntohl (msg->put_path_length);
559
560 if ((getl + putl < getl) ||
561 ((msize / sizeof(struct GNUNET_DHT_PathElement)) < getl + putl))
562 {
563 GNUNET_break (0);
564 return GNUNET_SYSERR;
565 }
566 return GNUNET_OK;
567}
568
569
570/**
571 * Process a get response monitor message from the service.
572 *
573 * @param cls The DHT handle.
574 * @param msg monitor get response message from the service
575 */
576static void
577handle_monitor_get_resp (void *cls,
578 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
579{
580 struct GNUNET_DHT_Handle *handle = cls;
581 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
582 const struct GNUNET_DHT_PathElement *path;
583 uint32_t getl = ntohl (msg->get_path_length);
584 uint32_t putl = ntohl (msg->put_path_length);
585 struct GNUNET_DHT_MonitorHandle *mh;
586
587 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
588 for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
589 {
590 if (NULL == mh->get_resp_cb)
591 continue;
592 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
593 (mh->type == ntohl (msg->type))) &&
594 ((NULL == mh->key) ||
595 (0 == memcmp (mh->key,
596 &msg->key,
597 sizeof(struct GNUNET_HashCode)))))
598 mh->get_resp_cb (mh->cb_cls,
599 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
600 path,
601 getl,
602 &path[getl],
603 putl,
604 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
605 &msg->key,
606 (const void *) &path[getl + putl],
607 msize - sizeof(struct GNUNET_DHT_PathElement) * (putl
608 + getl));
609 }
610}
611
612
613/**
614 * Check validity of a put monitor message from the service.
615 *
616 * @param cls The DHT handle.
617 * @param msg Monitor put message from the service.
618 * @return #GNUNET_OK if everything went fine,
619 * #GNUNET_SYSERR if the message is malformed.
620 */
621static enum GNUNET_GenericReturnValue
622check_monitor_put (void *cls,
623 const struct GNUNET_DHT_MonitorPutMessage *msg)
624{
625 size_t msize;
626 uint32_t putl;
627
628 msize = ntohs (msg->header.size) - sizeof(*msg);
629 putl = ntohl (msg->put_path_length);
630 if ((msize / sizeof(struct GNUNET_DHT_PathElement)) < putl)
631 {
632 GNUNET_break (0);
633 return GNUNET_SYSERR;
634 }
635 return GNUNET_OK;
636}
637
638
639/**
640 * Process a put monitor message from the service.
641 *
642 * @param cls The DHT handle.
643 * @param msg Monitor put message from the service.
644 */
645static void
646handle_monitor_put (void *cls,
647 const struct GNUNET_DHT_MonitorPutMessage *msg)
648{
649 struct GNUNET_DHT_Handle *handle = cls;
650 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
651 uint32_t putl = ntohl (msg->put_path_length);
652 const struct GNUNET_DHT_PathElement *path;
653 struct GNUNET_DHT_MonitorHandle *mh;
654
655 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
656 for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
657 {
658 if (NULL == mh->put_cb)
659 continue;
660 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
661 (mh->type == ntohl (msg->type))) &&
662 ((NULL == mh->key) ||
663 (0 == memcmp (mh->key,
664 &msg->key,
665 sizeof(struct GNUNET_HashCode)))))
666 mh->put_cb (mh->cb_cls,
667 ntohl (msg->options),
668 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
669 ntohl (msg->hop_count),
670 ntohl (msg->desired_replication_level),
671 putl,
672 path,
673 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
674 &msg->key,
675 (const void *) &path[putl],
676 msize - sizeof(struct GNUNET_DHT_PathElement) * putl);
677 }
678}
679
680
681/**
682 * Verify that client result message received from the service is well-formed.
683 *
684 * @param cls The DHT handle.
685 * @param msg Monitor put message from the service.
686 * @return #GNUNET_OK if everything went fine,
687 * #GNUNET_SYSERR if the message is malformed.
688 */
689static enum GNUNET_GenericReturnValue
690check_client_result (void *cls,
691 const struct GNUNET_DHT_ClientResultMessage *msg)
692{
693 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
694 uint32_t put_path_length = ntohl (msg->put_path_length);
695 uint32_t get_path_length = ntohl (msg->get_path_length);
696 size_t meta_length;
697
698 meta_length =
699 sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + put_path_length);
700 if ((msize < meta_length) ||
701 (get_path_length >
702 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
703 (put_path_length >
704 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)))
705 {
706 GNUNET_break (0);
707 return GNUNET_SYSERR;
708 }
709 return GNUNET_OK;
710}
711
712
713/**
714 * Process a given reply that might match the given request.
715 *
716 * @param cls the `struct GNUNET_DHT_ClientResultMessage`
717 * @param key query of the request
718 * @param value the `struct GNUNET_DHT_GetHandle` of a request matching the same key
719 * @return #GNUNET_YES to continue to iterate over all results
720 */
721static enum GNUNET_GenericReturnValue
722process_client_result (void *cls,
723 const struct GNUNET_HashCode *key,
724 void *value)
725{
726 const struct GNUNET_DHT_ClientResultMessage *crm = cls;
727 struct GNUNET_DHT_GetHandle *get_handle = value;
728 size_t msize = ntohs (crm->header.size) - sizeof(*crm);
729 uint32_t put_path_length = ntohl (crm->put_path_length);
730 uint32_t get_path_length = ntohl (crm->get_path_length);
731 const struct GNUNET_DHT_PathElement *put_path;
732 const struct GNUNET_DHT_PathElement *get_path;
733 struct GNUNET_HashCode hc;
734 size_t data_length;
735 size_t meta_length;
736 const void *data;
737
738 if (crm->unique_id != get_handle->unique_id)
739 {
740 /* UID mismatch */
741 LOG (GNUNET_ERROR_TYPE_DEBUG,
742 "Ignoring reply for %s: UID mismatch: %llu/%llu\n",
743 GNUNET_h2s (key),
744 (unsigned long long) crm->unique_id,
745 (unsigned long long) get_handle->unique_id);
746 return GNUNET_YES;
747 }
748 /* FIXME: might want to check that type matches */
749 meta_length =
750 sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + put_path_length);
751 data_length = msize - meta_length;
752 put_path = (const struct GNUNET_DHT_PathElement *) &crm[1];
753 get_path = &put_path[put_path_length];
754 {
755 char *pp;
756 char *gp;
757
758 gp = GNUNET_DHT_pp2s (get_path,
759 get_path_length);
760 pp = GNUNET_DHT_pp2s (put_path,
761 put_path_length);
762 LOG (GNUNET_ERROR_TYPE_DEBUG,
763 "Giving %u byte reply for %s to application (GP: %s, PP: %s)\n",
764 (unsigned int) data_length,
765 GNUNET_h2s (key),
766 gp,
767 pp);
768 GNUNET_free (gp);
769 GNUNET_free (pp);
770 }
771 data = &get_path[get_path_length];
772 /* remember that we've seen this result */
773 GNUNET_CRYPTO_hash (data,
774 data_length,
775 &hc);
776 if (get_handle->seen_results_size == get_handle->seen_results_end)
777 GNUNET_array_grow (get_handle->seen_results,
778 get_handle->seen_results_size,
779 get_handle->seen_results_size * 2 + 1);
780 get_handle->seen_results[get_handle->seen_results_end++] = hc;
781 /* no need to block it explicitly, service already knows about it! */
782 get_handle->iter (get_handle->iter_cls,
783 GNUNET_TIME_absolute_ntoh (crm->expiration),
784 key,
785 get_path,
786 get_path_length,
787 put_path,
788 put_path_length,
789 ntohl (crm->type),
790 data_length,
791 data);
792 return GNUNET_YES;
793}
794
795
796/**
797 * Process a client result message received from the service.
798 *
799 * @param cls The DHT handle.
800 * @param msg Monitor put message from the service.
801 */
802static void
803handle_client_result (void *cls,
804 const struct GNUNET_DHT_ClientResultMessage *msg)
805{
806 struct GNUNET_DHT_Handle *handle = cls;
807
808 GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests,
809 &msg->key,
810 &process_client_result,
811 (void *) msg);
812}
813
814
815/**
816 * Process a MQ PUT transmission notification.
817 *
818 * @param cls The DHT handle.
819 */
820static void
821handle_put_cont (void *cls)
822{
823 struct GNUNET_DHT_PutHandle *ph = cls;
824 GNUNET_SCHEDULER_TaskCallback cont;
825 void *cont_cls;
826
827 cont = ph->cont;
828 cont_cls = ph->cont_cls;
829 ph->env = NULL;
830 GNUNET_DHT_put_cancel (ph);
831 if (NULL != cont)
832 cont (cont_cls);
833}
834
835
836/**
837 * Try to (re)connect to the DHT service.
838 *
839 * @param h DHT handle to reconnect
840 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
841 */
842static enum GNUNET_GenericReturnValue
843try_connect (struct GNUNET_DHT_Handle *h)
844{
845 struct GNUNET_MQ_MessageHandler handlers[] = {
846 GNUNET_MQ_hd_var_size (monitor_get,
847 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
848 struct GNUNET_DHT_MonitorGetMessage,
849 h),
850 GNUNET_MQ_hd_var_size (monitor_get_resp,
851 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP,
852 struct GNUNET_DHT_MonitorGetRespMessage,
853 h),
854 GNUNET_MQ_hd_var_size (monitor_put,
855 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT,
856 struct GNUNET_DHT_MonitorPutMessage,
857 h),
858 GNUNET_MQ_hd_var_size (client_result,
859 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT,
860 struct GNUNET_DHT_ClientResultMessage,
861 h),
862 GNUNET_MQ_handler_end ()
863 };
864
865 if (NULL != h->mq)
866 return GNUNET_OK;
867 h->mq = GNUNET_CLIENT_connect (h->cfg,
868 "dht",
869 handlers,
870 &mq_error_handler,
871 h);
872 if (NULL == h->mq)
873 {
874 LOG (GNUNET_ERROR_TYPE_WARNING,
875 "Failed to connect to the DHT service!\n");
876 return GNUNET_NO;
877 }
878 return GNUNET_YES;
879}
880
881
882struct GNUNET_DHT_Handle *
883GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
884 unsigned int ht_len)
885{
886 struct GNUNET_DHT_Handle *handle;
887
888 handle = GNUNET_new (struct GNUNET_DHT_Handle);
889 handle->cfg = cfg;
890 handle->uid_gen
891 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
892 UINT64_MAX);
893 handle->active_requests
894 = GNUNET_CONTAINER_multihashmap_create (ht_len,
895 GNUNET_YES);
896 if (GNUNET_NO == try_connect (handle))
897 {
898 GNUNET_DHT_disconnect (handle);
899 return NULL;
900 }
901 return handle;
902}
903
904
905void
906GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle)
907{
908 struct GNUNET_DHT_PutHandle *ph;
909
910 GNUNET_assert (0 ==
911 GNUNET_CONTAINER_multihashmap_size (handle->active_requests));
912 while (NULL != (ph = handle->put_head))
913 {
914 if (NULL != ph->cont)
915 ph->cont (ph->cont_cls);
916 GNUNET_DHT_put_cancel (ph);
917 }
918 if (NULL != handle->mq)
919 {
920 GNUNET_MQ_destroy (handle->mq);
921 handle->mq = NULL;
922 }
923 if (NULL != handle->reconnect_task)
924 {
925 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
926 handle->reconnect_task = NULL;
927 }
928 GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests);
929 GNUNET_free (handle);
930}
931
932
933struct GNUNET_DHT_PutHandle *
934GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
935 const struct GNUNET_HashCode *key,
936 uint32_t desired_replication_level,
937 enum GNUNET_DHT_RouteOption options,
938 enum GNUNET_BLOCK_Type type,
939 size_t size,
940 const void *data,
941 struct GNUNET_TIME_Absolute exp,
942 GNUNET_SCHEDULER_TaskCallback cont,
943 void *cont_cls)
944{
945 struct GNUNET_MQ_Envelope *env;
946 struct GNUNET_DHT_ClientPutMessage *put_msg;
947 size_t msize;
948 struct GNUNET_DHT_PutHandle *ph;
949
950 msize = sizeof(struct GNUNET_DHT_ClientPutMessage) + size;
951 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
952 (size >= GNUNET_MAX_MESSAGE_SIZE))
953 {
954 GNUNET_break (0);
955 return NULL;
956 }
957 if (NULL == handle->mq)
958 return NULL;
959 LOG (GNUNET_ERROR_TYPE_DEBUG,
960 "Sending PUT for %s to DHT via %p\n",
961 GNUNET_h2s (key),
962 handle);
963 ph = GNUNET_new (struct GNUNET_DHT_PutHandle);
964 ph->dht_handle = handle;
965 ph->cont = cont;
966 ph->cont_cls = cont_cls;
967 GNUNET_CONTAINER_DLL_insert_tail (handle->put_head,
968 handle->put_tail,
969 ph);
970 env = GNUNET_MQ_msg_extra (put_msg,
971 size,
972 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT);
973 GNUNET_MQ_notify_sent (env,
974 &handle_put_cont,
975 ph);
976 ph->env = env;
977 put_msg->type = htonl ((uint32_t) type);
978 put_msg->options = htonl ((uint32_t) options);
979 put_msg->desired_replication_level = htonl (desired_replication_level);
980 put_msg->expiration = GNUNET_TIME_absolute_hton (exp);
981 put_msg->key = *key;
982 GNUNET_memcpy (&put_msg[1],
983 data,
984 size);
985 GNUNET_MQ_send (handle->mq,
986 env);
987 return ph;
988}
989
990
991void
992GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph)
993{
994 struct GNUNET_DHT_Handle *handle = ph->dht_handle;
995
996 if (NULL != ph->env)
997 GNUNET_MQ_notify_sent (ph->env,
998 NULL,
999 NULL);
1000 GNUNET_CONTAINER_DLL_remove (handle->put_head,
1001 handle->put_tail,
1002 ph);
1003 GNUNET_free (ph);
1004}
1005
1006
1007struct GNUNET_DHT_GetHandle *
1008GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1009 enum GNUNET_BLOCK_Type type,
1010 const struct GNUNET_HashCode *key,
1011 uint32_t desired_replication_level,
1012 enum GNUNET_DHT_RouteOption options,
1013 const void *xquery,
1014 size_t xquery_size,
1015 GNUNET_DHT_GetIterator iter,
1016 void *iter_cls)
1017{
1018 struct GNUNET_DHT_GetHandle *gh;
1019 size_t msize;
1020
1021 msize = sizeof(struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1022 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1023 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1024 {
1025 GNUNET_break (0);
1026 return NULL;
1027 }
1028 LOG (GNUNET_ERROR_TYPE_DEBUG,
1029 "Sending query for %s to DHT %p\n",
1030 GNUNET_h2s (key),
1031 handle);
1032 gh = GNUNET_malloc (sizeof(struct GNUNET_DHT_GetHandle)
1033 + xquery_size);
1034 gh->iter = iter;
1035 gh->iter_cls = iter_cls;
1036 gh->dht_handle = handle;
1037 gh->key = *key;
1038 gh->unique_id = ++handle->uid_gen;
1039 gh->xquery_size = xquery_size;
1040 gh->desired_replication_level = desired_replication_level;
1041 gh->type = type;
1042 gh->options = options;
1043 GNUNET_memcpy (&gh[1],
1044 xquery,
1045 xquery_size);
1046 GNUNET_CONTAINER_multihashmap_put (handle->active_requests,
1047 &gh->key,
1048 gh,
1049 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1050 if (NULL != handle->mq)
1051 send_get (gh);
1052 return gh;
1053}
1054
1055
1056void
1057GNUNET_DHT_get_filter_known_results (struct GNUNET_DHT_GetHandle *get_handle,
1058 unsigned int num_results,
1059 const struct GNUNET_HashCode *results)
1060{
1061 unsigned int needed;
1062 unsigned int had;
1063
1064 had = get_handle->seen_results_end;
1065 needed = had + num_results;
1066 if (needed > get_handle->seen_results_size)
1067 GNUNET_array_grow (get_handle->seen_results,
1068 get_handle->seen_results_size,
1069 needed);
1070 GNUNET_memcpy (&get_handle->seen_results[get_handle->seen_results_end],
1071 results,
1072 num_results * sizeof(struct GNUNET_HashCode));
1073 get_handle->seen_results_end += num_results;
1074 if (NULL != get_handle->dht_handle->mq)
1075 send_get_known_results (get_handle,
1076 had);
1077}
1078
1079
1080void
1081GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle)
1082{
1083 struct GNUNET_DHT_Handle *handle = get_handle->dht_handle;
1084
1085 LOG (GNUNET_ERROR_TYPE_DEBUG,
1086 "Sending STOP for %s to DHT via %p\n",
1087 GNUNET_h2s (&get_handle->key),
1088 handle);
1089 if (NULL != handle->mq)
1090 {
1091 struct GNUNET_MQ_Envelope *env;
1092 struct GNUNET_DHT_ClientGetStopMessage *stop_msg;
1093
1094 env = GNUNET_MQ_msg (stop_msg,
1095 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP);
1096 stop_msg->reserved = htonl (0);
1097 stop_msg->unique_id = get_handle->unique_id;
1098 stop_msg->key = get_handle->key;
1099 GNUNET_MQ_send (handle->mq,
1100 env);
1101 }
1102 GNUNET_assert (GNUNET_YES ==
1103 GNUNET_CONTAINER_multihashmap_remove (handle->active_requests,
1104 &get_handle->key,
1105 get_handle));
1106 GNUNET_array_grow (get_handle->seen_results,
1107 get_handle->seen_results_end,
1108 0);
1109 GNUNET_free (get_handle);
1110}
1111
1112
1113struct GNUNET_DHT_MonitorHandle *
1114GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle,
1115 enum GNUNET_BLOCK_Type type,
1116 const struct GNUNET_HashCode *key,
1117 GNUNET_DHT_MonitorGetCB get_cb,
1118 GNUNET_DHT_MonitorGetRespCB get_resp_cb,
1119 GNUNET_DHT_MonitorPutCB put_cb,
1120 void *cb_cls)
1121{
1122 struct GNUNET_DHT_MonitorHandle *mh;
1123
1124 mh = GNUNET_new (struct GNUNET_DHT_MonitorHandle);
1125 mh->get_cb = get_cb;
1126 mh->get_resp_cb = get_resp_cb;
1127 mh->put_cb = put_cb;
1128 mh->cb_cls = cb_cls;
1129 mh->type = type;
1130 mh->dht_handle = handle;
1131 if (NULL != key)
1132 {
1133 mh->key = GNUNET_new (struct GNUNET_HashCode);
1134 *mh->key = *key;
1135 }
1136 GNUNET_CONTAINER_DLL_insert (handle->monitor_head,
1137 handle->monitor_tail,
1138 mh);
1139 if (NULL != handle->mq)
1140 send_monitor_start (mh);
1141 return mh;
1142}
1143
1144
1145void
1146GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *mh)
1147{
1148 struct GNUNET_DHT_Handle *handle = mh->dht_handle;
1149 struct GNUNET_DHT_MonitorStartStopMessage *m;
1150 struct GNUNET_MQ_Envelope *env;
1151
1152 GNUNET_CONTAINER_DLL_remove (handle->monitor_head,
1153 handle->monitor_tail,
1154 mh);
1155 env = GNUNET_MQ_msg (m,
1156 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP);
1157 m->type = htonl (mh->type);
1158 m->get = htons (NULL != mh->get_cb);
1159 m->get_resp = htons (NULL != mh->get_resp_cb);
1160 m->put = htons (NULL != mh->put_cb);
1161 if (NULL != mh->key)
1162 {
1163 m->filter_key = htons (1);
1164 m->key = *mh->key;
1165 }
1166 GNUNET_MQ_send (handle->mq,
1167 env);
1168 GNUNET_free (mh->key);
1169 GNUNET_free (mh);
1170}
1171
1172
1173char *
1174GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement *path,
1175 unsigned int path_len)
1176{
1177 char *buf;
1178 size_t off;
1179 size_t plen = path_len * 5 + 1;
1180
1181 GNUNET_assert (path_len < UINT32_MAX / 5);
1182 off = 0;
1183 buf = GNUNET_malloc (plen);
1184 for (unsigned int i = 0; i < path_len; i++)
1185 {
1186 off += GNUNET_snprintf (&buf[off],
1187 plen - off,
1188 "%s%s",
1189 GNUNET_i2s (&path[i].pred),
1190 (i == path_len - 1) ? "" : "-");
1191 }
1192 return buf;
1193}
1194
1195
1196unsigned int
1197GNUNET_DHT_verify_path (const struct GNUNET_HashCode *key,
1198 const void *data,
1199 size_t data_size,
1200 struct GNUNET_TIME_Absolute exp_time,
1201 const struct GNUNET_DHT_PathElement *put_path,
1202 unsigned int put_path_len,
1203 const struct GNUNET_DHT_PathElement *get_path,
1204 unsigned int get_path_len,
1205 const struct GNUNET_PeerIdentity *me)
1206{
1207 struct GNUNET_DHT_HopSignature hs = {
1208 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
1209 .purpose.size = htonl (sizeof (hs)),
1210 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
1211 .key = *key,
1212 };
1213 unsigned int i;
1214
1215 if (0 == get_path_len + put_path_len)
1216 return 0;
1217 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1218 "Verifying signatures with GPL: %u PPL: %u!\n",
1219 get_path_len,
1220 put_path_len);
1221 i = put_path_len + get_path_len - 1;
1222 GNUNET_CRYPTO_hash (data,
1223 data_size,
1224 &hs.h_data);
1225 while (i > 0)
1226 {
1227 hs.pred = (i - 1 >= put_path_len)
1228 ? get_path[i - put_path_len - 1].pred
1229 : put_path[i - 1].pred;
1230 if (i + 1 == get_path_len + put_path_len)
1231 hs.succ = *me;
1232 else
1233 hs.succ = (i + 1 >= put_path_len)
1234 ? get_path[i + 1 - put_path_len].pred
1235 : put_path[i + 1].pred;
1236 if (GNUNET_OK !=
1237 GNUNET_CRYPTO_eddsa_verify (
1238 GNUNET_SIGNATURE_PURPOSE_DHT_HOP,
1239 &hs,
1240 (i - 1 >= put_path_len)
1241 ? &get_path[i - put_path_len - 1].sig
1242 : &put_path[i - 1].sig,
1243 (i >= put_path_len)
1244 ? &get_path[i - put_path_len].pred.public_key
1245 : &put_path[i].pred.public_key))
1246 return i;
1247 i--;
1248 }
1249 return i;
1250}
1251
1252
1253/* end of dht_api.c */
diff --git a/src/dht/dht_test_lib.c b/src/dht/dht_test_lib.c
deleted file mode 100644
index 29c5088d1..000000000
--- a/src/dht/dht_test_lib.c
+++ /dev/null
@@ -1,202 +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 dht/dht_test_lib.c
22 * @author Christian Grothoff
23 * @brief library for writing DHT tests
24 */
25#include "platform.h"
26#include "dht_test_lib.h"
27
28/**
29 * Test context for a DHT Test.
30 */
31struct GNUNET_DHT_TEST_Context
32{
33 /**
34 * Array of running peers.
35 */
36 struct GNUNET_TESTBED_Peer **peers;
37
38 /**
39 * Array of handles to the DHT for each peer.
40 */
41 struct GNUNET_DHT_Handle **dhts;
42
43 /**
44 * Operation associated with the connection to the DHT.
45 */
46 struct GNUNET_TESTBED_Operation **ops;
47
48 /**
49 * Main function of the test to run once all DHTs are available.
50 */
51 GNUNET_DHT_TEST_AppMain app_main;
52
53 /**
54 * Closure for 'app_main'.
55 */
56 void *app_main_cls;
57
58 /**
59 * Number of peers running, size of the arrays above.
60 */
61 unsigned int num_peers;
62};
63
64
65/**
66 * Adapter function called to establish a connection to
67 * the DHT service.
68 *
69 * @param cls closure
70 * @param cfg configuration of the peer to connect to; will be available until
71 * GNUNET_TESTBED_operation_done() is called on the operation returned
72 * from GNUNET_TESTBED_service_connect()
73 * @return service handle to return in 'op_result', NULL on error
74 */
75static void *
76dht_connect_adapter (void *cls,
77 const struct GNUNET_CONFIGURATION_Handle *cfg)
78{
79 return GNUNET_DHT_connect (cfg, 16);
80}
81
82
83/**
84 * Adapter function called to destroy a connection to
85 * the DHT service.
86 *
87 * @param cls closure
88 * @param op_result service handle returned from the connect adapter
89 */
90static void
91dht_disconnect_adapter (void *cls,
92 void *op_result)
93{
94 struct GNUNET_DHT_Handle *dht = op_result;
95
96 GNUNET_DHT_disconnect (dht);
97}
98
99
100/**
101 * Callback to be called when a service connect operation is completed
102 *
103 * @param cls the callback closure from functions generating an operation
104 * @param op the operation that has been finished
105 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
106 * @param emsg error message in case the operation has failed; will be NULL if
107 * operation has executed successfully.
108 */
109static void
110dht_connect_cb (void *cls,
111 struct GNUNET_TESTBED_Operation *op,
112 void *ca_result,
113 const char *emsg)
114{
115 struct GNUNET_DHT_TEST_Context *ctx = cls;
116
117 if (NULL != emsg)
118 {
119 fprintf (stderr,
120 "Failed to connect to DHT service: %s\n",
121 emsg);
122 GNUNET_SCHEDULER_shutdown ();
123 return;
124 }
125 for (unsigned int i = 0; i < ctx->num_peers; i++)
126 if (op == ctx->ops[i])
127 ctx->dhts[i] = ca_result;
128 for (unsigned int i = 0; i < ctx->num_peers; i++)
129 if (NULL == ctx->dhts[i])
130 return;
131 /* still some DHT connections missing */
132 /* all DHT connections ready! */
133 ctx->app_main (ctx->app_main_cls,
134 ctx,
135 ctx->num_peers,
136 ctx->peers,
137 ctx->dhts);
138}
139
140
141void
142GNUNET_DHT_TEST_cleanup (struct GNUNET_DHT_TEST_Context *ctx)
143{
144 for (unsigned int i = 0; i < ctx->num_peers; i++)
145 GNUNET_TESTBED_operation_done (ctx->ops[i]);
146 GNUNET_free (ctx->ops);
147 GNUNET_free (ctx->dhts);
148 GNUNET_free (ctx);
149 GNUNET_SCHEDULER_shutdown ();
150}
151
152
153static void
154dht_test_run (void *cls,
155 struct GNUNET_TESTBED_RunHandle *h,
156 unsigned int num_peers,
157 struct GNUNET_TESTBED_Peer **peers,
158 unsigned int links_succeeded,
159 unsigned int links_failed)
160{
161 struct GNUNET_DHT_TEST_Context *ctx = cls;
162
163 GNUNET_assert (num_peers == ctx->num_peers);
164 ctx->peers = peers;
165 for (unsigned int i = 0; i < num_peers; i++)
166 ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
167 peers[i],
168 "dht",
169 &dht_connect_cb,
170 ctx,
171 &dht_connect_adapter,
172 &dht_disconnect_adapter,
173 ctx);
174}
175
176
177void
178GNUNET_DHT_TEST_run (const char *testname,
179 const char *cfgname,
180 unsigned int num_peers,
181 GNUNET_DHT_TEST_AppMain tmain,
182 void *tmain_cls)
183{
184 struct GNUNET_DHT_TEST_Context *ctx;
185
186 ctx = GNUNET_new (struct GNUNET_DHT_TEST_Context);
187 ctx->num_peers = num_peers;
188 ctx->ops = GNUNET_new_array (num_peers,
189 struct GNUNET_TESTBED_Operation *);
190 ctx->dhts = GNUNET_new_array (num_peers,
191 struct GNUNET_DHT_Handle *);
192 ctx->app_main = tmain;
193 ctx->app_main_cls = tmain_cls;
194 (void) GNUNET_TESTBED_test_run (testname,
195 cfgname,
196 num_peers,
197 0LL, NULL, NULL,
198 &dht_test_run, ctx);
199}
200
201
202/* end of dht_test_lib.c */
diff --git a/src/dht/dht_test_lib.h b/src/dht/dht_test_lib.h
deleted file mode 100644
index efffc9ef7..000000000
--- a/src/dht/dht_test_lib.h
+++ /dev/null
@@ -1,95 +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 dht/dht_test_lib.h
22 * @author Christian Grothoff
23 * @brief library for writing DHT tests
24 */
25#ifndef DHT_TEST_LIB_H
26#define DHT_TEST_LIB_H
27
28#ifdef __cplusplus
29extern "C"
30{
31#if 0 /* keep Emacsens' auto-indent happy */
32}
33#endif
34#endif
35
36#include "gnunet_testbed_service.h"
37#include "gnunet_dht_service.h"
38
39/**
40 * Test context for a DHT Test.
41 */
42struct GNUNET_DHT_TEST_Context;
43
44
45/**
46 * Main function of a DHT test.
47 *
48 * @param cls closure
49 * @param ctx argument to give to GNUNET_DHT_TEST_cleanup on test end
50 * @param num_peers number of peers that are running
51 * @param peers array of peers
52 * @param dhts handle to each of the DHTs of the peers
53 */
54typedef void (*GNUNET_DHT_TEST_AppMain) (void *cls,
55 struct GNUNET_DHT_TEST_Context *ctx,
56 unsigned int num_peers,
57 struct GNUNET_TESTBED_Peer **peers,
58 struct GNUNET_DHT_Handle **dhts);
59
60
61/**
62 * Run a test using the given name, configuration file and number of
63 * peers.
64 *
65 * @param testname name of the test (for logging)
66 * @param cfgname name of the configuration file
67 * @param num_peers number of peers to start
68 * @param tmain main function to run once the testbed is ready
69 * @param tmain_cls closure for 'tmain'
70 */
71void
72GNUNET_DHT_TEST_run (const char *testname,
73 const char *cfgname,
74 unsigned int num_peers,
75 GNUNET_DHT_TEST_AppMain tmain,
76 void *tmain_cls);
77
78
79/**
80 * Clean up the testbed.
81 *
82 * @param ctx handle for the testbed
83 */
84void
85GNUNET_DHT_TEST_cleanup (struct GNUNET_DHT_TEST_Context *ctx);
86
87#if 0 /* keep Emacsens' auto-indent happy */
88{
89#endif
90#ifdef __cplusplus
91}
92#endif
93
94/* ifndef DHT_TEST_LIB_H */
95#endif
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
deleted file mode 100644
index f1076490b..000000000
--- a/src/dht/gnunet-dht-get.c
+++ /dev/null
@@ -1,310 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2022 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 dht/gnunet-dht-get.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
30/**
31 * The type of the query
32 */
33static unsigned int query_type;
34
35/**
36 * Desired replication level
37 */
38static unsigned int replication = 5;
39
40/**
41 * The key for the query
42 */
43static char *query_key;
44
45/**
46 * User supplied timeout value
47 */
48static struct GNUNET_TIME_Relative timeout_request = { 60000 };
49
50/**
51 * Be verbose
52 */
53static unsigned int verbose;
54
55/**
56 * Use DHT demultixplex_everywhere
57 */
58static int demultixplex_everywhere;
59
60/**
61 * Handle to the DHT
62 */
63static struct GNUNET_DHT_Handle *dht_handle;
64
65/**
66 * Global handle of the configuration
67 */
68static const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70/**
71 * Handle for the get request
72 */
73static struct GNUNET_DHT_GetHandle *get_handle;
74
75/**
76 * Count of results found
77 */
78static unsigned int result_count;
79
80/**
81 * Global status value
82 */
83static int ret;
84
85/**
86 * Task scheduled to handle timeout.
87 */
88static struct GNUNET_SCHEDULER_Task *tt;
89
90
91/**
92 * Task run to clean up on shutdown.
93 *
94 * @param cls unused
95 */
96static void
97cleanup_task (void *cls)
98{
99 if (NULL != get_handle)
100 {
101 GNUNET_DHT_get_stop (get_handle);
102 get_handle = NULL;
103 }
104 if (NULL != dht_handle)
105 {
106 GNUNET_DHT_disconnect (dht_handle);
107 dht_handle = NULL;
108 }
109 if (NULL != tt)
110 {
111 GNUNET_SCHEDULER_cancel (tt);
112 tt = NULL;
113 }
114}
115
116
117/**
118 * Task run on timeout. Triggers shutdown.
119 *
120 * @param cls unused
121 */
122static void
123timeout_task (void *cls)
124{
125 tt = NULL;
126 GNUNET_SCHEDULER_shutdown ();
127}
128
129
130/**
131 * Iterator called on each result obtained for a DHT
132 * operation that expects a reply
133 *
134 * @param cls closure
135 * @param exp when will this value expire
136 * @param key key of the result
137 * @param get_path peers on reply path (or NULL if not recorded)
138 * @param get_path_length number of entries in get_path
139 * @param put_path peers on the PUT path (or NULL if not recorded)
140 * @param put_path_length number of entries in get_path
141 * @param type type of the result
142 * @param size number of bytes in data
143 * @param data pointer to the result data
144 */
145static void
146get_result_iterator (void *cls,
147 struct GNUNET_TIME_Absolute exp,
148 const struct GNUNET_HashCode *key,
149 const struct GNUNET_DHT_PathElement *get_path,
150 unsigned int get_path_length,
151 const struct GNUNET_DHT_PathElement *put_path,
152 unsigned int put_path_length,
153 enum GNUNET_BLOCK_Type type,
154 size_t size,
155 const void *data)
156{
157 fprintf (stdout,
158 (GNUNET_BLOCK_TYPE_TEST == type)
159 ? _ ("Result %d, type %d:\n%.*s\n")
160 : _ ("Result %d, type %d:\n"),
161 result_count,
162 type,
163 (unsigned int) size,
164 (char *) data);
165 if (verbose)
166 {
167 fprintf (stdout,
168 " GET path: ");
169 for (unsigned int i = 0; i < get_path_length; i++)
170 fprintf (stdout,
171 "%s%s",
172 (0 == i) ? "" : "-",
173 GNUNET_i2s (&get_path[i].pred));
174 fprintf (stdout,
175 "\n PUT path: ");
176 for (unsigned int i = 0; i < put_path_length; i++)
177 fprintf (stdout,
178 "%s%s",
179 (0 == i) ? "" : "-",
180 GNUNET_i2s (&put_path[i].pred));
181 fprintf (stdout,
182 "\n");
183 }
184 result_count++;
185}
186
187
188/**
189 * Main function that will be run by the scheduler.
190 *
191 * @param cls closure
192 * @param args remaining command-line arguments
193 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
194 * @param c configuration
195 */
196static void
197run (void *cls,
198 char *const *args,
199 const char *cfgfile,
200 const struct GNUNET_CONFIGURATION_Handle *c)
201{
202 struct GNUNET_HashCode key;
203
204 cfg = c;
205 if (NULL == query_key)
206 {
207 fprintf (stderr,
208 "%s",
209 _ ("Must provide key for DHT GET!\n"));
210 ret = 1;
211 return;
212 }
213 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
214 {
215 fprintf (stderr,
216 "%s",
217 _ ("Failed to connect to DHT service!\n"));
218 ret = 1;
219 return;
220 }
221 if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */
222 query_type = GNUNET_BLOCK_TYPE_TEST;
223 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
224 if (verbose)
225 fprintf (stderr,
226 "%s `%s' \n",
227 _ ("Issuing DHT GET with key"),
228 GNUNET_h2s_full (&key));
229 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
230 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, &timeout_task, NULL);
231 get_handle = GNUNET_DHT_get_start (dht_handle,
232 query_type,
233 &key,
234 replication,
235 (demultixplex_everywhere)
236 ? GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
237 : GNUNET_DHT_RO_NONE,
238 NULL,
239 0,
240 &get_result_iterator,
241 NULL);
242}
243
244
245/**
246 * Entry point for gnunet-dht-get
247 *
248 * @param argc number of arguments from the command line
249 * @param argv command line arguments
250 * @return 0 ok, 1 on error
251 */
252int
253main (int argc, char *const *argv)
254{
255 struct GNUNET_GETOPT_CommandLineOption options[] = {
256 GNUNET_GETOPT_option_string (
257 'k',
258 "key",
259 "KEY",
260 gettext_noop ("the query key"),
261 &query_key),
262 GNUNET_GETOPT_option_uint (
263 'r',
264 "replication",
265 "LEVEL",
266 gettext_noop ("how many parallel requests (replicas) to create"),
267 &replication),
268 GNUNET_GETOPT_option_uint (
269 't',
270 "type",
271 "TYPE",
272 gettext_noop ("the type of data to look for"),
273 &query_type),
274 GNUNET_GETOPT_option_relative_time (
275 'T',
276 "timeout",
277 "TIMEOUT",
278 gettext_noop ("how long to execute this query before giving up?"),
279 &timeout_request),
280 GNUNET_GETOPT_option_flag (
281 'x',
282 "demultiplex",
283 gettext_noop (
284 "use DHT's demultiplex everywhere option"),
285 &demultixplex_everywhere),
286 GNUNET_GETOPT_option_verbose (&verbose),
287 GNUNET_GETOPT_OPTION_END
288 };
289
290
291 if (GNUNET_OK !=
292 GNUNET_STRINGS_get_utf8_args (argc, argv,
293 &argc, &argv))
294 return 2;
295 return (GNUNET_OK ==
296 GNUNET_PROGRAM_run (
297 argc,
298 argv,
299 "gnunet-dht-get",
300 gettext_noop (
301 "Issue a GET request to the GNUnet DHT, prints results."),
302 options,
303 &run,
304 NULL))
305 ? ret
306 : 1;
307}
308
309
310/* end of gnunet-dht-get.c */
diff --git a/src/dht/gnunet-dht-monitor.c b/src/dht/gnunet-dht-monitor.c
deleted file mode 100644
index b4ec497e4..000000000
--- a/src/dht/gnunet-dht-monitor.c
+++ /dev/null
@@ -1,345 +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 dht/gnunet-dht-monitor.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Bartlomiej Polot
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29/**
30 * The type of the query
31 */
32static unsigned int block_type;
33
34/**
35 * The key to be monitored
36 */
37static char *query_key;
38
39/**
40 * User supplied timeout value (in seconds)
41 */
42static struct GNUNET_TIME_Relative timeout_request = { 60000 };
43
44/**
45 * Be verbose
46 */
47static int verbose;
48
49/**
50 * Handle to the DHT
51 */
52static struct GNUNET_DHT_Handle *dht_handle;
53
54/**
55 * Global handle of the configuration
56 */
57static const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59/**
60 * Handle for the get request
61 */
62static struct GNUNET_DHT_MonitorHandle *monitor_handle;
63
64/**
65 * Count of messages received
66 */
67static unsigned int result_count;
68
69/**
70 * Global status value
71 */
72static int ret;
73
74/**
75 * Task scheduled to handle timeout.
76 */
77static struct GNUNET_SCHEDULER_Task *tt;
78
79
80/**
81 * Stop monitoring request and start shutdown
82 *
83 * @param cls closure (unused)
84 */
85static void
86cleanup_task (void *cls)
87{
88 if (verbose)
89 fprintf (stderr, "%s", "Cleaning up!\n");
90 if (NULL != monitor_handle)
91 {
92 GNUNET_DHT_monitor_stop (monitor_handle);
93 monitor_handle = NULL;
94 }
95 if (NULL != dht_handle)
96 {
97 GNUNET_DHT_disconnect (dht_handle);
98 dht_handle = NULL;
99 }
100 if (NULL != tt)
101 {
102 GNUNET_SCHEDULER_cancel (tt);
103 tt = NULL;
104 }
105}
106
107
108/**
109 * We hit a timeout. Stop monitoring request and start shutdown
110 *
111 * @param cls closure (unused)
112 */
113static void
114timeout_task (void *cls)
115{
116 tt = NULL;
117 GNUNET_SCHEDULER_shutdown ();
118}
119
120
121/**
122 * Callback called on each GET request going through the DHT.
123 *
124 * @param cls Closure.
125 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
126 * @param type The type of data in the request.
127 * @param hop_count Hop count so far.
128 * @param path_length number of entries in path (or 0 if not recorded).
129 * @param path peers on the GET path (or NULL if not recorded).
130 * @param desired_replication_level Desired replication level.
131 * @param key Key of the requested data.
132 */
133static void
134get_callback (void *cls,
135 enum GNUNET_DHT_RouteOption options,
136 enum GNUNET_BLOCK_Type type,
137 uint32_t hop_count,
138 uint32_t desired_replication_level,
139 unsigned int path_length,
140 const struct GNUNET_DHT_PathElement *path,
141 const struct GNUNET_HashCode *key)
142{
143 fprintf (stdout,
144 "GET #%u: type %d, key `%s'\n",
145 result_count,
146 (int) type,
147 GNUNET_h2s_full (key));
148 result_count++;
149}
150
151
152/**
153 * Callback called on each GET reply going through the DHT.
154 *
155 * @param cls Closure.
156 * @param type The type of data in the result.
157 * @param get_path Peers on GET path (or NULL if not recorded).
158 * @param get_path_length number of entries in get_path.
159 * @param put_path peers on the PUT path (or NULL if not recorded).
160 * @param put_path_length number of entries in get_path.
161 * @param exp Expiration time of the data.
162 * @param key Key of the data.
163 * @param data Pointer to the result data.
164 * @param size Number of bytes in data.
165 */
166static void
167get_resp_callback (void *cls,
168 enum GNUNET_BLOCK_Type type,
169 const struct GNUNET_DHT_PathElement *get_path,
170 unsigned int get_path_length,
171 const struct GNUNET_DHT_PathElement *put_path,
172 unsigned int put_path_length,
173 struct GNUNET_TIME_Absolute exp,
174 const struct GNUNET_HashCode *key,
175 const void *data,
176 size_t size)
177{
178 fprintf (stdout,
179 (GNUNET_BLOCK_TYPE_TEST == type)
180 ? "RESPONSE #%u (%s): type %d, key `%s', data `%.*s'\n"
181 : "RESPONSE #%u (%s): type %d, key `%s'\n",
182 result_count,
183 GNUNET_STRINGS_absolute_time_to_string (exp),
184 (int) type,
185 GNUNET_h2s_full (key),
186 (unsigned int) size,
187 (char *) data);
188 result_count++;
189}
190
191
192/**
193 * Callback called on each PUT request going through the DHT.
194 *
195 * @param cls Closure.
196 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
197 * @param type The type of data in the request.
198 * @param hop_count Hop count so far.
199 * @param path_length number of entries in path (or 0 if not recorded).
200 * @param path peers on the PUT path (or NULL if not recorded).
201 * @param desired_replication_level Desired replication level.
202 * @param exp Expiration time of the data.
203 * @param key Key under which data is to be stored.
204 * @param data Pointer to the data carried.
205 * @param size Number of bytes in data.
206 */
207static void
208put_callback (void *cls,
209 enum GNUNET_DHT_RouteOption options,
210 enum GNUNET_BLOCK_Type type,
211 uint32_t hop_count,
212 uint32_t desired_replication_level,
213 unsigned int path_length,
214 const struct GNUNET_DHT_PathElement *path,
215 struct GNUNET_TIME_Absolute exp,
216 const struct GNUNET_HashCode *key,
217 const void *data,
218 size_t size)
219{
220 fprintf (stdout,
221 (GNUNET_BLOCK_TYPE_TEST == type)
222 ? "PUT %u (%s): type %d, key `%s', data `%.*s'\n"
223 : "PUT %u (%s): type %d, key `%s'\n",
224 result_count,
225 GNUNET_STRINGS_absolute_time_to_string (exp),
226 (int) type,
227 GNUNET_h2s_full (key),
228 (unsigned int) size,
229 (char *) data);
230 result_count++;
231}
232
233
234/**
235 * Main function that will be run by the scheduler.
236 *
237 * @param cls closure
238 * @param args remaining command-line arguments
239 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
240 * @param c configuration
241 */
242static void
243run (void *cls,
244 char *const *args,
245 const char *cfgfile,
246 const struct GNUNET_CONFIGURATION_Handle *c)
247{
248 struct GNUNET_HashCode *key;
249 struct GNUNET_HashCode hc;
250
251 cfg = c;
252
253 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
254 {
255 fprintf (stderr, "%s", _ ("Failed to connect to DHT service!\n"));
256 ret = 1;
257 return;
258 }
259 if (GNUNET_BLOCK_TYPE_ANY == block_type) /* Type of data not set */
260 block_type = GNUNET_BLOCK_TYPE_TEST;
261 if (NULL != query_key)
262 {
263 key = &hc;
264 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (query_key, key))
265 GNUNET_CRYPTO_hash (query_key, strlen (query_key), key);
266 }
267 else
268 {
269 key = NULL;
270 }
271 if (verbose)
272 fprintf (stderr,
273 "Monitoring for %s\n",
274 GNUNET_STRINGS_relative_time_to_string (timeout_request,
275 GNUNET_NO));
276 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, &timeout_task, NULL);
277 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
278 monitor_handle = GNUNET_DHT_monitor_start (dht_handle,
279 block_type,
280 key,
281 &get_callback,
282 &get_resp_callback,
283 &put_callback,
284 NULL);
285}
286
287
288/**
289 * Entry point for gnunet-dht-monitor
290 *
291 * @param argc number of arguments from the command line
292 * @param argv command line arguments
293 * @return 0 ok, 1 on error
294 */
295int
296main (int argc, char *const *argv)
297{
298 struct GNUNET_GETOPT_CommandLineOption options[] = {
299 GNUNET_GETOPT_option_string ('k',
300 "key",
301 "KEY",
302 gettext_noop ("the query key"),
303 &query_key),
304
305 GNUNET_GETOPT_option_uint ('t',
306 "type",
307 "TYPE",
308 gettext_noop ("the type of data to look for"),
309 &block_type),
310
311 GNUNET_GETOPT_option_relative_time (
312 'T',
313 "timeout",
314 "TIMEOUT",
315 gettext_noop ("how long should the monitor command run"),
316 &timeout_request),
317
318 GNUNET_GETOPT_option_flag ('V',
319 "verbose",
320 gettext_noop (
321 "be verbose (print progress information)"),
322 &verbose),
323
324 GNUNET_GETOPT_OPTION_END
325 };
326
327
328 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
329 return 2;
330
331 return (GNUNET_OK ==
332 GNUNET_PROGRAM_run (argc,
333 argv,
334 "gnunet-dht-monitor",
335 gettext_noop (
336 "Prints all packets that go through the DHT."),
337 options,
338 &run,
339 NULL))
340 ? ret
341 : 1;
342}
343
344
345/* end of gnunet-dht-monitor.c */
diff --git a/src/dht/gnunet-dht-put.c b/src/dht/gnunet-dht-put.c
deleted file mode 100644
index 531107ef2..000000000
--- a/src/dht/gnunet-dht-put.c
+++ /dev/null
@@ -1,250 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 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 * @file dht/gnunet-dht-put.c
22 * @brief search for data in DHT
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_dht_service.h"
28
29/**
30 * The type of the query
31 */
32static unsigned int query_type;
33
34/**
35 * The key used in the DHT
36 */
37struct GNUNET_HashCode key;
38
39/**
40 * The key for the query
41 */
42static char *query_key;
43
44/**
45 * User supplied expiration value
46 */
47static struct GNUNET_TIME_Relative expiration;
48
49/**
50 * Desired replication level.
51 */
52static unsigned int replication = 5;
53
54/**
55 * Be verbose
56 */
57static unsigned int verbose;
58
59/**
60 * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE.
61 */
62static int demultixplex_everywhere;
63
64/**
65 * Use #GNUNET_DHT_RO_RECORD_ROUTE.
66 */
67static int record_route;
68
69/**
70 * Handle to the DHT
71 */
72static struct GNUNET_DHT_Handle *dht_handle;
73
74
75/**
76 * Global handle of the configuration
77 */
78static const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80/**
81 * Global status value
82 */
83static int ret;
84
85/**
86 * The data to insert into the dht
87 */
88static char *data;
89
90
91static void
92shutdown_task (void *cls)
93{
94 if (NULL != dht_handle)
95 {
96 GNUNET_DHT_disconnect (dht_handle);
97 dht_handle = NULL;
98 }
99}
100
101
102/**
103 * Signature of the main function of a task.
104 *
105 * @param cls closure
106 */
107static void
108message_sent_cont (void *cls)
109{
110 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
111}
112
113
114/**
115 * Main function that will be run by the scheduler.
116 *
117 * @param cls closure
118 * @param args remaining command-line arguments
119 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
120 * @param c configuration
121 */
122static void
123run (void *cls,
124 char *const *args,
125 const char *cfgfile,
126 const struct GNUNET_CONFIGURATION_Handle *c)
127{
128 enum GNUNET_DHT_RouteOption ro;
129
130 cfg = c;
131 if ((NULL == query_key) || (NULL == data))
132 {
133 fprintf (stderr, "%s", _ ("Must provide KEY and DATA for DHT put!\n"));
134 ret = 1;
135 return;
136 }
137
138 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
139 {
140 fprintf (stderr, _ ("Could not connect to DHT service!\n"));
141 ret = 1;
142 return;
143 }
144 if (GNUNET_BLOCK_TYPE_ANY == query_type) /* Type of data not set */
145 query_type = GNUNET_BLOCK_TYPE_TEST;
146
147 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
148
149 if (verbose)
150 fprintf (stderr,
151 _ ("Issuing put request for `%s' with data `%s'!\n"),
152 query_key,
153 data);
154 ro = GNUNET_DHT_RO_NONE;
155 if (demultixplex_everywhere)
156 ro |= GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
157 if (record_route)
158 ro |= GNUNET_DHT_RO_RECORD_ROUTE;
159 GNUNET_DHT_put (dht_handle,
160 &key,
161 replication,
162 ro,
163 query_type,
164 strlen (data),
165 data,
166 GNUNET_TIME_relative_to_absolute (expiration),
167 &message_sent_cont,
168 NULL);
169}
170
171
172/**
173 * Entry point for gnunet-dht-put
174 *
175 * @param argc number of arguments from the command line
176 * @param argv command line arguments
177 * @return 0 ok, 1 on error
178 */
179int
180main (int argc, char *const *argv)
181{
182 struct GNUNET_GETOPT_CommandLineOption options[] = {
183 GNUNET_GETOPT_option_string (
184 'd',
185 "data",
186 "DATA",
187 gettext_noop (
188 "the data to insert under the key"),
189 &data),
190 GNUNET_GETOPT_option_relative_time (
191 'e',
192 "expiration",
193 "EXPIRATION",
194 gettext_noop ("how long to store this entry in the dht (in seconds)"),
195 &expiration),
196 GNUNET_GETOPT_option_string (
197 'k',
198 "key",
199 "KEY",
200 gettext_noop ("the query key"),
201 &query_key),
202 GNUNET_GETOPT_option_flag (
203 'x',
204 "demultiplex",
205 gettext_noop (
206 "use DHT's demultiplex everywhere option"),
207 &demultixplex_everywhere),
208 GNUNET_GETOPT_option_uint (
209 'r',
210 "replication",
211 "LEVEL",
212 gettext_noop ("how many replicas to create"),
213 &replication),
214 GNUNET_GETOPT_option_flag (
215 'R',
216 "record",
217 gettext_noop ("use DHT's record route option"),
218 &record_route),
219 GNUNET_GETOPT_option_uint (
220 't',
221 "type",
222 "TYPE",
223 gettext_noop ("the type to insert data as"),
224 &query_type),
225 GNUNET_GETOPT_option_verbose (&verbose),
226 GNUNET_GETOPT_OPTION_END
227 };
228
229
230 if (GNUNET_OK !=
231 GNUNET_STRINGS_get_utf8_args (argc, argv,
232 &argc, &argv))
233 return 2;
234 expiration = GNUNET_TIME_UNIT_HOURS;
235 return (GNUNET_OK ==
236 GNUNET_PROGRAM_run (
237 argc,
238 argv,
239 "gnunet-dht-put",
240 gettext_noop (
241 "Issue a PUT request to the GNUnet DHT insert DATA under KEY."),
242 options,
243 &run,
244 NULL))
245 ? ret
246 : 1;
247}
248
249
250/* end of gnunet-dht-put.c */
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c
deleted file mode 100644
index da46dcfee..000000000
--- a/src/dht/gnunet-service-dht.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file dht/gnunet-service-dht.c
23 * @brief GNUnet DHT service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_block_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_transport_hello_service.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_dht_service.h"
34#include "gnunet_statistics_service.h"
35#include "gnunet-service-dht.h"
36#include "gnunet-service-dht_datacache.h"
37#include "gnunet-service-dht_hello.h"
38#include "gnunet-service-dht_neighbours.h"
39#include "gnunet-service-dht_nse.h"
40#include "gnunet-service-dht_routing.h"
41
42/**
43 * Our HELLO
44 */
45struct GNUNET_MessageHeader *GDS_my_hello;
46
47/**
48 * Handle to get our current HELLO.
49 */
50static struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
51
52/**
53 * Hello address expiration
54 */
55struct GNUNET_TIME_Relative hello_expiration;
56
57
58#include "gnunet-service-dht_clients.c"
59
60
61/**
62 * Receive the HELLO from transport service, free current and replace
63 * if necessary.
64 *
65 * @param cls NULL
66 * @param message HELLO message of peer
67 */
68static void
69process_hello (void *cls,
70 const struct GNUNET_MessageHeader *message)
71{
72 GNUNET_free (GDS_my_hello);
73 GDS_my_hello = GNUNET_malloc (ntohs (message->size));
74 GNUNET_memcpy (GDS_my_hello,
75 message,
76 ntohs (message->size));
77}
78
79
80/**
81 * Task run during shutdown.
82 *
83 * @param cls unused
84 */
85static void
86shutdown_task (void *cls)
87{
88 if (NULL != ghh)
89 {
90 GNUNET_TRANSPORT_hello_get_cancel (ghh);
91 ghh = NULL;
92 }
93 GDS_NEIGHBOURS_done ();
94 GDS_DATACACHE_done ();
95 GDS_ROUTING_done ();
96 GDS_HELLO_done ();
97 GDS_NSE_done ();
98 if (NULL != GDS_block_context)
99 {
100 GNUNET_BLOCK_context_destroy (GDS_block_context);
101 GDS_block_context = NULL;
102 }
103 if (NULL != GDS_stats)
104 {
105 GNUNET_STATISTICS_destroy (GDS_stats,
106 GNUNET_YES);
107 GDS_stats = NULL;
108 }
109 GNUNET_free (GDS_my_hello);
110 GDS_my_hello = NULL;
111 GDS_CLIENTS_stop ();
112}
113
114
115/**
116 * Process dht requests.
117 *
118 * @param cls closure
119 * @param c configuration to use
120 * @param service the initialized service
121 */
122static void
123run (void *cls,
124 const struct GNUNET_CONFIGURATION_Handle *c,
125 struct GNUNET_SERVICE_Handle *service)
126{
127 GDS_cfg = c;
128 GDS_service = service;
129 if (GNUNET_OK !=
130 GNUNET_CONFIGURATION_get_value_time (c,
131 "transport",
132 "HELLO_EXPIRATION",
133 &hello_expiration))
134 {
135 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
136 }
137 GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
138 GDS_stats = GNUNET_STATISTICS_create ("dht",
139 GDS_cfg);
140 GNUNET_SERVICE_suspend (GDS_service);
141 GDS_CLIENTS_init ();
142 GDS_ROUTING_init ();
143 GDS_NSE_init ();
144 GDS_DATACACHE_init ();
145 GDS_HELLO_init ();
146 if (GNUNET_OK != GDS_NEIGHBOURS_init ())
147 {
148 shutdown_task (NULL);
149 return;
150 }
151 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
152 NULL);
153 ghh = GNUNET_TRANSPORT_hello_get (GDS_cfg,
154 GNUNET_TRANSPORT_AC_GLOBAL,
155 &process_hello,
156 NULL);
157}
158
159
160/* Finally, define the main method */
161GDS_DHT_SERVICE_INIT ("dht", &run);
162
163
164/* end of gnunet-service-dht.c */
diff --git a/src/dht/gnunet-service-dht.h b/src/dht/gnunet-service-dht.h
deleted file mode 100644
index 367ff426e..000000000
--- a/src/dht/gnunet-service-dht.h
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file dht/gnunet-service-dht.h
23 * @brief GNUnet DHT globals
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_DHT_H
27#define GNUNET_SERVICE_DHT_H
28
29#include "gnunet-service-dht_datacache.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_transport_service.h"
32
33
34#define DEBUG_DHT GNUNET_EXTRA_LOGGING
35
36/**
37 * Configuration we use.
38 */
39extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
40
41/**
42 * Handle for the service.
43 */
44extern struct GNUNET_SERVICE_Handle *GDS_service;
45
46/**
47 * Our handle to the BLOCK library.
48 */
49extern struct GNUNET_BLOCK_Context *GDS_block_context;
50
51/**
52 * Handle for the statistics service.
53 */
54extern struct GNUNET_STATISTICS_Handle *GDS_stats;
55
56/**
57 * Our HELLO
58 */
59extern struct GNUNET_MessageHeader *GDS_my_hello;
60
61
62/**
63 * Handle a reply we've received from another peer. If the reply
64 * matches any of our pending queries, forward it to the respective
65 * client(s).
66 *
67 * @param bd block details
68 * @param query_hash hash of the original query, might not match key in @a bd
69 * @param get_path_length number of entries in @a get_path
70 * @param get_path path the reply has taken
71 */
72void
73GDS_CLIENTS_handle_reply (const struct GDS_DATACACHE_BlockData *bd,
74 const struct GNUNET_HashCode *query_hash,
75 unsigned int get_path_length,
76 const struct GNUNET_DHT_PathElement *get_path);
77
78
79/**
80 * Check if some client is monitoring GET messages and notify
81 * them in that case.
82 *
83 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
84 * @param type The type of data in the request.
85 * @param hop_count Hop count so far.
86 * @param path_length number of entries in path (or 0 if not recorded).
87 * @param path peers on the GET path (or NULL if not recorded).
88 * @param desired_replication_level Desired replication level.
89 * @param key Key of the requested data.
90 */
91void
92GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption options,
93 enum GNUNET_BLOCK_Type type,
94 uint32_t hop_count,
95 uint32_t desired_replication_level,
96 unsigned int path_length,
97 const struct GNUNET_DHT_PathElement *path,
98 const struct GNUNET_HashCode *key);
99
100
101/**
102 * Check if some client is monitoring GET RESP messages and notify
103 * them in that case.
104 *
105 * @param bd block details
106 * @param get_path Peers on GET path (or NULL if not recorded).
107 * @param get_path_length number of entries in @a get_path.
108 */
109void
110GDS_CLIENTS_process_get_resp (const struct GDS_DATACACHE_BlockData *bd,
111 const struct GNUNET_DHT_PathElement *get_path,
112 unsigned int get_path_length);
113
114
115/**
116 * Check if some client is monitoring PUT messages and notify
117 * them in that case. The @a path should include our own
118 * peer ID (if recorded).
119 *
120 * @param options routing options to apply
121 * @param bd details about the block
122 * @param hop_count Hop count so far.
123 * @param desired_replication_level Desired replication level.
124 */
125void
126GDS_CLIENTS_process_put (enum GNUNET_DHT_RouteOption options,
127 const struct GDS_DATACACHE_BlockData *bd,
128 uint32_t hop_count,
129 uint32_t desired_replication_level);
130
131#endif
diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c
deleted file mode 100644
index a1c3024de..000000000
--- a/src/dht/gnunet-service-dht_clients.c
+++ /dev/null
@@ -1,1531 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016, 2017, 2022 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 dht/gnunet-service-dht_clients.c
23 * @brief GNUnet DHT service's client management code
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27
28#include "platform.h"
29#include "gnunet_constants.h"
30#include "gnunet_protocols.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet-service-dht.h"
33#include "gnunet-service-dht_datacache.h"
34#include "gnunet-service-dht_neighbours.h"
35#include "dht.h"
36
37
38/**
39 * Should routing details be logged to stderr (for debugging)?
40 */
41#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
42 __VA_ARGS__)
43
44#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
45
46
47/**
48 * Struct containing information about a client,
49 * handle to connect to it, and any pending messages
50 * that need to be sent to it.
51 */
52struct ClientHandle;
53
54
55/**
56 * Entry in the local forwarding map for a client's GET request.
57 */
58struct ClientQueryRecord
59{
60 /**
61 * The key this request was about
62 */
63 struct GNUNET_HashCode key;
64
65 /**
66 * Kept in a DLL with @e client.
67 */
68 struct ClientQueryRecord *next;
69
70 /**
71 * Kept in a DLL with @e client.
72 */
73 struct ClientQueryRecord *prev;
74
75 /**
76 * Client responsible for the request.
77 */
78 struct ClientHandle *ch;
79
80 /**
81 * Extended query (see gnunet_block_lib.h), allocated at the end of this struct.
82 */
83 const void *xquery;
84
85 /**
86 * Array of (hashes of) replies we have already seen for this request.
87 */
88 struct GNUNET_HashCode *seen_replies;
89
90 /**
91 * Pointer to this nodes heap location in the retry-heap (for fast removal)
92 */
93 struct GNUNET_CONTAINER_HeapNode *hnode;
94
95 /**
96 * What's the delay between re-try operations that we currently use for this
97 * request?
98 */
99 struct GNUNET_TIME_Relative retry_frequency;
100
101 /**
102 * What's the next time we should re-try this request?
103 */
104 struct GNUNET_TIME_Absolute retry_time;
105
106 /**
107 * The unique identifier of this request
108 */
109 uint64_t unique_id;
110
111 /**
112 * Number of bytes in xquery.
113 */
114 size_t xquery_size;
115
116 /**
117 * Number of entries in @e seen_replies.
118 */
119 unsigned int seen_replies_count;
120
121 /**
122 * Desired replication level
123 */
124 uint32_t replication;
125
126 /**
127 * Any message options for this request
128 */
129 enum GNUNET_DHT_RouteOption msg_options;
130
131 /**
132 * The type for the data for the GET request.
133 */
134 enum GNUNET_BLOCK_Type type;
135};
136
137
138/**
139 * Struct containing parameters of monitoring requests.
140 */
141struct ClientMonitorRecord
142{
143 /**
144 * Next element in DLL.
145 */
146 struct ClientMonitorRecord *next;
147
148 /**
149 * Previous element in DLL.
150 */
151 struct ClientMonitorRecord *prev;
152
153 /**
154 * Client to notify of these requests.
155 */
156 struct ClientHandle *ch;
157
158 /**
159 * Key of data of interest. All bits zero for 'all'.
160 */
161 struct GNUNET_HashCode key;
162
163 /**
164 * Type of blocks that are of interest
165 */
166 enum GNUNET_BLOCK_Type type;
167
168 /**
169 * Flag whether to notify about GET messages.
170 */
171 int16_t get;
172
173 /**
174 * Flag whether to notify about GET_REPONSE messages.
175 */
176 int16_t get_resp;
177
178 /**
179 * Flag whether to notify about PUT messages.
180 */
181 uint16_t put;
182
183};
184
185
186/**
187 * Struct containing information about a client,
188 * handle to connect to it, and any pending messages
189 * that need to be sent to it.
190 */
191struct ClientHandle
192{
193 /**
194 * Linked list of active queries of this client.
195 */
196 struct ClientQueryRecord *cqr_head;
197
198 /**
199 * Linked list of active queries of this client.
200 */
201 struct ClientQueryRecord *cqr_tail;
202
203 /**
204 * The handle to this client
205 */
206 struct GNUNET_SERVICE_Client *client;
207
208 /**
209 * The message queue to this client
210 */
211 struct GNUNET_MQ_Handle *mq;
212};
213
214
215/**
216 * Our handle to the BLOCK library.
217 */
218struct GNUNET_BLOCK_Context *GDS_block_context;
219
220/**
221 * Handle for the statistics service.
222 */
223struct GNUNET_STATISTICS_Handle *GDS_stats;
224
225/**
226 * Handle for the service.
227 */
228struct GNUNET_SERVICE_Handle *GDS_service;
229
230/**
231 * The configuration the DHT service is running with
232 */
233const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
234
235/**
236 * List of active monitoring requests.
237 */
238static struct ClientMonitorRecord *monitor_head;
239
240/**
241 * List of active monitoring requests.
242 */
243static struct ClientMonitorRecord *monitor_tail;
244
245/**
246 * Hashmap for fast key based lookup, maps keys to `struct ClientQueryRecord` entries.
247 */
248static struct GNUNET_CONTAINER_MultiHashMap *forward_map;
249
250/**
251 * Heap with all of our client's request, sorted by retry time (earliest on top).
252 */
253static struct GNUNET_CONTAINER_Heap *retry_heap;
254
255/**
256 * Task that re-transmits requests (using retry_heap).
257 */
258static struct GNUNET_SCHEDULER_Task *retry_task;
259
260
261/**
262 * Free data structures associated with the given query.
263 *
264 * @param record record to remove
265 */
266static void
267remove_client_query_record (struct ClientQueryRecord *record)
268{
269 struct ClientHandle *ch = record->ch;
270
271 GNUNET_CONTAINER_DLL_remove (ch->cqr_head,
272 ch->cqr_tail,
273 record);
274 GNUNET_assert (GNUNET_YES ==
275 GNUNET_CONTAINER_multihashmap_remove (forward_map,
276 &record->key,
277 record));
278 if (NULL != record->hnode)
279 GNUNET_CONTAINER_heap_remove_node (record->hnode);
280 GNUNET_array_grow (record->seen_replies,
281 record->seen_replies_count,
282 0);
283 GNUNET_free (record);
284}
285
286
287/**
288 * Functions with this signature are called whenever a local client is
289 * connects to us.
290 *
291 * @param cls closure (NULL for dht)
292 * @param client identification of the client
293 * @param mq message queue for talking to @a client
294 * @return our `struct ClientHandle` for @a client
295 */
296static void *
297client_connect_cb (void *cls,
298 struct GNUNET_SERVICE_Client *client,
299 struct GNUNET_MQ_Handle *mq)
300{
301 struct ClientHandle *ch;
302
303 (void) cls;
304 ch = GNUNET_new (struct ClientHandle);
305 ch->client = client;
306 ch->mq = mq;
307 return ch;
308}
309
310
311/**
312 * Functions with this signature are called whenever a client
313 * is disconnected on the network level.
314 *
315 * @param cls closure (NULL for dht)
316 * @param client identification of the client
317 * @param app_ctx our `struct ClientHandle` for @a client
318 */
319static void
320client_disconnect_cb (void *cls,
321 struct GNUNET_SERVICE_Client *client,
322 void *app_ctx)
323{
324 struct ClientHandle *ch = app_ctx;
325
326 (void) cls;
327 (void) client;
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "Local client %p disconnects\n",
330 ch);
331 {
332 struct ClientMonitorRecord *next;
333
334 for (struct ClientMonitorRecord *monitor = monitor_head;
335 NULL != monitor;
336 monitor = next)
337 {
338 next = monitor->next;
339 if (monitor->ch != ch)
340 continue;
341 GNUNET_CONTAINER_DLL_remove (monitor_head,
342 monitor_tail,
343 monitor);
344 GNUNET_free (monitor);
345 }
346 }
347
348 {
349 struct ClientQueryRecord *cqr;
350
351 while (NULL != (cqr = ch->cqr_head))
352 remove_client_query_record (cqr);
353 }
354 GNUNET_free (ch);
355}
356
357
358/**
359 * Route the given request via the DHT. This includes updating
360 * the bloom filter and retransmission times, building the P2P
361 * message and initiating the routing operation.
362 *
363 * @param cqr request to transmit
364 */
365static void
366transmit_request (struct ClientQueryRecord *cqr)
367{
368 struct GNUNET_BLOCK_Group *bg;
369 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
370
371 GNUNET_STATISTICS_update (GDS_stats,
372 "# GET requests from clients injected",
373 1,
374 GNUNET_NO);
375 bg = GNUNET_BLOCK_group_create (GDS_block_context,
376 cqr->type,
377 GNUNET_CRYPTO_random_u32 (
378 GNUNET_CRYPTO_QUALITY_WEAK,
379 UINT32_MAX),
380 NULL, /* raw data */
381 0, /* raw data size */
382 "seen-set-size",
383 cqr->seen_replies_count,
384 NULL);
385 GNUNET_BLOCK_group_set_seen (bg,
386 cqr->seen_replies,
387 cqr->seen_replies_count);
388 peer_bf
389 = GNUNET_CONTAINER_bloomfilter_init (NULL,
390 DHT_BLOOM_SIZE,
391 GNUNET_CONSTANTS_BLOOMFILTER_K);
392 LOG (GNUNET_ERROR_TYPE_DEBUG,
393 "Initiating GET for %s, replication %u, already have %u replies\n",
394 GNUNET_h2s (&cqr->key),
395 cqr->replication,
396 cqr->seen_replies_count);
397 GDS_NEIGHBOURS_handle_get (cqr->type,
398 cqr->msg_options,
399 cqr->replication,
400 0 /* hop count */,
401 &cqr->key,
402 cqr->xquery,
403 cqr->xquery_size,
404 bg,
405 peer_bf);
406 GNUNET_BLOCK_group_destroy (bg);
407 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
408
409 /* Exponential back-off for retries.
410 * max. is #GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD (15 min) */
411 cqr->retry_frequency = GNUNET_TIME_STD_BACKOFF (cqr->retry_frequency);
412 cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency);
413}
414
415
416/**
417 * Task that looks at the #retry_heap and transmits all of the requests
418 * on the heap that are ready for transmission. Then re-schedules
419 * itself (unless the heap is empty).
420 *
421 * @param cls unused
422 */
423static void
424transmit_next_request_task (void *cls)
425{
426 struct ClientQueryRecord *cqr;
427
428 (void) cls;
429 retry_task = NULL;
430 while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap)))
431 {
432 cqr->hnode = NULL;
433 if (! GNUNET_TIME_absolute_is_past (cqr->retry_time))
434 {
435 cqr->hnode
436 = GNUNET_CONTAINER_heap_insert (retry_heap,
437 cqr,
438 cqr->retry_time.abs_value_us);
439 retry_task
440 = GNUNET_SCHEDULER_add_at (cqr->retry_time,
441 &transmit_next_request_task,
442 NULL);
443 return;
444 }
445 transmit_request (cqr);
446 cqr->hnode
447 = GNUNET_CONTAINER_heap_insert (retry_heap,
448 cqr,
449 cqr->retry_time.abs_value_us);
450 }
451}
452
453
454/**
455 * Check DHT PUT messages from the client.
456 *
457 * @param cls the client we received this message from
458 * @param dht_msg the actual message received
459 * @return #GNUNET_OK (always)
460 */
461static enum GNUNET_GenericReturnValue
462check_dht_local_put (void *cls,
463 const struct GNUNET_DHT_ClientPutMessage *dht_msg)
464{
465 uint32_t replication_level = ntohl (dht_msg->desired_replication_level);
466
467 (void) cls;
468 if (replication_level > GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL)
469 {
470 GNUNET_break_op (0);
471 return GNUNET_SYSERR;
472 }
473 return GNUNET_OK;
474}
475
476
477/**
478 * Handler for PUT messages.
479 *
480 * @param cls the client we received this message from
481 * @param dht_msg the actual message received
482 */
483static void
484handle_dht_local_put (void *cls,
485 const struct GNUNET_DHT_ClientPutMessage *dht_msg)
486{
487 struct ClientHandle *ch = cls;
488 uint16_t size = ntohs (dht_msg->header.size);
489 enum GNUNET_DHT_RouteOption options
490 = (enum GNUNET_DHT_RouteOption) ntohl (dht_msg->options);
491 uint32_t replication_level
492 = ntohl (dht_msg->desired_replication_level);
493 struct GDS_DATACACHE_BlockData bd = {
494 .key = dht_msg->key,
495 .expiration_time = GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
496 .data = &dht_msg[1],
497 .data_size = size - sizeof (*dht_msg),
498 .type = ntohl (dht_msg->type)
499 };
500
501 LOG (GNUNET_ERROR_TYPE_DEBUG,
502 "Handling local PUT of %lu-bytes for query %s of type %u\n",
503 (unsigned long) (size - sizeof(struct GNUNET_DHT_ClientPutMessage)),
504 GNUNET_h2s (&dht_msg->key),
505 (unsigned int) bd.type);
506 GNUNET_STATISTICS_update (GDS_stats,
507 "# PUT requests received from clients",
508 1,
509 GNUNET_NO);
510 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
511 "CLIENT-PUT %s\n",
512 GNUNET_h2s_full (&dht_msg->key));
513 /* give to local clients */
514 GDS_CLIENTS_handle_reply (&bd,
515 &bd.key,
516 0, NULL /* get path */);
517
518 {
519 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
520
521 peer_bf
522 = GNUNET_CONTAINER_bloomfilter_init (NULL,
523 DHT_BLOOM_SIZE,
524 GNUNET_CONSTANTS_BLOOMFILTER_K);
525 /* store locally */
526 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
527 (GDS_am_closest_peer (&dht_msg->key,
528 peer_bf)))
529 GDS_DATACACHE_handle_put (&bd);
530 /* route to other peers */
531 if (GNUNET_OK !=
532 GDS_NEIGHBOURS_handle_put (&bd,
533 options,
534 replication_level,
535 0 /* hop count */,
536 peer_bf))
537 {
538 GNUNET_STATISTICS_update (GDS_stats,
539 "# Local PUT requests not routed",
540 1,
541 GNUNET_NO);
542 }
543 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
544 }
545 GDS_CLIENTS_process_put (
546 options,
547 &bd,
548 0, /* hop count */
549 replication_level);
550 GNUNET_SERVICE_client_continue (ch->client);
551}
552
553
554/**
555 * Handle a result from local datacache for a GET operation.
556 *
557 * @param cls the `struct ClientHandle` of the client doing the query
558 * @param bd details about the block that was found
559 */
560static void
561handle_local_result (void *cls,
562 const struct GDS_DATACACHE_BlockData *bd)
563{
564 /* FIXME: use 'cls' instead of looking up the client? */
565 GDS_CLIENTS_handle_reply (bd,
566 &bd->key,
567 0, NULL /* get_path */);
568}
569
570
571/**
572 * Check DHT GET messages from the client.
573 *
574 * @param cls the client we received this message from
575 * @param message the actual message received
576 * @return #GNUNET_OK (always)
577 */
578static enum GNUNET_GenericReturnValue
579check_dht_local_get (void *cls,
580 const struct GNUNET_DHT_ClientGetMessage *get)
581{
582 (void) cls;
583 (void) get;
584 /* always well-formed */
585 return GNUNET_OK;
586}
587
588
589/**
590 * Handler for DHT GET messages from the client.
591 *
592 * @param cls the client we received this message from
593 * @param message the actual message received
594 */
595static void
596handle_dht_local_get (void *cls,
597 const struct GNUNET_DHT_ClientGetMessage *get)
598{
599 struct ClientHandle *ch = cls;
600 struct ClientQueryRecord *cqr;
601 uint16_t size = ntohs (get->header.size);
602 const char *xquery = (const char *) &get[1];
603 size_t xquery_size = size - sizeof(struct GNUNET_DHT_ClientGetMessage);
604
605 LOG (GNUNET_ERROR_TYPE_DEBUG,
606 "Received GET request for %s from local client %p, xq: %.*s\n",
607 GNUNET_h2s (&get->key),
608 ch->client,
609 (int) xquery_size,
610 xquery);
611 GNUNET_STATISTICS_update (GDS_stats,
612 "# GET requests received from clients",
613 1,
614 GNUNET_NO);
615 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
616 "CLIENT-GET %s\n",
617 GNUNET_h2s_full (&get->key));
618
619 cqr = GNUNET_malloc (sizeof(struct ClientQueryRecord) + xquery_size);
620 cqr->key = get->key;
621 cqr->ch = ch;
622 cqr->xquery = (const void *) &cqr[1];
623 GNUNET_memcpy (&cqr[1],
624 xquery,
625 xquery_size);
626 cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap,
627 cqr,
628 0);
629 cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS;
630 cqr->retry_time = GNUNET_TIME_absolute_get ();
631 cqr->unique_id = get->unique_id;
632 cqr->xquery_size = xquery_size;
633 cqr->replication = ntohl (get->desired_replication_level);
634 cqr->msg_options = (enum GNUNET_DHT_RouteOption) ntohl (get->options);
635 cqr->type = ntohl (get->type);
636 GNUNET_CONTAINER_DLL_insert (ch->cqr_head,
637 ch->cqr_tail,
638 cqr);
639 GNUNET_CONTAINER_multihashmap_put (forward_map,
640 &cqr->key,
641 cqr,
642 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
643 GDS_CLIENTS_process_get (cqr->msg_options,
644 cqr->type,
645 0, /* hop count */
646 cqr->replication,
647 0, /* path length */
648 NULL,
649 &get->key);
650 /* start remote requests */
651 if (NULL != retry_task)
652 GNUNET_SCHEDULER_cancel (retry_task);
653 retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task,
654 NULL);
655 /* perform local lookup */
656 GDS_DATACACHE_handle_get (&get->key,
657 cqr->type,
658 cqr->xquery,
659 xquery_size,
660 NULL,
661 &handle_local_result,
662 ch);
663 GNUNET_SERVICE_client_continue (ch->client);
664}
665
666
667/**
668 * Closure for #find_by_unique_id().
669 */
670struct FindByUniqueIdContext
671{
672 /**
673 * Where to store the result, if found.
674 */
675 struct ClientQueryRecord *cqr;
676
677 /**
678 * Unique ID to look for.
679 */
680 uint64_t unique_id;
681};
682
683
684/**
685 * Function called for each existing DHT record for the given
686 * query. Checks if it matches the UID given in the closure
687 * and if so returns the entry as a result.
688 *
689 * @param cls the search context
690 * @param key query for the lookup (not used)
691 * @param value the `struct ClientQueryRecord`
692 * @return #GNUNET_YES to continue iteration (result not yet found)
693 */
694static enum GNUNET_GenericReturnValue
695find_by_unique_id (void *cls,
696 const struct GNUNET_HashCode *key,
697 void *value)
698{
699 struct FindByUniqueIdContext *fui_ctx = cls;
700 struct ClientQueryRecord *cqr = value;
701
702 if (cqr->unique_id != fui_ctx->unique_id)
703 return GNUNET_YES;
704 fui_ctx->cqr = cqr;
705 return GNUNET_NO;
706}
707
708
709/**
710 * Check "GET result seen" messages from the client.
711 *
712 * @param cls the client we received this message from
713 * @param message the actual message received
714 * @return #GNUNET_OK if @a seen is well-formed
715 */
716static enum GNUNET_GenericReturnValue
717check_dht_local_get_result_seen (
718 void *cls,
719 const struct GNUNET_DHT_ClientGetResultSeenMessage *seen)
720{
721 uint16_t size = ntohs (seen->header.size);
722 unsigned int hash_count =
723 (size - sizeof(*seen))
724 / sizeof(struct GNUNET_HashCode);
725
726 if (size != sizeof(*seen) + hash_count * sizeof(struct GNUNET_HashCode))
727 {
728 GNUNET_break (0);
729 return GNUNET_SYSERR;
730 }
731 return GNUNET_OK;
732}
733
734
735/**
736 * Handler for "GET result seen" messages from the client.
737 *
738 * @param cls the client we received this message from
739 * @param message the actual message received
740 */
741static void
742handle_dht_local_get_result_seen (
743 void *cls,
744 const struct GNUNET_DHT_ClientGetResultSeenMessage *seen)
745{
746 struct ClientHandle *ch = cls;
747 uint16_t size = ntohs (seen->header.size);
748 unsigned int hash_count = (size - sizeof(*seen))
749 / sizeof(struct GNUNET_HashCode);
750 const struct GNUNET_HashCode *hc = (const struct GNUNET_HashCode*) &seen[1];
751 struct FindByUniqueIdContext fui_ctx = {
752 .unique_id = seen->unique_id
753 };
754 unsigned int old_count;
755 struct ClientQueryRecord *cqr;
756
757 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
758 &seen->key,
759 &find_by_unique_id,
760 &fui_ctx);
761 if (NULL == (cqr = fui_ctx.cqr))
762 {
763 GNUNET_break (0);
764 GNUNET_SERVICE_client_drop (ch->client);
765 return;
766 }
767 /* finally, update 'seen' list */
768 old_count = cqr->seen_replies_count;
769 GNUNET_array_grow (cqr->seen_replies,
770 cqr->seen_replies_count,
771 cqr->seen_replies_count + hash_count);
772 GNUNET_memcpy (&cqr->seen_replies[old_count],
773 hc,
774 sizeof(struct GNUNET_HashCode) * hash_count);
775}
776
777
778/**
779 * Closure for #remove_by_unique_id().
780 */
781struct RemoveByUniqueIdContext
782{
783 /**
784 * Client that issued the removal request.
785 */
786 struct ClientHandle *ch;
787
788 /**
789 * Unique ID of the request.
790 */
791 uint64_t unique_id;
792};
793
794
795/**
796 * Iterator over hash map entries that frees all entries
797 * that match the given client and unique ID.
798 *
799 * @param cls unique ID and client to search for in source routes
800 * @param key current key code
801 * @param value value in the hash map, a ClientQueryRecord
802 * @return #GNUNET_YES (we should continue to iterate)
803 */
804static enum GNUNET_GenericReturnValue
805remove_by_unique_id (void *cls,
806 const struct GNUNET_HashCode *key,
807 void *value)
808{
809 const struct RemoveByUniqueIdContext *ctx = cls;
810 struct ClientQueryRecord *cqr = value;
811
812 if (cqr->unique_id != ctx->unique_id)
813 return GNUNET_YES;
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "Removing client %p's record for key %s (by unique id)\n",
816 ctx->ch->client,
817 GNUNET_h2s (key));
818 remove_client_query_record (cqr);
819 return GNUNET_YES;
820}
821
822
823/**
824 * Handler for any generic DHT stop messages, calls the appropriate handler
825 * depending on message type (if processed locally)
826 *
827 * @param cls client we received this message from
828 * @param message the actual message received
829 *
830 */
831static void
832handle_dht_local_get_stop (
833 void *cls,
834 const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg)
835{
836 struct ClientHandle *ch = cls;
837 struct RemoveByUniqueIdContext ctx;
838
839 GNUNET_STATISTICS_update (GDS_stats,
840 "# GET STOP requests received from clients",
841 1,
842 GNUNET_NO);
843 LOG (GNUNET_ERROR_TYPE_DEBUG,
844 "Received GET STOP request for %s from local client %p\n",
845 GNUNET_h2s (&dht_stop_msg->key),
846 ch->client);
847 ctx.ch = ch;
848 ctx.unique_id = dht_stop_msg->unique_id;
849 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
850 &dht_stop_msg->key,
851 &remove_by_unique_id,
852 &ctx);
853 GNUNET_SERVICE_client_continue (ch->client);
854}
855
856
857/**
858 * Closure for #forward_reply()
859 */
860struct ForwardReplyContext
861{
862 /**
863 * Block details.
864 */
865 const struct GDS_DATACACHE_BlockData *bd;
866
867 /**
868 * GET path taken.
869 */
870 const struct GNUNET_DHT_PathElement *get_path;
871
872 /**
873 * Number of entries in @e get_path.
874 */
875 unsigned int get_path_length;
876
877};
878
879
880/**
881 * Iterator over hash map entries that send a given reply to
882 * each of the matching clients. With some tricky recycling
883 * of the buffer.
884 *
885 * @param cls the `struct ForwardReplyContext`
886 * @param query_hash hash of the query for which this may be a reply
887 * @param value value in the hash map, a ClientQueryRecord
888 * @return #GNUNET_YES (we should continue to iterate),
889 * if the result is mal-formed, #GNUNET_NO
890 */
891static enum GNUNET_GenericReturnValue
892forward_reply (void *cls,
893 const struct GNUNET_HashCode *query_hash,
894 void *value)
895{
896 struct ForwardReplyContext *frc = cls;
897 struct ClientQueryRecord *record = value;
898 struct GNUNET_MQ_Envelope *env;
899 struct GNUNET_DHT_ClientResultMessage *reply;
900 enum GNUNET_BLOCK_ReplyEvaluationResult eval;
901 bool do_free;
902 struct GNUNET_HashCode ch;
903 struct GNUNET_DHT_PathElement *paths;
904
905 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
906 "CLIENT-RESULT %s\n",
907 GNUNET_h2s_full (&frc->bd->key));
908 if ( (record->type != GNUNET_BLOCK_TYPE_ANY) &&
909 (record->type != frc->bd->type) )
910 {
911 LOG (GNUNET_ERROR_TYPE_DEBUG,
912 "Record type mismatch, not passing request for key %s to local client\n",
913 GNUNET_h2s (&frc->bd->key));
914 GNUNET_STATISTICS_update (GDS_stats,
915 "# Key match, type mismatches in REPLY to CLIENT",
916 1,
917 GNUNET_NO);
918 return GNUNET_YES; /* type mismatch */
919 }
920 if ( (0 == (record->msg_options & GNUNET_DHT_RO_FIND_PEER)) &&
921 (0 != GNUNET_memcmp (&frc->bd->key,
922 query_hash)) )
923 {
924 GNUNET_STATISTICS_update (GDS_stats,
925 "# Inexact key match, but exact match required",
926 1,
927 GNUNET_NO);
928 return GNUNET_YES; /* type mismatch */
929 }
930 GNUNET_CRYPTO_hash (frc->bd->data,
931 frc->bd->data_size,
932 &ch);
933 for (unsigned int i = 0; i < record->seen_replies_count; i++)
934 if (0 ==
935 GNUNET_memcmp (&record->seen_replies[i],
936 &ch))
937 {
938 LOG (GNUNET_ERROR_TYPE_DEBUG,
939 "Duplicate reply, not passing request for key %s to local client\n",
940 GNUNET_h2s (&frc->bd->key));
941 GNUNET_STATISTICS_update (GDS_stats,
942 "# Duplicate REPLIES to CLIENT request dropped",
943 1,
944 GNUNET_NO);
945 return GNUNET_YES; /* duplicate */
946 }
947 eval
948 = GNUNET_BLOCK_check_reply (GDS_block_context,
949 record->type,
950 NULL,
951 &frc->bd->key,
952 record->xquery,
953 record->xquery_size,
954 frc->bd->data,
955 frc->bd->data_size);
956 LOG (GNUNET_ERROR_TYPE_DEBUG,
957 "Evaluation result is %d for key %s for local client's query\n",
958 (int) eval,
959 GNUNET_h2s (&frc->bd->key));
960 switch (eval)
961 {
962 case GNUNET_BLOCK_REPLY_OK_LAST:
963 do_free = true;
964 break;
965 case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED:
966 case GNUNET_BLOCK_REPLY_OK_MORE:
967 GNUNET_array_append (record->seen_replies,
968 record->seen_replies_count,
969 ch);
970 do_free = false;
971 break;
972 case GNUNET_BLOCK_REPLY_OK_DUPLICATE:
973 /* should be impossible to encounter here */
974 GNUNET_break (0);
975 return GNUNET_YES;
976 case GNUNET_BLOCK_REPLY_INVALID:
977 GNUNET_break_op (0);
978 return GNUNET_NO;
979 case GNUNET_BLOCK_REPLY_IRRELEVANT:
980 return GNUNET_YES;
981 default:
982 GNUNET_break (0);
983 return GNUNET_NO;
984 }
985 GNUNET_STATISTICS_update (GDS_stats,
986 "# RESULTS queued for clients",
987 1,
988 GNUNET_NO);
989 env = GNUNET_MQ_msg_extra (reply,
990 frc->bd->data_size
991 + (frc->get_path_length + frc->bd->put_path_length)
992 * sizeof(struct GNUNET_DHT_PathElement),
993 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT);
994 reply->type = htonl (frc->bd->type);
995 reply->get_path_length = htonl (frc->get_path_length);
996 reply->put_path_length = htonl (frc->bd->put_path_length);
997 reply->unique_id = record->unique_id;
998 reply->expiration = GNUNET_TIME_absolute_hton (frc->bd->expiration_time);
999 reply->key = frc->bd->key;
1000 paths = (struct GNUNET_DHT_PathElement *) &reply[1];
1001 GNUNET_memcpy (paths,
1002 frc->bd->put_path,
1003 sizeof(struct GNUNET_DHT_PathElement)
1004 * frc->bd->put_path_length);
1005 GNUNET_memcpy (&paths[frc->bd->put_path_length],
1006 frc->get_path,
1007 sizeof(struct GNUNET_DHT_PathElement) * frc->get_path_length);
1008 GNUNET_memcpy (&paths[frc->get_path_length + frc->bd->put_path_length],
1009 frc->bd->data,
1010 frc->bd->data_size);
1011 LOG (GNUNET_ERROR_TYPE_DEBUG,
1012 "Sending reply to query %s for client %p\n",
1013 GNUNET_h2s (query_hash),
1014 record->ch->client);
1015 GNUNET_MQ_send (record->ch->mq,
1016 env);
1017 if (GNUNET_YES == do_free)
1018 remove_client_query_record (record);
1019 return GNUNET_YES;
1020}
1021
1022
1023void
1024GDS_CLIENTS_handle_reply (const struct GDS_DATACACHE_BlockData *bd,
1025 const struct GNUNET_HashCode *query_hash,
1026 unsigned int get_path_length,
1027 const struct GNUNET_DHT_PathElement *get_path)
1028{
1029 struct ForwardReplyContext frc;
1030 size_t msize = sizeof (struct GNUNET_DHT_ClientResultMessage)
1031 + bd->data_size
1032 + (get_path_length + bd->put_path_length)
1033 * sizeof(struct GNUNET_DHT_PathElement);
1034
1035 if (msize >= GNUNET_MAX_MESSAGE_SIZE)
1036 {
1037 GNUNET_break (0);
1038 return;
1039 }
1040 frc.bd = bd;
1041 frc.get_path = get_path;
1042 frc.get_path_length = get_path_length;
1043 LOG (GNUNET_ERROR_TYPE_DEBUG,
1044 "Forwarding reply for query hash %s to client\n",
1045 GNUNET_h2s (query_hash));
1046 if (0 ==
1047 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
1048 query_hash,
1049 &forward_reply,
1050 &frc))
1051 {
1052 LOG (GNUNET_ERROR_TYPE_DEBUG,
1053 "No matching client for reply for query %s\n",
1054 GNUNET_h2s (query_hash));
1055 GNUNET_STATISTICS_update (GDS_stats,
1056 "# REPLIES ignored for CLIENTS (no match)",
1057 1,
1058 GNUNET_NO);
1059 }
1060}
1061
1062
1063/* ************* logic for monitors ************** */
1064
1065
1066/**
1067 * Handler for monitor start messages
1068 *
1069 * @param cls the client we received this message from
1070 * @param msg the actual message received
1071 *
1072 */
1073static void
1074handle_dht_local_monitor (void *cls,
1075 const struct GNUNET_DHT_MonitorStartStopMessage *msg)
1076{
1077 struct ClientHandle *ch = cls;
1078 struct ClientMonitorRecord *r;
1079
1080 r = GNUNET_new (struct ClientMonitorRecord);
1081 r->ch = ch;
1082 r->type = ntohl (msg->type);
1083 r->get = ntohs (msg->get);
1084 r->get_resp = ntohs (msg->get_resp);
1085 r->put = ntohs (msg->put);
1086 if (0 != ntohs (msg->filter_key))
1087 r->key = msg->key;
1088 GNUNET_CONTAINER_DLL_insert (monitor_head,
1089 monitor_tail,
1090 r);
1091 GNUNET_SERVICE_client_continue (ch->client);
1092}
1093
1094
1095/**
1096 * Handler for monitor stop messages
1097 *
1098 * @param cls the client we received this message from
1099 * @param msg the actual message received
1100 */
1101static void
1102handle_dht_local_monitor_stop (
1103 void *cls,
1104 const struct GNUNET_DHT_MonitorStartStopMessage *msg)
1105{
1106 struct ClientHandle *ch = cls;
1107
1108 GNUNET_SERVICE_client_continue (ch->client);
1109 for (struct ClientMonitorRecord *r = monitor_head;
1110 NULL != r;
1111 r = r->next)
1112 {
1113 bool keys_match;
1114
1115 keys_match =
1116 (GNUNET_is_zero (&r->key))
1117 ? (0 == ntohs (msg->filter_key))
1118 : ( (0 != ntohs (msg->filter_key)) &&
1119 (! GNUNET_memcmp (&r->key,
1120 &msg->key)) );
1121 if ( (ch == r->ch) &&
1122 (ntohl (msg->type) == r->type) &&
1123 (r->get == msg->get) &&
1124 (r->get_resp == msg->get_resp) &&
1125 (r->put == msg->put) &&
1126 keys_match)
1127 {
1128 GNUNET_CONTAINER_DLL_remove (monitor_head,
1129 monitor_tail,
1130 r);
1131 GNUNET_free (r);
1132 return; /* Delete only ONE entry */
1133 }
1134 }
1135}
1136
1137
1138/**
1139 * Function to call by #for_matching_monitors().
1140 *
1141 * @param cls closure
1142 * @param m a matching monitor
1143 */
1144typedef void
1145(*MonitorAction)(void *cls,
1146 struct ClientMonitorRecord *m);
1147
1148
1149/**
1150 * Call @a cb on all monitors that watch for blocks of @a type
1151 * and key @a key.
1152 *
1153 * @param type the type to match
1154 * @param key the key to match
1155 * @param cb function to call
1156 * @param cb_cls closure for @a cb
1157 */
1158static void
1159for_matching_monitors (enum GNUNET_BLOCK_Type type,
1160 const struct GNUNET_HashCode *key,
1161 MonitorAction cb,
1162 void *cb_cls)
1163{
1164 struct ClientHandle **cl = NULL;
1165 unsigned int cl_size = 0;
1166
1167 for (struct ClientMonitorRecord *m = monitor_head;
1168 NULL != m;
1169 m = m->next)
1170 {
1171 if ( ( (GNUNET_BLOCK_TYPE_ANY == m->type) ||
1172 (m->type == type) ) &&
1173 ( (GNUNET_is_zero (&m->key)) ||
1174 (0 ==
1175 GNUNET_memcmp (key,
1176 &m->key)) ) )
1177 {
1178 unsigned int i;
1179
1180 /* Don't send duplicates */
1181 for (i = 0; i < cl_size; i++)
1182 if (cl[i] == m->ch)
1183 break;
1184 if (i < cl_size)
1185 continue;
1186 GNUNET_array_append (cl,
1187 cl_size,
1188 m->ch);
1189 cb (cb_cls,
1190 m);
1191 }
1192 }
1193 GNUNET_free (cl);
1194}
1195
1196
1197/**
1198 * Closure for #get_action();
1199 */
1200struct GetActionContext
1201{
1202 enum GNUNET_DHT_RouteOption options;
1203 enum GNUNET_BLOCK_Type type;
1204 uint32_t hop_count;
1205 uint32_t desired_replication_level;
1206 unsigned int get_path_length;
1207 const struct GNUNET_DHT_PathElement *get_path;
1208 const struct GNUNET_HashCode *key;
1209};
1210
1211
1212/**
1213 * Function called on monitors that match a GET.
1214 * Sends the GET notification to the monitor.
1215 *
1216 * @param cls a `struct GetActionContext`
1217 * @param m a matching monitor
1218 */
1219static void
1220get_action (void *cls,
1221 struct ClientMonitorRecord *m)
1222{
1223 struct GetActionContext *gac = cls;
1224 struct GNUNET_MQ_Envelope *env;
1225 struct GNUNET_DHT_MonitorGetMessage *mmsg;
1226 struct GNUNET_DHT_PathElement *msg_path;
1227 size_t msize;
1228
1229 msize = gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement);
1230 env = GNUNET_MQ_msg_extra (mmsg,
1231 msize,
1232 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET);
1233 mmsg->options = htonl (gac->options);
1234 mmsg->type = htonl (gac->type);
1235 mmsg->hop_count = htonl (gac->hop_count);
1236 mmsg->desired_replication_level = htonl (gac->desired_replication_level);
1237 mmsg->get_path_length = htonl (gac->get_path_length);
1238 mmsg->key = *gac->key;
1239 msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1240 GNUNET_memcpy (msg_path,
1241 gac->get_path,
1242 gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1243 GNUNET_MQ_send (m->ch->mq,
1244 env);
1245}
1246
1247
1248/**
1249 * Check if some client is monitoring GET messages and notify
1250 * them in that case. If tracked, @a path should include the local peer.
1251 *
1252 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
1253 * @param type The type of data in the request.
1254 * @param hop_count Hop count so far.
1255 * @param path_length number of entries in path (or 0 if not recorded).
1256 * @param path peers on the GET path (or NULL if not recorded).
1257 * @param desired_replication_level Desired replication level.
1258 * @param key Key of the requested data.
1259 */
1260void
1261GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption options,
1262 enum GNUNET_BLOCK_Type type,
1263 uint32_t hop_count,
1264 uint32_t desired_replication_level,
1265 unsigned int path_length,
1266 const struct GNUNET_DHT_PathElement *path,
1267 const struct GNUNET_HashCode *key)
1268{
1269 struct GetActionContext gac = {
1270 .options = options,
1271 .type = type,
1272 .hop_count = hop_count,
1273 .desired_replication_level = desired_replication_level,
1274 .get_path_length = path_length,
1275 .get_path = path,
1276 .key = key
1277 };
1278
1279 for_matching_monitors (type,
1280 key,
1281 &get_action,
1282 &gac);
1283}
1284
1285
1286/**
1287 * Closure for response_action().
1288 */
1289struct ResponseActionContext
1290{
1291 const struct GDS_DATACACHE_BlockData *bd;
1292 const struct GNUNET_DHT_PathElement *get_path;
1293 unsigned int get_path_length;
1294};
1295
1296
1297/**
1298 * Function called on monitors that match a response.
1299 * Sends the response notification to the monitor.
1300 *
1301 * @param cls a `struct ResponseActionContext`
1302 * @param m a matching monitor
1303 */
1304static void
1305response_action (void *cls,
1306 struct ClientMonitorRecord *m)
1307{
1308 const struct ResponseActionContext *resp_ctx = cls;
1309 const struct GDS_DATACACHE_BlockData *bd = resp_ctx->bd;
1310
1311 struct GNUNET_MQ_Envelope *env;
1312 struct GNUNET_DHT_MonitorGetRespMessage *mmsg;
1313 struct GNUNET_DHT_PathElement *path;
1314 size_t msize;
1315
1316 msize = bd->data_size;
1317 msize += (resp_ctx->get_path_length + bd->put_path_length)
1318 * sizeof(struct GNUNET_DHT_PathElement);
1319 env = GNUNET_MQ_msg_extra (mmsg,
1320 msize,
1321 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP);
1322 mmsg->type = htonl (bd->type);
1323 mmsg->put_path_length = htonl (bd->put_path_length);
1324 mmsg->get_path_length = htonl (resp_ctx->get_path_length);
1325 mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1326 mmsg->key = bd->key;
1327 path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1328 GNUNET_memcpy (path,
1329 bd->put_path,
1330 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
1331 GNUNET_memcpy (path,
1332 resp_ctx->get_path,
1333 resp_ctx->get_path_length * sizeof(struct
1334 GNUNET_DHT_PathElement));
1335 GNUNET_memcpy (&path[resp_ctx->get_path_length],
1336 bd->data,
1337 bd->data_size);
1338 GNUNET_MQ_send (m->ch->mq,
1339 env);
1340}
1341
1342
1343void
1344GDS_CLIENTS_process_get_resp (const struct GDS_DATACACHE_BlockData *bd,
1345 const struct GNUNET_DHT_PathElement *get_path,
1346 unsigned int get_path_length)
1347{
1348 struct ResponseActionContext rac = {
1349 .bd = bd,
1350 .get_path = get_path,
1351 .get_path_length = get_path_length
1352 };
1353
1354 for_matching_monitors (bd->type,
1355 &bd->key,
1356 &response_action,
1357 &rac);
1358}
1359
1360
1361/**
1362 * Closure for put_action().
1363 */
1364struct PutActionContext
1365{
1366 const struct GDS_DATACACHE_BlockData *bd;
1367 enum GNUNET_DHT_RouteOption options;
1368 uint32_t hop_count;
1369 uint32_t desired_replication_level;
1370};
1371
1372
1373/**
1374 * Function called on monitors that match a PUT.
1375 * Sends the PUT notification to the monitor.
1376 *
1377 * @param cls a `struct PutActionContext`
1378 * @param m a matching monitor
1379 */
1380static void
1381put_action (void *cls,
1382 struct ClientMonitorRecord *m)
1383{
1384 const struct PutActionContext *put_ctx = cls;
1385 const struct GDS_DATACACHE_BlockData *bd = put_ctx->bd;
1386 struct GNUNET_MQ_Envelope *env;
1387 struct GNUNET_DHT_MonitorPutMessage *mmsg;
1388 struct GNUNET_DHT_PathElement *msg_path;
1389 size_t msize;
1390
1391 msize = bd->data_size
1392 + bd->put_path_length
1393 * sizeof(struct GNUNET_DHT_PathElement);
1394 env = GNUNET_MQ_msg_extra (mmsg,
1395 msize,
1396 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT);
1397 mmsg->options = htonl (put_ctx->options);
1398 mmsg->type = htonl (bd->type);
1399 mmsg->hop_count = htonl (put_ctx->hop_count);
1400 mmsg->desired_replication_level = htonl (put_ctx->desired_replication_level);
1401 mmsg->put_path_length = htonl (bd->put_path_length);
1402 mmsg->key = bd->key;
1403 mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1404 msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1405 GNUNET_memcpy (msg_path,
1406 bd->put_path,
1407 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
1408 GNUNET_memcpy (&msg_path[bd->put_path_length],
1409 bd->data,
1410 bd->data_size);
1411 GNUNET_MQ_send (m->ch->mq,
1412 env);
1413}
1414
1415
1416void
1417GDS_CLIENTS_process_put (enum GNUNET_DHT_RouteOption options,
1418 const struct GDS_DATACACHE_BlockData *bd,
1419 uint32_t hop_count,
1420 uint32_t desired_replication_level)
1421{
1422 struct PutActionContext put_ctx = {
1423 .bd = bd,
1424 .hop_count = hop_count,
1425 .desired_replication_level = desired_replication_level,
1426 .options = options
1427 };
1428
1429 for_matching_monitors (bd->type,
1430 &bd->key,
1431 &put_action,
1432 &put_ctx);
1433}
1434
1435
1436/* ********************** Initialization logic ***************** */
1437
1438
1439/**
1440 * Initialize client subsystem.
1441 *
1442 * @param server the initialized server
1443 */
1444static void
1445GDS_CLIENTS_init (void)
1446{
1447 forward_map
1448 = GNUNET_CONTAINER_multihashmap_create (1024,
1449 GNUNET_YES);
1450 retry_heap
1451 = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1452}
1453
1454
1455/**
1456 * Shutdown client subsystem.
1457 */
1458static void
1459GDS_CLIENTS_stop (void)
1460{
1461 if (NULL != retry_task)
1462 {
1463 GNUNET_SCHEDULER_cancel (retry_task);
1464 retry_task = NULL;
1465 }
1466}
1467
1468
1469/**
1470 * Define "main" method using service macro.
1471 *
1472 * @param name name of the service, like "dht" or "xdht"
1473 * @param run name of the initializaton method for the service
1474 */
1475#define GDS_DHT_SERVICE_INIT(name, run) \
1476 GNUNET_SERVICE_MAIN \
1477 (name, \
1478 GNUNET_SERVICE_OPTION_NONE, \
1479 run, \
1480 &client_connect_cb, \
1481 &client_disconnect_cb, \
1482 NULL, \
1483 GNUNET_MQ_hd_var_size (dht_local_put, \
1484 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, \
1485 struct GNUNET_DHT_ClientPutMessage, \
1486 NULL), \
1487 GNUNET_MQ_hd_var_size (dht_local_get, \
1488 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, \
1489 struct GNUNET_DHT_ClientGetMessage, \
1490 NULL), \
1491 GNUNET_MQ_hd_fixed_size (dht_local_get_stop, \
1492 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP, \
1493 struct GNUNET_DHT_ClientGetStopMessage, \
1494 NULL), \
1495 GNUNET_MQ_hd_fixed_size (dht_local_monitor, \
1496 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START, \
1497 struct GNUNET_DHT_MonitorStartStopMessage, \
1498 NULL), \
1499 GNUNET_MQ_hd_fixed_size (dht_local_monitor_stop, \
1500 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP, \
1501 struct GNUNET_DHT_MonitorStartStopMessage, \
1502 NULL), \
1503 GNUNET_MQ_hd_var_size (dht_local_get_result_seen, \
1504 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN, \
1505 struct GNUNET_DHT_ClientGetResultSeenMessage, \
1506 NULL), \
1507 GNUNET_MQ_handler_end ())
1508
1509
1510/**
1511 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1512 */
1513void __attribute__ ((destructor))
1514GDS_CLIENTS_done ()
1515{
1516 if (NULL != retry_heap)
1517 {
1518 GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap));
1519 GNUNET_CONTAINER_heap_destroy (retry_heap);
1520 retry_heap = NULL;
1521 }
1522 if (NULL != forward_map)
1523 {
1524 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map));
1525 GNUNET_CONTAINER_multihashmap_destroy (forward_map);
1526 forward_map = NULL;
1527 }
1528}
1529
1530
1531/* end of gnunet-service-dht_clients.c */
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
deleted file mode 100644
index cb778717b..000000000
--- a/src/dht/gnunet-service-dht_datacache.c
+++ /dev/null
@@ -1,365 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2015, 2017, 2022 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 dht/gnunet-service-dht_datacache.c
22 * @brief GNUnet DHT service's datacache integration
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_datacache_lib.h"
28#include "gnunet-service-dht_datacache.h"
29#include "gnunet-service-dht_neighbours.h"
30#include "gnunet-service-dht_routing.h"
31#include "gnunet-service-dht.h"
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "dht-dhtcache", __VA_ARGS__)
34
35/**
36 * How many "closest" results to we return for migration when
37 * asked (at most)?
38 */
39#define NUM_CLOSEST 42
40
41
42/**
43 * Handle to the datacache service (for inserting/retrieving data)
44 */
45static struct GNUNET_DATACACHE_Handle *datacache;
46
47
48void
49GDS_DATACACHE_handle_put (const struct GDS_DATACACHE_BlockData *bd)
50{
51 struct GNUNET_HashCode xor;
52 enum GNUNET_GenericReturnValue r;
53
54 if (NULL == datacache)
55 {
56 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
57 "PUT request received, but have no datacache!\n");
58 return;
59 }
60 if (bd->data_size >= GNUNET_MAX_MESSAGE_SIZE)
61 {
62 GNUNET_break (0);
63 return;
64 }
65 /* Put size is actual data size plus struct overhead plus path length (if any) */
66 GNUNET_STATISTICS_update (GDS_stats,
67 "# ITEMS stored in datacache",
68 1,
69 GNUNET_NO);
70 GNUNET_CRYPTO_hash_xor (&bd->key,
71 &my_identity_hash,
72 &xor);
73 r = GNUNET_DATACACHE_put (datacache,
74 &bd->key,
75 GNUNET_CRYPTO_hash_count_leading_zeros (&xor),
76 bd->data_size,
77 bd->data,
78 bd->type,
79 bd->expiration_time,
80 bd->put_path_length,
81 bd->put_path);
82 LOG (GNUNET_ERROR_TYPE_DEBUG,
83 "DATACACHE PUT for key %s [%lu] completed (%d) after %u hops\n",
84 GNUNET_h2s (&bd->key),
85 (unsigned long) bd->data_size,
86 r,
87 bd->put_path_length);
88}
89
90
91/**
92 * Context containing information about a GET request.
93 */
94struct GetRequestContext
95{
96 /**
97 * extended query (see gnunet_block_lib.h).
98 */
99 const void *xquery;
100
101 /**
102 * The key this request was about
103 */
104 struct GNUNET_HashCode key;
105
106 /**
107 * Block group to use to evaluate replies (updated)
108 */
109 struct GNUNET_BLOCK_Group *bg;
110
111 /**
112 * Function to call on results.
113 */
114 GDS_DATACACHE_GetCallback gc;
115
116 /**
117 * Closure for @e gc.
118 */
119 void *gc_cls;
120
121 /**
122 * Number of bytes in xquery.
123 */
124 size_t xquery_size;
125
126 /**
127 * Return value to give back.
128 */
129 enum GNUNET_BLOCK_EvaluationResult eval;
130};
131
132
133/**
134 * Iterator for local get request results,
135 *
136 * @param cls closure for iterator, a `struct GetRequestContext`
137 * @param exp when does this value expire?
138 * @param key the key this data is stored under
139 * @param data_size the size of the data identified by key
140 * @param data the actual data
141 * @param type the type of the @a data
142 * @param put_path_length number of peers in @a put_path
143 * @param put_path path the reply took on put
144 * @return #GNUNET_OK to continue iteration, anything else
145 * to stop iteration.
146 */
147static enum GNUNET_GenericReturnValue
148datacache_get_iterator (void *cls,
149 const struct GNUNET_HashCode *key,
150 size_t data_size,
151 const char *data,
152 enum GNUNET_BLOCK_Type type,
153 struct GNUNET_TIME_Absolute exp,
154 unsigned int put_path_length,
155 const struct GNUNET_DHT_PathElement *put_path)
156{
157 struct GetRequestContext *ctx = cls;
158 enum GNUNET_BLOCK_ReplyEvaluationResult eval;
159 struct GDS_DATACACHE_BlockData bd = {
160 .key = *key,
161 .expiration_time = exp,
162 .put_path = put_path,
163 .data = data,
164 .data_size = data_size,
165 .put_path_length = put_path_length,
166 .type = type
167 };
168
169 if (GNUNET_TIME_absolute_is_past (exp))
170 {
171 GNUNET_break (0); /* why does datacache return expired values? */
172 return GNUNET_OK; /* skip expired record */
173 }
174 eval
175 = GNUNET_BLOCK_check_reply (GDS_block_context,
176 bd.type,
177 ctx->bg,
178 &bd.key,
179 ctx->xquery,
180 ctx->xquery_size,
181 bd.data,
182 bd.data_size);
183 LOG (GNUNET_ERROR_TYPE_DEBUG,
184 "Evaluated reply for query %s in datacache, result is %d\n",
185 GNUNET_h2s (key),
186 (int) eval);
187 ctx->eval = eval;
188 switch (eval)
189 {
190 case GNUNET_BLOCK_REPLY_OK_MORE:
191 case GNUNET_BLOCK_REPLY_OK_LAST:
192 case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED:
193 /* forward to initiator */
194 GNUNET_STATISTICS_update (GDS_stats,
195 "# Good RESULTS found in datacache",
196 1,
197 GNUNET_NO);
198 ctx->gc (ctx->gc_cls,
199 &bd);
200 break;
201 case GNUNET_BLOCK_REPLY_OK_DUPLICATE:
202 GNUNET_STATISTICS_update (GDS_stats,
203 "# Duplicate RESULTS found in datacache",
204 1,
205 GNUNET_NO);
206 break;
207 case GNUNET_BLOCK_REPLY_INVALID:
208 /* maybe it expired? */
209 GNUNET_STATISTICS_update (GDS_stats,
210 "# Invalid RESULTS found in datacache",
211 1,
212 GNUNET_NO);
213 break;
214 case GNUNET_BLOCK_REPLY_IRRELEVANT:
215 GNUNET_STATISTICS_update (GDS_stats,
216 "# Irrelevant RESULTS found in datacache",
217 1,
218 GNUNET_NO);
219 break;
220 }
221 return (eval == GNUNET_BLOCK_REPLY_OK_LAST) ? GNUNET_NO : GNUNET_OK;
222}
223
224
225enum GNUNET_BLOCK_EvaluationResult
226GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
227 enum GNUNET_BLOCK_Type type,
228 const void *xquery,
229 size_t xquery_size,
230 struct GNUNET_BLOCK_Group *bg,
231 GDS_DATACACHE_GetCallback gc,
232 void *gc_cls)
233{
234 struct GetRequestContext ctx;
235 unsigned int r;
236
237 if (NULL == datacache)
238 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
239 GNUNET_STATISTICS_update (GDS_stats,
240 "# GET requests given to datacache",
241 1,
242 GNUNET_NO);
243 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
244 ctx.key = *key;
245 ctx.xquery = xquery;
246 ctx.xquery_size = xquery_size;
247 ctx.bg = bg;
248 ctx.gc = gc;
249 ctx.gc_cls = gc_cls;
250 r = GNUNET_DATACACHE_get (datacache,
251 key,
252 type,
253 &datacache_get_iterator,
254 &ctx);
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "DATACACHE GET for key %s completed (%d). %u results found.\n",
257 GNUNET_h2s (key),
258 ctx.eval,
259 r);
260 return ctx.eval;
261}
262
263
264/**
265 * Closure for #datacache_get_successors_iterator().
266 */
267struct SuccContext
268{
269 /**
270 * Function to call on the result
271 */
272 GDS_DATACACHE_GetCallback cb;
273
274 /**
275 * Closure for @e cb.
276 */
277 void *cb_cls;
278
279};
280
281
282/**
283 * Iterator for local get request results,
284 *
285 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
286 * @param key the key this data is stored under
287 * @param size the size of the data identified by key
288 * @param data the actual data
289 * @param type the type of the data
290 * @param exp when does this value expire?
291 * @param put_path_length number of peers in @a put_path
292 * @param put_path path the reply took on put
293 * @return #GNUNET_OK to continue iteration, anything else
294 * to stop iteration.
295 */
296static enum GNUNET_GenericReturnValue
297datacache_get_successors_iterator (void *cls,
298 const struct GNUNET_HashCode *key,
299 size_t size,
300 const char *data,
301 enum GNUNET_BLOCK_Type type,
302 struct GNUNET_TIME_Absolute exp,
303 unsigned int put_path_length,
304 const struct
305 GNUNET_DHT_PathElement *put_path)
306{
307 const struct SuccContext *sc = cls;
308 struct GDS_DATACACHE_BlockData bd = {
309 .key = *key,
310 .expiration_time = exp,
311 .put_path = put_path,
312 .data = data,
313 .data_size = size,
314 .put_path_length = put_path_length,
315 .type = type
316 };
317
318 /* NOTE: The datacache currently does not store the RO from
319 the original 'put', so we don't know the 'correct' option
320 at this point anymore. Thus, we conservatively assume
321 that recording is desired (for now). */
322 sc->cb (sc->cb_cls,
323 &bd);
324 return GNUNET_OK;
325}
326
327
328void
329GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
330 GDS_DATACACHE_GetCallback cb,
331 void *cb_cls)
332{
333 struct SuccContext sc = {
334 .cb = cb,
335 .cb_cls = cb_cls
336 };
337
338 (void) GNUNET_DATACACHE_get_closest (datacache,
339 key,
340 NUM_CLOSEST,
341 &datacache_get_successors_iterator,
342 &sc);
343}
344
345
346void
347GDS_DATACACHE_init ()
348{
349 datacache = GNUNET_DATACACHE_create (GDS_cfg,
350 "dhtcache");
351}
352
353
354void
355GDS_DATACACHE_done ()
356{
357 if (NULL != datacache)
358 {
359 GNUNET_DATACACHE_destroy (datacache);
360 datacache = NULL;
361 }
362}
363
364
365/* end of gnunet-service-dht_datacache.c */
diff --git a/src/dht/gnunet-service-dht_datacache.h b/src/dht/gnunet-service-dht_datacache.h
deleted file mode 100644
index 691a51e0e..000000000
--- a/src/dht/gnunet-service-dht_datacache.h
+++ /dev/null
@@ -1,147 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2022 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 dht/gnunet-service-dht_datacache.h
23 * @brief GNUnet DHT service's datacache integration
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#ifndef GNUNET_SERVICE_DHT_DATACACHE_H
28#define GNUNET_SERVICE_DHT_DATACACHE_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_block_lib.h"
32#include "gnunet_dht_service.h"
33
34
35/**
36 * Information about a block stored in the datacache.
37 */
38struct GDS_DATACACHE_BlockData
39{
40 /**
41 * Key of the block.
42 */
43 struct GNUNET_HashCode key;
44
45 /**
46 * When does the block expire?
47 */
48 struct GNUNET_TIME_Absolute expiration_time;
49
50 /**
51 * PUT path taken by the block, array of peer identities.
52 */
53 const struct GNUNET_DHT_PathElement *put_path;
54
55 /**
56 * Actual block data.
57 */
58 const void *data;
59
60 /**
61 * Number of bytes in @a data.
62 */
63 size_t data_size;
64
65 /**
66 * Length of the @e put_path array.
67 */
68 unsigned int put_path_length;
69
70 /**
71 * Type of the block.
72 */
73 enum GNUNET_BLOCK_Type type;
74};
75
76
77/**
78 * Handle a datum we've received from another peer. Cache if
79 * possible.
80 *
81 * @param bd block data to cache
82 */
83void
84GDS_DATACACHE_handle_put (const struct GDS_DATACACHE_BlockData *bd);
85
86
87/**
88 * Handle a result for a GET operation.
89 *
90 * @param cls closure
91 * @param bd block details
92 */
93typedef void
94(*GDS_DATACACHE_GetCallback)(void *cls,
95 const struct GDS_DATACACHE_BlockData *bd);
96
97
98/**
99 * Handle a GET request we've received from another peer.
100 *
101 * @param key the query
102 * @param type requested data type
103 * @param xquery extended query
104 * @param xquery_size number of bytes in xquery
105 * @param bg block group to use for evaluation of replies
106 * @param gc function to call on the results
107 * @param gc_cls closure for @a gc
108 * @return evaluation result for the local replies
109 */
110enum GNUNET_BLOCK_EvaluationResult
111GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
112 enum GNUNET_BLOCK_Type type,
113 const void *xquery,
114 size_t xquery_size,
115 struct GNUNET_BLOCK_Group *bg,
116 GDS_DATACACHE_GetCallback gc,
117 void *gc_cls);
118
119
120/**
121 * Handle a request for data close to a key that we have received from
122 * another peer.
123 *
124 * @param key the location at which the peer is looking for data that is close
125 * @param cb function to call with the result
126 * @param cb_cls closure for @a cb
127 */
128void
129GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
130 GDS_DATACACHE_GetCallback cb,
131 void *cb_cls);
132
133
134/**
135 * Initialize datacache subsystem.
136 */
137void
138GDS_DATACACHE_init (void);
139
140
141/**
142 * Shutdown datacache subsystem.
143 */
144void
145GDS_DATACACHE_done (void);
146
147#endif
diff --git a/src/dht/gnunet-service-dht_hello.c b/src/dht/gnunet-service-dht_hello.c
deleted file mode 100644
index 949456575..000000000
--- a/src/dht/gnunet-service-dht_hello.c
+++ /dev/null
@@ -1,154 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify 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 dht/gnunet-service-dht_hello.c
23 * @brief GNUnet DHT integration with peerinfo
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - consider adding mechanism to remove expired HELLOs
28 */
29#include "platform.h"
30#include "gnunet-service-dht.h"
31#include "gnunet-service-dht_hello.h"
32#include "gnunet_peerinfo_service.h"
33
34
35/**
36 * Handle for peerinfo notifications.
37 */
38static struct GNUNET_PEERINFO_NotifyContext *pnc;
39
40/**
41 * Hash map of peers to HELLOs.
42 */
43static struct GNUNET_CONTAINER_MultiPeerMap *peer_to_hello;
44
45
46/**
47 * Obtain a peer's HELLO if available
48 *
49 * @param peer peer to look for a HELLO from
50 * @return HELLO for the given peer
51 */
52const struct GNUNET_HELLO_Message *
53GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer)
54{
55 if (NULL == peer_to_hello)
56 return NULL;
57 return GNUNET_CONTAINER_multipeermap_get (peer_to_hello,
58 peer);
59}
60
61
62/**
63 * Function called for each HELLO known to PEERINFO.
64 *
65 * @param cls closure
66 * @param peer id of the peer, NULL for last call
67 * @param hello hello message for the peer (can be NULL)
68 * @param err_msg error message (not used)
69 *
70 * FIXME this is called once per address. Merge instead of replacing?
71 */
72static void
73process_hello (void *cls,
74 const struct GNUNET_PeerIdentity *peer,
75 const struct GNUNET_HELLO_Message *hello,
76 const char *err_msg)
77{
78 struct GNUNET_TIME_Absolute ex;
79 struct GNUNET_HELLO_Message *hm;
80
81 if (NULL == hello)
82 return;
83 ex = GNUNET_HELLO_get_last_expiration (hello);
84 if (0 == GNUNET_TIME_absolute_get_remaining (ex).rel_value_us)
85 return;
86 GNUNET_STATISTICS_update (GDS_stats,
87 "# HELLOs obtained from peerinfo",
88 1,
89 GNUNET_NO);
90 hm = GNUNET_CONTAINER_multipeermap_get (peer_to_hello,
91 peer);
92 GNUNET_free (hm);
93 hm = GNUNET_malloc (GNUNET_HELLO_size (hello));
94 GNUNET_memcpy (hm,
95 hello,
96 GNUNET_HELLO_size (hello));
97 GNUNET_assert (GNUNET_SYSERR !=
98 GNUNET_CONTAINER_multipeermap_put (peer_to_hello,
99 peer,
100 hm,
101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
102}
103
104
105/**
106 * Initialize HELLO subsystem.
107 */
108void
109GDS_HELLO_init ()
110{
111 pnc = GNUNET_PEERINFO_notify (GDS_cfg,
112 GNUNET_NO,
113 &process_hello,
114 NULL);
115 peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256,
116 GNUNET_NO);
117}
118
119
120/**
121 * Free memory occopied by the HELLO.
122 */
123static enum GNUNET_GenericReturnValue
124free_hello (void *cls,
125 const struct GNUNET_PeerIdentity *key,
126 void *hello)
127{
128 GNUNET_free (hello);
129 return GNUNET_OK;
130}
131
132
133/**
134 * Shutdown HELLO subsystem.
135 */
136void
137GDS_HELLO_done ()
138{
139 if (NULL != pnc)
140 {
141 GNUNET_PEERINFO_notify_cancel (pnc);
142 pnc = NULL;
143 }
144 if (NULL != peer_to_hello)
145 {
146 GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello,
147 &free_hello,
148 NULL);
149 GNUNET_CONTAINER_multipeermap_destroy (peer_to_hello);
150 }
151}
152
153
154/* end of gnunet-service-dht_hello.c */
diff --git a/src/dht/gnunet-service-dht_hello.h b/src/dht/gnunet-service-dht_hello.h
deleted file mode 100644
index f8b90862d..000000000
--- a/src/dht/gnunet-service-dht_hello.h
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify 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 dht/gnunet-service-dht_hello.h
23 * @brief GNUnet DHT integration with peerinfo
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_DHT_HELLO_H
27#define GNUNET_SERVICE_DHT_HELLO_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_hello_lib.h"
31
32/**
33 * Obtain a peer's HELLO if available
34 *
35 * @param peer peer to look for a HELLO from
36 * @return HELLO for the given peer
37 */
38const struct GNUNET_HELLO_Message *
39GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer);
40
41
42/**
43 * Initialize HELLO subsystem.
44 */
45void
46GDS_HELLO_init (void);
47
48
49/**
50 * Shutdown HELLO subsystem.
51 */
52void
53GDS_HELLO_done (void);
54
55#endif
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
deleted file mode 100644
index cf150ea0c..000000000
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ /dev/null
@@ -1,2532 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2017, 2021, 2022 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 dht/gnunet-service-dht_neighbours.c
23 * @brief GNUnet DHT service's bucket and neighbour management code
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_protocols.h"
30#include "gnunet_signatures.h"
31#include "gnunet_ats_service.h"
32#include "gnunet_core_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet-service-dht.h"
35#include "gnunet-service-dht_hello.h"
36#include "gnunet-service-dht_neighbours.h"
37#include "gnunet-service-dht_nse.h"
38#include "gnunet-service-dht_routing.h"
39#include "dht.h"
40
41#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
42 __VA_ARGS__)
43
44/**
45 * Enable slow sanity checks to debug issues.
46 */
47#define SANITY_CHECKS 1
48
49/**
50 * How many buckets will we allow in total.
51 */
52#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
53
54/**
55 * What is the maximum number of peers in a given bucket.
56 */
57#define DEFAULT_BUCKET_SIZE 8
58
59/**
60 * Desired replication level for FIND PEER requests
61 */
62#define FIND_PEER_REPLICATION_LEVEL 4
63
64/**
65 * Maximum allowed number of pending messages per peer.
66 */
67#define MAXIMUM_PENDING_PER_PEER 64
68
69/**
70 * How long at least to wait before sending another find peer request.
71 * This is basically the frequency at which we will usually send out
72 * requests when we are 'perfectly' connected.
73 */
74#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
75 GNUNET_TIME_UNIT_MINUTES, 2)
76
77/**
78 * How long to additionally wait on average per #bucket_size to send out the
79 * FIND PEER requests if we did successfully connect (!) to a a new peer and
80 * added it to a bucket (as counted in #newly_found_peers). This time is
81 * Multiplied by 100 * newly_found_peers / bucket_size to get the new delay
82 * for finding peers (the #DHT_MINIMUM_FIND_PEER_INTERVAL is still added on
83 * top). Also the range in which we randomize, so the effective value
84 * is half of the number given here.
85 */
86#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
87 GNUNET_TIME_UNIT_SECONDS, 6)
88
89/**
90 * How long at most to wait for transmission of a GET request to another peer?
91 */
92#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
93
94/**
95 * Hello address expiration
96 */
97extern struct GNUNET_TIME_Relative hello_expiration;
98
99
100GNUNET_NETWORK_STRUCT_BEGIN
101
102/**
103 * P2P PUT message
104 */
105struct PeerPutMessage
106{
107 /**
108 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
109 */
110 struct GNUNET_MessageHeader header;
111
112 /**
113 * Content type.
114 */
115 uint32_t type GNUNET_PACKED;
116
117 /**
118 * Processing options
119 */
120 uint16_t options GNUNET_PACKED;
121
122 /**
123 * Hop count
124 */
125 uint16_t hop_count GNUNET_PACKED;
126
127 /**
128 * Replication level for this message
129 */
130 uint16_t desired_replication_level GNUNET_PACKED;
131
132 /**
133 * Length of the PUT path that follows (if tracked).
134 */
135 uint16_t put_path_length GNUNET_PACKED;
136
137 /**
138 * When does the content expire?
139 */
140 struct GNUNET_TIME_AbsoluteNBO expiration_time;
141
142 /**
143 * Bloomfilter (for peer identities) to stop circular routes
144 */
145 char bloomfilter[DHT_BLOOM_SIZE];
146
147 /**
148 * The key we are storing under.
149 */
150 struct GNUNET_HashCode key;
151
152 /* put path (if tracked) */
153
154 /* Payload */
155};
156
157
158/**
159 * P2P Result message
160 */
161struct PeerResultMessage
162{
163 /**
164 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
165 */
166 struct GNUNET_MessageHeader header;
167
168 /**
169 * Content type.
170 */
171 uint32_t type GNUNET_PACKED;
172
173 /**
174 * Reserved.
175 */
176 uint32_t reserved GNUNET_PACKED;
177
178 /**
179 * Length of the PUT path that follows (if tracked).
180 */
181 uint16_t put_path_length GNUNET_PACKED;
182
183 /**
184 * Length of the GET path that follows (if tracked).
185 */
186 uint16_t get_path_length GNUNET_PACKED;
187
188 /**
189 * When does the content expire?
190 */
191 struct GNUNET_TIME_AbsoluteNBO expiration_time;
192
193 /**
194 * The key of the corresponding GET request.
195 */
196 struct GNUNET_HashCode key;
197
198 /* put path (if tracked) */
199
200 /* get path (if tracked) */
201
202 /* Payload */
203};
204
205
206/**
207 * P2P GET message
208 */
209struct PeerGetMessage
210{
211 /**
212 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
213 */
214 struct GNUNET_MessageHeader header;
215
216 /**
217 * Desired content type.
218 */
219 uint32_t type GNUNET_PACKED;
220
221 /**
222 * Processing options
223 */
224 uint16_t options GNUNET_PACKED;
225
226 /**
227 * Hop count
228 */
229 uint16_t hop_count GNUNET_PACKED;
230
231 /**
232 * Desired replication level for this request.
233 */
234 uint16_t desired_replication_level GNUNET_PACKED;
235
236 /**
237 * Size of the extended query.
238 */
239 uint16_t xquery_size;
240
241 /**
242 * Bloomfilter (for peer identities) to stop circular routes
243 */
244 char bloomfilter[DHT_BLOOM_SIZE];
245
246 /**
247 * The key we are looking for.
248 */
249 struct GNUNET_HashCode key;
250
251 /**
252 * Bloomfilter mutator.
253 */
254 uint32_t bf_mutator;
255
256 /* xquery */
257
258 /* result bloomfilter */
259};
260GNUNET_NETWORK_STRUCT_END
261
262
263/**
264 * Entry for a peer in a bucket.
265 */
266struct PeerInfo
267{
268 /**
269 * Next peer entry (DLL)
270 */
271 struct PeerInfo *next;
272
273 /**
274 * Prev peer entry (DLL)
275 */
276 struct PeerInfo *prev;
277
278 /**
279 * Handle for sending messages to this peer.
280 */
281 struct GNUNET_MQ_Handle *mq;
282
283 /**
284 * What is the identity of the peer?
285 */
286 const struct GNUNET_PeerIdentity *id;
287
288 /**
289 * Hash of @e id.
290 */
291 struct GNUNET_HashCode phash;
292
293 /**
294 * Which bucket is this peer in?
295 */
296 int peer_bucket;
297};
298
299
300/**
301 * Peers are grouped into buckets.
302 */
303struct PeerBucket
304{
305 /**
306 * Head of DLL
307 */
308 struct PeerInfo *head;
309
310 /**
311 * Tail of DLL
312 */
313 struct PeerInfo *tail;
314
315 /**
316 * Number of peers in the bucket.
317 */
318 unsigned int peers_size;
319};
320
321
322/**
323 * Information about a peer that we would like to connect to.
324 */
325struct ConnectInfo
326{
327 /**
328 * Handle to active HELLO offer operation, or NULL.
329 */
330 struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
331
332 /**
333 * Handle to active connectivity suggestion operation, or NULL.
334 */
335 struct GNUNET_ATS_ConnectivitySuggestHandle *sh;
336
337 /**
338 * How much would we like to connect to this peer?
339 */
340 uint32_t strength;
341};
342
343
344/**
345 * Do we cache all results that we are routing in the local datacache?
346 */
347static int cache_results;
348
349/**
350 * The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
351 */
352static unsigned int closest_bucket;
353
354/**
355 * How many peers have we added since we sent out our last
356 * find peer request?
357 */
358static unsigned int newly_found_peers;
359
360/**
361 * Option for testing that disables the 'connect' function of the DHT.
362 */
363static int disable_try_connect;
364
365/**
366 * The buckets. Array of size #MAX_BUCKETS. Offset 0 means 0 bits matching.
367 */
368static struct PeerBucket k_buckets[MAX_BUCKETS];
369
370/**
371 * Hash map of all CORE-connected peers, for easy removal from
372 * #k_buckets on disconnect. Values are of type `struct PeerInfo`.
373 */
374static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
375
376/**
377 * Hash map of all peers we would like to be connected to.
378 * Values are of type `struct ConnectInfo`.
379 */
380static struct GNUNET_CONTAINER_MultiPeerMap *all_desired_peers;
381
382/**
383 * Maximum size for each bucket.
384 */
385static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
386
387/**
388 * Task that sends FIND PEER requests.
389 */
390static struct GNUNET_SCHEDULER_Task *find_peer_task;
391
392/**
393 * Identity of this peer.
394 */
395static struct GNUNET_PeerIdentity my_identity;
396
397/**
398 * Hash of the identity of this peer.
399 */
400struct GNUNET_HashCode my_identity_hash;
401
402/**
403 * Handle to CORE.
404 */
405static struct GNUNET_CORE_Handle *core_api;
406
407/**
408 * Handle to ATS connectivity.
409 */
410static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
411
412/**
413 * Our private key.
414 */
415static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
416
417
418/**
419 * Sign that we are routing a message from @a pred to @a succ.
420 * (So the route is $PRED->us->$SUCC).
421 *
422 * @param key key of the data (not necessarily the query hash)
423 * @param data payload (the block)
424 * @param data_size number of bytes in @a data
425 * @param exp_time expiration time of @a data
426 * @param pred predecessor peer ID
427 * @param succ successor peer ID
428 * @param[out] sig where to write the signature
429 * (of purpose #GNUNET_SIGNATURE_PURPOSE_DHT_HOP)
430 */
431static void
432sign_path (const struct GNUNET_HashCode *key,
433 const void *data,
434 size_t data_size,
435 struct GNUNET_TIME_Absolute exp_time,
436 const struct GNUNET_PeerIdentity *pred,
437 const struct GNUNET_PeerIdentity *succ,
438 struct GNUNET_CRYPTO_EddsaSignature *sig)
439{
440 struct GNUNET_DHT_HopSignature hs = {
441 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
442 .purpose.size = htonl (sizeof (hs)),
443 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
444 .key = *key,
445 .pred = *pred,
446 .succ = *succ
447 };
448
449 GNUNET_CRYPTO_hash (data,
450 data_size,
451 &hs.h_data);
452 GNUNET_CRYPTO_eddsa_sign (&my_private_key,
453 &hs,
454 sig);
455}
456
457
458/**
459 * Find the optimal bucket for this key.
460 *
461 * @param hc the hashcode to compare our identity to
462 * @return the proper bucket index, or -1
463 * on error (same hashcode)
464 */
465static int
466find_bucket (const struct GNUNET_HashCode *hc)
467{
468 struct GNUNET_HashCode xor;
469 unsigned int bits;
470
471 GNUNET_CRYPTO_hash_xor (hc,
472 &my_identity_hash,
473 &xor);
474 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
475 if (bits == MAX_BUCKETS)
476 {
477 /* How can all bits match? Got my own ID? */
478 GNUNET_break (0);
479 return -1;
480 }
481 return MAX_BUCKETS - bits - 1;
482}
483
484
485/**
486 * Function called when #GNUNET_TRANSPORT_offer_hello() is done.
487 * Clean up the "oh" field in the @a cls
488 *
489 * @param cls a `struct ConnectInfo`
490 */
491static void
492offer_hello_done (void *cls)
493{
494 struct ConnectInfo *ci = cls;
495
496 ci->oh = NULL;
497}
498
499
500/**
501 * Function called for all entries in #all_desired_peers to clean up.
502 *
503 * @param cls NULL
504 * @param peer peer the entry is for
505 * @param value the value to remove
506 * @return #GNUNET_YES
507 */
508static enum GNUNET_GenericReturnValue
509free_connect_info (void *cls,
510 const struct GNUNET_PeerIdentity *peer,
511 void *value)
512{
513 struct ConnectInfo *ci = value;
514
515 (void) cls;
516 GNUNET_assert (GNUNET_YES ==
517 GNUNET_CONTAINER_multipeermap_remove (all_desired_peers,
518 peer,
519 ci));
520 if (NULL != ci->sh)
521 {
522 GNUNET_ATS_connectivity_suggest_cancel (ci->sh);
523 ci->sh = NULL;
524 }
525 if (NULL != ci->oh)
526 {
527 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
528 ci->oh = NULL;
529 }
530 GNUNET_free (ci);
531 return GNUNET_YES;
532}
533
534
535/**
536 * Consider if we want to connect to a given peer, and if so
537 * let ATS know. If applicable, the HELLO is offered to the
538 * TRANSPORT service.
539 *
540 * @param pid peer to consider connectivity requirements for
541 * @param h a HELLO message, or NULL
542 */
543static void
544try_connect (const struct GNUNET_PeerIdentity *pid,
545 const struct GNUNET_MessageHeader *h)
546{
547 int bucket_idx;
548 struct GNUNET_HashCode pid_hash;
549 struct ConnectInfo *ci;
550 uint32_t strength;
551 struct PeerBucket *bucket;
552
553 GNUNET_CRYPTO_hash (pid,
554 sizeof(struct GNUNET_PeerIdentity),
555 &pid_hash);
556 bucket_idx = find_bucket (&pid_hash);
557 if (bucket_idx < 0)
558 {
559 GNUNET_break (0);
560 return; /* self!? */
561 }
562 bucket = &k_buckets[bucket_idx];
563 ci = GNUNET_CONTAINER_multipeermap_get (all_desired_peers,
564 pid);
565 if (bucket->peers_size < bucket_size)
566 strength = (bucket_size - bucket->peers_size) * bucket_idx;
567 else
568 strength = 0;
569 if (GNUNET_YES ==
570 GNUNET_CONTAINER_multipeermap_contains (all_connected_peers,
571 pid))
572 strength *= 2; /* double for connected peers */
573 if ( (0 == strength) &&
574 (NULL != ci) )
575 {
576 /* release request */
577 GNUNET_assert (GNUNET_YES ==
578 free_connect_info (NULL,
579 pid,
580 ci));
581 return;
582 }
583 if (NULL == ci)
584 {
585 ci = GNUNET_new (struct ConnectInfo);
586 GNUNET_assert (GNUNET_OK ==
587 GNUNET_CONTAINER_multipeermap_put (all_desired_peers,
588 pid,
589 ci,
590 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
591 }
592 if ( (NULL != ci->oh) &&
593 (NULL != h) )
594 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
595 if (NULL != h)
596 ci->oh = GNUNET_TRANSPORT_offer_hello (GDS_cfg,
597 h,
598 &offer_hello_done,
599 ci);
600 if ( (NULL != ci->sh) &&
601 (ci->strength != strength) )
602 GNUNET_ATS_connectivity_suggest_cancel (ci->sh);
603 if (ci->strength != strength)
604 {
605 ci->sh = GNUNET_ATS_connectivity_suggest (ats_ch,
606 pid,
607 strength);
608 ci->strength = strength;
609 }
610}
611
612
613/**
614 * Function called for each peer in #all_desired_peers during
615 * #update_connect_preferences() if we have reason to adjust
616 * the strength of our desire to keep connections to certain
617 * peers. Calls #try_connect() to update the calculations for
618 * the given @a pid.
619 *
620 * @param cls NULL
621 * @param pid peer to update
622 * @param value unused
623 * @return #GNUNET_YES (continue to iterate)
624 */
625static enum GNUNET_GenericReturnValue
626update_desire_strength (void *cls,
627 const struct GNUNET_PeerIdentity *pid,
628 void *value)
629{
630 (void) cls;
631 (void) value;
632 try_connect (pid,
633 NULL);
634 return GNUNET_YES;
635}
636
637
638/**
639 * Update our preferences for connectivity as given to ATS.
640 */
641static void
642update_connect_preferences (void)
643{
644 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
645 &update_desire_strength,
646 NULL);
647}
648
649
650/**
651 * Add each of the peers we already know to the Bloom filter of
652 * the request so that we don't get duplicate HELLOs.
653 *
654 * @param cls the `struct GNUNET_BLOCK_Group`
655 * @param key peer identity to add to the bloom filter
656 * @param value the peer information
657 * @return #GNUNET_YES (we should continue to iterate)
658 */
659static enum GNUNET_GenericReturnValue
660add_known_to_bloom (void *cls,
661 const struct GNUNET_PeerIdentity *key,
662 void *value)
663{
664 struct GNUNET_BLOCK_Group *bg = cls;
665 struct PeerInfo *pi = value;
666
667 GNUNET_BLOCK_group_set_seen (bg,
668 &pi->phash,
669 1);
670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
672 GNUNET_i2s (key));
673 return GNUNET_YES;
674}
675
676
677/**
678 * Task to send a find peer message for our own peer identifier
679 * so that we can find the closest peers in the network to ourselves
680 * and attempt to connect to them.
681 *
682 * @param cls closure for this task, NULL
683 */
684static void
685send_find_peer_message (void *cls)
686{
687 (void) cls;
688
689 /* Compute when to do this again (and if we should
690 even send a message right now) */
691 {
692 struct GNUNET_TIME_Relative next_send_time;
693 bool done_early;
694
695 find_peer_task = NULL;
696 done_early = (newly_found_peers > bucket_size);
697 /* schedule next round, taking longer if we found more peers
698 in the last round. */
699 next_send_time.rel_value_us =
700 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
701 + GNUNET_CRYPTO_random_u64 (
702 GNUNET_CRYPTO_QUALITY_WEAK,
703 GNUNET_TIME_relative_multiply (
704 DHT_AVG_FIND_PEER_INTERVAL,
705 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
706 newly_found_peers = 0;
707 GNUNET_assert (NULL == find_peer_task);
708 find_peer_task =
709 GNUNET_SCHEDULER_add_delayed (next_send_time,
710 &send_find_peer_message,
711 NULL);
712 if (done_early)
713 return;
714 }
715
716 /* actually send 'find peer' request */
717 {
718 struct GNUNET_BLOCK_Group *bg;
719 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
720
721 bg = GNUNET_BLOCK_group_create (GDS_block_context,
722 GNUNET_BLOCK_TYPE_DHT_HELLO,
723 GNUNET_CRYPTO_random_u32 (
724 GNUNET_CRYPTO_QUALITY_WEAK,
725 UINT32_MAX),
726 NULL,
727 0,
728 "filter-size",
729 DHT_BLOOM_SIZE,
730 NULL);
731 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
732 &add_known_to_bloom,
733 bg);
734 peer_bf
735 = GNUNET_CONTAINER_bloomfilter_init (NULL,
736 DHT_BLOOM_SIZE,
737 GNUNET_CONSTANTS_BLOOMFILTER_K);
738 if (GNUNET_OK !=
739 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO,
740 GNUNET_DHT_RO_FIND_PEER
741 | GNUNET_DHT_RO_RECORD_ROUTE,
742 FIND_PEER_REPLICATION_LEVEL,
743 0, /* hop count */
744 &my_identity_hash,
745 NULL, 0, /* xquery */
746 bg,
747 peer_bf))
748 {
749 GNUNET_STATISTICS_update (GDS_stats,
750 "# Failed to initiate FIND PEER lookup",
751 1,
752 GNUNET_NO);
753 }
754 else
755 {
756 GNUNET_STATISTICS_update (GDS_stats,
757 "# FIND PEER messages initiated",
758 1,
759 GNUNET_NO);
760 }
761 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
762 GNUNET_BLOCK_group_destroy (bg);
763 }
764}
765
766
767/**
768 * Method called whenever a peer connects.
769 *
770 * @param cls closure
771 * @param peer peer identity this notification is about
772 * @param mq message queue for sending messages to @a peer
773 * @return our `struct PeerInfo` for @a peer
774 */
775static void *
776handle_core_connect (void *cls,
777 const struct GNUNET_PeerIdentity *peer,
778 struct GNUNET_MQ_Handle *mq)
779{
780 struct PeerInfo *pi;
781 struct PeerBucket *bucket;
782
783 (void) cls;
784 /* Check for connect to self message */
785 if (0 == GNUNET_memcmp (&my_identity,
786 peer))
787 return NULL;
788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789 "Connected to peer %s\n",
790 GNUNET_i2s (peer));
791 GNUNET_assert (NULL ==
792 GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
793 peer));
794 GNUNET_STATISTICS_update (GDS_stats,
795 "# peers connected",
796 1,
797 GNUNET_NO);
798 pi = GNUNET_new (struct PeerInfo);
799 pi->id = peer;
800 pi->mq = mq;
801 GNUNET_CRYPTO_hash (peer,
802 sizeof(struct GNUNET_PeerIdentity),
803 &pi->phash);
804 pi->peer_bucket = find_bucket (&pi->phash);
805 GNUNET_assert ( (pi->peer_bucket >= 0) &&
806 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
807 bucket = &k_buckets[pi->peer_bucket];
808 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
809 bucket->tail,
810 pi);
811 bucket->peers_size++;
812 closest_bucket = GNUNET_MAX (closest_bucket,
813 (unsigned int) pi->peer_bucket + 1);
814 GNUNET_assert (GNUNET_OK ==
815 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
816 pi->id,
817 pi,
818 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
819 if (bucket->peers_size <= bucket_size)
820 {
821 update_connect_preferences ();
822 newly_found_peers++;
823 }
824 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
825 (GNUNET_YES != disable_try_connect) )
826 {
827 /* got a first connection, good time to start with FIND PEER requests... */
828 GNUNET_assert (NULL == find_peer_task);
829 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
830 NULL);
831 }
832 return pi;
833}
834
835
836/**
837 * Method called whenever a peer disconnects.
838 *
839 * @param cls closure
840 * @param peer peer identity this notification is about
841 * @param internal_cls our `struct PeerInfo` for @a peer
842 */
843static void
844handle_core_disconnect (void *cls,
845 const struct GNUNET_PeerIdentity *peer,
846 void *internal_cls)
847{
848 struct PeerInfo *to_remove = internal_cls;
849 struct PeerBucket *bucket;
850
851 (void) cls;
852 /* Check for disconnect from self message (on shutdown) */
853 if (NULL == to_remove)
854 return;
855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
856 "Disconnected from peer %s\n",
857 GNUNET_i2s (peer));
858 GNUNET_STATISTICS_update (GDS_stats,
859 "# peers connected",
860 -1,
861 GNUNET_NO);
862 GNUNET_assert (GNUNET_YES ==
863 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
864 peer,
865 to_remove));
866 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
867 (GNUNET_YES != disable_try_connect))
868 {
869 GNUNET_SCHEDULER_cancel (find_peer_task);
870 find_peer_task = NULL;
871 }
872 GNUNET_assert (to_remove->peer_bucket >= 0);
873 bucket = &k_buckets[to_remove->peer_bucket];
874 GNUNET_CONTAINER_DLL_remove (bucket->head,
875 bucket->tail,
876 to_remove);
877 GNUNET_assert (bucket->peers_size > 0);
878 bucket->peers_size--;
879 while ( (closest_bucket > 0) &&
880 (0 == k_buckets[closest_bucket - 1].peers_size))
881 closest_bucket--;
882 if (bucket->peers_size < bucket_size)
883 update_connect_preferences ();
884 GNUNET_free (to_remove);
885}
886
887
888/**
889 * To how many peers should we (on average) forward the request to
890 * obtain the desired target_replication count (on average).
891 *
892 * @param hop_count number of hops the message has traversed
893 * @param target_replication the number of total paths desired
894 * @return Some number of peers to forward the message to
895 */
896static unsigned int
897get_forward_count (uint32_t hop_count,
898 uint32_t target_replication)
899{
900 uint32_t random_value;
901 uint32_t forward_count;
902 float target_value;
903
904 if (0 == target_replication)
905 target_replication = 1; /* 0 is verboten */
906 if (target_replication > GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL)
907 target_replication = GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL;
908 if (hop_count > GDS_NSE_get () * 4.0)
909 {
910 /* forcefully terminate */
911 GNUNET_STATISTICS_update (GDS_stats,
912 "# requests TTL-dropped",
913 1,
914 GNUNET_NO);
915 return 0;
916 }
917 if (hop_count > GDS_NSE_get () * 2.0)
918 {
919 /* Once we have reached our ideal number of hops, only forward to 1 peer */
920 return 1;
921 }
922 /* bound by system-wide maximum */
923 target_replication =
924 GNUNET_MIN (GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL,
925 target_replication);
926 target_value =
927 1 + (target_replication - 1.0) / (GDS_NSE_get ()
928 + ((float) (target_replication - 1.0)
929 * hop_count));
930
931
932 /* Set forward count to floor of target_value */
933 forward_count = (uint32_t) target_value;
934 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
935 target_value = target_value - forward_count;
936 random_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
937 UINT32_MAX);
938 if (random_value < (target_value * UINT32_MAX))
939 forward_count++;
940 return GNUNET_MIN (forward_count,
941 GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL);
942}
943
944
945/**
946 * Check whether my identity is closer than any known peers. If a
947 * non-null bloomfilter is given, check if this is the closest peer
948 * that hasn't already been routed to.
949 *
950 * @param key hash code to check closeness to
951 * @param bloom bloomfilter, exclude these entries from the decision
952 * @return #GNUNET_YES if node location is closest,
953 * #GNUNET_NO otherwise.
954 */
955enum GNUNET_GenericReturnValue
956GDS_am_closest_peer (const struct GNUNET_HashCode *key,
957 const struct GNUNET_CONTAINER_BloomFilter *bloom)
958{
959 if (0 == GNUNET_memcmp (&my_identity_hash,
960 key))
961 return GNUNET_YES;
962 for (int bucket_num = find_bucket (key);
963 bucket_num < closest_bucket;
964 bucket_num++)
965 {
966 unsigned int count = 0;
967
968 GNUNET_assert (bucket_num >= 0);
969 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
970 NULL != pos;
971 pos = pos->next)
972 {
973 if (count >= bucket_size)
974 break; /* we only consider first #bucket_size entries per bucket */
975 count++;
976 if ( (NULL != bloom) &&
977 (GNUNET_YES ==
978 GNUNET_CONTAINER_bloomfilter_test (bloom,
979 &pos->phash)) )
980 continue; /* Ignore filtered peers */
981 /* All peers in this bucket must be closer than us, as
982 they mismatch with our PID on the pivotal bit. So
983 because an unfiltered peer exists, we are not the
984 closest. */
985 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
986 &my_identity_hash,
987 key);
988 switch (delta)
989 {
990 case -1: /* pos closer */
991 return GNUNET_NO;
992 case 0: /* identical, impossible! */
993 GNUNET_assert (0);
994 break;
995 case 1: /* I am closer */
996 break;
997 }
998 }
999 }
1000 /* No closer (unfiltered) peers found; we must be the closest! */
1001 return GNUNET_YES;
1002}
1003
1004
1005/**
1006 * Select a peer from the routing table that would be a good routing
1007 * destination for sending a message for @a key. The resulting peer
1008 * must not be in the set of @a bloom blocked peers.
1009 *
1010 * Note that we should not ALWAYS select the closest peer to the
1011 * target, we do a "random" peer selection if the number of @a hops
1012 * is below the logarithm of the network size estimate.
1013 *
1014 * In all cases, we only consider at most the first #bucket_size peers of any
1015 * #k_buckets. The other peers in the bucket are there because GNUnet doesn't
1016 * really allow the DHT to "reject" connections, but we only use the first
1017 * #bucket_size, even if more exist. (The idea is to ensure that those
1018 * connections are frequently used, and for others to be not used by the DHT,
1019 * and thus possibly dropped by transport due to disuse).
1020 *
1021 * @param key the key we are selecting a peer to route to
1022 * @param bloom a Bloom filter containing entries this request has seen already
1023 * @param hops how many hops has this message traversed thus far
1024 * @return Peer to route to, or NULL on error
1025 */
1026static struct PeerInfo *
1027select_peer (const struct GNUNET_HashCode *key,
1028 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1029 uint32_t hops)
1030{
1031 if (0 == closest_bucket)
1032 {
1033 GNUNET_STATISTICS_update (GDS_stats,
1034 "# Peer selection failed",
1035 1,
1036 GNUNET_NO);
1037 return NULL; /* we have zero connections */
1038 }
1039 if (hops >= GDS_NSE_get ())
1040 {
1041 /* greedy selection (closest peer that is not in Bloom filter) */
1042 struct PeerInfo *chosen = NULL;
1043 int best_bucket;
1044 int bucket_offset;
1045
1046 {
1047 struct GNUNET_HashCode xor;
1048
1049 GNUNET_CRYPTO_hash_xor (key,
1050 &my_identity_hash,
1051 &xor);
1052 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1053 }
1054 if (best_bucket >= closest_bucket)
1055 bucket_offset = closest_bucket - 1;
1056 else
1057 bucket_offset = best_bucket;
1058 while (-1 != bucket_offset)
1059 {
1060 struct PeerBucket *bucket = &k_buckets[bucket_offset];
1061 unsigned int count = 0;
1062
1063 for (struct PeerInfo *pos = bucket->head;
1064 NULL != pos;
1065 pos = pos->next)
1066 {
1067 if (count >= bucket_size)
1068 break; /* we only consider first #bucket_size entries per bucket */
1069 count++;
1070 if (GNUNET_YES ==
1071 GNUNET_CONTAINER_bloomfilter_test (bloom,
1072 &pos->phash))
1073 {
1074 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1076 GNUNET_i2s (pos->id),
1077 GNUNET_h2s (key));
1078 continue;
1079 }
1080 if (NULL == chosen)
1081 {
1082 /* First candidate */
1083 chosen = pos;
1084 }
1085 else
1086 {
1087 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1088 &chosen->phash,
1089 key);
1090 switch (delta)
1091 {
1092 case -1: /* pos closer */
1093 chosen = pos;
1094 break;
1095 case 0: /* identical, impossible! */
1096 GNUNET_assert (0);
1097 break;
1098 case 1: /* chosen closer */
1099 break;
1100 }
1101 }
1102 count++;
1103 } /* for all (#bucket_size) peers in bucket */
1104 if (NULL != chosen)
1105 break;
1106
1107 /* If we chose nothing in first iteration, first go through deeper
1108 buckets (best chance to find a good match), and if we still found
1109 nothing, then to shallower buckets. Terminate on any match in the
1110 current bucket, as this search order guarantees that it can only get
1111 worse as we keep going. */
1112 if (bucket_offset > best_bucket)
1113 {
1114 /* Go through more deeper buckets */
1115 bucket_offset++;
1116 if (bucket_offset == closest_bucket)
1117 {
1118 /* Can't go any deeper, if nothing selected,
1119 go for shallower buckets */
1120 bucket_offset = best_bucket - 1;
1121 }
1122 }
1123 else
1124 {
1125 /* We're either at the 'best_bucket' or already moving
1126 on to shallower buckets. */
1127 if (bucket_offset == best_bucket)
1128 bucket_offset++; /* go for deeper buckets */
1129 else
1130 bucket_offset--; /* go for shallower buckets */
1131 }
1132 } /* for applicable buckets (starting at best match) */
1133 if (NULL == chosen)
1134 {
1135 GNUNET_STATISTICS_update (GDS_stats,
1136 "# Peer selection failed",
1137 1,
1138 GNUNET_NO);
1139 return NULL;
1140 }
1141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1142 "Selected peer `%s' in greedy routing for %s\n",
1143 GNUNET_i2s (chosen->id),
1144 GNUNET_h2s (key));
1145 return chosen;
1146 } /* end of 'greedy' peer selection */
1147
1148 /* select "random" peer */
1149 /* count number of peers that are available and not filtered,
1150 but limit to at most #bucket_size peers, starting with
1151 those 'furthest' from us. */
1152 {
1153 unsigned int total = 0;
1154 unsigned int selected;
1155
1156 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1157 {
1158 unsigned int count = 0;
1159
1160 for (struct PeerInfo *pos = k_buckets[bc].head;
1161 NULL != pos;
1162 pos = pos->next)
1163 {
1164 count++;
1165 if (count > bucket_size)
1166 break; /* limits search to #bucket_size peers per bucket */
1167 if (GNUNET_YES ==
1168 GNUNET_CONTAINER_bloomfilter_test (bloom,
1169 &pos->phash))
1170 {
1171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172 "Excluded peer `%s' due to BF match in random routing for %s\n",
1173 GNUNET_i2s (pos->id),
1174 GNUNET_h2s (key));
1175 continue; /* Ignore filtered peers */
1176 }
1177 total++;
1178 } /* for all peers in bucket */
1179 } /* for all buckets */
1180 if (0 == total) /* No peers to select from! */
1181 {
1182 GNUNET_STATISTICS_update (GDS_stats,
1183 "# Peer selection failed",
1184 1,
1185 GNUNET_NO);
1186 return NULL;
1187 }
1188
1189 /* Now actually choose a peer */
1190 selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1191 total);
1192 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1193 {
1194 unsigned int count = 0;
1195
1196 for (struct PeerInfo *pos = k_buckets[bc].head;
1197 pos != NULL;
1198 pos = pos->next)
1199 {
1200 count++;
1201 if (count > bucket_size)
1202 break; /* limits search to #bucket_size peers per bucket */
1203
1204 if (GNUNET_YES ==
1205 GNUNET_CONTAINER_bloomfilter_test (bloom,
1206 &pos->phash))
1207 continue; /* Ignore bloomfiltered peers */
1208 if (0 == selected--)
1209 {
1210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1211 "Selected peer `%s' in random routing for %s\n",
1212 GNUNET_i2s (pos->id),
1213 GNUNET_h2s (key));
1214 return pos;
1215 }
1216 } /* for peers in bucket */
1217 } /* for all buckets */
1218 } /* random peer selection scope */
1219 GNUNET_break (0);
1220 return NULL;
1221}
1222
1223
1224/**
1225 * Compute the set of peers that the given request should be
1226 * forwarded to.
1227 *
1228 * @param key routing key
1229 * @param[in,out] bloom Bloom filter excluding peers as targets,
1230 * all selected peers will be added to the Bloom filter
1231 * @param hop_count number of hops the request has traversed so far
1232 * @param target_replication desired number of replicas
1233 * @param[out] targets where to store an array of target peers (to be
1234 * free()ed by the caller)
1235 * @return number of peers returned in @a targets.
1236 */
1237static unsigned int
1238get_target_peers (const struct GNUNET_HashCode *key,
1239 struct GNUNET_CONTAINER_BloomFilter *bloom,
1240 uint32_t hop_count,
1241 uint32_t target_replication,
1242 struct PeerInfo ***targets)
1243{
1244 unsigned int target;
1245 unsigned int off;
1246 struct PeerInfo **rtargets;
1247
1248 GNUNET_assert (NULL != bloom);
1249 target = get_forward_count (hop_count,
1250 target_replication);
1251 if (0 == target)
1252 {
1253 *targets = NULL;
1254 return 0;
1255 }
1256 rtargets = GNUNET_new_array (target,
1257 struct PeerInfo *);
1258 for (off = 0; off < target; off++)
1259 {
1260 struct PeerInfo *nxt;
1261
1262 nxt = select_peer (key,
1263 bloom,
1264 hop_count);
1265 if (NULL == nxt)
1266 break;
1267 rtargets[off] = nxt;
1268 GNUNET_break (GNUNET_NO ==
1269 GNUNET_CONTAINER_bloomfilter_test (bloom,
1270 &nxt->phash));
1271 GNUNET_CONTAINER_bloomfilter_add (bloom,
1272 &nxt->phash);
1273 }
1274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1275 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1276 off,
1277 GNUNET_CONTAINER_multipeermap_size (all_connected_peers),
1278 (unsigned int) hop_count,
1279 GNUNET_h2s (key),
1280 target);
1281 if (0 == off)
1282 {
1283 GNUNET_free (rtargets);
1284 *targets = NULL;
1285 return 0;
1286 }
1287 *targets = rtargets;
1288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1289 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1290 GNUNET_h2s (key),
1291 off,
1292 target);
1293 return off;
1294}
1295
1296
1297enum GNUNET_GenericReturnValue
1298GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1299 enum GNUNET_DHT_RouteOption options,
1300 uint32_t desired_replication_level,
1301 uint32_t hop_count,
1302 struct GNUNET_CONTAINER_BloomFilter *bf)
1303{
1304 unsigned int target_count;
1305 struct PeerInfo **targets;
1306 size_t msize;
1307 unsigned int skip_count;
1308 unsigned int put_path_length = bd->put_path_length;
1309
1310 GNUNET_assert (NULL != bf);
1311#if SANITY_CHECKS
1312 if (0 !=
1313 GNUNET_DHT_verify_path (&bd->key,
1314 bd->data,
1315 bd->data_size,
1316 bd->expiration_time,
1317 bd->put_path,
1318 bd->put_path_length,
1319 NULL, 0, /* get_path */
1320 &my_identity))
1321 {
1322 GNUNET_break_op (0);
1323 put_path_length = 0;
1324 }
1325#endif
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Adding myself (%s) to PUT bloomfilter for %s\n",
1328 GNUNET_i2s (&my_identity),
1329 GNUNET_h2s (&bd->key));
1330 GNUNET_CONTAINER_bloomfilter_add (bf,
1331 &my_identity_hash);
1332 GNUNET_STATISTICS_update (GDS_stats,
1333 "# PUT requests routed",
1334 1,
1335 GNUNET_NO);
1336 target_count
1337 = get_target_peers (&bd->key,
1338 bf,
1339 hop_count,
1340 desired_replication_level,
1341 &targets);
1342 if (0 == target_count)
1343 {
1344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1345 "Routing PUT for %s terminates after %u hops at %s\n",
1346 GNUNET_h2s (&bd->key),
1347 (unsigned int) hop_count,
1348 GNUNET_i2s (&my_identity));
1349 return GNUNET_NO;
1350 }
1351 msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1352 + bd->data_size;
1353 if (msize + sizeof(struct PeerPutMessage)
1354 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1355 {
1356 put_path_length = 0;
1357 msize = bd->data_size;
1358 }
1359 if (msize + sizeof(struct PeerPutMessage)
1360 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1361 {
1362 GNUNET_break (0);
1363 GNUNET_free (targets);
1364 return GNUNET_NO;
1365 }
1366 skip_count = 0;
1367 for (unsigned int i = 0; i < target_count; i++)
1368 {
1369 struct PeerInfo *target = targets[i];
1370 struct GNUNET_MQ_Envelope *env;
1371 struct PeerPutMessage *ppm;
1372 struct GNUNET_DHT_PathElement *pp;
1373
1374 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1375 {
1376 /* skip */
1377 GNUNET_STATISTICS_update (GDS_stats,
1378 "# P2P messages dropped due to full queue",
1379 1,
1380 GNUNET_NO);
1381 skip_count++;
1382 continue;
1383 }
1384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1385 "Routing PUT for %s after %u hops to %s\n",
1386 GNUNET_h2s (&bd->key),
1387 (unsigned int) hop_count,
1388 GNUNET_i2s (target->id));
1389 env = GNUNET_MQ_msg_extra (ppm,
1390 msize,
1391 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
1392 ppm->options = htonl (options);
1393 ppm->type = htonl (bd->type);
1394 ppm->hop_count = htonl (hop_count + 1);
1395 ppm->desired_replication_level = htonl (desired_replication_level);
1396 ppm->put_path_length = htonl (put_path_length);
1397 ppm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1398 GNUNET_break (GNUNET_YES ==
1399 GNUNET_CONTAINER_bloomfilter_test (bf,
1400 &target->phash));
1401 GNUNET_assert (GNUNET_OK ==
1402 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
1403 ppm->bloomfilter,
1404 DHT_BLOOM_SIZE));
1405 ppm->key = bd->key;
1406 pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1407 GNUNET_memcpy (pp,
1408 bd->put_path,
1409 sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1410 /* 0 == put_path_length means path is not being tracked */
1411 if (0 != put_path_length)
1412 {
1413 /* Note that the signature in 'put_path' was not initialized before,
1414 so this is crucial to avoid sending garbage. */
1415 sign_path (&bd->key,
1416 bd->data,
1417 bd->data_size,
1418 bd->expiration_time,
1419 &pp[put_path_length - 1].pred,
1420 target->id,
1421 &pp[put_path_length - 1].sig);
1422 }
1423
1424 GNUNET_memcpy (&pp[put_path_length],
1425 bd->data,
1426 bd->data_size);
1427 GNUNET_MQ_send (target->mq,
1428 env);
1429 }
1430 GNUNET_free (targets);
1431 GNUNET_STATISTICS_update (GDS_stats,
1432 "# PUT messages queued for transmission",
1433 target_count - skip_count,
1434 GNUNET_NO);
1435 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1436}
1437
1438
1439enum GNUNET_GenericReturnValue
1440GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1441 enum GNUNET_DHT_RouteOption options,
1442 uint32_t desired_replication_level,
1443 uint32_t hop_count,
1444 const struct GNUNET_HashCode *key,
1445 const void *xquery,
1446 size_t xquery_size,
1447 struct GNUNET_BLOCK_Group *bg,
1448 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1449{
1450 unsigned int target_count;
1451 struct PeerInfo **targets;
1452 size_t msize;
1453 size_t reply_bf_size;
1454 void *reply_bf;
1455 unsigned int skip_count;
1456 uint32_t bf_nonce;
1457
1458 GNUNET_assert (NULL != peer_bf);
1459 GNUNET_STATISTICS_update (GDS_stats,
1460 "# GET requests routed",
1461 1,
1462 GNUNET_NO);
1463 target_count = get_target_peers (key,
1464 peer_bf,
1465 hop_count,
1466 desired_replication_level,
1467 &targets);
1468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1469 "Adding myself (%s) to GET bloomfilter for %s\n",
1470 GNUNET_i2s (&my_identity),
1471 GNUNET_h2s (key));
1472 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1473 &my_identity_hash);
1474 if (0 == target_count)
1475 {
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477 "Routing GET for %s terminates after %u hops at %s\n",
1478 GNUNET_h2s (key),
1479 (unsigned int) hop_count,
1480 GNUNET_i2s (&my_identity));
1481 return GNUNET_NO;
1482 }
1483 if (GNUNET_OK !=
1484 GNUNET_BLOCK_group_serialize (bg,
1485 &bf_nonce,
1486 &reply_bf,
1487 &reply_bf_size))
1488 {
1489 reply_bf = NULL;
1490 reply_bf_size = 0;
1491 bf_nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1492 UINT32_MAX);
1493 }
1494 msize = xquery_size + reply_bf_size;
1495 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1496 {
1497 GNUNET_break (0);
1498 GNUNET_free (reply_bf);
1499 GNUNET_free (targets);
1500 return GNUNET_NO;
1501 }
1502 /* forward request */
1503 skip_count = 0;
1504 for (unsigned int i = 0; i < target_count; i++)
1505 {
1506 struct PeerInfo *target = targets[i];
1507 struct GNUNET_MQ_Envelope *env;
1508 struct PeerGetMessage *pgm;
1509 char *xq;
1510
1511 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1512 {
1513 /* skip */
1514 GNUNET_STATISTICS_update (GDS_stats,
1515 "# P2P messages dropped due to full queue",
1516 1,
1517 GNUNET_NO);
1518 skip_count++;
1519 continue;
1520 }
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 "Routing GET for %s after %u hops to %s\n",
1523 GNUNET_h2s (key),
1524 (unsigned int) hop_count,
1525 GNUNET_i2s (target->id));
1526 env = GNUNET_MQ_msg_extra (pgm,
1527 msize,
1528 GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
1529 pgm->options = htonl (options);
1530 pgm->type = htonl (type);
1531 pgm->hop_count = htonl (hop_count + 1);
1532 pgm->desired_replication_level = htonl (desired_replication_level);
1533 pgm->xquery_size = htonl (xquery_size);
1534 pgm->bf_mutator = bf_nonce;
1535 GNUNET_break (GNUNET_YES ==
1536 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1537 &target->phash));
1538 GNUNET_assert (GNUNET_OK ==
1539 GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf,
1540 pgm->bloomfilter,
1541 DHT_BLOOM_SIZE));
1542 pgm->key = *key;
1543 xq = (char *) &pgm[1];
1544 GNUNET_memcpy (xq,
1545 xquery,
1546 xquery_size);
1547 GNUNET_memcpy (&xq[xquery_size],
1548 reply_bf,
1549 reply_bf_size);
1550 GNUNET_MQ_send (target->mq,
1551 env);
1552 }
1553 GNUNET_STATISTICS_update (GDS_stats,
1554 "# GET messages queued for transmission",
1555 target_count - skip_count,
1556 GNUNET_NO);
1557 GNUNET_free (targets);
1558 GNUNET_free (reply_bf);
1559 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1560}
1561
1562
1563struct PeerInfo *
1564GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
1565{
1566 return GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
1567 target);
1568}
1569
1570
1571void
1572GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1573 const struct GDS_DATACACHE_BlockData *bd,
1574 const struct GNUNET_HashCode *query_hash,
1575 unsigned int get_path_length,
1576 const struct GNUNET_DHT_PathElement *get_path)
1577{
1578 struct GNUNET_MQ_Envelope *env;
1579 struct PeerResultMessage *prm;
1580 struct GNUNET_DHT_PathElement *paths;
1581 size_t msize;
1582 unsigned int ppl = bd->put_path_length;
1583
1584#if SANITY_CHECKS
1585 if (0 !=
1586 GNUNET_DHT_verify_path (&bd->key,
1587 bd->data,
1588 bd->data_size,
1589 bd->expiration_time,
1590 bd->put_path,
1591 bd->put_path_length,
1592 get_path,
1593 get_path_length,
1594 &my_identity))
1595 {
1596 GNUNET_break_op (0);
1597 get_path_length = 0;
1598 ppl = 0;
1599 }
1600#endif
1601 msize = bd->data_size + (get_path_length + ppl)
1602 * sizeof(struct GNUNET_DHT_PathElement);
1603 if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1604 (get_path_length >
1605 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1606 (ppl >
1607 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1608 (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
1609 {
1610 ppl = 0;
1611 get_path_length = 0;
1612 msize = bd->data_size + (get_path_length + ppl)
1613 * sizeof(struct GNUNET_DHT_PathElement);
1614 }
1615 if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1616 (get_path_length >
1617 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1618 (ppl >
1619 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1620 (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
1621 {
1622 GNUNET_break (0);
1623 return;
1624 }
1625 if (GNUNET_MQ_get_length (pi->mq) >= MAXIMUM_PENDING_PER_PEER)
1626 {
1627 /* skip */
1628 GNUNET_STATISTICS_update (GDS_stats,
1629 "# P2P messages dropped due to full queue",
1630 1,
1631 GNUNET_NO);
1632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1633 "Peer queue full, ignoring reply for key %s\n",
1634 GNUNET_h2s (&bd->key));
1635 return;
1636 }
1637
1638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1639 "Forwarding reply for key %s to peer %s\n",
1640 GNUNET_h2s (query_hash),
1641 GNUNET_i2s (pi->id));
1642 GNUNET_STATISTICS_update (GDS_stats,
1643 "# RESULT messages queued for transmission",
1644 1,
1645 GNUNET_NO);
1646 env = GNUNET_MQ_msg_extra (prm,
1647 msize,
1648 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1649 prm->type = htonl (bd->type);
1650 prm->put_path_length = htonl (ppl);
1651 prm->get_path_length = htonl (get_path_length);
1652 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1653 prm->key = *query_hash;
1654 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1655 GNUNET_memcpy (paths,
1656 bd->put_path,
1657 ppl * sizeof(struct GNUNET_DHT_PathElement));
1658 GNUNET_memcpy (&paths[ppl],
1659 get_path,
1660 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1661 /* 0 == get_path_length means path is not being tracked */
1662 if (0 != get_path_length)
1663 {
1664 /* Note that the signature in 'get_path' was not initialized before,
1665 so this is crucial to avoid sending garbage. */
1666 sign_path (&bd->key,
1667 bd->data,
1668 bd->data_size,
1669 bd->expiration_time,
1670 &paths[ppl + get_path_length - 1].pred,
1671 pi->id,
1672 &paths[ppl + get_path_length - 1].sig);
1673 }
1674 GNUNET_memcpy (&paths[ppl + get_path_length],
1675 bd->data,
1676 bd->data_size);
1677 GNUNET_MQ_send (pi->mq,
1678 env);
1679}
1680
1681
1682/**
1683 * To be called on core init.
1684 *
1685 * @param cls service closure
1686 * @param identity the public identity of this peer
1687 */
1688static void
1689core_init (void *cls,
1690 const struct GNUNET_PeerIdentity *identity)
1691{
1692 (void) cls;
1693 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1694 "CORE called, I am %s\n",
1695 GNUNET_i2s (identity));
1696 my_identity = *identity;
1697 GNUNET_CRYPTO_hash (identity,
1698 sizeof(struct GNUNET_PeerIdentity),
1699 &my_identity_hash);
1700 GNUNET_SERVICE_resume (GDS_service);
1701}
1702
1703
1704/**
1705 * Check validity of a p2p put request.
1706 *
1707 * @param cls closure with the `struct PeerInfo` of the sender
1708 * @param message message
1709 * @return #GNUNET_OK if the message is valid
1710 */
1711static enum GNUNET_GenericReturnValue
1712check_dht_p2p_put (void *cls,
1713 const struct PeerPutMessage *put)
1714{
1715 uint16_t msize = ntohs (put->header.size);
1716 uint32_t putlen = ntohl (put->put_path_length);
1717
1718 (void) cls;
1719 if ( (msize <
1720 sizeof(struct PeerPutMessage)
1721 + putlen * sizeof(struct GNUNET_DHT_PathElement)) ||
1722 (putlen >
1723 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
1724 {
1725 GNUNET_break_op (0);
1726 return GNUNET_SYSERR;
1727 }
1728 return GNUNET_OK;
1729}
1730
1731
1732/**
1733 * Core handler for p2p put requests.
1734 *
1735 * @param cls closure with the `struct PeerInfo` of the sender
1736 * @param message message
1737 */
1738static void
1739handle_dht_p2p_put (void *cls,
1740 const struct PeerPutMessage *put)
1741{
1742 struct PeerInfo *peer = cls;
1743 uint16_t msize = ntohs (put->header.size);
1744 enum GNUNET_DHT_RouteOption options
1745 = (enum GNUNET_DHT_RouteOption) ntohl (put->options);
1746 struct GDS_DATACACHE_BlockData bd = {
1747 .key = put->key,
1748 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1749 .type = ntohl (put->type)
1750 };
1751 const struct GNUNET_DHT_PathElement *put_path
1752 = (const struct GNUNET_DHT_PathElement *) &put[1];
1753 uint32_t putlen
1754 = ntohl (put->put_path_length);
1755
1756 bd.data_size = msize - (sizeof(*put)
1757 + putlen * sizeof(struct GNUNET_DHT_PathElement));
1758 bd.data = &put_path[putlen];
1759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1760 "PUT for `%s' from %s\n",
1761 GNUNET_h2s (&put->key),
1762 GNUNET_i2s (peer->id));
1763 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
1764 {
1765 GNUNET_STATISTICS_update (GDS_stats,
1766 "# Expired PUTs discarded",
1767 1,
1768 GNUNET_NO);
1769 return;
1770 }
1771 GNUNET_STATISTICS_update (GDS_stats,
1772 "# P2P PUT requests received",
1773 1,
1774 GNUNET_NO);
1775 GNUNET_STATISTICS_update (GDS_stats,
1776 "# P2P PUT bytes received",
1777 msize,
1778 GNUNET_NO);
1779 {
1780 struct GNUNET_HashCode test_key;
1781 enum GNUNET_GenericReturnValue ret;
1782
1783 ret = GNUNET_BLOCK_get_key (GDS_block_context,
1784 bd.type,
1785 bd.data,
1786 bd.data_size,
1787 &test_key);
1788 switch (ret)
1789 {
1790 case GNUNET_YES:
1791 if (0 != GNUNET_memcmp (&test_key,
1792 &bd.key))
1793 {
1794 GNUNET_break_op (0);
1795 return;
1796 }
1797 break;
1798 case GNUNET_NO:
1799 GNUNET_break_op (0);
1800 return;
1801 case GNUNET_SYSERR:
1802 /* cannot verify, good luck */
1803 break;
1804 }
1805 }
1806
1807 if (GNUNET_NO ==
1808 GNUNET_BLOCK_check_block (GDS_block_context,
1809 bd.type,
1810 &bd.key,
1811 bd.data,
1812 bd.data_size))
1813 {
1814 GNUNET_break_op (0);
1815 return;
1816 }
1817
1818 {
1819 struct GNUNET_CONTAINER_BloomFilter *bf;
1820 struct GNUNET_DHT_PathElement pp[putlen + 1];
1821
1822 bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter,
1823 DHT_BLOOM_SIZE,
1824 GNUNET_CONSTANTS_BLOOMFILTER_K);
1825 GNUNET_break_op (GNUNET_YES ==
1826 GNUNET_CONTAINER_bloomfilter_test (bf,
1827 &peer->phash));
1828 /* extend 'put path' by sender */
1829 bd.put_path = (const struct GNUNET_DHT_PathElement *) pp;
1830 bd.put_path_length = putlen + 1;
1831 if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
1832 {
1833#if SANITY_CHECKS
1834 for (unsigned int i = 0; i <= putlen; i++)
1835 {
1836 for (unsigned int j = 0; j < i; j++)
1837 {
1838 GNUNET_break (0 !=
1839 GNUNET_memcmp (&pp[i].pred,
1840 &pp[j].pred));
1841 }
1842 GNUNET_break (0 !=
1843 GNUNET_memcmp (&pp[i].pred,
1844 peer->id));
1845 }
1846 if (0 !=
1847 GNUNET_DHT_verify_path (&bd.key,
1848 bd.data,
1849 bd.data_size,
1850 bd.expiration_time,
1851 bd.put_path,
1852 putlen,
1853 NULL, 0, /* get_path */
1854 &my_identity))
1855 {
1856 GNUNET_break_op (0);
1857 putlen = 0;
1858 }
1859#endif
1860 GNUNET_memcpy (pp,
1861 put_path,
1862 putlen * sizeof(struct GNUNET_DHT_PathElement));
1863 pp[putlen].pred = *peer->id;
1864 /* zero-out signature, not valid until we actually do forward! */
1865 memset (&pp[putlen].sig,
1866 0,
1867 sizeof (pp[putlen].sig));
1868 putlen++;
1869 }
1870 else
1871 {
1872 bd.put_path_length = 0;
1873 }
1874
1875 /* give to local clients */
1876 GDS_CLIENTS_handle_reply (&bd,
1877 &bd.key,
1878 0, NULL /* get path */);
1879
1880 /* store locally */
1881 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1882 (GDS_am_closest_peer (&put->key,
1883 bf)) )
1884 GDS_DATACACHE_handle_put (&bd);
1885 {
1886 enum GNUNET_GenericReturnValue forwarded;
1887
1888 /* route to other peers */
1889 forwarded
1890 = GDS_NEIGHBOURS_handle_put (&bd,
1891 options,
1892 ntohl (put->desired_replication_level),
1893 ntohl (put->hop_count),
1894 bf);
1895 /* notify monitoring clients */
1896 GDS_CLIENTS_process_put (options
1897 | ((GNUNET_OK == forwarded)
1898 ? GNUNET_DHT_RO_LAST_HOP
1899 : 0),
1900 &bd,
1901 ntohl (put->hop_count),
1902 ntohl (put->desired_replication_level));
1903 }
1904 GNUNET_CONTAINER_bloomfilter_free (bf);
1905 }
1906}
1907
1908
1909/**
1910 * We have received a FIND PEER request. Send matching
1911 * HELLOs back.
1912 *
1913 * @param pi sender of the FIND PEER request
1914 * @param key peers close to this key are desired
1915 * @param bg group for filtering peers
1916 */
1917static void
1918handle_find_peer (struct PeerInfo *pi,
1919 const struct GNUNET_HashCode *query_hash,
1920 struct GNUNET_BLOCK_Group *bg)
1921{
1922 int bucket_idx;
1923 struct PeerBucket *bucket;
1924 struct PeerInfo *peer;
1925 unsigned int choice;
1926 struct GDS_DATACACHE_BlockData bd = {
1927 .type = GNUNET_BLOCK_TYPE_DHT_HELLO
1928 };
1929
1930 /* first, check about our own HELLO */
1931 if (NULL != GDS_my_hello)
1932 {
1933 bd.expiration_time = GNUNET_TIME_relative_to_absolute (
1934 hello_expiration),
1935 bd.key = my_identity_hash,
1936 bd.data = GDS_my_hello;
1937 bd.data_size = GNUNET_HELLO_size (
1938 (const struct GNUNET_HELLO_Message *) GDS_my_hello);
1939 GNUNET_break (bd.data_size >= sizeof(struct GNUNET_MessageHeader));
1940 if (GNUNET_BLOCK_REPLY_OK_MORE ==
1941 GNUNET_BLOCK_check_reply (GDS_block_context,
1942 GNUNET_BLOCK_TYPE_DHT_HELLO,
1943 bg,
1944 &my_identity_hash,
1945 NULL, 0,
1946 bd.data,
1947 bd.data_size))
1948 {
1949 GDS_NEIGHBOURS_handle_reply (pi,
1950 &bd,
1951 query_hash,
1952 0, NULL /* get path */);
1953 }
1954 else
1955 {
1956 GNUNET_STATISTICS_update (GDS_stats,
1957 "# FIND PEER requests ignored due to Bloomfilter",
1958 1,
1959 GNUNET_NO);
1960 }
1961 }
1962 else
1963 {
1964 GNUNET_STATISTICS_update (GDS_stats,
1965 "# FIND PEER requests ignored due to lack of HELLO",
1966 1,
1967 GNUNET_NO);
1968 }
1969
1970 /* then, also consider sending a random HELLO from the closest bucket */
1971 /* FIXME: How can this be true? Shouldnt we just do find_bucket() ? */
1972 if (0 ==
1973 GNUNET_memcmp (&my_identity_hash,
1974 query_hash))
1975 bucket_idx = closest_bucket - 1;
1976 else
1977 bucket_idx = GNUNET_MIN ((int) closest_bucket - 1,
1978 find_bucket (query_hash));
1979 if (bucket_idx < 0)
1980 return;
1981 bucket = &k_buckets[bucket_idx];
1982 if (bucket->peers_size == 0)
1983 return;
1984 choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1985 bucket->peers_size);
1986 peer = bucket->head;
1987 while (choice > 0)
1988 {
1989 GNUNET_assert (NULL != peer);
1990 peer = peer->next;
1991 choice--;
1992 }
1993 choice = bucket->peers_size;
1994
1995 {
1996 const struct GNUNET_HELLO_Message *hello;
1997 size_t hello_size;
1998
1999 do
2000 {
2001 peer = peer->next;
2002 if (0 == choice--)
2003 return; /* no non-masked peer available */
2004 if (NULL == peer)
2005 peer = bucket->head;
2006 hello = GDS_HELLO_get (peer->id);
2007 } while ( (NULL == hello) ||
2008 (GNUNET_BLOCK_REPLY_OK_MORE !=
2009 GNUNET_BLOCK_check_reply (
2010 GDS_block_context,
2011 GNUNET_BLOCK_TYPE_DHT_HELLO,
2012 bg,
2013 &peer->phash,
2014 NULL, 0, /* xquery */
2015 hello,
2016 (hello_size = GNUNET_HELLO_size (hello)))));
2017 bd.expiration_time = GNUNET_TIME_relative_to_absolute (
2018 GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION);
2019 bd.key = peer->phash;
2020 bd.data = hello;
2021 bd.data_size = hello_size;
2022 GDS_NEIGHBOURS_handle_reply (pi,
2023 &bd,
2024 query_hash,
2025 0, NULL /* get path */);
2026 }
2027}
2028
2029
2030/**
2031 * Handle an exact result from local datacache for a GET operation.
2032 *
2033 * @param cls the `struct PeerInfo` for which this is a reply
2034 * @param bd details about the block we found locally
2035 */
2036static void
2037handle_local_result (void *cls,
2038 const struct GDS_DATACACHE_BlockData *bd)
2039{
2040 struct PeerInfo *peer = cls;
2041
2042 GDS_NEIGHBOURS_handle_reply (peer,
2043 bd,
2044 &bd->key,
2045 0, NULL /* get path */);
2046}
2047
2048
2049/**
2050 * Check validity of p2p get request.
2051 *
2052 * @param cls closure with the `struct PeerInfo` of the sender
2053 * @param get the message
2054 * @return #GNUNET_OK if the message is well-formed
2055 */
2056static enum GNUNET_GenericReturnValue
2057check_dht_p2p_get (void *cls,
2058 const struct PeerGetMessage *get)
2059{
2060 uint16_t msize = ntohs (get->header.size);
2061 uint32_t xquery_size = ntohl (get->xquery_size);
2062
2063 (void) cls;
2064 if (msize < sizeof(*get) + xquery_size)
2065 {
2066 GNUNET_break_op (0);
2067 return GNUNET_SYSERR;
2068 }
2069 return GNUNET_OK;
2070}
2071
2072
2073/**
2074 * Core handler for p2p get requests.
2075 *
2076 * @param cls closure with the `struct PeerInfo` of the sender
2077 * @param get the message
2078 */
2079static void
2080handle_dht_p2p_get (void *cls,
2081 const struct PeerGetMessage *get)
2082{
2083 struct PeerInfo *peer = cls;
2084 uint16_t msize = ntohs (get->header.size);
2085 uint32_t xquery_size = ntohl (get->xquery_size);
2086 uint32_t hop_count = ntohl (get->hop_count);
2087 size_t reply_bf_size = msize - (sizeof(*get) + xquery_size);
2088 enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2089 enum GNUNET_DHT_RouteOption options = (enum GNUNET_DHT_RouteOption) ntohl (
2090 get->options);
2091 enum GNUNET_BLOCK_ReplyEvaluationResult eval = GNUNET_BLOCK_REPLY_OK_MORE;
2092 const void *xquery = (const void *) &get[1];
2093
2094 /* parse and validate message */
2095 GNUNET_STATISTICS_update (GDS_stats,
2096 "# P2P GET requests received",
2097 1,
2098 GNUNET_NO);
2099 GNUNET_STATISTICS_update (GDS_stats,
2100 "# P2P GET bytes received",
2101 msize,
2102 GNUNET_NO);
2103 if (GNUNET_NO ==
2104 GNUNET_BLOCK_check_query (GDS_block_context,
2105 type,
2106 &get->key,
2107 xquery,
2108 xquery_size))
2109 {
2110 /* request invalid */
2111 GNUNET_break_op (0);
2112 return;
2113 }
2114
2115 {
2116 struct GNUNET_BLOCK_Group *bg;
2117 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2118
2119 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2120 DHT_BLOOM_SIZE,
2121 GNUNET_CONSTANTS_BLOOMFILTER_K);
2122 GNUNET_break_op (GNUNET_YES ==
2123 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2124 &peer->phash));
2125 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2126 type,
2127 get->bf_mutator,
2128 xquery + xquery_size,
2129 reply_bf_size,
2130 "filter-size",
2131 reply_bf_size,
2132 NULL);
2133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2134 "GET for %s at %s after %u hops\n",
2135 GNUNET_h2s (&get->key),
2136 GNUNET_i2s (&my_identity),
2137 (unsigned int) hop_count);
2138 /* local lookup (this may update the reply_bf) */
2139 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2140 (GDS_am_closest_peer (&get->key,
2141 peer_bf)) )
2142 {
2143 if ((0 != (options & GNUNET_DHT_RO_FIND_PEER)))
2144 {
2145 GNUNET_STATISTICS_update (GDS_stats,
2146 "# P2P FIND PEER requests processed",
2147 1,
2148 GNUNET_NO);
2149 handle_find_peer (peer,
2150 &get->key,
2151 bg);
2152 }
2153 else
2154 {
2155 eval = GDS_DATACACHE_handle_get (&get->key,
2156 type,
2157 xquery,
2158 xquery_size,
2159 bg,
2160 &handle_local_result,
2161 peer);
2162 }
2163 }
2164 else
2165 {
2166 GNUNET_STATISTICS_update (GDS_stats,
2167 "# P2P GET requests ONLY routed",
2168 1,
2169 GNUNET_NO);
2170 }
2171
2172 /* remember request for routing replies */
2173 GDS_ROUTING_add (peer->id,
2174 type,
2175 bg, /* bg now owned by routing, but valid at least until end of this function! */
2176 options,
2177 &get->key,
2178 xquery,
2179 xquery_size);
2180
2181 /* P2P forwarding */
2182 {
2183 bool forwarded = false;
2184 uint32_t desired_replication_level = ntohl (
2185 get->desired_replication_level);
2186
2187 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2188 forwarded = (GNUNET_OK ==
2189 GDS_NEIGHBOURS_handle_get (type,
2190 options,
2191 desired_replication_level,
2192 hop_count,
2193 &get->key,
2194 xquery,
2195 xquery_size,
2196 bg,
2197 peer_bf));
2198 GDS_CLIENTS_process_get (
2199 options
2200 | (forwarded
2201 ? 0
2202 : GNUNET_DHT_RO_LAST_HOP),
2203 type,
2204 hop_count,
2205 desired_replication_level,
2206 0,
2207 NULL,
2208 &get->key);
2209 }
2210 /* clean up; note that 'bg' is owned by routing now! */
2211 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2212 }
2213}
2214
2215
2216/**
2217 * Process a reply, after the @a get_path has been updated.
2218 *
2219 * @param bd block details
2220 * @param query_hash hash of the original query, might not match key in @a bd
2221 * @param get_path_length number of entries in @a get_path
2222 * @param get_path path the reply has taken
2223 */
2224static void
2225process_reply_with_path (const struct GDS_DATACACHE_BlockData *bd,
2226 const struct GNUNET_HashCode *query_hash,
2227 unsigned int get_path_length,
2228 const struct GNUNET_DHT_PathElement *get_path)
2229{
2230 /* forward to local clients */
2231 GDS_CLIENTS_handle_reply (bd,
2232 query_hash,
2233 get_path_length,
2234 get_path);
2235 GDS_CLIENTS_process_get_resp (bd,
2236 get_path,
2237 get_path_length);
2238 if (GNUNET_YES == cache_results)
2239 {
2240 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2241 + bd->put_path_length)];
2242 struct GDS_DATACACHE_BlockData bdx = *bd;
2243
2244 GNUNET_memcpy (xput_path,
2245 bd->put_path,
2246 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
2247 GNUNET_memcpy (&xput_path[bd->put_path_length],
2248 get_path,
2249 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2250 bdx.put_path = xput_path;
2251 bdx.put_path_length += get_path_length;
2252 GDS_DATACACHE_handle_put (&bdx);
2253 }
2254 /* forward to other peers */
2255 GDS_ROUTING_process (bd,
2256 query_hash,
2257 get_path_length,
2258 get_path);
2259}
2260
2261
2262/**
2263 * Check validity of p2p result message.
2264 *
2265 * @param cls closure
2266 * @param message message
2267 * @return #GNUNET_YES if the message is well-formed
2268 */
2269static enum GNUNET_GenericReturnValue
2270check_dht_p2p_result (void *cls,
2271 const struct PeerResultMessage *prm)
2272{
2273 uint32_t get_path_length = ntohl (prm->get_path_length);
2274 uint32_t put_path_length = ntohl (prm->put_path_length);
2275 uint16_t msize = ntohs (prm->header.size);
2276
2277 (void) cls;
2278 if ( (msize <
2279 sizeof(struct PeerResultMessage)
2280 + (get_path_length + put_path_length)
2281 * sizeof(struct GNUNET_DHT_PathElement)) ||
2282 (get_path_length >
2283 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2284 (put_path_length >
2285 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2286 {
2287 GNUNET_break_op (0);
2288 return GNUNET_SYSERR;
2289 }
2290 return GNUNET_OK;
2291}
2292
2293
2294/**
2295 * Core handler for p2p result messages.
2296 *
2297 * @param cls closure
2298 * @param message message
2299 */
2300static void
2301handle_dht_p2p_result (void *cls,
2302 const struct PeerResultMessage *prm)
2303{
2304 struct PeerInfo *peer = cls;
2305 uint16_t msize = ntohs (prm->header.size);
2306 uint32_t get_path_length = ntohl (prm->get_path_length);
2307 struct GDS_DATACACHE_BlockData bd = {
2308 .expiration_time = GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2309 .put_path = (const struct GNUNET_DHT_PathElement *) &prm[1],
2310 .put_path_length = ntohl (prm->put_path_length),
2311 .type = ntohl (prm->type)
2312 };
2313 const struct GNUNET_DHT_PathElement *get_path
2314 = &bd.put_path[bd.put_path_length];
2315
2316 /* parse and validate message */
2317 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2318 {
2319 GNUNET_STATISTICS_update (GDS_stats,
2320 "# Expired results discarded",
2321 1,
2322 GNUNET_NO);
2323 return;
2324 }
2325 get_path = &bd.put_path[bd.put_path_length];
2326 bd.data = (const void *) &get_path[get_path_length];
2327 bd.data_size = msize - (sizeof(struct PeerResultMessage)
2328 + (get_path_length + bd.put_path_length)
2329 * sizeof(struct GNUNET_DHT_PathElement));
2330 GNUNET_STATISTICS_update (GDS_stats,
2331 "# P2P RESULTS received",
2332 1,
2333 GNUNET_NO);
2334 GNUNET_STATISTICS_update (GDS_stats,
2335 "# P2P RESULT bytes received",
2336 msize,
2337 GNUNET_NO);
2338 {
2339 enum GNUNET_GenericReturnValue ret;
2340 const struct GNUNET_HashCode *pquery;
2341
2342 ret = GNUNET_BLOCK_get_key (GDS_block_context,
2343 bd.type,
2344 bd.data,
2345 bd.data_size,
2346 &bd.key);
2347 if (GNUNET_NO == ret)
2348 {
2349 GNUNET_break_op (0);
2350 return;
2351 }
2352 pquery = (GNUNET_OK == ret) ? &bd.key : &prm->key;
2353 if (GNUNET_OK !=
2354 GNUNET_BLOCK_check_block (GDS_block_context,
2355 bd.type,
2356 pquery,
2357 bd.data,
2358 bd.data_size))
2359 {
2360 GNUNET_break_op (0);
2361 return;
2362 }
2363 }
2364
2365 /* if we got a HELLO, consider it for our own routing table */
2366 if (GNUNET_BLOCK_TYPE_DHT_HELLO == bd.type)
2367 {
2368 const struct GNUNET_MessageHeader *h = bd.data;
2369 struct GNUNET_PeerIdentity pid;
2370
2371 /* Should be a HELLO, validate and consider using it! */
2372 if (bd.data_size < sizeof(struct GNUNET_HELLO_Message))
2373 {
2374 GNUNET_break (0);
2375 return;
2376 }
2377 if (bd.data_size != ntohs (h->size))
2378 {
2379 GNUNET_break (0);
2380 return;
2381 }
2382 if (GNUNET_OK !=
2383 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h,
2384 &pid))
2385 {
2386 GNUNET_break_op (0);
2387 return;
2388 }
2389 if ( (GNUNET_YES != disable_try_connect) &&
2390 (0 != GNUNET_memcmp (&my_identity,
2391 &pid)) )
2392 try_connect (&pid,
2393 h);
2394 }
2395
2396 /* First, check if 'peer' is already on the path, and if
2397 so, truncate it instead of expanding. */
2398 for (unsigned int i = 0; i <= get_path_length; i++)
2399 if (0 == GNUNET_memcmp (&get_path[i].pred,
2400 peer->id))
2401 {
2402 process_reply_with_path (&bd,
2403 &prm->key,
2404 i, get_path);
2405 return;
2406 }
2407
2408 /* Need to append 'peer' to 'get_path' (normal case) */
2409 {
2410 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2411
2412 GNUNET_memcpy (xget_path,
2413 get_path,
2414 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2415 xget_path[get_path_length].pred = *peer->id;
2416 memset (&xget_path[get_path_length].sig,
2417 0,
2418 sizeof (xget_path[get_path_length].sig));
2419 process_reply_with_path (&bd,
2420 &prm->key,
2421 get_path_length + 1, xget_path);
2422 }
2423}
2424
2425
2426enum GNUNET_GenericReturnValue
2427GDS_NEIGHBOURS_init ()
2428{
2429 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2430 GNUNET_MQ_hd_var_size (dht_p2p_get,
2431 GNUNET_MESSAGE_TYPE_DHT_P2P_GET,
2432 struct PeerGetMessage,
2433 NULL),
2434 GNUNET_MQ_hd_var_size (dht_p2p_put,
2435 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT,
2436 struct PeerPutMessage,
2437 NULL),
2438 GNUNET_MQ_hd_var_size (dht_p2p_result,
2439 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2440 struct PeerResultMessage,
2441 NULL),
2442 GNUNET_MQ_handler_end ()
2443 };
2444 unsigned long long temp_config_num;
2445
2446 disable_try_connect
2447 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2448 "DHT",
2449 "DISABLE_TRY_CONNECT");
2450 if (GNUNET_OK ==
2451 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
2452 "DHT",
2453 "bucket_size",
2454 &temp_config_num))
2455 bucket_size = (unsigned int) temp_config_num;
2456 cache_results
2457 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2458 "DHT",
2459 "CACHE_RESULTS");
2460 {
2461 char *keyfile;
2462
2463 if (GNUNET_OK !=
2464 GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
2465 "PEER",
2466 "PRIVATE_KEY",
2467 &keyfile))
2468 {
2469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2470 "Core service is lacking HOSTKEY configuration setting. Exiting.\n");
2471 return GNUNET_SYSERR;
2472 }
2473 if (GNUNET_SYSERR ==
2474 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
2475 GNUNET_YES,
2476 &my_private_key))
2477 {
2478 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2479 "Failed to setup peer's private key\n");
2480 GNUNET_free (keyfile);
2481 return GNUNET_SYSERR;
2482 }
2483 GNUNET_free (keyfile);
2484 }
2485
2486 ats_ch = GNUNET_ATS_connectivity_init (GDS_cfg);
2487 core_api = GNUNET_CORE_connect (GDS_cfg,
2488 NULL,
2489 &core_init,
2490 &handle_core_connect,
2491 &handle_core_disconnect,
2492 core_handlers);
2493 if (NULL == core_api)
2494 return GNUNET_SYSERR;
2495 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2496 GNUNET_YES);
2497 all_desired_peers = GNUNET_CONTAINER_multipeermap_create (256,
2498 GNUNET_NO);
2499 return GNUNET_OK;
2500}
2501
2502
2503void
2504GDS_NEIGHBOURS_done ()
2505{
2506 if (NULL == core_api)
2507 return;
2508 GNUNET_CORE_disconnect (core_api);
2509 core_api = NULL;
2510 GNUNET_assert (0 ==
2511 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2512 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2513 all_connected_peers = NULL;
2514 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
2515 &free_connect_info,
2516 NULL);
2517 GNUNET_CONTAINER_multipeermap_destroy (all_desired_peers);
2518 all_desired_peers = NULL;
2519 GNUNET_ATS_connectivity_done (ats_ch);
2520 ats_ch = NULL;
2521 GNUNET_assert (NULL == find_peer_task);
2522}
2523
2524
2525struct GNUNET_PeerIdentity *
2526GDS_NEIGHBOURS_get_id ()
2527{
2528 return &my_identity;
2529}
2530
2531
2532/* end of gnunet-service-dht_neighbours.c */
diff --git a/src/dht/gnunet-service-dht_neighbours.h b/src/dht/gnunet-service-dht_neighbours.h
deleted file mode 100644
index 35bbb125d..000000000
--- a/src/dht/gnunet-service-dht_neighbours.h
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2022 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 dht/gnunet-service-dht_neighbours.h
23 * @brief GNUnet DHT routing code
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#ifndef GNUNET_SERVICE_DHT_NEIGHBOURS_H
28#define GNUNET_SERVICE_DHT_NEIGHBOURS_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_block_lib.h"
32#include "gnunet_dht_service.h"
33#include "gnunet-service-dht_datacache.h"
34
35/**
36 * Hash of the identity of this peer.
37 */
38extern struct GNUNET_HashCode my_identity_hash;
39
40
41struct PeerInfo;
42
43/**
44 * Lookup peer by peer's identity.
45 *
46 * @param target peer to look up
47 * @return NULL if we are not connected to @a target
48 */
49struct PeerInfo *
50GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target);
51
52
53/**
54 * Perform a PUT operation. Forwards the given request to other
55 * peers. Does not store the data locally. Does not give the
56 * data to local clients. May do nothing if this is the only
57 * peer in the network (or if we are the closest peer in the
58 * network).
59 *
60 * @param bd data about the block
61 * @param options routing options
62 * @param desired_replication_level desired replication level
63 * @param hop_count how many hops has this message traversed so far
64 * @param bf Bloom filter of peers this PUT has already traversed
65 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
66 */
67enum GNUNET_GenericReturnValue
68GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
69 enum GNUNET_DHT_RouteOption options,
70 uint32_t desired_replication_level,
71 uint32_t hop_count,
72 struct GNUNET_CONTAINER_BloomFilter *bf);
73
74
75/**
76 * Perform a GET operation. Forwards the given request to other
77 * peers. Does not lookup the key locally. May do nothing if this is
78 * the only peer in the network (or if we are the closest peer in the
79 * network).
80 *
81 * @param type type of the block
82 * @param options routing options
83 * @param desired_replication_level desired replication count
84 * @param hop_count how many hops did this request traverse so far?
85 * @param key key for the content
86 * @param xquery extended query
87 * @param xquery_size number of bytes in @a xquery
88 * @param bg block group to filter replies
89 * @param peer_bf filter for peers not to select (again, updated)
90 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
91 */
92enum GNUNET_GenericReturnValue
93GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
94 enum GNUNET_DHT_RouteOption options,
95 uint32_t desired_replication_level,
96 uint32_t hop_count,
97 const struct GNUNET_HashCode *key,
98 const void *xquery,
99 size_t xquery_size,
100 struct GNUNET_BLOCK_Group *bg,
101 struct GNUNET_CONTAINER_BloomFilter *peer_bf);
102
103
104/**
105 * Handle a reply (route to origin). Only forwards the reply back to
106 * other peers waiting for it. Does not do local caching or
107 * forwarding to local clients.
108 *
109 * @param pi neighbour that should receive the block
110 * @param type type of the block
111 * @param bd details about the reply
112 * @param query_hash query that was used for the request
113 * @param get_path_length number of entries in put_path
114 * @param get_path peers this reply has traversed so far (if tracked)
115 */
116void
117GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
118 const struct GDS_DATACACHE_BlockData *bd,
119 const struct GNUNET_HashCode *query_hash,
120 unsigned int get_path_length,
121 const struct GNUNET_DHT_PathElement *get_path);
122
123
124/**
125 * Check whether my identity is closer than any known peers. If a
126 * non-null bloomfilter is given, check if this is the closest peer
127 * that hasn't already been routed to.
128 *
129 * @param key hash code to check closeness to
130 * @param bloom bloomfilter, exclude these entries from the decision
131 * @return #GNUNET_YES if node location is closest,
132 * #GNUNET_NO otherwise.
133 */
134enum GNUNET_GenericReturnValue
135GDS_am_closest_peer (const struct GNUNET_HashCode *key,
136 const struct GNUNET_CONTAINER_BloomFilter *bloom);
137
138
139/**
140 * Initialize neighbours subsystem.
141 *
142 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
143 */
144enum GNUNET_GenericReturnValue
145GDS_NEIGHBOURS_init (void);
146
147
148/**
149 * Shutdown neighbours subsystem.
150 */
151void
152GDS_NEIGHBOURS_done (void);
153
154
155/**
156 * Get the ID of the local node.
157 *
158 * @return identity of the local node
159 */
160struct GNUNET_PeerIdentity *
161GDS_NEIGHBOURS_get_id (void);
162
163
164#endif
diff --git a/src/dht/gnunet-service-dht_nse.c b/src/dht/gnunet-service-dht_nse.c
deleted file mode 100644
index 58f18816a..000000000
--- a/src/dht/gnunet-service-dht_nse.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 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 dht/gnunet-service-dht_nse.c
23 * @brief GNUnet DHT integration with NSE
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_nse_service.h"
28#include "gnunet-service-dht.h"
29#include "gnunet-service-dht_nse.h"
30
31/**
32 * log of the current network size estimate, used as the point where
33 * we switch between random and deterministic routing. Default
34 * value of 4.0 is used if NSE module is not available (i.e. not
35 * configured).
36 */
37static double log_of_network_size_estimate = 4.0;
38
39/**
40 * Network size estimation handle.
41 */
42static struct GNUNET_NSE_Handle *nse;
43
44
45/**
46 * Callback that is called when network size estimate is updated.
47 *
48 * @param cls closure
49 * @param timestamp time when the estimate was received from the server (or created by the server)
50 * @param logestimate the log(Base 2) value of the current network size estimate
51 * @param std_dev standard deviation for the estimate
52 *
53 */
54static void
55update_network_size_estimate (void *cls,
56 struct GNUNET_TIME_Absolute timestamp,
57 double logestimate,
58 double std_dev)
59{
60 GNUNET_STATISTICS_update (GDS_stats,
61 "# Network size estimates received",
62 1, GNUNET_NO);
63 /* do not allow estimates < 0.5 */
64 log_of_network_size_estimate = GNUNET_MAX (0.5, logestimate);
65}
66
67
68/**
69 * Return the log of the current network size estimate.
70 *
71 * @return log of NSE
72 */
73double
74GDS_NSE_get ()
75{
76 return log_of_network_size_estimate;
77}
78
79
80/**
81 * Initialize NSE subsystem.
82 */
83void
84GDS_NSE_init ()
85{
86 unsigned long long hops;
87
88 if ( (GNUNET_YES ==
89 GNUNET_CONFIGURATION_have_value (GDS_cfg,
90 "dht",
91 "FORCE_NSE")) &&
92 (GNUNET_OK ==
93 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
94 "dht",
95 "FORCE_NSE",
96 &hops)) )
97 {
98 log_of_network_size_estimate = (double) hops;
99 return;
100 }
101 nse = GNUNET_NSE_connect (GDS_cfg,
102 &update_network_size_estimate,
103 NULL);
104}
105
106
107/**
108 * Shutdown NSE subsystem.
109 */
110void
111GDS_NSE_done ()
112{
113 if (NULL != nse)
114 {
115 GNUNET_NSE_disconnect (nse);
116 nse = NULL;
117 }
118}
119
120
121/* end of gnunet-service-dht_nse.c */
diff --git a/src/dht/gnunet-service-dht_nse.h b/src/dht/gnunet-service-dht_nse.h
deleted file mode 100644
index e99389e74..000000000
--- a/src/dht/gnunet-service-dht_nse.h
+++ /dev/null
@@ -1,52 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify 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 dht/gnunet-service-dht_nse.h
23 * @brief GNUnet DHT integration with NSE
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_DHT_NSE_H
27#define GNUNET_SERVICE_DHT_NSE_H
28
29
30/**
31 * Return the log of the current network size estimate.
32 *
33 * @return log of NSE
34 */
35double
36GDS_NSE_get (void);
37
38
39/**
40 * Initialize NSE subsystem.
41 */
42void
43GDS_NSE_init (void);
44
45
46/**
47 * Shutdown NSE subsystem.
48 */
49void
50GDS_NSE_done (void);
51
52#endif
diff --git a/src/dht/gnunet-service-dht_routing.c b/src/dht/gnunet-service-dht_routing.c
deleted file mode 100644
index e7b5c3571..000000000
--- a/src/dht/gnunet-service-dht_routing.c
+++ /dev/null
@@ -1,419 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2022 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 dht/gnunet-service-dht_routing.c
23 * @brief GNUnet DHT tracking of requests for routing replies
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet-service-dht_neighbours.h"
28#include "gnunet-service-dht_routing.h"
29#include "gnunet-service-dht.h"
30
31
32/**
33 * Number of requests we track at most (for routing replies).
34 * TODO: make configurable!
35 */
36#define DHT_MAX_RECENT (1024 * 128)
37
38
39/**
40 * Information we keep about all recent GET requests
41 * so that we can route replies.
42 */
43struct RecentRequest
44{
45 /**
46 * The peer this request was received from.
47 */
48 struct GNUNET_PeerIdentity peer;
49
50 /**
51 * Key of this request.
52 */
53 struct GNUNET_HashCode key;
54
55 /**
56 * Position of this node in the min heap.
57 */
58 struct GNUNET_CONTAINER_HeapNode *heap_node;
59
60 /**
61 * Block group for filtering replies.
62 */
63 struct GNUNET_BLOCK_Group *bg;
64
65 /**
66 * extended query (see gnunet_block_lib.h). Allocated at the
67 * end of this struct.
68 */
69 const void *xquery;
70
71 /**
72 * Number of bytes in xquery.
73 */
74 size_t xquery_size;
75
76 /**
77 * Type of the requested block.
78 */
79 enum GNUNET_BLOCK_Type type;
80
81 /**
82 * Request options.
83 */
84 enum GNUNET_DHT_RouteOption options;
85};
86
87
88/**
89 * Recent requests by time inserted.
90 */
91static struct GNUNET_CONTAINER_Heap *recent_heap;
92
93/**
94 * Recently seen requests by key.
95 */
96static struct GNUNET_CONTAINER_MultiHashMap *recent_map;
97
98
99/**
100 * Closure for the process() function.
101 */
102struct ProcessContext
103{
104 /**
105 * Block data.
106 */
107 const struct GDS_DATACACHE_BlockData *bd;
108
109 /**
110 * Path of the reply.
111 */
112 const struct GNUNET_DHT_PathElement *get_path;
113
114 /**
115 * Number of entries in @e get_path.
116 */
117 unsigned int get_path_length;
118
119};
120
121
122/**
123 * Forward the result to the given peer if it matches the request.
124 *
125 * @param cls the `struct ProcessContext` with the result
126 * @param query_hash the hash from the original query
127 * @param value the `struct RecentRequest` with the request
128 * @return #GNUNET_OK (continue to iterate)
129 */
130static enum GNUNET_GenericReturnValue
131process (void *cls,
132 const struct GNUNET_HashCode *query_hash,
133 void *value)
134{
135 struct ProcessContext *pc = cls;
136 struct RecentRequest *rr = value;
137 enum GNUNET_BLOCK_ReplyEvaluationResult eval;
138 unsigned int get_path_length;
139 struct GDS_DATACACHE_BlockData bdx = *pc->bd;
140
141 if ( (rr->type != GNUNET_BLOCK_TYPE_ANY) &&
142 (rr->type != pc->bd->type) )
143 return GNUNET_OK; /* type mismatch */
144 if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE))
145 {
146 get_path_length = pc->get_path_length;
147 }
148 else
149 {
150 get_path_length = 0;
151 bdx.put_path_length = 0;
152 bdx.put_path = NULL;
153 }
154 if ( (0 == (rr->options & GNUNET_DHT_RO_FIND_PEER)) &&
155 (0 != GNUNET_memcmp (query_hash,
156 &bdx.key)) )
157 {
158 GNUNET_STATISTICS_update (GDS_stats,
159 "# Inexact matches discarded in exact search",
160 1,
161 GNUNET_NO);
162 return GNUNET_OK; /* exact search, but inexact match */
163 }
164 eval = GNUNET_BLOCK_check_reply (GDS_block_context,
165 bdx.type,
166 rr->bg,
167 &bdx.key,
168 rr->xquery,
169 rr->xquery_size,
170 bdx.data,
171 bdx.data_size);
172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173 "Result for %s of type %d was evaluated as %d\n",
174 GNUNET_h2s (&bdx.key),
175 bdx.type,
176 eval);
177 switch (eval)
178 {
179 case GNUNET_BLOCK_REPLY_OK_MORE:
180 case GNUNET_BLOCK_REPLY_OK_LAST:
181 case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED:
182 {
183 struct PeerInfo *pi;
184
185 GNUNET_STATISTICS_update (GDS_stats,
186 "# Good REPLIES matched against routing table",
187 1,
188 GNUNET_NO);
189 pi = GDS_NEIGHBOURS_lookup_peer (&rr->peer);
190 if (NULL == pi)
191 {
192 /* peer disconnected in the meantime, drop reply */
193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194 "No matching peer for reply for key %s\n",
195 GNUNET_h2s (query_hash));
196 return GNUNET_OK;
197 }
198 GDS_NEIGHBOURS_handle_reply (pi,
199 &bdx,
200 query_hash,
201 get_path_length, pc->get_path);
202 }
203 break;
204 case GNUNET_BLOCK_REPLY_OK_DUPLICATE:
205 GNUNET_STATISTICS_update (GDS_stats,
206 "# Duplicate REPLIES matched against routing table",
207 1,
208 GNUNET_NO);
209 return GNUNET_OK;
210 case GNUNET_BLOCK_REPLY_INVALID:
211 GNUNET_break (0);
212 GNUNET_STATISTICS_update (GDS_stats,
213 "# Invalid REPLIES matched against routing table",
214 1,
215 GNUNET_NO);
216 return GNUNET_OK;
217 case GNUNET_BLOCK_REPLY_IRRELEVANT:
218 GNUNET_STATISTICS_update (GDS_stats,
219 "# Irrelevant REPLIES matched against routing table",
220 1,
221 GNUNET_NO);
222 return GNUNET_OK;
223 default:
224 GNUNET_break (0);
225 return GNUNET_OK;
226 }
227 return GNUNET_OK;
228}
229
230
231/**
232 * Handle a reply (route to origin). Only forwards the reply back to
233 * other peers waiting for it. Does not do local caching or
234 * forwarding to local clients. Essentially calls
235 * GDS_NEIGHBOURS_handle_reply() for all peers that sent us a matching
236 * request recently.
237 *
238 * @param bd block details
239 * @param query_hash query used in the inquiry
240 * @param get_path_length number of entries in @a get_path
241 * @param get_path peers this reply has traversed so far (if tracked)
242 */
243void
244GDS_ROUTING_process (const struct GDS_DATACACHE_BlockData *bd,
245 const struct GNUNET_HashCode *query_hash,
246 unsigned int get_path_length,
247 const struct GNUNET_DHT_PathElement *get_path)
248{
249 struct ProcessContext pc = {
250 .bd = bd,
251 .get_path = get_path,
252 .get_path_length = get_path_length
253 };
254
255 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
256 query_hash,
257 &process,
258 &pc);
259}
260
261
262/**
263 * Remove the oldest entry from the DHT routing table. Must only
264 * be called if it is known that there is at least one entry
265 * in the heap and hashmap.
266 */
267static void
268expire_oldest_entry (void)
269{
270 struct RecentRequest *recent_req;
271
272 GNUNET_STATISTICS_update (GDS_stats,
273 "# Old entries removed from routing table",
274 1,
275 GNUNET_NO);
276 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
277 GNUNET_assert (recent_req != NULL);
278 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
279 GNUNET_BLOCK_group_destroy (recent_req->bg);
280 GNUNET_assert (GNUNET_YES ==
281 GNUNET_CONTAINER_multihashmap_remove (recent_map,
282 &recent_req->key,
283 recent_req));
284 GNUNET_free (recent_req);
285}
286
287
288/**
289 * Try to combine multiple recent requests for the same value
290 * (if they come from the same peer).
291 *
292 * @param cls the new `struct RecentRequest` (to discard upon successful combination)
293 * @param key the query
294 * @param value the existing `struct RecentRequest` (to update upon successful combination)
295 * @return #GNUNET_OK (continue to iterate),
296 * #GNUNET_SYSERR if the request was successfully combined
297 */
298static enum GNUNET_GenericReturnValue
299try_combine_recent (void *cls,
300 const struct GNUNET_HashCode *key,
301 void *value)
302{
303 struct RecentRequest *in = cls;
304 struct RecentRequest *rr = value;
305
306 if ( (0 != GNUNET_memcmp (&in->peer,
307 &rr->peer)) ||
308 (in->type != rr->type) ||
309 (in->xquery_size != rr->xquery_size) ||
310 (0 != memcmp (in->xquery,
311 rr->xquery,
312 in->xquery_size) ) )
313 return GNUNET_OK;
314 GNUNET_break (GNUNET_SYSERR !=
315 GNUNET_BLOCK_group_merge (in->bg,
316 rr->bg));
317 rr->bg = in->bg;
318 GNUNET_free (in);
319 return GNUNET_SYSERR;
320}
321
322
323/**
324 * Add a new entry to our routing table.
325 *
326 * @param sender peer that originated the request
327 * @param type type of the block
328 * @param options options for processing
329 * @param key key for the content
330 * @param xquery extended query
331 * @param xquery_size number of bytes in @a xquery
332 * @param reply_bf bloomfilter to filter duplicates
333 * @param reply_bf_mutator mutator for @a reply_bf
334 */
335void
336GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
337 enum GNUNET_BLOCK_Type type,
338 struct GNUNET_BLOCK_Group *bg,
339 enum GNUNET_DHT_RouteOption options,
340 const struct GNUNET_HashCode *key,
341 const void *xquery,
342 size_t xquery_size)
343{
344 struct RecentRequest *recent_req;
345
346 while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT)
347 expire_oldest_entry ();
348 GNUNET_STATISTICS_update (GDS_stats,
349 "# Entries added to routing table",
350 1,
351 GNUNET_NO);
352 recent_req = GNUNET_malloc (sizeof(struct RecentRequest) + xquery_size);
353 recent_req->peer = *sender;
354 recent_req->key = *key;
355 recent_req->bg = bg;
356 recent_req->type = type;
357 recent_req->options = options;
358 recent_req->xquery = &recent_req[1];
359 GNUNET_memcpy (&recent_req[1],
360 xquery,
361 xquery_size);
362 recent_req->xquery_size = xquery_size;
363 if (GNUNET_SYSERR ==
364 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
365 key,
366 &try_combine_recent,
367 recent_req))
368 {
369 GNUNET_STATISTICS_update (GDS_stats,
370 "# DHT requests combined",
371 1,
372 GNUNET_NO);
373 return;
374 }
375 recent_req->heap_node
376 = GNUNET_CONTAINER_heap_insert (
377 recent_heap,
378 recent_req,
379 GNUNET_TIME_absolute_get ().abs_value_us);
380 (void) GNUNET_CONTAINER_multihashmap_put (
381 recent_map,
382 key,
383 recent_req,
384 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
385}
386
387
388/**
389 * Initialize routing subsystem.
390 */
391void
392GDS_ROUTING_init ()
393{
394 recent_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
395 recent_map = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3,
396 GNUNET_NO);
397}
398
399
400/**
401 * Shutdown routing subsystem.
402 */
403void
404GDS_ROUTING_done ()
405{
406 while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0)
407 expire_oldest_entry ();
408 GNUNET_assert (0 ==
409 GNUNET_CONTAINER_heap_get_size (recent_heap));
410 GNUNET_CONTAINER_heap_destroy (recent_heap);
411 recent_heap = NULL;
412 GNUNET_assert (0 ==
413 GNUNET_CONTAINER_multihashmap_size (recent_map));
414 GNUNET_CONTAINER_multihashmap_destroy (recent_map);
415 recent_map = NULL;
416}
417
418
419/* end of gnunet-service-dht_routing.c */
diff --git a/src/dht/gnunet-service-dht_routing.h b/src/dht/gnunet-service-dht_routing.h
deleted file mode 100644
index 1e35f3dc0..000000000
--- a/src/dht/gnunet-service-dht_routing.h
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2022 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 dht/gnunet-service-dht_routing.h
23 * @brief GNUnet DHT tracking of requests for routing replies
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_DHT_ROUTING_H
27#define GNUNET_SERVICE_DHT_ROUTING_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_block_lib.h"
31#include "gnunet_dht_service.h"
32
33
34/**
35 * Handle a reply (route to origin). Only forwards the reply back to
36 * other peers waiting for it. Does not do local caching or
37 * forwarding to local clients. Essentially calls
38 * GDS_NEIGHBOURS_handle_reply() for all peers that sent us a matching
39 * request recently.
40 *
41 * @param bd block details
42 * @param query_hash query used in the inquiry
43 * @param get_path_length number of entries in @a get_path
44 * @param get_path peers this reply has traversed so far (if tracked)
45 */
46void
47GDS_ROUTING_process (const struct GDS_DATACACHE_BlockData *bd,
48 const struct GNUNET_HashCode *query_hash,
49 unsigned int get_path_length,
50 const struct GNUNET_DHT_PathElement *get_path);
51
52
53/**
54 * Add a new entry to our routing table.
55 *
56 * @param sender peer that originated the request
57 * @param type type of the block
58 * @param bg block group to evaluate replies, henceforth owned by routing
59 * @param options options for processing
60 * @param key key for the content
61 * @param xquery extended query
62 * @param xquery_size number of bytes in @a xquery
63 */
64void
65GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
66 enum GNUNET_BLOCK_Type type,
67 struct GNUNET_BLOCK_Group *bg,
68 enum GNUNET_DHT_RouteOption options,
69 const struct GNUNET_HashCode *key,
70 const void *xquery,
71 size_t xquery_size);
72
73
74/**
75 * Initialize routing subsystem.
76 */
77void
78GDS_ROUTING_init (void);
79
80
81/**
82 * Shutdown routing subsystem.
83 */
84void
85GDS_ROUTING_done (void);
86
87#endif
diff --git a/src/dht/gnunet_dht_profiler.c b/src/dht/gnunet_dht_profiler.c
deleted file mode 100644
index bac101bdd..000000000
--- a/src/dht/gnunet_dht_profiler.c
+++ /dev/null
@@ -1,1029 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014, 2018 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 dht/gnunet_dht_profiler.c
23 * @brief Profiler for GNUnet DHT
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "gnunet_dht_service.h"
31#include "gnunet_constants.h"
32
33
34#define MESSAGE(...) \
35 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, __VA_ARGS__)
36
37#define DEBUG(...) \
38 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
39
40/**
41 * Number of peers which should perform a PUT out of 100 peers
42 */
43static unsigned int put_probability = 100;
44
45/**
46 * Configuration
47 */
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50/**
51 * Name of the file with the hosts to run the test over
52 */
53static char *hosts_file;
54
55/**
56 * Context for a peer which actively does DHT PUT/GET
57 */
58struct ActiveContext;
59
60/**
61 * Context to hold data of peer
62 */
63struct Context
64{
65 /**
66 * The testbed peer this context belongs to
67 */
68 struct GNUNET_TESTBED_Peer *peer;
69
70 /**
71 * Testbed operation acting on this peer
72 */
73 struct GNUNET_TESTBED_Operation *op;
74
75 /**
76 * Active context; NULL if this peer is not an active peer
77 */
78 struct ActiveContext *ac;
79};
80
81
82/**
83 * Context for a peer which actively does DHT PUT/GET
84 */
85struct ActiveContext
86{
87 /**
88 * The linked peer context
89 */
90 struct Context *ctx;
91
92 /**
93 * Handler to the DHT service
94 */
95 struct GNUNET_DHT_Handle *dht;
96
97 /**
98 * The active context used for our DHT GET
99 */
100 struct ActiveContext *get_ac;
101
102 /**
103 * The put handle
104 */
105 struct GNUNET_DHT_PutHandle *dht_put;
106
107 /**
108 * The get handle
109 */
110 struct GNUNET_DHT_GetHandle *dht_get;
111
112 /**
113 * The hashes of the values stored via this activity context.
114 * Array of length #num_puts_per_peer.
115 */
116 struct GNUNET_HashCode *hash;
117
118 /**
119 * Delay task
120 */
121 struct GNUNET_SCHEDULER_Task *delay_task;
122
123 /**
124 * How many puts should we still issue?
125 */
126 unsigned int put_count;
127
128 /**
129 * The number of peers currently doing GET on our data
130 */
131 uint16_t nrefs;
132};
133
134
135/**
136 * An array of contexts. The size of this array should be equal to @a num_peers
137 */
138static struct Context *a_ctx;
139
140/**
141 * Array of active peers
142 */
143static struct ActiveContext *a_ac;
144
145/**
146 * The delay between rounds for collecting statistics
147 */
148static struct GNUNET_TIME_Relative delay_stats;
149
150/**
151 * The delay to start puts.
152 */
153static struct GNUNET_TIME_Relative delay_put;
154
155/**
156 * The delay to start puts.
157 */
158static struct GNUNET_TIME_Relative delay_get;
159
160/**
161 * The timeout for GET and PUT
162 */
163static struct GNUNET_TIME_Relative timeout;
164
165/**
166 * Number of peers
167 */
168static unsigned int num_peers;
169
170/**
171 * Number of active peers
172 */
173static unsigned int n_active;
174
175/**
176 * Number of DHT service connections we currently have
177 */
178static unsigned int n_dht;
179
180/**
181 * Number of DHT PUTs made
182 */
183static unsigned long long n_puts;
184
185/**
186 * Number of DHT PUTs to be made per peer.
187 */
188static unsigned int num_puts_per_peer = 1;
189
190/**
191 * Number of DHT PUTs succeeded
192 */
193static unsigned long long n_puts_ok;
194
195/**
196 * Number of DHT GETs made
197 */
198static unsigned int n_gets;
199
200/**
201 * Number of DHT GETs succeeded
202 */
203static unsigned int n_gets_ok;
204
205/**
206 * Number of DHT GETs succeeded
207 */
208static unsigned int n_gets_fail;
209
210/**
211 * Replication degree
212 */
213static unsigned int replication;
214
215/**
216 * Testbed Operation (to get stats).
217 */
218static struct GNUNET_TESTBED_Operation *bandwidth_stats_op;
219
220/**
221 * Testbed peer handles.
222 */
223static struct GNUNET_TESTBED_Peer **testbed_handles;
224
225/**
226 * Total number of messages sent by peer.
227 */
228static uint64_t outgoing_bandwidth;
229
230/**
231 * Total number of messages received by peer.
232 */
233static uint64_t incoming_bandwidth;
234
235/**
236 * Average number of hops taken to do put.
237 */
238static double average_put_path_length;
239
240/**
241 * Average number of hops taken to do get.
242 */
243static double average_get_path_length;
244
245/**
246 * Total put path length across all peers.
247 */
248static unsigned int total_put_path_length;
249
250/**
251 * Total get path length across all peers.
252 */
253static unsigned int total_get_path_length;
254
255/**
256 * Counter to keep track of peers added to peer_context lists.
257 */
258static int peers_started = 0;
259
260/**
261 * Should we do a PUT (mode = 0) or GET (mode = 1);
262 */
263static enum
264{
265 MODE_PUT = 0,
266
267 MODE_GET = 1
268} mode;
269
270
271/**
272 * Are we shutting down
273 */
274static int in_shutdown = 0;
275
276
277/**
278 * Connect to DHT services of active peers
279 */
280static void
281start_profiling (void);
282
283
284/**
285 * Shutdown task. Cleanup all resources and operations.
286 *
287 * @param cls NULL
288 */
289static void
290do_shutdown (void *cls)
291{
292 struct ActiveContext *ac;
293
294 in_shutdown = GNUNET_YES;
295 if (NULL != a_ctx)
296 {
297 for (unsigned int cnt = 0; cnt < num_peers; cnt++)
298 {
299 /* Cleanup active context if this peer is an active peer */
300 ac = a_ctx[cnt].ac;
301 if (NULL != ac)
302 {
303 if (NULL != ac->delay_task)
304 GNUNET_SCHEDULER_cancel (ac->delay_task);
305 if (NULL != ac->hash)
306 free (ac->hash);
307 if (NULL != ac->dht_put)
308 GNUNET_DHT_put_cancel (ac->dht_put);
309 if (NULL != ac->dht_get)
310 GNUNET_DHT_get_stop (ac->dht_get);
311 }
312 /* Cleanup testbed operation handle at the last as this operation may
313 contain service connection to DHT */
314 if (NULL != a_ctx[cnt].op)
315 GNUNET_TESTBED_operation_done (a_ctx[cnt].op);
316 }
317 GNUNET_free (a_ctx);
318 a_ctx = NULL;
319 }
320 // FIXME: Should we collect stats only for put/get not for other messages.
321 if (NULL != bandwidth_stats_op)
322 {
323 GNUNET_TESTBED_operation_done (bandwidth_stats_op);
324 bandwidth_stats_op = NULL;
325 }
326 GNUNET_free (a_ac);
327}
328
329
330/**
331 * Stats callback. Finish the stats testbed operation and when all stats have
332 * been iterated, shutdown the test.
333 *
334 * @param cls closure
335 * @param op the operation that has been finished
336 * @param emsg error message in case the operation has failed; will be NULL if
337 * operation has executed successfully.
338 */
339static void
340bandwidth_stats_cont (void *cls,
341 struct GNUNET_TESTBED_Operation *op,
342 const char *emsg)
343{
344 MESSAGE ("# Outgoing (core) bandwidth: %llu bytes\n",
345 (unsigned long long) outgoing_bandwidth);
346 MESSAGE ("# Incoming (core) bandwidth: %llu bytes\n",
347 (unsigned long long) incoming_bandwidth);
348 fprintf (stderr,
349 "Benchmark done. Collect data via gnunet-statistics, then press ENTER to exit.\n");
350 (void) getchar ();
351 GNUNET_SCHEDULER_shutdown ();
352}
353
354
355/**
356 * Process statistic values.
357 *
358 * @param cls closure
359 * @param peer the peer the statistic belong to
360 * @param subsystem name of subsystem that created the statistic
361 * @param name the name of the datum
362 * @param value the current value
363 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
364 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
365 */
366static int
367bandwidth_stats_iterator (void *cls,
368 const struct GNUNET_TESTBED_Peer *peer,
369 const char *subsystem,
370 const char *name,
371 uint64_t value,
372 int is_persistent)
373{
374 static const char *s_sent = "# bytes encrypted";
375 static const char *s_recv = "# bytes decrypted";
376
377 if (0 == strncmp (s_sent, name, strlen (s_sent)))
378 outgoing_bandwidth = outgoing_bandwidth + value;
379 else if (0 == strncmp (s_recv, name, strlen (s_recv)))
380 incoming_bandwidth = incoming_bandwidth + value;
381 return GNUNET_OK;
382}
383
384
385static void
386summarize ()
387{
388 MESSAGE ("# PUTS started: %llu\n",
389 n_puts);
390 MESSAGE ("# PUTS succeeded: %llu\n",
391 n_puts_ok);
392 MESSAGE ("# GETS made: %u\n",
393 n_gets);
394 MESSAGE ("# GETS succeeded: %u\n",
395 n_gets_ok);
396 MESSAGE ("# GETS failed: %u\n",
397 n_gets_fail);
398 MESSAGE ("# average_put_path_length: %f\n",
399 average_put_path_length);
400 MESSAGE ("# average_get_path_length: %f\n",
401 average_get_path_length);
402
403 if (NULL == testbed_handles)
404 {
405 MESSAGE ("No peers found\n");
406 return;
407 }
408 /* Collect Stats*/
409 bandwidth_stats_op = GNUNET_TESTBED_get_statistics (n_active,
410 testbed_handles,
411 "core",
412 NULL,
413 &bandwidth_stats_iterator,
414 &bandwidth_stats_cont,
415 NULL);
416}
417
418
419/**
420 * Task to cancel DHT GET.
421 *
422 * @param cls NULL
423 */
424static void
425cancel_get (void *cls)
426{
427 struct ActiveContext *ac = cls;
428 struct Context *ctx = ac->ctx;
429
430 ac->delay_task = NULL;
431 GNUNET_assert (NULL != ac->dht_get);
432 GNUNET_DHT_get_stop (ac->dht_get);
433 ac->dht_get = NULL;
434 n_gets_fail++;
435 GNUNET_assert (NULL != ctx->op);
436 GNUNET_TESTBED_operation_done (ctx->op);
437 ctx->op = NULL;
438
439 /* If profiling is complete, summarize */
440 if (n_active == n_gets_fail + n_gets_ok)
441 {
442 average_put_path_length = (double) total_put_path_length
443 / (double) n_active;
444 average_get_path_length = (double) total_get_path_length
445 / (double ) n_gets_ok;
446 summarize ();
447 }
448}
449
450
451/**
452 * Iterator called on each result obtained for a DHT
453 * operation that expects a reply
454 *
455 * @param cls closure
456 * @param exp when will this value expire
457 * @param key key of the result
458 * @param get_path peers on reply path (or NULL if not recorded)
459 * [0] = datastore's first neighbor, [length - 1] = local peer
460 * @param get_path_length number of entries in @a get_path
461 * @param put_path peers on the PUT path (or NULL if not recorded)
462 * [0] = origin, [length - 1] = datastore
463 * @param put_path_length number of entries in @a put_path
464 * @param type type of the result
465 * @param size number of bytes in @a data
466 * @param data pointer to the result data
467 */
468static void
469get_iter (void *cls,
470 struct GNUNET_TIME_Absolute exp,
471 const struct GNUNET_HashCode *key,
472 const struct GNUNET_DHT_PathElement *get_path,
473 unsigned int get_path_length,
474 const struct GNUNET_DHT_PathElement *put_path,
475 unsigned int put_path_length,
476 enum GNUNET_BLOCK_Type type,
477 size_t size, const void *data)
478{
479 struct ActiveContext *ac = cls;
480 struct ActiveContext *get_ac = ac->get_ac;
481 struct Context *ctx = ac->ctx;
482
483 /* we found the data we are looking for */
484 DEBUG ("We found a GET request; %u remaining\n",
485 n_gets - (n_gets_fail + n_gets_ok)); // FIXME: It always prints 1.
486 n_gets_ok++;
487 get_ac->nrefs--;
488 GNUNET_DHT_get_stop (ac->dht_get);
489 ac->dht_get = NULL;
490 if (ac->delay_task != NULL)
491 GNUNET_SCHEDULER_cancel (ac->delay_task);
492 ac->delay_task = NULL;
493 GNUNET_assert (NULL != ctx->op);
494 GNUNET_TESTBED_operation_done (ctx->op);
495 ctx->op = NULL;
496
497 total_put_path_length = total_put_path_length + (double) put_path_length;
498 total_get_path_length = total_get_path_length + (double) get_path_length;
499 DEBUG ("total_put_path_length = %u,put_path \n",
500 total_put_path_length);
501 /* Summarize if profiling is complete */
502 if (n_active == n_gets_fail + n_gets_ok)
503 {
504 average_put_path_length = (double) total_put_path_length
505 / (double) n_active;
506 average_get_path_length = (double) total_get_path_length
507 / (double ) n_gets_ok;
508 summarize ();
509 }
510}
511
512
513/**
514 * Task to do DHT GETs
515 *
516 * @param cls the active context
517 */
518static void
519delayed_get (void *cls)
520{
521 struct ActiveContext *ac = cls;
522 struct ActiveContext *get_ac;
523 unsigned int r;
524
525 ac->delay_task = NULL;
526 get_ac = NULL;
527 while (1)
528 {
529 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
530 n_active);
531 get_ac = &a_ac[r];
532 if (NULL != get_ac->hash)
533 break;
534 }
535 get_ac->nrefs++;
536 ac->get_ac = get_ac;
537 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
538 num_puts_per_peer);
539 DEBUG ("GET_REQUEST_START key %s \n",
540 GNUNET_h2s (&get_ac->hash[r]));
541 ac->dht_get = GNUNET_DHT_get_start (ac->dht,
542 GNUNET_BLOCK_TYPE_TEST,
543 &get_ac->hash[r],
544 1, /* replication level */
545 GNUNET_DHT_RO_NONE,
546 NULL,
547 0, /* extended query and size */
548 &get_iter,
549 ac); /* GET iterator and closure */
550 n_gets++;
551
552 /* schedule the timeout task for GET */
553 ac->delay_task = GNUNET_SCHEDULER_add_delayed (timeout,
554 &cancel_get,
555 ac);
556}
557
558
559/**
560 * Task to do DHT PUTs. If the "put_count" hits zero,
561 * we stop the TESTBED operation (connection to DHT)
562 * so that others PUTs have a chance.
563 *
564 * @param cls the active context
565 */
566static void
567delayed_put (void *cls);
568
569
570/**
571 * Conclude individual PUT operation, schedule the
572 * next one.
573 *
574 * @param cls the active context
575 */
576static void
577put_cont (void *cls)
578{
579 struct ActiveContext *ac = cls;
580
581 ac->dht_put = NULL;
582 n_puts_ok++;
583 ac->delay_task = GNUNET_SCHEDULER_add_now (&delayed_put,
584 ac);
585}
586
587
588/**
589 * Task to do DHT PUTs. If the "put_count" hits zero,
590 * we stop the TESTBED operation (connection to DHT)
591 * so that others PUTs have a chance.
592 *
593 * @param cls the active context
594 */
595static void
596delayed_put (void *cls)
597{
598 struct ActiveContext *ac = cls;
599 char block[65536];
600 size_t block_size;
601
602 ac->delay_task = NULL;
603 if (0 == ac->put_count)
604 {
605 struct Context *ctx = ac->ctx;
606 struct GNUNET_TESTBED_Operation *op;
607
608 GNUNET_assert (NULL != ctx);
609 op = ctx->op;
610 ctx->op = NULL;
611 GNUNET_TESTBED_operation_done (op);
612 return;
613 }
614
615
616 /* Generate and DHT PUT some random data */
617 block_size = 16; /* minimum */
618 /* make random payload, reserve 512 - 16 bytes for DHT headers */
619 block_size += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
620 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
621 - 512);
622 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
623 block,
624 block_size);
625 ac->put_count--;
626 GNUNET_CRYPTO_hash (block,
627 block_size,
628 &ac->hash[ac->put_count]);
629 DEBUG ("PUT_REQUEST_START key %s\n",
630 GNUNET_h2s (&ac->hash[ac->put_count]));
631 ac->dht_put = GNUNET_DHT_put (ac->dht,
632 &ac->hash[ac->put_count],
633 replication,
634 GNUNET_DHT_RO_RECORD_ROUTE,
635 GNUNET_BLOCK_TYPE_TEST,
636 block_size,
637 block,
638 GNUNET_TIME_UNIT_FOREVER_ABS, /* expiration time */
639 &put_cont,
640 ac); /* continuation and its closure */
641 n_puts++;
642}
643
644
645/**
646 * Connection to DHT has been established. Call the delay task.
647 *
648 * @param cls the active context
649 * @param op the operation that has been finished
650 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
651 * @param emsg error message in case the operation has failed; will be NULL if
652 * operation has executed successfully.
653 */
654static void
655dht_connected (void *cls,
656 struct GNUNET_TESTBED_Operation *op,
657 void *ca_result,
658 const char *emsg)
659{
660 struct ActiveContext *ac = cls;
661 struct Context *ctx = ac->ctx;
662
663 GNUNET_assert (NULL != ctx); // FIXME: Fails
664 GNUNET_assert (NULL != ctx->op);
665 GNUNET_assert (ctx->op == op);
666 ac->dht = (struct GNUNET_DHT_Handle *) ca_result;
667 if (NULL != emsg)
668 {
669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
670 "Connection to DHT service failed: %s\n",
671 emsg);
672 GNUNET_TESTBED_operation_done (ctx->op); /* Calls dht_disconnect() */
673 ctx->op = NULL;
674 return;
675 }
676 switch (mode)
677 {
678 case MODE_PUT:
679 {
680 struct GNUNET_TIME_Relative peer_delay_put;
681
682 peer_delay_put.rel_value_us =
683 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
684 delay_put.rel_value_us);
685 ac->put_count = num_puts_per_peer;
686 ac->hash = calloc (ac->put_count,
687 sizeof(struct GNUNET_HashCode));
688 if (NULL == ac->hash)
689 {
690 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
691 "calloc");
692 GNUNET_SCHEDULER_shutdown ();
693 return;
694 }
695 ac->delay_task = GNUNET_SCHEDULER_add_delayed (peer_delay_put,
696 &delayed_put,
697 ac);
698 break;
699 }
700
701 case MODE_GET:
702 {
703 struct GNUNET_TIME_Relative peer_delay_get;
704
705 peer_delay_get.rel_value_us =
706 delay_get.rel_value_us
707 + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
708 delay_get.rel_value_us);
709 ac->delay_task = GNUNET_SCHEDULER_add_delayed (peer_delay_get,
710 &delayed_get,
711 ac);
712 break;
713 }
714 }
715}
716
717
718/**
719 * Connect to DHT service and return the DHT client handler
720 *
721 * @param cls the active context
722 * @param cfg configuration of the peer to connect to; will be available until
723 * GNUNET_TESTBED_operation_done() is called on the operation returned
724 * from GNUNET_TESTBED_service_connect()
725 * @return service handle to return in 'op_result', NULL on error
726 */
727static void *
728dht_connect (void *cls,
729 const struct GNUNET_CONFIGURATION_Handle *cfg)
730{
731 n_dht++;
732 return GNUNET_DHT_connect (cfg,
733 10);
734}
735
736
737/**
738 * Adapter function called to destroy a connection to
739 * a service.
740 *
741 * @param cls the active context
742 * @param op_result service handle returned from the connect adapter
743 */
744static void
745dht_disconnect (void *cls,
746 void *op_result)
747{
748 struct ActiveContext *ac = cls;
749
750 GNUNET_assert (NULL != ac->dht);
751 GNUNET_assert (ac->dht == op_result);
752 GNUNET_DHT_disconnect (ac->dht);
753 ac->dht = NULL;
754 n_dht--;
755 if (0 != n_dht)
756 return;
757 if (GNUNET_YES == in_shutdown)
758 return;
759 switch (mode)
760 {
761 case MODE_PUT:
762 if (n_puts_ok != ((unsigned long long) n_active) * num_puts_per_peer)
763 return;
764 /* Start GETs if all PUTs have been made */
765 mode = MODE_GET;
766 start_profiling ();
767 return;
768
769 case MODE_GET:
770 if ((n_gets_ok + n_gets_fail) != n_active)
771 return;
772 break;
773 }
774}
775
776
777/**
778 * Connect to DHT services of active peers
779 */
780static void
781start_profiling ()
782{
783 struct Context *ctx;
784
785 DEBUG ("GNUNET_TESTBED_service_connect\n");
786 GNUNET_break (GNUNET_YES != in_shutdown);
787 for (unsigned int i = 0; i < n_active; i++)
788 {
789 struct ActiveContext *ac = &a_ac[i];
790 GNUNET_assert (NULL != (ctx = ac->ctx));
791 GNUNET_assert (NULL == ctx->op);
792 ctx->op = GNUNET_TESTBED_service_connect (ctx,
793 ctx->peer,
794 "dht",
795 &dht_connected, ac,
796 &dht_connect,
797 &dht_disconnect,
798 ac);
799 }
800}
801
802
803/**
804 * Callback called when DHT service on the peer is started
805 *
806 * @param cls the context
807 * @param op the operation that has been finished
808 * @param emsg error message in case the operation has failed; will be NULL if
809 * operation has executed successfully.
810 */
811static void
812service_started (void *cls,
813 struct GNUNET_TESTBED_Operation *op,
814 const char *emsg)
815{
816 struct Context *ctx = cls;
817
818 GNUNET_assert (NULL != ctx);
819 GNUNET_assert (NULL != ctx->op);
820 GNUNET_TESTBED_operation_done (ctx->op);
821 ctx->op = NULL;
822 peers_started++;
823 DEBUG ("Peers Started = %d; num_peers = %d \n",
824 peers_started,
825 num_peers);
826 if (peers_started == num_peers)
827 start_profiling ();
828}
829
830
831/**
832 * Signature of a main function for a testcase.
833 *
834 * @param cls closure
835 * @param h the run handle
836 * @param num_peers number of peers in 'peers'
837 * @param peers handle to peers run in the testbed
838 * @param links_succeeded the number of overlay link connection attempts that
839 * succeeded
840 * @param links_failed the number of overlay link
841 */
842static void
843test_run (void *cls,
844 struct GNUNET_TESTBED_RunHandle *h,
845 unsigned int num_peers,
846 struct GNUNET_TESTBED_Peer **peers,
847 unsigned int links_succeeded,
848 unsigned int links_failed)
849{
850 unsigned int ac_cnt;
851
852 testbed_handles = peers;
853 if (NULL == peers)
854 {
855 /* exit */
856 GNUNET_assert (0);
857 }
858 MESSAGE ("%u peers started, %u/%u links up\n",
859 num_peers,
860 links_succeeded,
861 links_succeeded + links_failed);
862 a_ctx = GNUNET_new_array (num_peers,
863 struct Context);
864 /* select the peers which actively participate in profiling */
865 n_active = num_peers * put_probability / 100;
866 if (0 == n_active)
867 {
868 GNUNET_SCHEDULER_shutdown ();
869 GNUNET_free (a_ctx);
870 a_ctx = NULL;
871 return;
872 }
873
874 a_ac = GNUNET_new_array (n_active,
875 struct ActiveContext);
876 ac_cnt = 0;
877 for (unsigned int cnt = 0; cnt < num_peers && ac_cnt < n_active; cnt++)
878 {
879 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
880 100) >= put_probability)
881 continue;
882
883 a_ctx[cnt].ac = &a_ac[ac_cnt];
884 a_ac[ac_cnt].ctx = &a_ctx[cnt];
885 ac_cnt++;
886 }
887 n_active = ac_cnt;
888
889 /* start DHT service on all peers */
890 for (unsigned int cnt = 0; cnt < num_peers; cnt++)
891 {
892 a_ctx[cnt].peer = peers[cnt];
893 a_ctx[cnt].op = GNUNET_TESTBED_peer_manage_service (&a_ctx[cnt],
894 peers[cnt],
895 "dht",
896 &service_started,
897 &a_ctx[cnt],
898 1);
899 }
900}
901
902
903/**
904 * Main function that will be run by the scheduler.
905 *
906 * @param cls closure
907 * @param args remaining command-line arguments
908 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
909 * @param config configuration
910 */
911static void
912run (void *cls,
913 char *const *args,
914 const char *cfgfile,
915 const struct GNUNET_CONFIGURATION_Handle *config)
916{
917 uint64_t event_mask;
918
919 if (0 == num_peers)
920 {
921 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
922 _ ("Exiting as the number of peers is %u\n"),
923 num_peers);
924 return;
925 }
926 cfg = config;
927 event_mask = 0;
928 GNUNET_TESTBED_run (hosts_file,
929 cfg,
930 num_peers,
931 event_mask,
932 NULL,
933 NULL,
934 &test_run,
935 NULL);
936 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
937 NULL);
938}
939
940
941/**
942 * Main function.
943 *
944 * @return 0 on success
945 */
946int
947main (int argc,
948 char *const *argv)
949{
950 int rc;
951 struct GNUNET_GETOPT_CommandLineOption options[] = {
952 GNUNET_GETOPT_option_uint ('n',
953 "peers",
954 "COUNT",
955 gettext_noop ("number of peers to start"),
956 &num_peers),
957 GNUNET_GETOPT_option_uint ('p',
958 "peer-put-count",
959 "COUNT",
960 gettext_noop (
961 "number of PUTs to perform per peer"),
962 &num_puts_per_peer),
963 GNUNET_GETOPT_option_string ('H',
964 "hosts",
965 "FILENAME",
966 gettext_noop (
967 "name of the file with the login information for the testbed"),
968 &hosts_file),
969 GNUNET_GETOPT_option_relative_time ('D',
970 "delay",
971 "DELAY",
972 gettext_noop (
973 "delay between rounds for collecting statistics (default: 30 sec)"),
974 &delay_stats),
975 GNUNET_GETOPT_option_relative_time ('P',
976 "PUT-delay",
977 "DELAY",
978 gettext_noop (
979 "delay to start doing PUTs (default: 1 sec)"),
980 &delay_put),
981 GNUNET_GETOPT_option_relative_time ('G',
982 "GET-delay",
983 "DELAY",
984 gettext_noop (
985 "delay to start doing GETs (default: 5 min)"),
986 &delay_get),
987 GNUNET_GETOPT_option_uint ('r',
988 "replication",
989 "DEGREE",
990 gettext_noop ("replication degree for DHT PUTs"),
991 &replication),
992 GNUNET_GETOPT_option_uint ('R',
993 "random-chance",
994 "PROBABILITY",
995 gettext_noop (
996 "chance that a peer is selected at random for PUTs"),
997 &put_probability),
998 GNUNET_GETOPT_option_relative_time ('t',
999 "timeout",
1000 "TIMEOUT",
1001 gettext_noop (
1002 "timeout for DHT PUT and GET requests (default: 1 min)"),
1003 &timeout),
1004 GNUNET_GETOPT_OPTION_END
1005 };
1006
1007 if (GNUNET_OK !=
1008 GNUNET_STRINGS_get_utf8_args (argc, argv,
1009 &argc, &argv))
1010 return 2;
1011 /* set default delays */
1012 delay_stats = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1013 delay_put = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1014 delay_get = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1015 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1016 replication = 1; /* default replication */
1017 rc = 0;
1018 if (GNUNET_OK !=
1019 GNUNET_PROGRAM_run (argc,
1020 argv,
1021 "gnunet-dht-profiler",
1022 gettext_noop (
1023 "Measure quality and performance of the DHT service."),
1024 options,
1025 &run,
1026 NULL))
1027 rc = 1;
1028 return rc;
1029}
diff --git a/src/dht/plugin_block_dht.c b/src/dht/plugin_block_dht.c
deleted file mode 100644
index 7c6fb9ed6..000000000
--- a/src/dht/plugin_block_dht.c
+++ /dev/null
@@ -1,393 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010, 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 dht/plugin_block_dht.c
23 * @brief block plugin for DHT internals (right now, find-peer requests only);
24 * other plugins should be used to store "useful" data in the
25 * DHT (see fs block plugin)
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_constants.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_block_plugin.h"
32#include "gnunet_block_group_lib.h"
33
34#define DEBUG_DHT GNUNET_EXTRA_LOGGING
35
36/**
37 * Number of bits we set per entry in the bloomfilter.
38 * Do not change!
39 */
40#define BLOOMFILTER_K 16
41
42
43/**
44 * Create a new block group.
45 *
46 * @param ctx block context in which the block group is created
47 * @param type type of the block for which we are creating the group
48 * @param nonce random value used to seed the group creation
49 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
50 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
51 * @param va variable arguments specific to @a type
52 * @return block group handle, NULL if block groups are not supported
53 * by this @a type of block (this is not an error)
54 */
55static struct GNUNET_BLOCK_Group *
56block_plugin_dht_create_group (void *cls,
57 enum GNUNET_BLOCK_Type type,
58 uint32_t nonce,
59 const void *raw_data,
60 size_t raw_data_size,
61 va_list va)
62{
63 unsigned int bf_size;
64 const char *guard;
65
66 guard = va_arg (va, const char *);
67 if (0 == strcmp (guard,
68 "seen-set-size"))
69 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va,
70 unsigned int),
71 BLOOMFILTER_K);
72 else if (0 == strcmp (guard,
73 "filter-size"))
74 bf_size = va_arg (va, unsigned int);
75 else
76 {
77 GNUNET_break (0);
78 bf_size = 8;
79 }
80 GNUNET_break (NULL == va_arg (va, const char *));
81 return GNUNET_BLOCK_GROUP_bf_create (cls,
82 bf_size,
83 BLOOMFILTER_K,
84 type,
85 nonce,
86 raw_data,
87 raw_data_size);
88}
89
90
91/**
92 * Function called to validate a reply or a request. For
93 * request evaluation, simply pass "NULL" for the @a reply_block.
94 *
95 * @param cls closure
96 * @param ctx context
97 * @param type block type
98 * @param group block group to check against
99 * @param eo control flags
100 * @param query original query (hash)
101 * @param xquery extended 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 */
107static enum GNUNET_BLOCK_EvaluationResult
108block_plugin_dht_evaluate (void *cls,
109 struct GNUNET_BLOCK_Context *ctx,
110 enum GNUNET_BLOCK_Type type,
111 struct GNUNET_BLOCK_Group *group,
112 enum GNUNET_BLOCK_EvaluationOptions eo,
113 const struct GNUNET_HashCode *query,
114 const void *xquery,
115 size_t xquery_size,
116 const void *reply_block,
117 size_t reply_block_size)
118{
119 const struct GNUNET_HELLO_Message *hello;
120 struct GNUNET_PeerIdentity pid;
121 const struct GNUNET_MessageHeader *msg;
122 struct GNUNET_HashCode phash;
123
124 if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
125 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
126 if (0 != xquery_size)
127 {
128 GNUNET_break_op (0);
129 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
130 }
131 if (NULL == reply_block)
132 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
133 if (reply_block_size < sizeof(struct GNUNET_MessageHeader))
134 {
135 GNUNET_break_op (0);
136 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
137 }
138 msg = reply_block;
139 if (reply_block_size != ntohs (msg->size))
140 {
141 GNUNET_break_op (0);
142 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
143 }
144 hello = reply_block;
145 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
146 {
147 GNUNET_break_op (0);
148 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
149 }
150 GNUNET_CRYPTO_hash (&pid,
151 sizeof(pid),
152 &phash);
153 if (GNUNET_YES ==
154 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
155 &phash))
156 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
157 return GNUNET_BLOCK_EVALUATION_OK_MORE;
158}
159
160
161/**
162 * Function called to validate a query.
163 *
164 * @param cls closure
165 * @param ctx block context
166 * @param type block type
167 * @param query original query (hash)
168 * @param xquery extrended query data (can be NULL, depending on type)
169 * @param xquery_size number of bytes in @a xquery
170 * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not
171 */
172static enum GNUNET_GenericReturnValue
173block_plugin_dht_check_query (void *cls,
174 enum GNUNET_BLOCK_Type type,
175 const struct GNUNET_HashCode *query,
176 const void *xquery,
177 size_t xquery_size)
178{
179 if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
180 return GNUNET_SYSERR;
181 if (0 != xquery_size)
182 {
183 GNUNET_break_op (0);
184 return GNUNET_NO;
185 }
186 return GNUNET_OK;
187}
188
189
190/**
191 * Function called to validate a block for storage.
192 *
193 * @param cls closure
194 * @param type block type
195 * @param query key for the block (hash), must match exactly
196 * @param block block data to validate
197 * @param block_size number of bytes in @a block
198 * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not
199 */
200static enum GNUNET_GenericReturnValue
201block_plugin_dht_check_block (void *cls,
202 enum GNUNET_BLOCK_Type type,
203 const struct GNUNET_HashCode *query,
204 const void *block,
205 size_t block_size)
206{
207 const struct GNUNET_HELLO_Message *hello;
208 struct GNUNET_PeerIdentity pid;
209 const struct GNUNET_MessageHeader *msg;
210
211 if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
212 return GNUNET_SYSERR;
213 if (block_size < sizeof(struct GNUNET_MessageHeader))
214 {
215 GNUNET_break_op (0);
216 return GNUNET_NO;
217 }
218 msg = block;
219 if (block_size != ntohs (msg->size))
220 {
221 GNUNET_break_op (0);
222 return GNUNET_NO;
223 }
224 hello = block;
225 if (GNUNET_OK !=
226 GNUNET_HELLO_get_id (hello,
227 &pid))
228 {
229 GNUNET_break_op (0);
230 return GNUNET_NO;
231 }
232 return GNUNET_OK;
233}
234
235
236/**
237 * Function called to validate a reply to a request. Note that it is assumed
238 * that the reply has already been matched to the key (and signatures checked)
239 * as it would be done with the GetKeyFunction and the
240 * BlockEvaluationFunction.
241 *
242 * @param cls closure
243 * @param type block type
244 * @param group which block group to use for evaluation
245 * @param query original query (hash)
246 * @param xquery extrended query data (can be NULL, depending on type)
247 * @param xquery_size number of bytes in @a xquery
248 * @param reply_block response to validate
249 * @param reply_block_size number of bytes in @a reply_block
250 * @return characterization of result
251 */
252static enum GNUNET_BLOCK_ReplyEvaluationResult
253block_plugin_dht_check_reply (
254 void *cls,
255 enum GNUNET_BLOCK_Type type,
256 struct GNUNET_BLOCK_Group *group,
257 const struct GNUNET_HashCode *query,
258 const void *xquery,
259 size_t xquery_size,
260 const void *reply_block,
261 size_t reply_block_size)
262{
263 const struct GNUNET_HELLO_Message *hello;
264 struct GNUNET_PeerIdentity pid;
265 const struct GNUNET_MessageHeader *msg;
266 struct GNUNET_HashCode phash;
267
268 if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
269 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
270 if (reply_block_size < sizeof(struct GNUNET_MessageHeader))
271 {
272 GNUNET_break_op (0);
273 return GNUNET_BLOCK_REPLY_INVALID;
274 }
275 msg = reply_block;
276 if (reply_block_size != ntohs (msg->size))
277 {
278 GNUNET_break_op (0);
279 return GNUNET_BLOCK_REPLY_INVALID;
280 }
281 hello = reply_block;
282 if (GNUNET_OK !=
283 GNUNET_HELLO_get_id (hello,
284 &pid))
285 {
286 GNUNET_break_op (0);
287 return GNUNET_BLOCK_REPLY_INVALID;
288 }
289 GNUNET_CRYPTO_hash (&pid,
290 sizeof(pid),
291 &phash);
292 if (GNUNET_YES ==
293 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
294 &phash))
295 return GNUNET_BLOCK_REPLY_OK_DUPLICATE;
296 return GNUNET_BLOCK_REPLY_OK_MORE;
297}
298
299
300/**
301 * Function called to obtain the key for a block.
302 *
303 * @param cls closure
304 * @param type block type
305 * @param block block to get the key for
306 * @param block_size number of bytes @a block
307 * @param[out] key set to the key (query) for the given block
308 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
309 * (or if extracting a key from a block of this type does not work)
310 */
311static enum GNUNET_GenericReturnValue
312block_plugin_dht_get_key (void *cls,
313 enum GNUNET_BLOCK_Type type,
314 const void *block,
315 size_t block_size,
316 struct GNUNET_HashCode *key)
317{
318 const struct GNUNET_MessageHeader *msg;
319 const struct GNUNET_HELLO_Message *hello;
320 struct GNUNET_PeerIdentity *pid;
321
322 if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
323 return GNUNET_SYSERR;
324 if (block_size < sizeof(struct GNUNET_MessageHeader))
325 {
326 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
327 "block-dht",
328 _ ("Block not of type %u\n"),
329 GNUNET_BLOCK_TYPE_DHT_HELLO);
330 return GNUNET_NO;
331 }
332 msg = block;
333 if (block_size != ntohs (msg->size))
334 {
335 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
336 "block-dht",
337 _ ("Size mismatch for block with type %u\n"),
338 GNUNET_BLOCK_TYPE_DHT_HELLO);
339 return GNUNET_NO;
340 }
341 hello = block;
342 memset (key, 0, sizeof(*key));
343 pid = (struct GNUNET_PeerIdentity *) key;
344 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, pid))
345 {
346 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
347 "block-dht",
348 _ ("Block of type %u is malformed\n"),
349 GNUNET_BLOCK_TYPE_DHT_HELLO);
350 return GNUNET_NO;
351 }
352 return GNUNET_OK;
353}
354
355
356/**
357 * Entry point for the plugin.
358 */
359void *
360libgnunet_plugin_block_dht_init (void *cls)
361{
362 static enum GNUNET_BLOCK_Type types[] = {
363 GNUNET_BLOCK_TYPE_DHT_HELLO,
364 GNUNET_BLOCK_TYPE_ANY /* end of list */
365 };
366 struct GNUNET_BLOCK_PluginFunctions *api;
367
368 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
369 api->evaluate = &block_plugin_dht_evaluate;
370 api->get_key = &block_plugin_dht_get_key;
371 api->check_query = &block_plugin_dht_check_query;
372 api->check_block = &block_plugin_dht_check_block;
373 api->check_reply = &block_plugin_dht_check_reply;
374 api->create_group = &block_plugin_dht_create_group;
375 api->types = types;
376 return api;
377}
378
379
380/**
381 * Exit point from the plugin.
382 */
383void *
384libgnunet_plugin_block_dht_done (void *cls)
385{
386 struct GNUNET_BLOCK_PluginFunctions *api = cls;
387
388 GNUNET_free (api);
389 return NULL;
390}
391
392
393/* end of plugin_block_dht.c */
diff --git a/src/dht/test_dht_2dtorus.conf b/src/dht/test_dht_2dtorus.conf
deleted file mode 100644
index 0e546cf68..000000000
--- a/src/dht/test_dht_2dtorus.conf
+++ /dev/null
@@ -1,37 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test_dht_2dtorus/
5
6[dht]
7START_ON_DEMAND = YES
8IMMEDIATE_START = YES
9
10[dhtcache]
11QUOTA = 1 MB
12DATABASE = heap
13
14[nat]
15DISABLEV6 = YES
16RETURN_LOCAL_ADDRESSES = YES
17ENABLE_UPNP = NO
18BEHIND_NAT = NO
19ALLOW_NAT = NO
20INTERNAL_ADDRESS = 127.0.0.1
21EXTERNAL_ADDRESS = 127.0.0.1
22
23[ats]
24WAN_QUOTA_IN = 1 GB
25WAN_QUOTA_OUT = 1 GB
26
27[testbed]
28OVERLAY_TOPOLOGY = 2D_TORUS
29
30[nse]
31START_ON_DEMAND = YES
32WORKDELAY = 500 ms
33INTERVAL = 60 s
34WORKBITS = 0
35
36[transport]
37PLUGINS = unix
diff --git a/src/dht/test_dht_api.c b/src/dht/test_dht_api.c
deleted file mode 100644
index 4d557bba8..000000000
--- a/src/dht/test_dht_api.c
+++ /dev/null
@@ -1,193 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 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 * @file dht/test_dht_api.c
22 * @brief base test case for dht api
23 * @author Christian Grothoff
24 *
25 * This test case tests DHT api to DUMMY DHT service communication.
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_dht_service.h"
32
33
34/**
35 * How long until we really give up on a particular testcase portion?
36 */
37#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
38 60)
39
40static struct GNUNET_DHT_Handle *dht_handle;
41
42static struct GNUNET_DHT_GetHandle *get_handle;
43
44static struct GNUNET_DHT_PutHandle *put_handle;
45
46static int ok = 1;
47
48static struct GNUNET_SCHEDULER_Task *die_task;
49
50
51static void
52do_shutdown (void *cls)
53{
54 if (NULL != die_task)
55 {
56 GNUNET_SCHEDULER_cancel (die_task);
57 die_task = NULL;
58 }
59 if (NULL != put_handle)
60 {
61 GNUNET_DHT_put_cancel (put_handle);
62 put_handle = NULL;
63 }
64 if (NULL != get_handle)
65 {
66 GNUNET_DHT_get_stop (get_handle);
67 get_handle = NULL;
68 }
69 GNUNET_DHT_disconnect (dht_handle);
70 dht_handle = NULL;
71}
72
73
74static void
75end_badly (void *cls)
76{
77 die_task = NULL;
78 fprintf (stderr,
79 "%s",
80 "Ending on an unhappy note.\n");
81 GNUNET_SCHEDULER_shutdown ();
82 ok = 1;
83}
84
85
86static void
87test_get_iterator (void *cls,
88 struct GNUNET_TIME_Absolute exp,
89 const struct GNUNET_HashCode *key,
90 const struct GNUNET_DHT_PathElement *get_path,
91 unsigned int get_path_length,
92 const struct GNUNET_DHT_PathElement *put_path,
93 unsigned int put_path_length,
94 enum GNUNET_BLOCK_Type type,
95 size_t size,
96 const void *data)
97{
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 "test_get_iterator called (we got a result), stopping get request!\n");
100 GNUNET_SCHEDULER_shutdown ();
101 ok = 0;
102}
103
104
105/**
106 * Signature of the main function of a task.
107 *
108 * @param cls closure
109 */
110static void
111test_get (void *cls)
112{
113 struct GNUNET_HashCode hash;
114
115 put_handle = NULL;
116 memset (&hash,
117 42,
118 sizeof(struct GNUNET_HashCode));
119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
120 "Called test_get!\n");
121 GNUNET_assert (dht_handle != NULL);
122 get_handle = GNUNET_DHT_get_start (dht_handle,
123 GNUNET_BLOCK_TYPE_TEST,
124 &hash,
125 1,
126 GNUNET_DHT_RO_NONE,
127 NULL,
128 0,
129 &test_get_iterator,
130 NULL);
131
132 if (NULL == get_handle)
133 {
134 GNUNET_break (0);
135 ok = 1;
136 GNUNET_SCHEDULER_shutdown ();
137 return;
138 }
139}
140
141
142static void
143run (void *cls,
144 const struct GNUNET_CONFIGURATION_Handle *cfg,
145 struct GNUNET_TESTING_Peer *peer)
146{
147 struct GNUNET_HashCode hash;
148 char *data;
149 size_t data_size = 42;
150
151 GNUNET_assert (ok == 1);
152 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
153 NULL);
154 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT,
155 &end_badly,
156 NULL);
157 memset (&hash,
158 42,
159 sizeof(struct GNUNET_HashCode));
160 data = GNUNET_malloc (data_size);
161 memset (data, 43, data_size);
162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
163 "Called test_put!\n");
164 dht_handle = GNUNET_DHT_connect (cfg,
165 100);
166 GNUNET_assert (NULL != dht_handle);
167 put_handle = GNUNET_DHT_put (dht_handle,
168 &hash,
169 1,
170 GNUNET_DHT_RO_NONE,
171 GNUNET_BLOCK_TYPE_TEST,
172 data_size,
173 data,
174 GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT),
175 &test_get,
176 NULL);
177 GNUNET_free (data);
178}
179
180
181int
182main (int argc,
183 char *argv[])
184{
185 if (0 != GNUNET_TESTING_peer_run ("test-dht-api",
186 "test_dht_api_data.conf",
187 &run, NULL))
188 return 1;
189 return ok;
190}
191
192
193/* end of test_dht_api.c */
diff --git a/src/dht/test_dht_api_data.conf b/src/dht/test_dht_api_data.conf
deleted file mode 100644
index cb875fad4..000000000
--- a/src/dht/test_dht_api_data.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-dht-api/
6
7[dhtcache]
8QUOTA = 1 MB
9DATABASE = heap
10
11[topology]
12TARGET-CONNECTION-COUNT = 16
13AUTOCONNECT = YES
14FRIENDS-ONLY = NO
15MINIMUM-FRIENDS = 0
16
17[ats]
18WAN_QUOTA_IN = 1 GB
19WAN_QUOTA_OUT = 1 GB
20
21[transport]
22plugins = tcp
23NEIGHBOUR_LIMIT = 50
24PORT = 2091
25
26[transport-tcp]
27TIMEOUT = 300 s
28
29[nat]
30DISABLEV6 = YES
31BINDTO = 127.0.0.1
32ENABLE_UPNP = NO
33BEHIND_NAT = NO
34ALLOW_NAT = NO
35INTERNAL_ADDRESS = 127.0.0.1
36EXTERNAL_ADDRESS = 127.0.0.1
37
38[dht]
39START_ON_DEMAND = YES
40IMMEDIATE_START = YES
41
42[nse]
43START_ON_DEMAND = YES
44WORKBITS = 1
diff --git a/src/dht/test_dht_api_peer1.conf b/src/dht/test_dht_api_peer1.conf
deleted file mode 100644
index 230aa0fa4..000000000
--- a/src/dht/test_dht_api_peer1.conf
+++ /dev/null
@@ -1,41 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[dhtcache]
5QUOTA = 1 MB
6DATABASE = heap
7
8[transport]
9PLUGINS = tcp
10ACCEPT_FROM6 = ::1;
11ACCEPT_FROM = 127.0.0.1;
12NEIGHBOUR_LIMIT = 50
13PORT = 12365
14
15[ats]
16WAN_QUOTA_IN = 1 GB
17WAN_QUOTA_OUT = 1 GB
18
19[transport-tcp]
20TIMEOUT = 300 s
21BINDTO = 127.0.0.1
22
23[PATHS]
24GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-dht-peer-1/
25
26[nat]
27DISABLEV6 = YES
28ENABLE_UPNP = NO
29BEHIND_NAT = NO
30ALLOW_NAT = NO
31INTERNAL_ADDRESS = 127.0.0.1
32EXTERNAL_ADDRESS = 127.0.0.1
33USE_LOCALADDR = NO
34
35[dht]
36START_ON_DEMAND = YES
37IMMEDIATE_START = YES
38
39[nse]
40START_ON_DEMAND = YES
41WORKBITS = 1
diff --git a/src/dht/test_dht_line.conf b/src/dht/test_dht_line.conf
deleted file mode 100644
index 62e337ef2..000000000
--- a/src/dht/test_dht_line.conf
+++ /dev/null
@@ -1,38 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test_dht_line/
5
6[dht]
7START_ON_DEMAND = YES
8IMMEDIATE_START = YES
9
10[dhtcache]
11QUOTA = 1 MB
12DATABASE = heap
13
14[nat]
15DISABLEV6 = YES
16RETURN_LOCAL_ADDRESSES = YES
17USE_LOCALADDR = YES
18ENABLE_UPNP = NO
19BEHIND_NAT = NO
20ALLOW_NAT = NO
21INTERNAL_ADDRESS = 127.0.0.1
22EXTERNAL_ADDRESS = 127.0.0.1
23
24[ats]
25WAN_QUOTA_IN = 1 GB
26WAN_QUOTA_OUT = 1 GB
27
28[testbed]
29OVERLAY_TOPOLOGY = LINE
30
31[transport]
32plugins = unix
33
34[nse]
35START_ON_DEMAND = YES
36WORKDELAY = 500 ms
37INTERVAL = 60 s
38WORKBITS = 0
diff --git a/src/dht/test_dht_monitor.c b/src/dht/test_dht_monitor.c
deleted file mode 100644
index 8af02ad8a..000000000
--- a/src/dht/test_dht_monitor.c
+++ /dev/null
@@ -1,435 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 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 dht/test_dht_monitor.c
22 * @brief Test for the dht monitoring API; checks that we receive "some" monitor events
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_testbed_service.h"
27#include "gnunet_dht_service.h"
28#include "dht_test_lib.h"
29
30
31/**
32 * How long do we run the test at most?
33 */
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
35
36/**
37 * How often do we run the PUTs?
38 */
39#define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
40 10)
41
42
43/**
44 * Information we keep for each GET operation.
45 */
46struct GetOperation
47{
48 /**
49 * DLL.
50 */
51 struct GetOperation *next;
52
53 /**
54 * DLL.
55 */
56 struct GetOperation *prev;
57
58 /**
59 * Handle for the operation.
60 */
61 struct GNUNET_DHT_GetHandle *get;
62};
63
64
65/**
66 * Return value from 'main'.
67 */
68static int ok;
69
70/**
71 * Head of list of active GET operations.
72 */
73static struct GetOperation *get_head;
74
75/**
76 * Tail of list of active GET operations.
77 */
78static struct GetOperation *get_tail;
79
80/**
81 * Array of the testbed's peers.
82 */
83static struct GNUNET_TESTBED_Peer **my_peers;
84
85/**
86 * Number of peers to run.
87 */
88static unsigned int NUM_PEERS = 3;
89
90/**
91 * Task called to disconnect peers.
92 */
93static struct GNUNET_SCHEDULER_Task *timeout_task;
94
95/**
96 * Task to do DHT_puts
97 */
98static struct GNUNET_SCHEDULER_Task *put_task;
99
100static struct GNUNET_DHT_MonitorHandle **monitors;
101
102static unsigned int monitor_counter;
103
104
105/**
106 * Task run on success or timeout to clean up.
107 * Terminates active get operations and shuts down
108 * the testbed.
109 *
110 * @param cls the `struct GNUNET_DHT_TEST_Context`
111 */
112static void
113shutdown_task (void *cls)
114{
115 struct GNUNET_DHT_TEST_Context *ctx = cls;
116 unsigned int i;
117 struct GetOperation *get_op;
118
119 ok = (monitor_counter > NUM_PEERS) ? 0 : 2;
120 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
121 "Received %u monitor events\n",
122 monitor_counter);
123 while (NULL != (get_op = get_tail))
124 {
125 GNUNET_DHT_get_stop (get_op->get);
126 GNUNET_CONTAINER_DLL_remove (get_head,
127 get_tail,
128 get_op);
129 GNUNET_free (get_op);
130 }
131 for (i = 0; i < NUM_PEERS; i++)
132 GNUNET_DHT_monitor_stop (monitors[i]);
133 GNUNET_free (monitors);
134 GNUNET_SCHEDULER_cancel (put_task);
135 GNUNET_DHT_TEST_cleanup (ctx);
136 if (NULL != timeout_task)
137 {
138 GNUNET_SCHEDULER_cancel (timeout_task);
139 timeout_task = NULL;
140 }
141}
142
143
144/**
145 * Task run on success or timeout to clean up.
146 * Terminates active get operations and shuts down
147 * the testbed.
148 *
149 * @param cls NULL
150 */
151static void
152timeout_task_cb (void *cls)
153{
154 timeout_task = NULL;
155 GNUNET_SCHEDULER_shutdown ();
156}
157
158
159/**
160 * Iterator called on each result obtained for a DHT
161 * operation that expects a reply
162 *
163 * @param cls closure with our 'struct GetOperation'
164 * @param exp when will this value expire
165 * @param key key of the result
166 * @param get_path peers on reply path (or NULL if not recorded)
167 * @param get_path_length number of entries in get_path
168 * @param put_path peers on the PUT path (or NULL if not recorded)
169 * @param put_path_length number of entries in get_path
170 * @param type type of the result
171 * @param size number of bytes in data
172 * @param data pointer to the result data
173 */
174static void
175dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
176 const struct GNUNET_HashCode *key,
177 const struct GNUNET_DHT_PathElement *get_path,
178 unsigned int get_path_length,
179 const struct GNUNET_DHT_PathElement *put_path,
180 unsigned int put_path_length,
181 enum GNUNET_BLOCK_Type type,
182 size_t size, const void *data)
183{
184 struct GetOperation *get_op = cls;
185 struct GNUNET_HashCode want;
186
187 if (sizeof(struct GNUNET_HashCode) != size)
188 {
189 GNUNET_break (0);
190 return;
191 }
192 GNUNET_CRYPTO_hash (key, sizeof(*key), &want);
193 if (0 != memcmp (&want, data, sizeof(want)))
194 {
195 GNUNET_break (0);
196 return;
197 }
198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
199 "Get successful\n");
200 GNUNET_DHT_get_stop (get_op->get);
201 GNUNET_CONTAINER_DLL_remove (get_head,
202 get_tail,
203 get_op);
204 GNUNET_free (get_op);
205 if (NULL != get_head)
206 return;
207 /* all DHT GET operations successful; terminate! */
208 ok = 0;
209 GNUNET_SCHEDULER_shutdown ();
210}
211
212
213/**
214 * Task to put the id of each peer into the DHT.
215 *
216 * @param cls array with NUM_PEERS DHT handles
217 */
218static void
219do_puts (void *cls)
220{
221 struct GNUNET_DHT_Handle **hs = cls;
222 struct GNUNET_HashCode key;
223 struct GNUNET_HashCode value;
224
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 "Putting values into DHT\n");
227 for (unsigned int i = 0; i < NUM_PEERS; i++)
228 {
229 GNUNET_CRYPTO_hash (&i, sizeof(i), &key);
230 GNUNET_CRYPTO_hash (&key, sizeof(key), &value);
231 GNUNET_DHT_put (hs[i], &key, 10U,
232 GNUNET_DHT_RO_RECORD_ROUTE
233 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
234 GNUNET_BLOCK_TYPE_TEST,
235 sizeof(value), &value,
236 GNUNET_TIME_UNIT_FOREVER_ABS,
237 NULL, NULL);
238 }
239 put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY,
240 &do_puts, hs);
241}
242
243
244/**
245 * Callback called on each GET request going through the DHT.
246 * Prints the info about the intercepted packet and increments a counter.
247 *
248 * @param cls Closure.
249 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
250 * @param type The type of data in the request.
251 * @param hop_count Hop count so far.
252 * @param path_length number of entries in path (or 0 if not recorded).
253 * @param path peers on the GET path (or NULL if not recorded).
254 * @param desired_replication_level Desired replication level.
255 * @param key Key of the requested data.
256 */
257static void
258monitor_get_cb (void *cls,
259 enum GNUNET_DHT_RouteOption options,
260 enum GNUNET_BLOCK_Type type,
261 uint32_t hop_count,
262 uint32_t desired_replication_level,
263 unsigned int path_length,
264 const struct GNUNET_DHT_PathElement *path,
265 const struct GNUNET_HashCode *key)
266{
267 unsigned int i;
268
269 i = (unsigned int) (long) cls;
270 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
271 "%u got a GET message for key %s\n",
272 i,
273 GNUNET_h2s (key));
274 monitor_counter++;
275}
276
277
278/**
279 * Callback called on each PUT request going through the DHT.
280 * Prints the info about the intercepted packet and increments a counter.
281 *
282 * @param cls Closure.
283 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
284 * @param type The type of data in the request.
285 * @param hop_count Hop count so far.
286 * @param path_length number of entries in path (or 0 if not recorded).
287 * @param path peers on the PUT path (or NULL if not recorded).
288 * @param desired_replication_level Desired replication level.
289 * @param exp Expiration time of the data.
290 * @param key Key under which data is to be stored.
291 * @param data Pointer to the data carried.
292 * @param size Number of bytes in data.
293 */
294static void
295monitor_put_cb (void *cls,
296 enum GNUNET_DHT_RouteOption options,
297 enum GNUNET_BLOCK_Type type,
298 uint32_t hop_count,
299 uint32_t desired_replication_level,
300 unsigned int path_length,
301 const struct GNUNET_DHT_PathElement *path,
302 struct GNUNET_TIME_Absolute exp,
303 const struct GNUNET_HashCode *key,
304 const void *data,
305 size_t size)
306{
307 unsigned int i;
308
309 i = (unsigned int) (long) cls;
310 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
311 "%u got a PUT message for key %s with %u bytes\n",
312 i,
313 GNUNET_h2s (key),
314 (unsigned int) size);
315 monitor_counter++;
316}
317
318
319/**
320 * Callback called on each GET reply going through the DHT.
321 * Prints the info about the intercepted packet and increments a counter.
322 *
323 * @param cls Closure.
324 * @param type The type of data in the result.
325 * @param get_path Peers on GET path (or NULL if not recorded).
326 * @param get_path_length number of entries in get_path.
327 * @param put_path peers on the PUT path (or NULL if not recorded).
328 * @param put_path_length number of entries in get_path.
329 * @param exp Expiration time of the data.
330 * @param key Key of the data.
331 * @param data Pointer to the result data.
332 * @param size Number of bytes in data.
333 */
334static void
335monitor_res_cb (void *cls,
336 enum GNUNET_BLOCK_Type type,
337 const struct GNUNET_DHT_PathElement *get_path,
338 unsigned int get_path_length,
339 const struct GNUNET_DHT_PathElement *put_path,
340 unsigned int put_path_length,
341 struct GNUNET_TIME_Absolute exp,
342 const struct GNUNET_HashCode *key,
343 const void *data,
344 size_t size)
345{
346 unsigned int i;
347
348 i = (unsigned int) (long) cls;
349 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
350 "%u got a REPLY message for key %s with %u bytes\n",
351 i,
352 GNUNET_h2s (key),
353 (unsigned int) size);
354 monitor_counter++;
355}
356
357
358/**
359 * Main function of the test.
360 *
361 * @param cls closure (NULL)
362 * @param ctx argument to give to GNUNET_DHT_TEST_cleanup on test end
363 * @param num_peers number of peers that are running
364 * @param peers array of peers
365 * @param dhts handle to each of the DHTs of the peers
366 */
367static void
368run (void *cls,
369 struct GNUNET_DHT_TEST_Context *ctx,
370 unsigned int num_peers,
371 struct GNUNET_TESTBED_Peer **peers,
372 struct GNUNET_DHT_Handle **dhts)
373{
374 unsigned int i;
375 unsigned int j;
376 struct GNUNET_HashCode key;
377 struct GetOperation *get_op;
378
379 GNUNET_assert (NUM_PEERS == num_peers);
380 my_peers = peers;
381 monitors = GNUNET_new_array (num_peers,
382 struct GNUNET_DHT_MonitorHandle *);
383 for (i = 0; i < num_peers; i++)
384 monitors[i] = GNUNET_DHT_monitor_start (dhts[i],
385 GNUNET_BLOCK_TYPE_ANY,
386 NULL,
387 &monitor_get_cb,
388 &monitor_res_cb,
389 &monitor_put_cb,
390 (void *) (long) i);
391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392 "Peers setup, starting test\n");
393 put_task = GNUNET_SCHEDULER_add_now (&do_puts, dhts);
394 for (i = 0; i < num_peers; i++)
395 {
396 GNUNET_CRYPTO_hash (&i, sizeof(i), &key);
397 for (j = 0; j < num_peers; j++)
398 {
399 get_op = GNUNET_new (struct GetOperation);
400 GNUNET_CONTAINER_DLL_insert (get_head,
401 get_tail,
402 get_op);
403 get_op->get = GNUNET_DHT_get_start (dhts[j],
404 GNUNET_BLOCK_TYPE_TEST, /* type */
405 &key, /*key to search */
406 4U, /* replication level */
407 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
408 NULL, /* xquery */
409 0, /* xquery bits */
410 &dht_get_handler, get_op);
411 }
412 }
413 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
414 &timeout_task_cb,
415 NULL);
416 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
417 ctx);
418}
419
420
421/**
422 * Main: start test
423 */
424int
425main (int xargc, char *xargv[])
426{
427 GNUNET_DHT_TEST_run ("test-dht-monitor",
428 "test_dht_monitor.conf",
429 NUM_PEERS,
430 &run, NULL);
431 return ok;
432}
433
434
435/* end of test_dht_monitor.c */
diff --git a/src/dht/test_dht_monitor.conf b/src/dht/test_dht_monitor.conf
deleted file mode 100644
index feefc2f5e..000000000
--- a/src/dht/test_dht_monitor.conf
+++ /dev/null
@@ -1,39 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4
5[dhtcache]
6QUOTA = 1 MB
7DATABASE = heap
8
9[transport]
10PLUGINS = tcp
11
12[ats]
13WAN_QUOTA_IN = 1 GB
14WAN_QUOTA_OUT = 1 GB
15
16[testbed]
17OVERLAY_TOPOLOGY = LINE
18
19[PATHS]
20GNUNET_TEST_HOME = $GNUNET_TMP/test-dht-monitor/
21
22[nat]
23DISABLEV6 = YES
24ENABLE_UPNP = NO
25BEHIND_NAT = NO
26ALLOW_NAT = NO
27INTERNAL_ADDRESS = 127.0.0.1
28EXTERNAL_ADDRESS = 127.0.0.1
29USE_LOCALADDR = YES
30RETURN_LOCAL_ADDRESSES = YES
31
32
33[dht]
34START_ON_DEMAND = YES
35IMMEDIATE_START = YES
36
37[nse]
38START_ON_DEMAND = YES
39WORKBITS = 1
diff --git a/src/dht/test_dht_multipeer.conf b/src/dht/test_dht_multipeer.conf
deleted file mode 100644
index ac35664c4..000000000
--- a/src/dht/test_dht_multipeer.conf
+++ /dev/null
@@ -1,40 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[dht]
5START_ON_DEMAND = YES
6IMMEDIATE_START = YES
7
8[dhtcache]
9QUOTA = 1 MB
10DATABASE = heap
11
12[transport]
13PLUGINS = unix
14
15[ats]
16WAN_QUOTA_IN = 1 GB
17WAN_QUOTA_OUT = 1 GB
18
19[testbed]
20OVERLAY_TOPOLOGY = FROM_FILE
21OVERLAY_TOPOLOGY_FILE = test_dht_multipeer_topology.dat
22
23[PATHS]
24GNUNET_TEST_HOME = $GNUNET_TMP/test-dht-multipeer/
25
26[nat]
27DISABLEV6 = YES
28RETURN_LOCAL_ADDRESSES = YES
29ENABLE_UPNP = NO
30BEHIND_NAT = NO
31ALLOW_NAT = NO
32INTERNAL_ADDRESS = 127.0.0.1
33EXTERNAL_ADDRESS = 127.0.0.1
34USE_LOCALADDR = YES
35
36[nse]
37START_ON_DEMAND = YES
38WORKDELAY = 500 ms
39INTERVAL = 60 s
40WORKBITS = 0
diff --git a/src/dht/test_dht_multipeer_topology.dat b/src/dht/test_dht_multipeer_topology.dat
deleted file mode 100644
index 2268c85cb..000000000
--- a/src/dht/test_dht_multipeer_topology.dat
+++ /dev/null
@@ -1,11 +0,0 @@
10:1|6|8
21:2|7|9
32:0|3|8
43:1|4|9
54:0|2|5
65:1|3|6
76:2|4|7
87:3|5|8
98:4|6|9
109:0|5|7
11
diff --git a/src/dht/test_dht_tools.conf b/src/dht/test_dht_tools.conf
deleted file mode 100644
index 05f7cc0e6..000000000
--- a/src/dht/test_dht_tools.conf
+++ /dev/null
@@ -1,157 +0,0 @@
1[dhtcache]
2QUOTA = 1 MB
3DATABASE = heap
4
5[transport]
6PLUGINS = tcp
7ACCEPT_FROM6 = ::1;
8ACCEPT_FROM = 127.0.0.1;
9NEIGHBOUR_LIMIT = 50
10PORT = 12365
11
12[ats]
13WAN_QUOTA_IN = 1 GB
14WAN_QUOTA_OUT = 1 GB
15
16[transport-tcp]
17TIMEOUT = 300 s
18BINDTO = 127.0.0.1
19
20[PATHS]
21GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-dht-peer-1/
22
23[nat]
24DISABLEV6 = YES
25ENABLE_UPNP = NO
26BEHIND_NAT = NO
27ALLOW_NAT = NO
28INTERNAL_ADDRESS = 127.0.0.1
29EXTERNAL_ADDRESS = 127.0.0.1
30USE_LOCALADDR = NO
31
32[dht]
33START_ON_DEMAND = YES
34IMMEDIATE_START = YES
35
36[nse]
37START_ON_DEMAND = YES
38WORKBITS = 1
39# Configuration to disable autostarting of
40# all services above the 'core' level.
41# (including resolver)
42
43[dns]
44START_ON_DEMAND = NO
45
46[cadet]
47START_ON_DEMAND = NO
48
49[datastore]
50START_ON_DEMAND = NO
51
52[fs]
53START_ON_DEMAND = NO
54
55[dv]
56START_ON_DEMAND = NO
57
58[vpn]
59START_ON_DEMAND = NO
60
61[consensus]
62START_ON_DEMAND = NO
63
64[resolver]
65START_ON_DEMAND = NO
66
67[namestore]
68START_ON_DEMAND = NO
69
70[namecache]
71START_ON_DEMAND = NO
72
73[identity]
74START_ON_DEMAND = NO
75
76[revocation]
77START_ON_DEMAND = NO
78
79[conversation]
80START_ON_DEMAND = NO
81
82[peerstore]
83START_ON_DEMAND = NO
84
85[psycstore]
86START_ON_DEMAND = NO
87
88[gns]
89START_ON_DEMAND = NO
90
91[regex]
92START_ON_DEMAND = NO
93
94[set]
95START_ON_DEMAND = NO
96
97[scalarproduct-bob]
98START_ON_DEMAND = NO
99
100[scalarproduct-alice]
101START_ON_DEMAND = NO
102
103[social]
104START_ON_DEMAND = NO
105
106[psyc]
107START_ON_DEMAND = NO
108
109[rps]
110START_ON_DEMAND = NO
111
112[multicast]
113START_ON_DEMAND = NO
114
115[sensordashboard]
116START_ON_DEMAND = NO
117
118[sensor]
119START_ON_DEMAND = NO
120# Configuration file that can be included to prevent ANY of the usual
121# IMMEDIATE_START = YES to be set. Also disables NSE POW calculation.
122#
123# This configuration is included from various configuration test files.
124# Whenever a new service is added that has IMMEDIATE_START = YES for
125# production should be disabled for (most) test suites, the option should
126# be added here instead of all over the place ;-).
127
128[core]
129IMMEDIATE_START = NO
130
131[fs]
132IMMEDIATE_START = NO
133
134[dht]
135IMMEDIATE_START = NO
136
137[cadet]
138IMMEDIATE_START = NO
139
140[nse]
141IMMEDIATE_START = NO
142WORKBITS = 0
143
144[revocation]
145IMMEDIATE_START = NO
146
147[topology]
148IMMEDIATE_START = NO
149
150[hostlist]
151IMMEDIATE_START = NO
152
153[gns]
154IMMEDIATE_START = NO
155
156[zonemaster]
157IMMEDIATE_START = NO
diff --git a/src/dht/test_dht_tools.py.in b/src/dht/test_dht_tools.py.in
deleted file mode 100644
index 84e297081..000000000
--- a/src/dht/test_dht_tools.py.in
+++ /dev/null
@@ -1,149 +0,0 @@
1#!@PYTHONEXE@
2#
3# This testcase simply checks that the DHT command-line tools work.
4# It launches a single peer, stores a value "testdata" under "testkey",
5# and then gives the system 50 ms to fetch it.
6#
7# This could fail if
8# - command line tool interfaces fail
9# - DHT plugins for storage are not installed / working
10# - block plugins for verification (the test plugin) is not installed
11#
12# The code does NOT depend on DHT routing or any actual P2P functionality.
13#
14
15import os
16import sys
17import shutil
18import re
19import subprocess
20import time
21import tempfile
22
23os.environ["PATH"] = "@bindirectory@" + ":" + os.environ["PATH"]
24
25if os.name == "nt":
26 tmp = os.getenv("TEMP")
27else:
28 tmp = "/tmp"
29
30if os.name == 'nt':
31 get = './gnunet-dht-get.exe'
32 put = './gnunet-dht-put.exe'
33 arm = 'gnunet-arm.exe'
34else:
35 get = './gnunet-dht-get'
36 put = './gnunet-dht-put'
37 arm = 'gnunet-arm'
38
39cfgfile = 'test_dht_api_peer1.conf'
40run_get = [get, '-c', cfgfile]
41run_put = [put, '-c', cfgfile]
42run_arm = [arm, '-c', cfgfile]
43debug = os.getenv('DEBUG')
44if debug:
45 run_arm += [debug.split(' ')]
46
47
48def cleanup(exitcode):
49 sys.exit(exitcode)
50
51
52def sub_run(args, want_stdo=True, want_stde=False, nofail=False):
53 if want_stdo:
54 stdo = subprocess.PIPE
55 else:
56 stdo = None
57 if want_stde:
58 stde = subprocess.PIPE
59 else:
60 stde = None
61 p = subprocess.Popen(args, stdout=stdo, stderr=stde)
62 stdo, stde = p.communicate()
63 if not nofail:
64 if p.returncode != 0:
65 sys.exit(p.returncode)
66 return (p.returncode, stdo, stde)
67
68
69def fail(result):
70 print(result)
71 r_arm(['-e'], want_stdo=False)
72 cleanup(1)
73
74
75def r_something(to_run, extra_args, failure=None, normal=True, **kw):
76 rc, stdo, stde = sub_run(to_run + extra_args, nofail=True, **kw)
77 if failure is not None:
78 failure(to_run + extra_args, rc, stdo, stde, normal)
79 return (rc, stdo, stde)
80
81
82def r_arm(extra_args, **kw):
83 return r_something(run_arm, extra_args, **kw)
84
85
86def r_get(extra_args, **kw):
87 return r_something(run_get, extra_args, **kw)
88
89
90def r_put(extra_args, **kw):
91 return r_something(run_put, extra_args, **kw)
92
93
94def end_arm_failure(command, rc, stdo, stde, normal):
95 if normal:
96 if rc != 0:
97 fail(
98 "FAIL: error running {}\nCommand output was:\n{}\n{}".format(
99 command, stdo, stde
100 )
101 )
102 else:
103 if rc == 0:
104 fail(
105 "FAIL: expected error while running {}\nCommand output was:\n{}\n{}"
106 .format(command, stdo, stde)
107 )
108
109
110def print_only_failure(command, rc, stdo, stde, normal):
111 if normal:
112 if rc != 0:
113 print(
114 "FAIL: error running {}\nCommand output was:\n{}\n{}".format(
115 command, stdo, stde
116 )
117 )
118 cleanup(1)
119 else:
120 if rc == 0:
121 print(
122 "FAIL: expected error while running {}\nCommand output was:\n{}\n{}"
123 .format(command, stdo, stde)
124 )
125 cleanup(1)
126
127
128print("TEST: Starting ARM...", end='')
129r_arm(['-s'], failure=end_arm_failure, want_stdo=False, want_stde=False)
130print("PASS")
131time.sleep(1)
132
133print("TEST: Testing put...", end='')
134r_put(['-k', 'testkey', '-d', 'testdata', '-t', '8'], failure=end_arm_failure)
135print("PASS")
136time.sleep(1)
137
138print("TEST: Testing get...", end='')
139rc, stdo, stde = r_get(['-k', 'testkey', '-T', '50 ms', '-t', '8'],
140 want_stdo=True,
141 failure=end_arm_failure)
142stdo = stdo.decode('utf-8').replace('\r', '').splitlines()
143expect = "Result 0, type 8:\ntestdata".splitlines()
144if len(stdo) != 2 or len(expect
145 ) != 2 or stdo[0] != expect[0] or stdo[1] != expect[1]:
146 fail("output `{}' differs from expected `{}'".format(stdo, expect))
147print("PASS")
148
149r_arm(['-e', '-d'], failure=print_only_failure)
diff --git a/src/dht/test_dht_tools.sh b/src/dht/test_dht_tools.sh
deleted file mode 100755
index 56cc99e15..000000000
--- a/src/dht/test_dht_tools.sh
+++ /dev/null
@@ -1,64 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3
4out=`mktemp /tmp/test-gnunet-dht-logXXXXXXXX`
5tempcfg=`mktemp /tmp/test-dht-tools.XXXXXXXX`
6checkout="check.out"
7armexe="gnunet-arm -c $tempcfg "
8putexe="gnunet-dht-put -c $tempcfg "
9getexe="gnunet-dht-get -c $tempcfg "
10peerinfo="gnunet-peerinfo -c $tempcfg -sq"
11stop_arm()
12{
13 if ! $armexe $DEBUG -e -d > $out ; then
14 echo "FAIL: error running $armexe"
15 echo "Command output was:"
16 cat $out
17 rm -f $out $tempcfg
18 exit 1
19 fi
20 rm -f $out $tempcfg
21}
22
23cp test_dht_tools.conf $tempcfg
24
25echo -n "TEST: Starting ARM..."
26if ! $armexe $DEBUG -s > $out ; then
27 echo "FAIL: error running $armexe"
28 echo "Command output was:"
29 cat $out
30 stop_arm
31 exit 1
32fi
33echo "PASS"
34
35echo -n "TEST: Testing put..."
36if ! $putexe -k testkey -d testdata -t 8 > $out ; then
37 echo "FAIL: error running $putexe"
38 echo "Command output was:"
39 cat $out
40 stop_arm
41 exit 1
42fi
43echo "PASS"
44
45echo -n "TEST: Testing get..."
46echo "Result 0, type 8:" > $checkout
47echo "testdata" >> $checkout
48
49if ! $getexe -k testkey -T 100ms -t 8 > $out ; then
50 echo "FAIL: error running $putexe"
51 echo "Command output was:"
52 cat $out
53 stop_arm
54 exit 1
55fi
56
57if ! diff --strip-trailing-cr -q $out $checkout ; then
58 echo "FAIL: $out and $checkout differ:"
59 diff --strip-trailing-cr $out $checkout
60 stop_arm
61 exit 1
62fi
63echo "PASS"
64stop_arm
diff --git a/src/dht/test_dht_topo.c b/src/dht/test_dht_topo.c
deleted file mode 100644
index eb7e80d3b..000000000
--- a/src/dht/test_dht_topo.c
+++ /dev/null
@@ -1,624 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file dht/test_dht_topo.c
22 * @author Christian Grothoff
23 * @brief Test for the dht service: store and retrieve in various topologies.
24 * Each peer stores a value from the DHT and then each peer tries to get each
25 * value from each other peer.
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "dht_test_lib.h"
31
32/**
33 * How long until we give up on fetching the data?
34 */
35#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
36 120)
37
38/**
39 * How frequently do we execute the PUTs?
40 */
41#define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
42 5)
43
44
45/**
46 * Information we keep for each GET operation.
47 */
48struct GetOperation
49{
50 /**
51 * DLL.
52 */
53 struct GetOperation *next;
54
55 /**
56 * DLL.
57 */
58 struct GetOperation *prev;
59
60 /**
61 * Operation to fetch @a me.
62 */
63 struct GNUNET_TESTBED_Operation *to;
64
65 /**
66 * Handle for the operation.
67 */
68 struct GNUNET_DHT_GetHandle *get;
69
70 /**
71 * DHT used by this operation.
72 */
73 struct GNUNET_DHT_Handle *dht;
74
75 /**
76 * Key we are looking up.
77 */
78 struct GNUNET_HashCode key;
79
80 /**
81 * At which peer is this operation being performed?
82 */
83 struct GNUNET_PeerIdentity me;
84};
85
86
87/**
88 * Result of the test.
89 */
90static int ok;
91
92/**
93 * Task to do DHT_puts
94 */
95static struct GNUNET_SCHEDULER_Task *put_task;
96
97/**
98 * Task to do DHT_gets
99 */
100static struct GNUNET_SCHEDULER_Task *get_task;
101
102/**
103 * Task to time out / regular shutdown.
104 */
105static struct GNUNET_SCHEDULER_Task *timeout_task;
106
107/**
108 * Head of list of active GET operations.
109 */
110static struct GetOperation *get_head;
111
112/**
113 * Tail of list of active GET operations.
114 */
115static struct GetOperation *get_tail;
116
117/**
118 * Array of the testbed's peers.
119 */
120static struct GNUNET_TESTBED_Peer **my_peers;
121
122/**
123 * Number of peers to run.
124 */
125static unsigned int NUM_PEERS;
126
127
128/**
129 * Statistics we print out.
130 */
131static struct
132{
133 const char *subsystem;
134 const char *name;
135 unsigned long long total;
136} stats[] = {
137 { "core", "# bytes decrypted", 0 },
138 { "core", "# bytes encrypted", 0 },
139 { "core", "# type maps received", 0 },
140 { "core", "# session keys confirmed via PONG", 0 },
141 { "core", "# peers connected", 0 },
142 { "core", "# key exchanges initiated", 0 },
143 { "core", "# send requests dropped (disconnected)", 0 },
144 { "core", "# transmissions delayed due to corking", 0 },
145 { "core", "# messages discarded (expired prior to transmission)", 0 },
146 { "core", "# messages discarded (disconnected)", 0 },
147 { "core", "# discarded CORE_SEND requests", 0 },
148 { "core", "# discarded lower priority CORE_SEND requests", 0 },
149 { "transport", "# bytes received via TCP", 0 },
150 { "transport", "# bytes transmitted via TCP", 0 },
151 { "dht", "# PUT messages queued for transmission", 0 },
152 { "dht", "# P2P PUT requests received", 0 },
153 { "dht", "# GET messages queued for transmission", 0 },
154 { "dht", "# P2P GET requests received", 0 },
155 { "dht", "# RESULT messages queued for transmission", 0 },
156 { "dht", "# P2P RESULTS received", 0 },
157 { "dht", "# Queued messages discarded (peer disconnected)", 0 },
158 { "dht", "# Peers excluded from routing due to Bloomfilter", 0 },
159 { "dht", "# Peer selection failed", 0 },
160 { "dht", "# FIND PEER requests ignored due to Bloomfilter", 0 },
161 { "dht", "# FIND PEER requests ignored due to lack of HELLO", 0 },
162 { "dht", "# P2P FIND PEER requests processed", 0 },
163 { "dht", "# P2P GET requests ONLY routed", 0 },
164 { "dht", "# Preference updates given to core", 0 },
165 { "dht", "# REPLIES ignored for CLIENTS (no match)", 0 },
166 { "dht", "# GET requests from clients injected", 0 },
167 { "dht", "# GET requests received from clients", 0 },
168 { "dht", "# GET STOP requests received from clients", 0 },
169 { "dht", "# ITEMS stored in datacache", 0 },
170 { "dht", "# Good RESULTS found in datacache", 0 },
171 { "dht", "# GET requests given to datacache", 0 },
172 { NULL, NULL, 0 }
173};
174
175
176static struct GNUNET_DHT_TEST_Context *
177stop_ops (void)
178{
179 struct GetOperation *get_op;
180 struct GNUNET_DHT_TEST_Context *ctx = NULL;
181
182 if (NULL != timeout_task)
183 {
184 ctx = GNUNET_SCHEDULER_cancel (timeout_task);
185 timeout_task = NULL;
186 }
187 if (NULL != put_task)
188 {
189 GNUNET_SCHEDULER_cancel (put_task);
190 put_task = NULL;
191 }
192 if (NULL != get_task)
193 {
194 GNUNET_SCHEDULER_cancel (get_task);
195 get_task = NULL;
196 }
197 while (NULL != (get_op = get_tail))
198 {
199 if (NULL != get_op->to)
200 {
201 GNUNET_TESTBED_operation_done (get_op->to);
202 get_op->to = NULL;
203 }
204 if (NULL != get_op->get)
205 {
206 GNUNET_DHT_get_stop (get_op->get);
207 get_op->get = NULL;
208 }
209 GNUNET_CONTAINER_DLL_remove (get_head,
210 get_tail,
211 get_op);
212 GNUNET_free (get_op);
213 }
214 return ctx;
215}
216
217
218/**
219 * Function called once we're done processing stats.
220 *
221 * @param cls the test context
222 * @param op the stats operation
223 * @param emsg error message on failure
224 */
225static void
226stats_finished (void *cls,
227 struct GNUNET_TESTBED_Operation *op,
228 const char *emsg)
229{
230 struct GNUNET_DHT_TEST_Context *ctx = cls;
231
232 if (NULL != op)
233 GNUNET_TESTBED_operation_done (op);
234 if (NULL != emsg)
235 {
236 fprintf (stderr,
237 _ ("Gathering statistics failed: %s\n"),
238 emsg);
239 GNUNET_SCHEDULER_cancel (put_task);
240 GNUNET_DHT_TEST_cleanup (ctx);
241 return;
242 }
243 for (unsigned int i = 0; NULL != stats[i].name; i++)
244 fprintf (stderr,
245 "%6s/%60s = %12llu\n",
246 stats[i].subsystem,
247 stats[i].name,
248 stats[i].total);
249 GNUNET_DHT_TEST_cleanup (ctx);
250 GNUNET_SCHEDULER_shutdown ();
251}
252
253
254/**
255 * Function called to process statistic values from all peers.
256 *
257 * @param cls closure
258 * @param peer the peer the statistic belong to
259 * @param subsystem name of subsystem that created the statistic
260 * @param name the name of the datum
261 * @param value the current value
262 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
263 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
264 */
265static enum GNUNET_GenericReturnValue
266handle_stats (void *cls,
267 const struct GNUNET_TESTBED_Peer *peer,
268 const char *subsystem,
269 const char *name,
270 uint64_t value,
271 int is_persistent)
272{
273 for (unsigned int i = 0; NULL != stats[i].name; i++)
274 if ((0 == strcasecmp (subsystem,
275 stats[i].subsystem)) &&
276 (0 == strcasecmp (name,
277 stats[i].name)))
278 stats[i].total += value;
279 return GNUNET_OK;
280}
281
282
283/**
284 * Task run on shutdown to clean up. Terminates active get operations
285 * and shuts down the testbed.
286 *
287 * @param cls the 'struct GNUNET_DHT_TestContext'
288 */
289static void
290shutdown_task (void *cls)
291{
292 struct GNUNET_DHT_TEST_Context *ctx;
293
294 (void) cls;
295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
296 "Performing shutdown\n");
297 ctx = stop_ops ();
298 if (NULL != ctx)
299 GNUNET_DHT_TEST_cleanup (ctx);
300}
301
302
303/**
304 * Task run on timeout to clean up. Terminates active get operations
305 * and shuts down the testbed.
306 *
307 * @param cls the `struct GNUNET_DHT_TestContext`
308 */
309static void
310timeout_cb (void *cls)
311{
312 struct GNUNET_DHT_TEST_Context *ctx = cls;
313
314 timeout_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
315 &timeout_cb,
316 ctx);
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 "Timeout\n");
319 GNUNET_SCHEDULER_shutdown ();
320}
321
322
323/**
324 * Iterator called on each result obtained for a DHT
325 * operation that expects a reply
326 *
327 * @param cls closure with our 'struct GetOperation'
328 * @param exp when will this value expire
329 * @param key key of the result
330 * @param get_path peers on reply path (or NULL if not recorded)
331 * @param get_path_length number of entries in @a get_path
332 * @param put_path peers on the PUT path (or NULL if not recorded)
333 * @param put_path_length number of entries in @a put_path
334 * @param type type of the result
335 * @param size number of bytes in @a data
336 * @param data pointer to the result data
337 */
338static void
339dht_get_handler (void *cls,
340 struct GNUNET_TIME_Absolute exp,
341 const struct GNUNET_HashCode *key,
342 const struct GNUNET_DHT_PathElement *get_path,
343 unsigned int get_path_length,
344 const struct GNUNET_DHT_PathElement *put_path,
345 unsigned int put_path_length,
346 enum GNUNET_BLOCK_Type type,
347 size_t size,
348 const void *data)
349{
350 struct GetOperation *get_op = cls;
351 struct GNUNET_HashCode want;
352 struct GNUNET_DHT_TEST_Context *ctx;
353
354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 "GET HANDLER called on PID %s\n",
356 GNUNET_i2s (&get_op->me));
357 if (sizeof(struct GNUNET_HashCode) != size)
358 {
359 GNUNET_break (0);
360 return;
361 }
362 GNUNET_CRYPTO_hash (key,
363 sizeof(*key),
364 &want);
365 if (0 != memcmp (&want,
366 data,
367 sizeof(want)))
368 {
369 GNUNET_break (0);
370 return;
371 }
372 if (0 !=
373 GNUNET_DHT_verify_path (key,
374 data,
375 size,
376 exp,
377 get_path,
378 get_path_length,
379 put_path,
380 put_path_length,
381 &get_op->me))
382 {
383 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
384 "Path signature verification failed!\n");
385 }
386 else
387 {
388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389 "Get successful\n");
390 ok--;
391 }
392 GNUNET_DHT_get_stop (get_op->get);
393 GNUNET_CONTAINER_DLL_remove (get_head,
394 get_tail,
395 get_op);
396 GNUNET_free (get_op);
397 if (NULL != get_head)
398 return;
399 /* all DHT GET operations successful; get stats! */
400 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
401 "All DHT operations successful. Obtaining stats!\n");
402 ctx = stop_ops ();
403 GNUNET_assert (NULL != ctx);
404 (void) GNUNET_TESTBED_get_statistics (NUM_PEERS,
405 my_peers,
406 NULL, NULL,
407 &handle_stats,
408 &stats_finished,
409 ctx);
410}
411
412
413/**
414 * Task to put the id of each peer into the DHT.
415 *
416 * @param cls array with NUM_PEERS DHT handles
417 * @param tc Task context
418 */
419static void
420do_puts (void *cls)
421{
422 struct GNUNET_DHT_Handle **hs = cls;
423 struct GNUNET_HashCode key;
424 struct GNUNET_HashCode value;
425
426 put_task = NULL;
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "Putting %u values into DHT\n",
429 NUM_PEERS);
430 for (unsigned int i = 0; i < NUM_PEERS; i++)
431 {
432 GNUNET_CRYPTO_hash (&i,
433 sizeof(i),
434 &key);
435 GNUNET_CRYPTO_hash (&key,
436 sizeof(key),
437 &value);
438 GNUNET_DHT_put (hs[i],
439 &key,
440 10U,
441 GNUNET_DHT_RO_RECORD_ROUTE
442 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
443 GNUNET_BLOCK_TYPE_TEST,
444 sizeof(value),
445 &value,
446 GNUNET_TIME_UNIT_FOREVER_ABS,
447 NULL,
448 NULL);
449 }
450 put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY,
451 &do_puts,
452 hs);
453}
454
455
456/**
457 * Callback to be called when the requested peer information is available
458 * The peer information in the callback is valid until the operation 'op' is canceled.
459 *
460 * @param cls a `struct GetOperation *`
461 * @param op the operation this callback corresponds to
462 * @param pinfo the result; will be NULL if the operation has failed
463 * @param emsg error message if the operation has failed; will be NULL if the
464 * operation is successful
465 */
466static void
467pid_cb (void *cls,
468 struct GNUNET_TESTBED_Operation *op,
469 const struct GNUNET_TESTBED_PeerInformation *pinfo,
470 const char *emsg)
471{
472 struct GetOperation *get_op = cls;
473
474 if (NULL != emsg)
475 {
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "Testbed failure: %s\n",
478 emsg);
479 GNUNET_TESTBED_operation_done (get_op->to);
480 get_op->to = NULL;
481 GNUNET_SCHEDULER_shutdown ();
482 return;
483 }
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 "Testbed provided PID %s\n",
486 GNUNET_i2s (pinfo->result.id));
487 get_op->me = *pinfo->result.id;
488 GNUNET_TESTBED_operation_done (get_op->to);
489 get_op->to = NULL;
490 get_op->get = GNUNET_DHT_get_start (get_op->dht,
491 GNUNET_BLOCK_TYPE_TEST,
492 &get_op->key,
493 4U, /* replication level */
494 GNUNET_DHT_RO_RECORD_ROUTE
495 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
496 NULL, /* xquery */
497 0, /* xquery bits */
498 &dht_get_handler,
499 get_op);
500}
501
502
503/**
504 * Start GET operations.
505 */
506static void
507start_get (void *cls)
508{
509 struct GNUNET_DHT_Handle **dhts = cls;
510
511 get_task = NULL;
512 for (unsigned int i = 0; i < NUM_PEERS; i++)
513 {
514 struct GNUNET_HashCode key;
515
516 GNUNET_CRYPTO_hash (&i,
517 sizeof(i),
518 &key);
519 for (unsigned int j = 0; j < NUM_PEERS; j++)
520 {
521 struct GetOperation *get_op;
522
523 get_op = GNUNET_new (struct GetOperation);
524 ok++;
525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526 "Starting GET %p\n",
527 get_op);
528 get_op->key = key;
529 get_op->dht = dhts[j];
530 get_op->to = GNUNET_TESTBED_peer_get_information (my_peers[j],
531 GNUNET_TESTBED_PIT_IDENTITY,
532 &pid_cb,
533 get_op);
534 GNUNET_CONTAINER_DLL_insert (get_head,
535 get_tail,
536 get_op);
537 }
538 }
539}
540
541
542/**
543 * Main function of the test.
544 *
545 * @param cls closure (NULL)
546 * @param ctx argument to give to #GNUNET_DHT_TEST_cleanup on test end
547 * @param num_peers number of @a peers that are running
548 * @param peers array of peers
549 * @param dhts handle to each of the DHTs of the peers
550 */
551static void
552run (void *cls,
553 struct GNUNET_DHT_TEST_Context *ctx,
554 unsigned int num_peers,
555 struct GNUNET_TESTBED_Peer **peers,
556 struct GNUNET_DHT_Handle **dhts)
557{
558 GNUNET_assert (NUM_PEERS == num_peers);
559 my_peers = peers;
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561 "Peers setup, starting test\n");
562 put_task = GNUNET_SCHEDULER_add_now (&do_puts,
563 dhts);
564 get_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
565 &start_get,
566 dhts);
567 timeout_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
568 &timeout_cb,
569 ctx);
570 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
571 ctx);
572}
573
574
575/**
576 * Main: start test
577 */
578int
579main (int xargc, char *xargv[])
580{
581 const char *cfg_filename;
582 const char *test_name;
583
584 unsetenv ("XDG_DATA_HOME");
585 unsetenv ("XDG_CONFIG_HOME");
586 unsetenv ("XDG_CACHE_HOME");
587 if (NULL != strstr (xargv[0], "test_dht_2dtorus"))
588 {
589 cfg_filename = "test_dht_2dtorus.conf";
590 test_name = "test-dht-2dtorus";
591 NUM_PEERS = 16;
592 }
593 else if (NULL != strstr (xargv[0], "test_dht_line"))
594 {
595 cfg_filename = "test_dht_line.conf";
596 test_name = "test-dht-line";
597 NUM_PEERS = 5;
598 }
599 else if (NULL != strstr (xargv[0], "test_dht_twopeer"))
600 {
601 cfg_filename = "test_dht_line.conf";
602 test_name = "test-dht-twopeer";
603 NUM_PEERS = 2;
604 }
605 else if (NULL != strstr (xargv[0], "test_dht_multipeer"))
606 {
607 cfg_filename = "test_dht_multipeer.conf";
608 test_name = "test-dht-multipeer";
609 NUM_PEERS = 10;
610 }
611 else
612 {
613 GNUNET_break (0);
614 return 1;
615 }
616 GNUNET_DHT_TEST_run (test_name,
617 cfg_filename,
618 NUM_PEERS,
619 &run, NULL);
620 return ok;
621}
622
623
624/* end of test_dht_topo.c */