aboutsummaryrefslogtreecommitdiff
path: root/src/dht
diff options
context:
space:
mode:
Diffstat (limited to 'src/dht')
-rw-r--r--src/dht/.gitignore13
-rw-r--r--src/dht/Makefile.am229
-rw-r--r--src/dht/dht.conf.in35
-rw-r--r--src/dht/dht.h408
-rw-r--r--src/dht/dht_api.c1436
-rw-r--r--src/dht/dht_test_lib.c202
-rw-r--r--src/dht/dht_test_lib.h95
-rwxr-xr-xsrc/dht/dhtu_testbed_connect.sh31
-rw-r--r--src/dht/dhtu_testbed_deploy.conf26
-rwxr-xr-xsrc/dht/dhtu_testbed_deploy.sh84
-rw-r--r--src/dht/gnunet-dht-get.c324
-rw-r--r--src/dht/gnunet-dht-hello.c178
-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.c543
-rw-r--r--src/dht/gnunet-service-dht.h218
-rw-r--r--src/dht/gnunet-service-dht_clients.c1665
-rw-r--r--src/dht/gnunet-service-dht_datacache.c318
-rw-r--r--src/dht/gnunet-service-dht_datacache.h156
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c2695
-rw-r--r--src/dht/gnunet-service-dht_neighbours.h228
-rw-r--r--src/dht/gnunet-service-dht_routing.c431
-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.c408
-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.c634
38 files changed, 0 insertions, 13316 deletions
diff --git a/src/dht/.gitignore b/src/dht/.gitignore
deleted file mode 100644
index bd8af1217..000000000
--- a/src/dht/.gitignore
+++ /dev/null
@@ -1,13 +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
13gnunet-dht-hello
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
deleted file mode 100644
index 68a17723d..000000000
--- a/src/dht/Makefile.am
+++ /dev/null
@@ -1,229 +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 gnunet-dht-hello
55
56noinst_PROGRAMS = \
57 gnunet-dht-profiler
58
59gnunet_service_dht_SOURCES = \
60 gnunet-service-dht.c gnunet-service-dht.h \
61 gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \
62 gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \
63 gnunet-service-dht_routing.c gnunet-service-dht_routing.h
64gnunet_service_dht_LDADD = \
65 libgnunetdht.la \
66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/core/libgnunetcore.la \
68 $(top_builddir)/src/nse/libgnunetnse.la \
69 $(top_builddir)/src/ats/libgnunetats.la \
70 $(top_builddir)/src/transport/libgnunettransport.la \
71 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
72 $(top_builddir)/src/hello/libgnunethello.la \
73 $(top_builddir)/src/block/libgnunetblock.la \
74 $(top_builddir)/src/block/libgnunetblockgroup.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/util/libgnunetutil.la
86gnunet_dht_get_LDFLAGS = \
87 $(GN_LIBINTL)
88
89gnunet_dht_hello_SOURCES = \
90 gnunet-dht-hello.c
91gnunet_dht_hello_LDADD = \
92 libgnunetdht.la \
93 $(top_builddir)/src/util/libgnunetutil.la
94gnunet_dht_hello_LDFLAGS = \
95 $(GN_LIBINTL)
96
97gnunet_dht_put_SOURCES = \
98 gnunet-dht-put.c
99gnunet_dht_put_LDADD = \
100 libgnunetdht.la \
101 $(top_builddir)/src/util/libgnunetutil.la
102gnunet_dht_put_LDFLAGS = \
103 $(GN_LIBINTL)
104
105gnunet_dht_monitor_SOURCES = \
106 gnunet-dht-monitor.c
107gnunet_dht_monitor_LDADD = \
108 libgnunetdht.la \
109 $(top_builddir)/src/util/libgnunetutil.la
110gnunet_dht_monitor_LDFLAGS = \
111 $(GN_LIBINTL)
112
113gnunet_dht_profiler_SOURCES = \
114 gnunet_dht_profiler.c
115gnunet_dht_profiler_LDADD = \
116 libgnunetdht.la \
117 $(top_builddir)/src/core/libgnunetcore.la \
118 $(top_builddir)/src/util/libgnunetutil.la \
119 $(top_builddir)/src/testing/libgnunettesting.la \
120 $(top_builddir)/src/testbed/libgnunettestbed.la
121gnunet_dht_profiler_LDFLAGS = \
122 $(GN_LIBINTL)
123
124noinst_LIBRARIES = libgnunetdhttest.a
125
126libgnunetdhttest_a_SOURCES = \
127 dht_test_lib.c dht_test_lib.h
128libgnunetdhttest_a_LIBADD = \
129 $(top_builddir)/src/util/libgnunetutil.la \
130 $(top_builddir)/src/testbed/libgnunettestbed.la \
131 libgnunetdht.la
132
133check_PROGRAMS = \
134 test_dht_api \
135 test_dht_twopeer \
136 test_dht_multipeer \
137 test_dht_line \
138 test_dht_2dtorus \
139 test_dht_monitor
140
141if HAVE_EXPERIMENTAL
142# These tests still do not work as testbed does
143# not support the respective topology op
144 NEW_TESTS = test_dht_2dtorus test_dht_multipeer
145endif
146
147if ENABLE_TEST_RUN
148AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
149TESTS = test_dht_api $(check_SCRIPTS) \
150 test_dht_twopeer \
151 test_dht_line \
152 test_dht_monitor \
153 $(NEW_TESTS)
154endif
155
156test_dht_api_SOURCES = \
157 test_dht_api.c
158test_dht_api_LDADD = \
159 $(top_builddir)/src/util/libgnunetutil.la \
160 $(top_builddir)/src/testing/libgnunettesting.la \
161 $(top_builddir)/src/hello/libgnunethello.la \
162 libgnunetdht.la
163
164test_dht_twopeer_SOURCES = \
165 test_dht_topo.c
166test_dht_twopeer_LDADD = \
167 libgnunetdhttest.a \
168 $(top_builddir)/src/util/libgnunetutil.la \
169 libgnunetdhttest.a \
170 $(top_builddir)/src/testbed/libgnunettestbed.la \
171 libgnunetdht.la
172
173test_dht_2dtorus_SOURCES = \
174 test_dht_topo.c
175test_dht_2dtorus_LDADD = \
176 libgnunetdhttest.a \
177 $(top_builddir)/src/util/libgnunetutil.la \
178 $(top_builddir)/src/testbed/libgnunettestbed.la \
179 libgnunetdht.la
180
181test_dht_line_SOURCES = \
182 test_dht_topo.c
183test_dht_line_LDADD = \
184 libgnunetdhttest.a \
185 $(top_builddir)/src/util/libgnunetutil.la \
186 $(top_builddir)/src/testbed/libgnunettestbed.la \
187 libgnunetdht.la
188
189test_dht_multipeer_SOURCES = \
190 test_dht_topo.c
191test_dht_multipeer_LDADD = \
192 libgnunetdhttest.a \
193 $(top_builddir)/src/util/libgnunetutil.la \
194 $(top_builddir)/src/statistics/libgnunetstatistics.la \
195 $(top_builddir)/src/testbed/libgnunettestbed.la \
196 libgnunetdht.la
197
198test_dht_monitor_SOURCES = \
199 test_dht_monitor.c
200test_dht_monitor_LDADD = \
201 libgnunetdhttest.a \
202 $(top_builddir)/src/util/libgnunetutil.la \
203 $(top_builddir)/src/testbed/libgnunettestbed.la \
204 libgnunetdht.la
205
206EXTRA_DIST = \
207 gnunet-service-dht_clients.c \
208 test_dht_api_data.conf \
209 test_dht_api_peer1.conf \
210 test_dht_monitor.conf \
211 test_dht_multipeer.conf \
212 test_dht_2dtorus.conf \
213 test_dht_line.conf \
214 test_dht_tools.conf \
215 test_dht_tools.py.in \
216 test_dht_multipeer_topology.dat \
217 dhtu_testbed_connect.sh \
218 dhtu_testbed_deploy.conf \
219 dhtu_testbed_deploy.sh
220
221if HAVE_PYTHON
222check_SCRIPTS = \
223 test_dht_tools.py
224endif
225
226SUFFIXES = .py.in .py
227.py.in.py:
228 $(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)/$< > $@
229 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 474198004..000000000
--- a/src/dht/dht_api.c
+++ /dev/null
@@ -1,1436 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2012, 2016, 2018, 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/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 * Handle to get a HELLO URL from the DHT for manual bootstrapping.
201 */
202struct GNUNET_DHT_HelloGetHandle
203{
204
205 /**
206 * DLL.
207 */
208 struct GNUNET_DHT_HelloGetHandle *next;
209
210 /**
211 * DLL.
212 */
213 struct GNUNET_DHT_HelloGetHandle *prev;
214
215 /**
216 * Function to call with the result.
217 */
218 GNUNET_DHT_HelloGetCallback cb;
219
220 /**
221 * Closure for @a cb.
222 */
223 void *cb_cls;
224
225 /**
226 * Connection to the DHT service.
227 */
228 struct GNUNET_DHT_Handle *dht_handle;
229
230};
231
232
233/**
234 * Connection to the DHT service.
235 */
236struct GNUNET_DHT_Handle
237{
238 /**
239 * Configuration to use.
240 */
241 const struct GNUNET_CONFIGURATION_Handle *cfg;
242
243 /**
244 * Connection to DHT service.
245 */
246 struct GNUNET_MQ_Handle *mq;
247
248 /**
249 * Head of linked list of messages we would like to monitor.
250 */
251 struct GNUNET_DHT_MonitorHandle *monitor_head;
252
253 /**
254 * Tail of linked list of messages we would like to monitor.
255 */
256 struct GNUNET_DHT_MonitorHandle *monitor_tail;
257
258 /**
259 * Head of active PUT requests.
260 */
261 struct GNUNET_DHT_PutHandle *put_head;
262
263 /**
264 * Tail of active PUT requests.
265 */
266 struct GNUNET_DHT_PutHandle *put_tail;
267
268 /**
269 * DLL.
270 */
271 struct GNUNET_DHT_HelloGetHandle *hgh_head;
272
273 /**
274 * DLL.
275 */
276 struct GNUNET_DHT_HelloGetHandle *hgh_tail;
277
278 /**
279 * Hash map containing the current outstanding unique GET requests
280 * (values are of type `struct GNUNET_DHT_GetHandle`).
281 */
282 struct GNUNET_CONTAINER_MultiHashMap *active_requests;
283
284 /**
285 * Task for trying to reconnect.
286 */
287 struct GNUNET_SCHEDULER_Task *reconnect_task;
288
289 /**
290 * How quickly should we retry? Used for exponential back-off on
291 * connect-errors.
292 */
293 struct GNUNET_TIME_Relative retry_time;
294
295 /**
296 * Generator for unique ids.
297 */
298 uint64_t uid_gen;
299};
300
301
302/**
303 * Try to (re)connect to the DHT service.
304 *
305 * @param h DHT handle to reconnect
306 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
307 */
308static enum GNUNET_GenericReturnValue
309try_connect (struct GNUNET_DHT_Handle *h);
310
311
312/**
313 * Send GET message for a @a get_handle to DHT.
314 *
315 * @param gh GET to generate messages for.
316 */
317static void
318send_get (struct GNUNET_DHT_GetHandle *gh)
319{
320 struct GNUNET_DHT_Handle *h = gh->dht_handle;
321 struct GNUNET_MQ_Envelope *env;
322 struct GNUNET_DHT_ClientGetMessage *get_msg;
323
324 env = GNUNET_MQ_msg_extra (get_msg,
325 gh->xquery_size,
326 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET);
327 get_msg->options = htonl ((uint32_t) gh->options);
328 get_msg->desired_replication_level = htonl (gh->desired_replication_level);
329 get_msg->type = htonl (gh->type);
330 get_msg->key = gh->key;
331 get_msg->unique_id = gh->unique_id;
332 GNUNET_memcpy (&get_msg[1],
333 &gh[1],
334 gh->xquery_size);
335 GNUNET_MQ_send (h->mq,
336 env);
337}
338
339
340/**
341 * Send GET message(s) for indicating which results are already known
342 * for a @a get_handle to DHT. Complex as we need to send the list of
343 * known results, which means we may need multiple messages to block
344 * known results from the result set.
345 *
346 * @param gh GET to generate messages for
347 * @param transmission_offset_start at which offset should we start?
348 */
349static void
350send_get_known_results (struct GNUNET_DHT_GetHandle *gh,
351 unsigned int transmission_offset_start)
352{
353 struct GNUNET_DHT_Handle *h = gh->dht_handle;
354 struct GNUNET_MQ_Envelope *env;
355 struct GNUNET_DHT_ClientGetResultSeenMessage *msg;
356 unsigned int delta;
357 unsigned int max;
358 unsigned int transmission_offset;
359
360 max = (GNUNET_MAX_MESSAGE_SIZE - sizeof(*msg))
361 / sizeof(struct GNUNET_HashCode);
362 transmission_offset = transmission_offset_start;
363 while (transmission_offset < gh->seen_results_end)
364 {
365 delta = gh->seen_results_end - transmission_offset;
366 if (delta > max)
367 delta = max;
368 env = GNUNET_MQ_msg_extra (msg,
369 delta * sizeof(struct GNUNET_HashCode),
370 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN);
371 msg->key = gh->key;
372 msg->unique_id = gh->unique_id;
373 GNUNET_memcpy (&msg[1],
374 &gh->seen_results[transmission_offset],
375 sizeof(struct GNUNET_HashCode) * delta);
376 GNUNET_MQ_send (h->mq,
377 env);
378 transmission_offset += delta;
379 }
380}
381
382
383/**
384 * Add the GET request corresponding to the given route handle
385 * to the pending queue (if it is not already in there).
386 *
387 * @param cls the `struct GNUNET_DHT_Handle *`
388 * @param key key for the request (not used)
389 * @param value the `struct GNUNET_DHT_GetHandle *`
390 * @return #GNUNET_YES (always)
391 */
392static enum GNUNET_GenericReturnValue
393add_get_request_to_pending (void *cls,
394 const struct GNUNET_HashCode *key,
395 void *value)
396{
397 struct GNUNET_DHT_Handle *handle = cls;
398 struct GNUNET_DHT_GetHandle *gh = value;
399
400 LOG (GNUNET_ERROR_TYPE_DEBUG,
401 "Retransmitting request related to %s to DHT %p\n",
402 GNUNET_h2s (key),
403 handle);
404 send_get (gh);
405 send_get_known_results (gh, 0);
406 return GNUNET_YES;
407}
408
409
410/**
411 * Send #GNUNET_MESSAGE_TYPE_DHT_MONITOR_START message.
412 *
413 * @param mh monitor handle to generate start message for
414 */
415static void
416send_monitor_start (struct GNUNET_DHT_MonitorHandle *mh)
417{
418 struct GNUNET_DHT_Handle *h = mh->dht_handle;
419 struct GNUNET_MQ_Envelope *env;
420 struct GNUNET_DHT_MonitorStartStopMessage *m;
421
422 env = GNUNET_MQ_msg (m,
423 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START);
424 m->type = htonl (mh->type);
425 m->get = htons (NULL != mh->get_cb);
426 m->get_resp = htons (NULL != mh->get_resp_cb);
427 m->put = htons (NULL != mh->put_cb);
428 if (NULL != mh->key)
429 {
430 m->filter_key = htons (1);
431 m->key = *mh->key;
432 }
433 GNUNET_MQ_send (h->mq,
434 env);
435}
436
437
438/**
439 * Try reconnecting to the dht service.
440 *
441 * @param cls a `struct GNUNET_DHT_Handle`
442 */
443static void
444try_reconnect (void *cls)
445{
446 struct GNUNET_DHT_Handle *h = cls;
447 struct GNUNET_DHT_MonitorHandle *mh;
448
449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "Reconnecting with DHT %p\n",
451 h);
452 h->retry_time = GNUNET_TIME_STD_BACKOFF (h->retry_time);
453 h->reconnect_task = NULL;
454 if (GNUNET_YES != try_connect (h))
455 {
456 LOG (GNUNET_ERROR_TYPE_WARNING,
457 "DHT reconnect failed!\n");
458 h->reconnect_task
459 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
460 &try_reconnect,
461 h);
462 return;
463 }
464 GNUNET_CONTAINER_multihashmap_iterate (h->active_requests,
465 &add_get_request_to_pending,
466 h);
467 for (mh = h->monitor_head; NULL != mh; mh = mh->next)
468 send_monitor_start (mh);
469}
470
471
472/**
473 * Try reconnecting to the DHT service.
474 *
475 * @param h handle to dht to (possibly) disconnect and reconnect
476 */
477static void
478do_disconnect (struct GNUNET_DHT_Handle *h)
479{
480 struct GNUNET_DHT_PutHandle *ph;
481 GNUNET_SCHEDULER_TaskCallback cont;
482 void *cont_cls;
483
484 if (NULL == h->mq)
485 return;
486 GNUNET_MQ_destroy (h->mq);
487 h->mq = NULL;
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489 "Disconnecting from DHT service, will try to reconnect in %s\n",
490 GNUNET_STRINGS_relative_time_to_string (h->retry_time,
491 GNUNET_YES));
492 /* notify client about all PUTs that (may) have failed due to disconnect */
493 while (NULL != (ph = h->put_head))
494 {
495 cont = ph->cont;
496 cont_cls = ph->cont_cls;
497 ph->env = NULL;
498 GNUNET_DHT_put_cancel (ph);
499 if (NULL != cont)
500 cont (cont_cls);
501 }
502 GNUNET_assert (NULL == h->reconnect_task);
503 h->reconnect_task
504 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
505 &try_reconnect,
506 h);
507}
508
509
510/**
511 * Generic error handler, called with the appropriate error code and
512 * the same closure specified at the creation of the message queue.
513 * Not every message queue implementation supports an error handler.
514 *
515 * @param cls closure with the `struct GNUNET_DHT_Handle *`
516 * @param error error code
517 */
518static void
519mq_error_handler (void *cls,
520 enum GNUNET_MQ_Error error)
521{
522 struct GNUNET_DHT_Handle *h = cls;
523
524 do_disconnect (h);
525}
526
527
528/**
529 * Verify integrity of a get monitor message from the service.
530 *
531 * @param cls The DHT handle.
532 * @param msg Monitor get message from the service.
533 * @return #GNUNET_OK if everything went fine,
534 * #GNUNET_SYSERR if the message is malformed.
535 */
536static enum GNUNET_GenericReturnValue
537check_monitor_get (void *cls,
538 const struct GNUNET_DHT_MonitorGetMessage *msg)
539{
540 uint32_t plen = ntohl (msg->get_path_length);
541 uint16_t msize = ntohs (msg->header.size) - sizeof(*msg);
542
543 if ((plen > UINT16_MAX) ||
544 (plen * sizeof(struct GNUNET_DHT_PathElement) != msize))
545 {
546 GNUNET_break (0);
547 return GNUNET_SYSERR;
548 }
549 return GNUNET_OK;
550}
551
552
553/**
554 * Process a get monitor message from the service.
555 *
556 * @param cls The DHT handle.
557 * @param msg Monitor get message from the service.
558 */
559static void
560handle_monitor_get (void *cls,
561 const struct GNUNET_DHT_MonitorGetMessage *msg)
562{
563 struct GNUNET_DHT_Handle *handle = cls;
564
565 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
566 NULL != mh;
567 mh = mh->next)
568 {
569 if (NULL == mh->get_cb)
570 continue;
571 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
572 (mh->type == ntohl (msg->type))) &&
573 ((NULL == mh->key) ||
574 (0 == memcmp (mh->key,
575 &msg->key,
576 sizeof(struct GNUNET_HashCode)))))
577 mh->get_cb (mh->cb_cls,
578 ntohl (msg->options),
579 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
580 ntohl (msg->hop_count),
581 ntohl (msg->desired_replication_level),
582 ntohl (msg->get_path_length),
583 (struct GNUNET_DHT_PathElement *) &msg[1],
584 &msg->key);
585 }
586}
587
588
589/**
590 * Validate a get response monitor message from the service.
591 *
592 * @param cls The DHT handle.
593 * @param msg monitor get response message from the service
594 * @return #GNUNET_OK if everything went fine,
595 * #GNUNET_SYSERR if the message is malformed.
596 */
597static enum GNUNET_GenericReturnValue
598check_monitor_get_resp (void *cls,
599 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
600{
601 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
602 uint32_t getl = ntohl (msg->get_path_length);
603 uint32_t putl = ntohl (msg->put_path_length);
604
605 if ((getl + putl < getl) ||
606 ((msize / sizeof(struct GNUNET_DHT_PathElement)) < getl + putl))
607 {
608 GNUNET_break (0);
609 return GNUNET_SYSERR;
610 }
611 return GNUNET_OK;
612}
613
614
615/**
616 * Process a get response monitor message from the service.
617 *
618 * @param cls The DHT handle.
619 * @param msg monitor get response message from the service
620 */
621static void
622handle_monitor_get_resp (void *cls,
623 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
624{
625 struct GNUNET_DHT_Handle *handle = cls;
626 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
627 const struct GNUNET_DHT_PathElement *path;
628 uint32_t getl = ntohl (msg->get_path_length);
629 uint32_t putl = ntohl (msg->put_path_length);
630
631
632 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
633 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
634 NULL != mh;
635 mh = mh->next)
636 {
637 if (NULL == mh->get_resp_cb)
638 continue;
639 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
640 (mh->type == ntohl (msg->type))) &&
641 ((NULL == mh->key) ||
642 (0 == memcmp (mh->key,
643 &msg->key,
644 sizeof(struct GNUNET_HashCode)))))
645 mh->get_resp_cb (mh->cb_cls,
646 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
647 &path[putl],
648 getl,
649 path,
650 putl,
651 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
652 &msg->key,
653 (const void *) &path[getl + putl],
654 msize - sizeof(struct GNUNET_DHT_PathElement) * (putl
655 + getl));
656 }
657}
658
659
660/**
661 * Check validity of a put monitor message from the service.
662 *
663 * @param cls The DHT handle.
664 * @param msg Monitor put message from the service.
665 * @return #GNUNET_OK if everything went fine,
666 * #GNUNET_SYSERR if the message is malformed.
667 */
668static enum GNUNET_GenericReturnValue
669check_monitor_put (void *cls,
670 const struct GNUNET_DHT_MonitorPutMessage *msg)
671{
672 size_t msize;
673 uint32_t putl;
674
675 msize = ntohs (msg->header.size) - sizeof(*msg);
676 putl = ntohl (msg->put_path_length);
677 if ((msize / sizeof(struct GNUNET_DHT_PathElement)) < putl)
678 {
679 GNUNET_break (0);
680 return GNUNET_SYSERR;
681 }
682 return GNUNET_OK;
683}
684
685
686/**
687 * Process a put monitor message from the service.
688 *
689 * @param cls The DHT handle.
690 * @param msg Monitor put message from the service.
691 */
692static void
693handle_monitor_put (void *cls,
694 const struct GNUNET_DHT_MonitorPutMessage *msg)
695{
696 struct GNUNET_DHT_Handle *handle = cls;
697 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
698 uint32_t putl = ntohl (msg->put_path_length);
699 const struct GNUNET_DHT_PathElement *path;
700 struct GNUNET_DHT_MonitorHandle *mh;
701
702 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
703 for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
704 {
705 if (NULL == mh->put_cb)
706 continue;
707 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
708 (mh->type == ntohl (msg->type))) &&
709 ((NULL == mh->key) ||
710 (0 == memcmp (mh->key,
711 &msg->key,
712 sizeof(struct GNUNET_HashCode)))))
713 mh->put_cb (mh->cb_cls,
714 ntohl (msg->options),
715 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
716 ntohl (msg->hop_count),
717 ntohl (msg->desired_replication_level),
718 putl,
719 path,
720 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
721 &msg->key,
722 (const void *) &path[putl],
723 msize - sizeof(struct GNUNET_DHT_PathElement) * putl);
724 }
725}
726
727
728/**
729 * Verify that client result message received from the service is well-formed.
730 *
731 * @param cls The DHT handle.
732 * @param msg Monitor put message from the service.
733 * @return #GNUNET_OK if everything went fine,
734 * #GNUNET_SYSERR if the message is malformed.
735 */
736static enum GNUNET_GenericReturnValue
737check_client_result (void *cls,
738 const struct GNUNET_DHT_ClientResultMessage *msg)
739{
740 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
741 uint32_t put_path_length = ntohl (msg->put_path_length);
742 uint32_t get_path_length = ntohl (msg->get_path_length);
743 size_t meta_length;
744
745 meta_length =
746 sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + put_path_length);
747 if ((msize < meta_length) ||
748 (get_path_length >
749 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
750 (put_path_length >
751 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)))
752 {
753 GNUNET_break (0);
754 return GNUNET_SYSERR;
755 }
756 return GNUNET_OK;
757}
758
759
760/**
761 * Process a given reply that might match the given request.
762 *
763 * @param cls the `struct GNUNET_DHT_ClientResultMessage`
764 * @param key query of the request
765 * @param value the `struct GNUNET_DHT_GetHandle` of a request matching the same key
766 * @return #GNUNET_YES to continue to iterate over all results
767 */
768static enum GNUNET_GenericReturnValue
769process_client_result (void *cls,
770 const struct GNUNET_HashCode *key,
771 void *value)
772{
773 const struct GNUNET_DHT_ClientResultMessage *crm = cls;
774 struct GNUNET_DHT_GetHandle *get_handle = value;
775 size_t msize = ntohs (crm->header.size) - sizeof(*crm);
776 uint16_t type = ntohl (crm->type);
777 uint32_t put_path_length = ntohl (crm->put_path_length);
778 uint32_t get_path_length = ntohl (crm->get_path_length);
779 const struct GNUNET_DHT_PathElement *put_path
780 = (const struct GNUNET_DHT_PathElement *) &crm[1];
781 const struct GNUNET_DHT_PathElement *get_path
782 = &put_path[put_path_length];
783 const void *data
784 = &get_path[get_path_length];
785 size_t meta_length
786 = sizeof(struct GNUNET_DHT_PathElement) * (get_path_length
787 + put_path_length);
788 size_t data_length
789 = msize - meta_length;
790 struct GNUNET_HashCode hc;
791
792 if (crm->unique_id != get_handle->unique_id)
793 {
794 /* UID mismatch */
795 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "Ignoring reply for %s: UID mismatch: %llu/%llu\n",
797 GNUNET_h2s (key),
798 (unsigned long long) crm->unique_id,
799 (unsigned long long) get_handle->unique_id);
800 return GNUNET_YES;
801 }
802 if ( (get_handle->type != GNUNET_BLOCK_TYPE_ANY) &&
803 (get_handle->type != type) )
804 {
805 /* type mismatch */
806 GNUNET_break (0);
807 return GNUNET_YES;
808 }
809
810 {
811 char *pp;
812 char *gp;
813
814 gp = GNUNET_DHT_pp2s (get_path,
815 get_path_length);
816 pp = GNUNET_DHT_pp2s (put_path,
817 put_path_length);
818 LOG (GNUNET_ERROR_TYPE_DEBUG,
819 "Giving %u byte reply for %s to application (GP: %s, PP: %s)\n",
820 (unsigned int) data_length,
821 GNUNET_h2s (key),
822 gp,
823 pp);
824 GNUNET_free (gp);
825 GNUNET_free (pp);
826 }
827 /* remember that we've seen this result */
828 GNUNET_CRYPTO_hash (data,
829 data_length,
830 &hc);
831 if (get_handle->seen_results_size == get_handle->seen_results_end)
832 GNUNET_array_grow (get_handle->seen_results,
833 get_handle->seen_results_size,
834 get_handle->seen_results_size * 2 + 1);
835 get_handle->seen_results[get_handle->seen_results_end++] = hc;
836 /* no need to block it explicitly, service already knows about it! */
837 get_handle->iter (get_handle->iter_cls,
838 GNUNET_TIME_absolute_ntoh (crm->expiration),
839 key,
840 get_path,
841 get_path_length,
842 put_path,
843 put_path_length,
844 type,
845 data_length,
846 data);
847 return GNUNET_YES;
848}
849
850
851/**
852 * Process a client result message received from the service.
853 *
854 * @param cls The DHT handle.
855 * @param msg Monitor put message from the service.
856 */
857static void
858handle_client_result (void *cls,
859 const struct GNUNET_DHT_ClientResultMessage *msg)
860{
861 struct GNUNET_DHT_Handle *handle = cls;
862
863 GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests,
864 &msg->key,
865 &process_client_result,
866 (void *) msg);
867}
868
869
870/**
871 * Process a client HELLO message received from the service.
872 *
873 * @param cls The DHT handle.
874 * @param hdr HELLO URL message from the service.
875 * @return #GNUNET_OK if @a hdr is well-formed
876 */
877static enum GNUNET_GenericReturnValue
878check_client_hello (void *cls,
879 const struct GNUNET_MessageHeader *hdr)
880{
881 uint16_t len = ntohs (hdr->size);
882 const char *buf = (const char *) &hdr[1];
883
884 (void) cls;
885 if ('\0' != buf[len - sizeof (*hdr) - 1])
886 {
887 GNUNET_break (0);
888 return GNUNET_SYSERR;
889 }
890 return GNUNET_OK;
891}
892
893
894/**
895 * Process a client HELLO message received from the service.
896 *
897 * @param cls The DHT handle.
898 * @param hdr HELLO URL message from the service.
899 */
900static void
901handle_client_hello (void *cls,
902 const struct GNUNET_MessageHeader *hdr)
903{
904 struct GNUNET_DHT_Handle *handle = cls;
905 const char *url = (const char *) &hdr[1];
906 struct GNUNET_DHT_HelloGetHandle *hgh;
907
908 while (NULL != (hgh = handle->hgh_head))
909 {
910 hgh->cb (hgh->cb_cls,
911 url);
912 GNUNET_DHT_hello_get_cancel (hgh);
913 }
914}
915
916
917/**
918 * Process a MQ PUT transmission notification.
919 *
920 * @param cls The DHT handle.
921 */
922static void
923handle_put_cont (void *cls)
924{
925 struct GNUNET_DHT_PutHandle *ph = cls;
926 GNUNET_SCHEDULER_TaskCallback cont;
927 void *cont_cls;
928
929 cont = ph->cont;
930 cont_cls = ph->cont_cls;
931 ph->env = NULL;
932 GNUNET_DHT_put_cancel (ph);
933 if (NULL != cont)
934 cont (cont_cls);
935}
936
937
938/**
939 * Try to (re)connect to the DHT service.
940 *
941 * @param h DHT handle to reconnect
942 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
943 */
944static enum GNUNET_GenericReturnValue
945try_connect (struct GNUNET_DHT_Handle *h)
946{
947 struct GNUNET_MQ_MessageHandler handlers[] = {
948 GNUNET_MQ_hd_var_size (monitor_get,
949 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
950 struct GNUNET_DHT_MonitorGetMessage,
951 h),
952 GNUNET_MQ_hd_var_size (monitor_get_resp,
953 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP,
954 struct GNUNET_DHT_MonitorGetRespMessage,
955 h),
956 GNUNET_MQ_hd_var_size (monitor_put,
957 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT,
958 struct GNUNET_DHT_MonitorPutMessage,
959 h),
960 GNUNET_MQ_hd_var_size (client_result,
961 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT,
962 struct GNUNET_DHT_ClientResultMessage,
963 h),
964 GNUNET_MQ_hd_var_size (client_hello,
965 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL,
966 struct GNUNET_MessageHeader,
967 h),
968 GNUNET_MQ_handler_end ()
969 };
970
971 if (NULL != h->mq)
972 return GNUNET_OK;
973 h->mq = GNUNET_CLIENT_connect (h->cfg,
974 "dht",
975 handlers,
976 &mq_error_handler,
977 h);
978 if (NULL == h->mq)
979 {
980 LOG (GNUNET_ERROR_TYPE_WARNING,
981 "Failed to connect to the DHT service!\n");
982 return GNUNET_NO;
983 }
984 return GNUNET_YES;
985}
986
987
988struct GNUNET_DHT_Handle *
989GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
990 unsigned int ht_len)
991{
992 struct GNUNET_DHT_Handle *handle;
993
994 handle = GNUNET_new (struct GNUNET_DHT_Handle);
995 handle->cfg = cfg;
996 handle->uid_gen
997 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
998 UINT64_MAX);
999 handle->active_requests
1000 = GNUNET_CONTAINER_multihashmap_create (ht_len,
1001 GNUNET_YES);
1002 if (GNUNET_NO == try_connect (handle))
1003 {
1004 GNUNET_DHT_disconnect (handle);
1005 return NULL;
1006 }
1007 return handle;
1008}
1009
1010
1011void
1012GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle)
1013{
1014 struct GNUNET_DHT_PutHandle *ph;
1015
1016 GNUNET_assert (0 ==
1017 GNUNET_CONTAINER_multihashmap_size (handle->active_requests));
1018 while (NULL != (ph = handle->put_head))
1019 {
1020 if (NULL != ph->cont)
1021 ph->cont (ph->cont_cls);
1022 GNUNET_DHT_put_cancel (ph);
1023 }
1024 if (NULL != handle->mq)
1025 {
1026 GNUNET_MQ_destroy (handle->mq);
1027 handle->mq = NULL;
1028 }
1029 if (NULL != handle->reconnect_task)
1030 {
1031 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1032 handle->reconnect_task = NULL;
1033 }
1034 GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests);
1035 GNUNET_free (handle);
1036}
1037
1038
1039struct GNUNET_DHT_PutHandle *
1040GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
1041 const struct GNUNET_HashCode *key,
1042 uint32_t desired_replication_level,
1043 enum GNUNET_DHT_RouteOption options,
1044 enum GNUNET_BLOCK_Type type,
1045 size_t size,
1046 const void *data,
1047 struct GNUNET_TIME_Absolute exp,
1048 GNUNET_SCHEDULER_TaskCallback cont,
1049 void *cont_cls)
1050{
1051 struct GNUNET_MQ_Envelope *env;
1052 struct GNUNET_DHT_ClientPutMessage *put_msg;
1053 size_t msize;
1054 struct GNUNET_DHT_PutHandle *ph;
1055
1056 msize = sizeof(struct GNUNET_DHT_ClientPutMessage) + size;
1057 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1058 (size >= GNUNET_MAX_MESSAGE_SIZE))
1059 {
1060 GNUNET_break (0);
1061 return NULL;
1062 }
1063 if (NULL == handle->mq)
1064 return NULL;
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Sending PUT for %s to DHT via %p\n",
1067 GNUNET_h2s (key),
1068 handle);
1069 ph = GNUNET_new (struct GNUNET_DHT_PutHandle);
1070 ph->dht_handle = handle;
1071 ph->cont = cont;
1072 ph->cont_cls = cont_cls;
1073 GNUNET_CONTAINER_DLL_insert_tail (handle->put_head,
1074 handle->put_tail,
1075 ph);
1076 env = GNUNET_MQ_msg_extra (put_msg,
1077 size,
1078 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT);
1079 GNUNET_MQ_notify_sent (env,
1080 &handle_put_cont,
1081 ph);
1082 ph->env = env;
1083 put_msg->type = htonl ((uint32_t) type);
1084 put_msg->options = htonl ((uint32_t) options);
1085 put_msg->desired_replication_level = htonl (desired_replication_level);
1086 put_msg->expiration = GNUNET_TIME_absolute_hton (exp);
1087 put_msg->key = *key;
1088 GNUNET_memcpy (&put_msg[1],
1089 data,
1090 size);
1091 GNUNET_MQ_send (handle->mq,
1092 env);
1093 return ph;
1094}
1095
1096
1097void
1098GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph)
1099{
1100 struct GNUNET_DHT_Handle *handle = ph->dht_handle;
1101
1102 if (NULL != ph->env)
1103 GNUNET_MQ_notify_sent (ph->env,
1104 NULL,
1105 NULL);
1106 GNUNET_CONTAINER_DLL_remove (handle->put_head,
1107 handle->put_tail,
1108 ph);
1109 GNUNET_free (ph);
1110}
1111
1112
1113struct GNUNET_DHT_GetHandle *
1114GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1115 enum GNUNET_BLOCK_Type type,
1116 const struct GNUNET_HashCode *key,
1117 uint32_t desired_replication_level,
1118 enum GNUNET_DHT_RouteOption options,
1119 const void *xquery,
1120 size_t xquery_size,
1121 GNUNET_DHT_GetIterator iter,
1122 void *iter_cls)
1123{
1124 struct GNUNET_DHT_GetHandle *gh;
1125 size_t msize;
1126
1127 msize = sizeof(struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1128 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1129 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1130 {
1131 GNUNET_break (0);
1132 return NULL;
1133 }
1134 LOG (GNUNET_ERROR_TYPE_DEBUG,
1135 "Sending query for %s to DHT %p\n",
1136 GNUNET_h2s (key),
1137 handle);
1138 gh = GNUNET_malloc (sizeof(struct GNUNET_DHT_GetHandle)
1139 + xquery_size);
1140 gh->iter = iter;
1141 gh->iter_cls = iter_cls;
1142 gh->dht_handle = handle;
1143 gh->key = *key;
1144 gh->unique_id = ++handle->uid_gen;
1145 gh->xquery_size = xquery_size;
1146 gh->desired_replication_level = desired_replication_level;
1147 gh->type = type;
1148 gh->options = options;
1149 GNUNET_memcpy (&gh[1],
1150 xquery,
1151 xquery_size);
1152 GNUNET_CONTAINER_multihashmap_put (handle->active_requests,
1153 &gh->key,
1154 gh,
1155 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1156 if (NULL != handle->mq)
1157 send_get (gh);
1158 return gh;
1159}
1160
1161
1162void
1163GNUNET_DHT_get_filter_known_results (struct GNUNET_DHT_GetHandle *get_handle,
1164 unsigned int num_results,
1165 const struct GNUNET_HashCode *results)
1166{
1167 unsigned int needed;
1168 unsigned int had;
1169
1170 had = get_handle->seen_results_end;
1171 needed = had + num_results;
1172 if (needed > get_handle->seen_results_size)
1173 GNUNET_array_grow (get_handle->seen_results,
1174 get_handle->seen_results_size,
1175 needed);
1176 GNUNET_memcpy (&get_handle->seen_results[get_handle->seen_results_end],
1177 results,
1178 num_results * sizeof(struct GNUNET_HashCode));
1179 get_handle->seen_results_end += num_results;
1180 if (NULL != get_handle->dht_handle->mq)
1181 send_get_known_results (get_handle,
1182 had);
1183}
1184
1185
1186void
1187GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle)
1188{
1189 struct GNUNET_DHT_Handle *handle = get_handle->dht_handle;
1190
1191 LOG (GNUNET_ERROR_TYPE_DEBUG,
1192 "Sending STOP for %s to DHT via %p\n",
1193 GNUNET_h2s (&get_handle->key),
1194 handle);
1195 if (NULL != handle->mq)
1196 {
1197 struct GNUNET_MQ_Envelope *env;
1198 struct GNUNET_DHT_ClientGetStopMessage *stop_msg;
1199
1200 env = GNUNET_MQ_msg (stop_msg,
1201 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP);
1202 stop_msg->reserved = htonl (0);
1203 stop_msg->unique_id = get_handle->unique_id;
1204 stop_msg->key = get_handle->key;
1205 GNUNET_MQ_send (handle->mq,
1206 env);
1207 }
1208 GNUNET_assert (GNUNET_YES ==
1209 GNUNET_CONTAINER_multihashmap_remove (handle->active_requests,
1210 &get_handle->key,
1211 get_handle));
1212 GNUNET_array_grow (get_handle->seen_results,
1213 get_handle->seen_results_end,
1214 0);
1215 GNUNET_free (get_handle);
1216}
1217
1218
1219struct GNUNET_DHT_MonitorHandle *
1220GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle,
1221 enum GNUNET_BLOCK_Type type,
1222 const struct GNUNET_HashCode *key,
1223 GNUNET_DHT_MonitorGetCB get_cb,
1224 GNUNET_DHT_MonitorGetRespCB get_resp_cb,
1225 GNUNET_DHT_MonitorPutCB put_cb,
1226 void *cb_cls)
1227{
1228 struct GNUNET_DHT_MonitorHandle *mh;
1229
1230 mh = GNUNET_new (struct GNUNET_DHT_MonitorHandle);
1231 mh->get_cb = get_cb;
1232 mh->get_resp_cb = get_resp_cb;
1233 mh->put_cb = put_cb;
1234 mh->cb_cls = cb_cls;
1235 mh->type = type;
1236 mh->dht_handle = handle;
1237 if (NULL != key)
1238 {
1239 mh->key = GNUNET_new (struct GNUNET_HashCode);
1240 *mh->key = *key;
1241 }
1242 GNUNET_CONTAINER_DLL_insert (handle->monitor_head,
1243 handle->monitor_tail,
1244 mh);
1245 if (NULL != handle->mq)
1246 send_monitor_start (mh);
1247 return mh;
1248}
1249
1250
1251void
1252GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *mh)
1253{
1254 struct GNUNET_DHT_Handle *handle = mh->dht_handle;
1255 struct GNUNET_DHT_MonitorStartStopMessage *m;
1256 struct GNUNET_MQ_Envelope *env;
1257
1258 GNUNET_CONTAINER_DLL_remove (handle->monitor_head,
1259 handle->monitor_tail,
1260 mh);
1261 env = GNUNET_MQ_msg (m,
1262 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP);
1263 m->type = htonl (mh->type);
1264 m->get = htons (NULL != mh->get_cb);
1265 m->get_resp = htons (NULL != mh->get_resp_cb);
1266 m->put = htons (NULL != mh->put_cb);
1267 if (NULL != mh->key)
1268 {
1269 m->filter_key = htons (1);
1270 m->key = *mh->key;
1271 }
1272 GNUNET_MQ_send (handle->mq,
1273 env);
1274 GNUNET_free (mh->key);
1275 GNUNET_free (mh);
1276}
1277
1278
1279char *
1280GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement *path,
1281 unsigned int path_len)
1282{
1283 char *buf;
1284 size_t off;
1285 size_t plen = path_len * 5 + 1;
1286
1287 GNUNET_assert (path_len < UINT32_MAX / 5);
1288 off = 0;
1289 buf = GNUNET_malloc (plen);
1290 for (unsigned int i = 0; i < path_len; i++)
1291 {
1292 off += GNUNET_snprintf (&buf[off],
1293 plen - off,
1294 "%s%s",
1295 GNUNET_i2s (&path[i].pred),
1296 (i == path_len - 1) ? "" : "-");
1297 }
1298 return buf;
1299}
1300
1301
1302unsigned int
1303GNUNET_DHT_verify_path (const void *data,
1304 size_t data_size,
1305 struct GNUNET_TIME_Absolute exp_time,
1306 const struct GNUNET_DHT_PathElement *put_path,
1307 unsigned int put_path_len,
1308 const struct GNUNET_DHT_PathElement *get_path,
1309 unsigned int get_path_len,
1310 const struct GNUNET_PeerIdentity *me)
1311{
1312 struct GNUNET_DHT_HopSignature hs = {
1313 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
1314 .purpose.size = htonl (sizeof (hs)),
1315 .expiration_time = GNUNET_TIME_absolute_hton (exp_time)
1316 };
1317 const struct GNUNET_PeerIdentity *pred;
1318 const struct GNUNET_PeerIdentity *succ;
1319 unsigned int i;
1320
1321 if (0 == get_path_len + put_path_len)
1322 return 0;
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "%s is verifying signatures with GPL: %u PPL: %u!\n",
1325 GNUNET_i2s (me),
1326 get_path_len,
1327 put_path_len);
1328 for (unsigned int j = 0; j<put_path_len; j++)
1329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1330 "PP%u=%s\n",
1331 j,
1332 GNUNET_i2s (&put_path[j].pred));
1333 for (unsigned int j = 0; j<get_path_len; j++)
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1335 "GP%u=%s\n",
1336 j,
1337 GNUNET_i2s (&get_path[j].pred));
1338
1339 i = put_path_len + get_path_len - 1;
1340 GNUNET_CRYPTO_hash (data,
1341 data_size,
1342 &hs.h_data);
1343 while (i > 0)
1344 {
1345 pred = (i - 1 >= put_path_len)
1346 ? &get_path[i - put_path_len - 1].pred
1347 : &put_path[i - 1].pred;
1348 if (i + 1 == get_path_len + put_path_len)
1349 succ = me;
1350 else
1351 succ = (i + 1 >= put_path_len)
1352 ? &get_path[i + 1 - put_path_len].pred
1353 : &put_path[i + 1].pred;
1354 hs.pred = *pred;
1355 hs.succ = *succ;
1356 if (GNUNET_OK !=
1357 GNUNET_CRYPTO_eddsa_verify (
1358 GNUNET_SIGNATURE_PURPOSE_DHT_HOP,
1359 &hs,
1360 (i - 1 >= put_path_len)
1361 ? &get_path[i - put_path_len - 1].sig
1362 : &put_path[i - 1].sig,
1363 (i >= put_path_len)
1364 ? &get_path[i - put_path_len].pred.public_key
1365 : &put_path[i].pred.public_key))
1366 {
1367 GNUNET_break_op (0);
1368 return i;
1369 }
1370 i--;
1371 }
1372 return i;
1373}
1374
1375
1376struct GNUNET_DHT_HelloGetHandle *
1377GNUNET_DHT_hello_get (struct GNUNET_DHT_Handle *dht_handle,
1378 GNUNET_DHT_HelloGetCallback cb,
1379 void *cb_cls)
1380{
1381 struct GNUNET_DHT_HelloGetHandle *hgh;
1382 struct GNUNET_MessageHeader *hdr;
1383 struct GNUNET_MQ_Envelope *env;
1384
1385 hgh = GNUNET_new (struct GNUNET_DHT_HelloGetHandle);
1386 hgh->cb = cb;
1387 hgh->cb_cls = cb_cls;
1388 hgh->dht_handle = dht_handle;
1389 GNUNET_CONTAINER_DLL_insert (dht_handle->hgh_head,
1390 dht_handle->hgh_tail,
1391 hgh);
1392 env = GNUNET_MQ_msg (hdr,
1393 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_GET);
1394 GNUNET_MQ_send (dht_handle->mq,
1395 env);
1396 return hgh;
1397}
1398
1399
1400void
1401GNUNET_DHT_hello_get_cancel (struct GNUNET_DHT_HelloGetHandle *hgh)
1402{
1403 struct GNUNET_DHT_Handle *dht_handle = hgh->dht_handle;
1404
1405 GNUNET_CONTAINER_DLL_remove (dht_handle->hgh_head,
1406 dht_handle->hgh_tail,
1407 hgh);
1408 GNUNET_free (hgh);
1409}
1410
1411
1412void
1413GNUNET_DHT_hello_offer (struct GNUNET_DHT_Handle *dht_handle,
1414 const char *url,
1415 GNUNET_SCHEDULER_TaskCallback cb,
1416 void *cb_cls)
1417{
1418 struct GNUNET_MessageHeader *hdr;
1419 size_t slen = strlen (url) + 1;
1420 struct GNUNET_MQ_Envelope *env;
1421
1422 env = GNUNET_MQ_msg_extra (hdr,
1423 slen,
1424 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL);
1425 memcpy (&hdr[1],
1426 url,
1427 slen);
1428 GNUNET_MQ_notify_sent (env,
1429 cb,
1430 cb_cls);
1431 GNUNET_MQ_send (dht_handle->mq,
1432 env);
1433}
1434
1435
1436/* 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/dhtu_testbed_connect.sh b/src/dht/dhtu_testbed_connect.sh
deleted file mode 100755
index 871e9eb1b..000000000
--- a/src/dht/dhtu_testbed_connect.sh
+++ /dev/null
@@ -1,31 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3
4# Helper script for dhtu_testbed_deploy.sh.
5# Do not invoke directly.
6
7n=$1
8CFG="/tmp/deployment/${n}.conf"
9HELLO=`gnunet-dht-hello -c $CFG`
10
11# Create dense topology:
12#for OFF in `seq 1 $MAX`
13#do
14# TCFG="/tmp/deployment/${OFF}.conf"
15# gnunet-dht-hello -c $TCFG $HELLO
16#done
17#exit 0
18
19# Create sparse topology:
20R=1
21while test `expr $R \* $R \* $R` -lt $MAX
22do
23 END=`expr $R \* $R`
24 for M in `seq $R $R $END`
25 do
26 OFF=`expr \( $n + $M \) % $MAX`
27 TCFG="/tmp/deployment/${OFF}.conf"
28 gnunet-dht-hello -c $TCFG $HELLO
29 done
30 R=`expr $R + 1`
31done
diff --git a/src/dht/dhtu_testbed_deploy.conf b/src/dht/dhtu_testbed_deploy.conf
deleted file mode 100644
index 59d69894a..000000000
--- a/src/dht/dhtu_testbed_deploy.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1# This file is in the public domain.
2
3# Simple configuration template to deploy a DHT testbed
4# with peers using the IP underlay.
5
6[paths]
7GNUNET_DATA_HOME=/tmp/%N%
8
9[dht]
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-dht-%N%.sock
11
12[dhtu-ip]
13ENABLED = YES
14NSE = 10
15UDP_PORT = %N%
16
17[dhtu-gnunet]
18ENABLED = NO
19
20[statistics]
21DISABLE = YES
22
23[dhtcache]
24DATABASE = heap
25QUOTA = 50 MB
26DISABLE_BF_RC = YES
diff --git a/src/dht/dhtu_testbed_deploy.sh b/src/dht/dhtu_testbed_deploy.sh
deleted file mode 100755
index 5a7fdde15..000000000
--- a/src/dht/dhtu_testbed_deploy.sh
+++ /dev/null
@@ -1,84 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3
4# We will use UDP ports above this number.
5MINPORT=10000
6
7# Cleanup to run whenever we exit
8function cleanup()
9{
10 for n in `jobs -p`
11 do
12 kill $n 2> /dev/null || true
13 done
14 wait
15}
16
17# Install cleanup handler (except for kill -9)
18trap cleanup EXIT
19
20if test -z "$1"
21then
22 echo "Call with the number of peers to launch."
23 exit 1
24fi
25
26if test ! -x `which parallel`
27then
28 echo "This script requires GNU parallel"
29 exit 1
30fi
31
32if test ! -x `which gnunet-service-dht`
33then
34 echo "This script requires gnunet-service-dht in \$PATH"
35 exit 1
36fi
37
38if test ! -x `which gnunet-dht-hello`
39then
40 echo "This script requires gnunet-dht-hello in \$PATH"
41 exit 1
42fi
43
44MAX=`expr $1 - 1`
45
46export GNUNET_FORCE_LOG="dht*;;;;DEBUG"
47
48echo -n "Starting $1 peers "
49mkdir -p /tmp/deployment
50for n in `seq 0 $MAX`
51do
52 PORT=`expr $MINPORT + $n`
53 CFG="/tmp/deployment/${n}.conf"
54 cat dhtu_testbed_deploy.conf | sed -e "s/%N%/$PORT/" > $CFG
55 gnunet-service-dht -c $CFG &> /tmp/deployment/$n.log &
56 echo -n "."
57done
58
59echo ""
60echo "$1 peers ready".
61
62unset GNUNET_FORCE_LOG
63
64function connect()
65{
66 n=$1
67}
68
69echo -n "Connecting peers ..."
70
71export MAX
72if test 0 != $MAX
73then
74 seq 0 $MAX | parallel ./dhtu_testbed_connect.sh :::
75fi
76
77
78echo ""
79echo "Network ready. Press ENTER to terminate the testbed!"
80echo "Interact with peers using '-c /tmp/deployment/\$N.conf'"
81
82read
83
84exit 0
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
deleted file mode 100644
index 42ffe75ba..000000000
--- a/src/dht/gnunet-dht-get.c
+++ /dev/null
@@ -1,324 +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 * Use #GNUNET_DHT_RO_RECORD_ROUTE.
62 */
63static int record_route;
64
65/**
66 * Handle to the DHT
67 */
68static struct GNUNET_DHT_Handle *dht_handle;
69
70/**
71 * Global handle of the configuration
72 */
73static const struct GNUNET_CONFIGURATION_Handle *cfg;
74
75/**
76 * Handle for the get request
77 */
78static struct GNUNET_DHT_GetHandle *get_handle;
79
80/**
81 * Count of results found
82 */
83static unsigned int result_count;
84
85/**
86 * Global status value
87 */
88static int ret;
89
90/**
91 * Task scheduled to handle timeout.
92 */
93static struct GNUNET_SCHEDULER_Task *tt;
94
95
96/**
97 * Task run to clean up on shutdown.
98 *
99 * @param cls unused
100 */
101static void
102cleanup_task (void *cls)
103{
104 if (NULL != get_handle)
105 {
106 GNUNET_DHT_get_stop (get_handle);
107 get_handle = NULL;
108 }
109 if (NULL != dht_handle)
110 {
111 GNUNET_DHT_disconnect (dht_handle);
112 dht_handle = NULL;
113 }
114 if (NULL != tt)
115 {
116 GNUNET_SCHEDULER_cancel (tt);
117 tt = NULL;
118 }
119}
120
121
122/**
123 * Task run on timeout. Triggers shutdown.
124 *
125 * @param cls unused
126 */
127static void
128timeout_task (void *cls)
129{
130 tt = NULL;
131 GNUNET_SCHEDULER_shutdown ();
132}
133
134
135/**
136 * Iterator called on each result obtained for a DHT
137 * operation that expects a reply
138 *
139 * @param cls closure
140 * @param exp when will this value expire
141 * @param key key of the result
142 * @param get_path peers on reply path (or NULL if not recorded)
143 * @param get_path_length number of entries in get_path
144 * @param put_path peers on the PUT path (or NULL if not recorded)
145 * @param put_path_length number of entries in get_path
146 * @param type type of the result
147 * @param size number of bytes in data
148 * @param data pointer to the result data
149 */
150static void
151get_result_iterator (void *cls,
152 struct GNUNET_TIME_Absolute exp,
153 const struct GNUNET_HashCode *key,
154 const struct GNUNET_DHT_PathElement *get_path,
155 unsigned int get_path_length,
156 const struct GNUNET_DHT_PathElement *put_path,
157 unsigned int put_path_length,
158 enum GNUNET_BLOCK_Type type,
159 size_t size,
160 const void *data)
161{
162 fprintf (stdout,
163 (GNUNET_BLOCK_TYPE_TEST == type)
164 ? _ ("Result %d, type %d:\n%.*s\n")
165 : _ ("Result %d, type %d:\n"),
166 result_count,
167 type,
168 (int) size,
169 (char *) data);
170 if (record_route && verbose)
171 {
172 fprintf (stdout,
173 " GET path: ");
174 for (unsigned int i = 0; i < get_path_length; i++)
175 fprintf (stdout,
176 "%s%s",
177 (0 == i) ? "" : "-",
178 GNUNET_i2s (&get_path[i].pred));
179 fprintf (stdout,
180 "\n PUT path: ");
181 for (unsigned int i = 0; i < put_path_length; i++)
182 fprintf (stdout,
183 "%s%s",
184 (0 == i) ? "" : "-",
185 GNUNET_i2s (&put_path[i].pred));
186 fprintf (stdout,
187 "\n");
188 }
189 result_count++;
190}
191
192
193/**
194 * Main function that will be run by the scheduler.
195 *
196 * @param cls closure
197 * @param args remaining command-line arguments
198 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
199 * @param c configuration
200 */
201static void
202run (void *cls,
203 char *const *args,
204 const char *cfgfile,
205 const struct GNUNET_CONFIGURATION_Handle *c)
206{
207 struct GNUNET_HashCode key;
208 enum GNUNET_DHT_RouteOption ro;
209
210 cfg = c;
211 if (NULL == query_key)
212 {
213 fprintf (stderr,
214 "%s",
215 _ ("Must provide key for DHT GET!\n"));
216 ret = 1;
217 return;
218 }
219 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg, 1)))
220 {
221 fprintf (stderr,
222 "%s",
223 _ ("Failed to connect to DHT service!\n"));
224 ret = 1;
225 return;
226 }
227 if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */
228 query_type = GNUNET_BLOCK_TYPE_TEST;
229 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
230 if (verbose)
231 fprintf (stderr,
232 "%s `%s' \n",
233 _ ("Issuing DHT GET with key"),
234 GNUNET_h2s_full (&key));
235 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
236 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, &timeout_task, NULL);
237 ro = GNUNET_DHT_RO_NONE;
238 if (demultixplex_everywhere)
239 ro |= GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
240 if (record_route)
241 ro |= GNUNET_DHT_RO_RECORD_ROUTE;
242 get_handle = GNUNET_DHT_get_start (dht_handle,
243 query_type,
244 &key,
245 replication,
246 ro,
247 NULL,
248 0,
249 &get_result_iterator,
250 NULL);
251}
252
253
254/**
255 * Entry point for gnunet-dht-get
256 *
257 * @param argc number of arguments from the command line
258 * @param argv command line arguments
259 * @return 0 ok, 1 on error
260 */
261int
262main (int argc, char *const *argv)
263{
264 struct GNUNET_GETOPT_CommandLineOption options[] = {
265 GNUNET_GETOPT_option_string (
266 'k',
267 "key",
268 "KEY",
269 gettext_noop ("the query key"),
270 &query_key),
271 GNUNET_GETOPT_option_uint (
272 'r',
273 "replication",
274 "LEVEL",
275 gettext_noop ("how many parallel requests (replicas) to create"),
276 &replication),
277 GNUNET_GETOPT_option_flag (
278 'R',
279 "record",
280 gettext_noop ("use DHT's record route option"),
281 &record_route),
282 GNUNET_GETOPT_option_uint (
283 't',
284 "type",
285 "TYPE",
286 gettext_noop ("the type of data to look for"),
287 &query_type),
288 GNUNET_GETOPT_option_relative_time (
289 'T',
290 "timeout",
291 "TIMEOUT",
292 gettext_noop ("how long to execute this query before giving up?"),
293 &timeout_request),
294 GNUNET_GETOPT_option_flag (
295 'x',
296 "demultiplex",
297 gettext_noop (
298 "use DHT's demultiplex everywhere option"),
299 &demultixplex_everywhere),
300 GNUNET_GETOPT_option_verbose (&verbose),
301 GNUNET_GETOPT_OPTION_END
302 };
303
304
305 if (GNUNET_OK !=
306 GNUNET_STRINGS_get_utf8_args (argc, argv,
307 &argc, &argv))
308 return 2;
309 return (GNUNET_OK ==
310 GNUNET_PROGRAM_run (
311 argc,
312 argv,
313 "gnunet-dht-get",
314 gettext_noop (
315 "Issue a GET request to the GNUnet DHT, prints results."),
316 options,
317 &run,
318 NULL))
319 ? ret
320 : 1;
321}
322
323
324/* end of gnunet-dht-get.c */
diff --git a/src/dht/gnunet-dht-hello.c b/src/dht/gnunet-dht-hello.c
deleted file mode 100644
index 369ed5643..000000000
--- a/src/dht/gnunet-dht-hello.c
+++ /dev/null
@@ -1,178 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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-hello.c
22 * @brief Obtain HELLO from DHT for bootstrapping
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_dht_service.h"
27
28#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
29
30/**
31 * Handle to the DHT
32 */
33static struct GNUNET_DHT_Handle *dht_handle;
34
35/**
36 * Handle to the DHT hello get operation.
37 */
38static struct GNUNET_DHT_HelloGetHandle *get_hello_handle;
39
40/**
41 * Global status value
42 */
43static int global_ret;
44
45
46/**
47 * Task run to clean up on shutdown.
48 *
49 * @param cls unused
50 */
51static void
52cleanup_task (void *cls)
53{
54 if (NULL != get_hello_handle)
55 {
56 GNUNET_DHT_hello_get_cancel (get_hello_handle);
57 get_hello_handle = NULL;
58 }
59 if (NULL != dht_handle)
60 {
61 GNUNET_DHT_disconnect (dht_handle);
62 dht_handle = NULL;
63 }
64}
65
66
67/**
68 * Task run when we are finished. Triggers shutdown.
69 *
70 * @param cls unused
71 */
72static void
73hello_done_cb (void *cls)
74{
75 GNUNET_SCHEDULER_shutdown ();
76}
77
78
79/**
80 * Function called on our HELLO.
81 *
82 * @param cls closure
83 * @param url the HELLO URL
84 */
85static void
86hello_result_cb (void *cls,
87 const char *url)
88{
89 get_hello_handle = NULL;
90 fprintf (stdout,
91 "%s\n",
92 url);
93 GNUNET_SCHEDULER_shutdown ();
94}
95
96
97/**
98 * Main function that will be run by the scheduler.
99 *
100 * @param cls closure, NULL
101 * @param args remaining command-line arguments
102 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
103 * @param cfg configuration
104 */
105static void
106run (void *cls,
107 char *const *args,
108 const char *cfgfile,
109 const struct GNUNET_CONFIGURATION_Handle *cfg)
110{
111 (void) cls;
112 (void) cfgfile;
113 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
114 NULL);
115 if (NULL == (dht_handle = GNUNET_DHT_connect (cfg,
116 1)))
117 {
118 fprintf (stderr,
119 _ ("Failed to connect to DHT service!\n"));
120 global_ret = EXIT_NOTCONFIGURED;
121 GNUNET_SCHEDULER_shutdown ();
122 return;
123 }
124 if (NULL == args[0])
125 {
126 get_hello_handle = GNUNET_DHT_hello_get (dht_handle,
127 &hello_result_cb,
128 NULL);
129 GNUNET_break (NULL != get_hello_handle);
130 }
131 else
132 {
133 GNUNET_DHT_hello_offer (dht_handle,
134 args[0],
135 &hello_done_cb,
136 NULL);
137 }
138}
139
140
141/**
142 * Entry point for gnunet-dht-hello
143 *
144 * @param argc number of arguments from the command line
145 * @param argv command line arguments
146 * @return 0 ok, 1 on error
147 */
148int
149main (int argc,
150 char *const *argv)
151{
152 struct GNUNET_GETOPT_CommandLineOption options[] = {
153 GNUNET_GETOPT_OPTION_END
154 };
155 enum GNUNET_GenericReturnValue iret;
156
157 if (GNUNET_OK !=
158 GNUNET_STRINGS_get_utf8_args (argc, argv,
159 &argc, &argv))
160 return 2;
161 iret = GNUNET_PROGRAM_run (
162 argc,
163 argv,
164 "gnunet-dht-hello [URL]",
165 gettext_noop (
166 "Obtain HELLO from DHT or provide HELLO to DHT for bootstrapping"),
167 options,
168 &run,
169 NULL);
170 if (GNUNET_SYSERR == iret)
171 return EXIT_FAILURE;
172 if (GNUNET_NO == iret)
173 return EXIT_SUCCESS;
174 return global_ret;
175}
176
177
178/* end of gnunet-dht-hello.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 39433791d..000000000
--- a/src/dht/gnunet-service-dht.c
+++ /dev/null
@@ -1,543 +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_hello_lib.h"
31#include "gnunet_hello_uri_lib.h"
32#include "gnunet_dht_service.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet-service-dht.h"
35#include "gnunet-service-dht_datacache.h"
36#include "gnunet-service-dht_neighbours.h"
37#include "gnunet-service-dht_routing.h"
38
39/**
40 * How often do we broadcast our HELLO to neighbours if
41 * nothing special happens?
42 */
43#define HELLO_FREQUENCY GNUNET_TIME_UNIT_HOURS
44
45
46/**
47 * Information we keep per underlay.
48 */
49struct GDS_Underlay
50{
51
52 /**
53 * Kept in a DLL.
54 */
55 struct GDS_Underlay *next;
56
57 /**
58 * Kept in a DLL.
59 */
60 struct GDS_Underlay *prev;
61
62 /**
63 * Environment for this underlay.
64 */
65 struct GNUNET_DHTU_PluginEnvironment env;
66
67 /**
68 * Underlay API handle.
69 */
70 struct GNUNET_DHTU_PluginFunctions *dhtu;
71
72 /**
73 * current network size estimate for this underlay.
74 */
75 double network_size_estimate;
76
77 /**
78 * Name of the underlay (i.e. "gnunet" or "ip").
79 */
80 char *name;
81
82 /**
83 * Name of the library providing the underlay.
84 */
85 char *libname;
86};
87
88
89/**
90 * An address of this peer.
91 */
92struct MyAddress
93{
94 /**
95 * Kept in a DLL.
96 */
97 struct MyAddress *next;
98
99 /**
100 * Kept in a DLL.
101 */
102 struct MyAddress *prev;
103
104 /**
105 * Underlay handle for the address.
106 */
107 struct GNUNET_DHTU_Source *source;
108
109 /**
110 * Textual representation of the address.
111 */
112 char *url;
113
114 /**
115 * Underlay of this address.
116 */
117 struct GDS_Underlay *u;
118};
119
120
121/**
122 * Our HELLO
123 */
124struct GNUNET_HELLO_Builder *GDS_my_hello;
125
126/**
127 * Identity of this peer.
128 */
129struct GNUNET_PeerIdentity GDS_my_identity;
130
131/**
132 * Hash of the identity of this peer.
133 */
134struct GNUNET_HashCode GDS_my_identity_hash;
135
136/**
137 * Our private key.
138 */
139struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key;
140
141/**
142 * Task broadcasting our HELLO.
143 */
144static struct GNUNET_SCHEDULER_Task *hello_task;
145
146/**
147 * Handles for the DHT underlays.
148 */
149static struct GDS_Underlay *u_head;
150
151/**
152 * Handles for the DHT underlays.
153 */
154static struct GDS_Underlay *u_tail;
155
156/**
157 * Head of addresses of this peer.
158 */
159static struct MyAddress *a_head;
160
161/**
162 * Tail of addresses of this peer.
163 */
164static struct MyAddress *a_tail;
165
166/**
167 * log of the current network size estimate, used as the point where
168 * we switch between random and deterministic routing.
169 */
170static double log_of_network_size_estimate;
171
172
173/**
174 * Callback that is called when network size estimate is updated.
175 *
176 * @param cls a `struct GDS_Underlay`
177 * @param timestamp time when the estimate was received from the server (or created by the server)
178 * @param logestimate the log(Base 2) value of the current network size estimate
179 * @param std_dev standard deviation for the estimate
180 *
181 */
182static void
183update_network_size_estimate (void *cls,
184 struct GNUNET_TIME_Absolute timestamp,
185 double logestimate,
186 double std_dev)
187{
188 struct GDS_Underlay *u = cls;
189 double sum = 0.0;
190
191 GNUNET_STATISTICS_update (GDS_stats,
192 "# Network size estimates received",
193 1,
194 GNUNET_NO);
195 /* do not allow estimates < 0.5 */
196 u->network_size_estimate = pow (2.0,
197 GNUNET_MAX (0.5,
198 logestimate));
199 for (struct GDS_Underlay *p = u_head; NULL != p; p = p->next)
200 sum += p->network_size_estimate;
201 if (sum <= 2.0)
202 log_of_network_size_estimate = 0.5;
203 else
204 log_of_network_size_estimate = log2 (sum);
205}
206
207
208/**
209 * Return the current NSE
210 *
211 * @return the current NSE as a logarithm
212 */
213double
214GDS_NSE_get (void)
215{
216 return log_of_network_size_estimate;
217}
218
219
220#include "gnunet-service-dht_clients.c"
221
222
223/**
224 * Task run periodically to broadcast our HELLO.
225 *
226 * @param cls NULL
227 */
228static void
229broadcast_hello (void *cls)
230{
231 struct GNUNET_MessageHeader *hello;
232
233 (void) cls;
234 /* TODO: randomize! */
235 hello_task = GNUNET_SCHEDULER_add_delayed (HELLO_FREQUENCY,
236 &broadcast_hello,
237 NULL);
238 hello = GNUNET_HELLO_builder_to_dht_hello_msg (GDS_my_hello,
239 &GDS_my_private_key);
240 if (NULL == hello)
241 {
242 GNUNET_break (0);
243 return;
244 }
245 GDS_NEIGHBOURS_broadcast (hello);
246 GNUNET_free (hello);
247}
248
249
250/**
251 * Function to call with new addresses of this peer.
252 *
253 * @param cls the closure
254 * @param address address under which we are likely reachable,
255 * pointer will remain valid until @e address_del_cb is called; to be used for HELLOs. Example: "ip+udp://$PID/1.1.1.1:2086/"
256 * @param source handle for sending from this address, NULL if we can only receive
257 * @param[out] ctx storage space for DHT to use in association with this address
258 */
259static void
260u_address_add (void *cls,
261 const char *address,
262 struct GNUNET_DHTU_Source *source,
263 void **ctx)
264{
265 struct GDS_Underlay *u = cls;
266 struct MyAddress *a;
267
268 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
269 "Underlay adds address %s for this peer\n",
270 address);
271 a = GNUNET_new (struct MyAddress);
272 a->source = source;
273 a->url = GNUNET_strdup (address);
274 a->u = u;
275 GNUNET_CONTAINER_DLL_insert (a_head,
276 a_tail,
277 a);
278 *ctx = a;
279 GNUNET_HELLO_builder_add_address (GDS_my_hello,
280 address);
281 if (NULL != hello_task)
282 GNUNET_SCHEDULER_cancel (hello_task);
283 hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
284 NULL);
285}
286
287
288/**
289 * Function to call with expired addresses of this peer.
290 *
291 * @param[in] ctx storage space used by the DHT in association with this address
292 */
293static void
294u_address_del (void *ctx)
295{
296 struct MyAddress *a = ctx;
297
298 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
299 "Underlay deletes address %s for this peer\n",
300 a->url);
301 GNUNET_HELLO_builder_del_address (GDS_my_hello,
302 a->url);
303 GNUNET_CONTAINER_DLL_remove (a_head,
304 a_tail,
305 a);
306 GNUNET_free (a->url);
307 GNUNET_free (a);
308 if (NULL != hello_task)
309 GNUNET_SCHEDULER_cancel (hello_task);
310 hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
311 NULL);
312}
313
314
315void
316GDS_u_try_connect (const struct GNUNET_PeerIdentity *pid,
317 const char *address)
318{
319 for (struct GDS_Underlay *u = u_head;
320 NULL != u;
321 u = u->next)
322 u->dhtu->try_connect (u->dhtu->cls,
323 pid,
324 address);
325}
326
327
328void
329GDS_u_send (struct GDS_Underlay *u,
330 struct GNUNET_DHTU_Target *target,
331 const void *msg,
332 size_t msg_size,
333 GNUNET_SCHEDULER_TaskCallback finished_cb,
334 void *finished_cb_cls)
335{
336 u->dhtu->send (u->dhtu->cls,
337 target,
338 msg,
339 msg_size,
340 finished_cb,
341 finished_cb_cls);
342}
343
344
345void
346GDS_u_drop (struct GDS_Underlay *u,
347 struct GNUNET_DHTU_PreferenceHandle *ph)
348{
349 u->dhtu->drop (ph);
350}
351
352
353struct GNUNET_DHTU_PreferenceHandle *
354GDS_u_hold (struct GDS_Underlay *u,
355 struct GNUNET_DHTU_Target *target)
356{
357 return u->dhtu->hold (u->dhtu->cls,
358 target);
359}
360
361
362/**
363 * Task run during shutdown.
364 *
365 * @param cls unused
366 */
367static void
368shutdown_task (void *cls)
369{
370 struct GDS_Underlay *u;
371
372 while (NULL != (u = u_head))
373 {
374 GNUNET_PLUGIN_unload (u->libname,
375 u->dhtu);
376 GNUNET_CONTAINER_DLL_remove (u_head,
377 u_tail,
378 u);
379 GNUNET_free (u->name);
380 GNUNET_free (u->libname);
381 GNUNET_free (u);
382 }
383 GDS_NEIGHBOURS_done ();
384 GDS_DATACACHE_done ();
385 GDS_ROUTING_done ();
386 if (NULL != GDS_block_context)
387 {
388 GNUNET_BLOCK_context_destroy (GDS_block_context);
389 GDS_block_context = NULL;
390 }
391 GDS_CLIENTS_stop ();
392 if (NULL != GDS_stats)
393 {
394 GNUNET_STATISTICS_destroy (GDS_stats,
395 GNUNET_YES);
396 GDS_stats = NULL;
397 }
398 if (NULL != GDS_my_hello)
399 {
400 GNUNET_HELLO_builder_free (GDS_my_hello);
401 GDS_my_hello = NULL;
402 }
403 if (NULL != hello_task)
404 {
405 GNUNET_SCHEDULER_cancel (hello_task);
406 hello_task = NULL;
407 }
408}
409
410
411/**
412 * Function iterating over all configuration sections.
413 * Loads plugins for enabled DHT underlays.
414 *
415 * @param cls NULL
416 * @param section configuration section to inspect
417 */
418static void
419load_underlay (void *cls,
420 const char *section)
421{
422 struct GDS_Underlay *u;
423 char *libname;
424
425 (void) cls;
426 if (0 != strncasecmp (section,
427 "dhtu-",
428 strlen ("dhtu-")))
429 return;
430 if (GNUNET_YES !=
431 GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
432 section,
433 "ENABLED"))
434 return;
435 section += strlen ("dhtu-");
436 u = GNUNET_new (struct GDS_Underlay);
437 u->env.cls = u;
438 u->env.cfg = GDS_cfg;
439 u->env.address_add_cb = &u_address_add;
440 u->env.address_del_cb = &u_address_del;
441 u->env.network_size_cb = &update_network_size_estimate;
442 u->env.connect_cb = &GDS_u_connect;
443 u->env.disconnect_cb = &GDS_u_disconnect;
444 u->env.receive_cb = &GDS_u_receive;
445 GNUNET_asprintf (&libname,
446 "libgnunet_plugin_dhtu_%s",
447 section);
448 u->dhtu = GNUNET_PLUGIN_load (libname,
449 &u->env);
450 if (NULL == u->dhtu)
451 {
452 GNUNET_free (libname);
453 GNUNET_free (u);
454 return;
455 }
456 u->libname = libname;
457 u->name = GNUNET_strdup (section);
458 GNUNET_CONTAINER_DLL_insert (u_head,
459 u_tail,
460 u);
461}
462
463
464/**
465 * Process dht requests.
466 *
467 * @param cls closure
468 * @param c configuration to use
469 * @param service the initialized service
470 */
471static void
472run (void *cls,
473 const struct GNUNET_CONFIGURATION_Handle *c,
474 struct GNUNET_SERVICE_Handle *service)
475{
476 GDS_cfg = c;
477 GDS_service = service;
478 {
479 char *keyfile;
480
481 if (GNUNET_OK !=
482 GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
483 "PEER",
484 "PRIVATE_KEY",
485 &keyfile))
486 {
487 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
488 "PEER",
489 "PRIVATE_KEY");
490 GNUNET_SCHEDULER_shutdown ();
491 return;
492 }
493 if (GNUNET_SYSERR ==
494 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
495 GNUNET_YES,
496 &GDS_my_private_key))
497 {
498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
499 "Failed to setup peer's private key\n");
500 GNUNET_free (keyfile);
501 GNUNET_SCHEDULER_shutdown ();
502 return;
503 }
504 GNUNET_free (keyfile);
505 }
506 GNUNET_CRYPTO_eddsa_key_get_public (&GDS_my_private_key,
507 &GDS_my_identity.public_key);
508 GDS_my_hello = GNUNET_HELLO_builder_new (&GDS_my_identity);
509 GNUNET_CRYPTO_hash (&GDS_my_identity,
510 sizeof(struct GNUNET_PeerIdentity),
511 &GDS_my_identity_hash);
512 GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
513 GDS_stats = GNUNET_STATISTICS_create ("dht",
514 GDS_cfg);
515 GDS_CLIENTS_init ();
516 GDS_ROUTING_init ();
517 GDS_DATACACHE_init ();
518 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
519 NULL);
520 if (GNUNET_OK !=
521 GDS_NEIGHBOURS_init ())
522 {
523 GNUNET_SCHEDULER_shutdown ();
524 return;
525 }
526 GNUNET_CONFIGURATION_iterate_sections (GDS_cfg,
527 &load_underlay,
528 NULL);
529 if (NULL == u_head)
530 {
531 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532 "No DHT underlays configured!\n");
533 GNUNET_SCHEDULER_shutdown ();
534 return;
535 }
536}
537
538
539/* Finally, define the main method */
540GDS_DHT_SERVICE_INIT ("dht", &run);
541
542
543/* 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 a1513fcce..000000000
--- a/src/dht/gnunet-service-dht.h
+++ /dev/null
@@ -1,218 +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-service-dht_neighbours.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_transport_service.h"
33
34
35#define DEBUG_DHT GNUNET_EXTRA_LOGGING
36
37/**
38 * Information we keep per underlay.
39 */
40struct GDS_Underlay;
41
42/**
43 * Configuration we use.
44 */
45extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
46
47/**
48 * Handle for the service.
49 */
50extern struct GNUNET_SERVICE_Handle *GDS_service;
51
52/**
53 * Our handle to the BLOCK library.
54 */
55extern struct GNUNET_BLOCK_Context *GDS_block_context;
56
57/**
58 * Handle for the statistics service.
59 */
60extern struct GNUNET_STATISTICS_Handle *GDS_stats;
61
62/**
63 * Our HELLO builder.
64 */
65extern struct GNUNET_HELLO_Builder *GDS_my_hello;
66
67/**
68 * Identity of this peer.
69 */
70extern struct GNUNET_PeerIdentity GDS_my_identity;
71
72/**
73 * Hash of the identity of this peer.
74 */
75extern struct GNUNET_HashCode GDS_my_identity_hash;
76
77/**
78 * Our private key.
79 */
80extern struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key;
81
82
83/**
84 * Ask all underlays to connect to peer @a pid at @a address.
85 *
86 * @param pid identity of the peer we would connect to
87 * @param address an address of @a pid
88 */
89void
90GDS_u_try_connect (const struct GNUNET_PeerIdentity *pid,
91 const char *address);
92
93
94/**
95 * Send message to some other participant over the network. Note that
96 * sending is not guaranteeing that the other peer actually received the
97 * message. For any given @a target, the DHT must wait for the @a
98 * finished_cb to be called before calling send() again.
99 *
100 * @param u underlay to use for transmission
101 * @param target receiver identification
102 * @param msg message
103 * @param msg_size number of bytes in @a msg
104 * @param finished_cb function called once transmission is done
105 * (not called if @a target disconnects, then only the
106 * disconnect_cb is called).
107 * @param finished_cb_cls closure for @a finished_cb
108 */
109void
110GDS_u_send (struct GDS_Underlay *u,
111 struct GNUNET_DHTU_Target *target,
112 const void *msg,
113 size_t msg_size,
114 GNUNET_SCHEDULER_TaskCallback finished_cb,
115 void *finished_cb_cls);
116
117
118/**
119 * Drop a hold @a ph from underlay @a u.
120 *
121 * @param u the underlay controlling the hold
122 * @param ph the preference handle
123 */
124void
125GDS_u_drop (struct GDS_Underlay *u,
126 struct GNUNET_DHTU_PreferenceHandle *ph);
127
128
129/**
130 * Create a hold on @a target at underlay @a u.
131 *
132 * @param u the underlay controlling the target
133 * @param target the peer to hold the connection to
134 */
135struct GNUNET_DHTU_PreferenceHandle *
136GDS_u_hold (struct GDS_Underlay *u,
137 struct GNUNET_DHTU_Target *target);
138
139
140/**
141 * Handle a reply we've received from another peer. If the reply
142 * matches any of our pending queries, forward it to the respective
143 * client(s).
144 *
145 * @param bd block details
146 * @param query_hash hash of the original query, might not match key in @a bd
147 * @param get_path_length number of entries in @a get_path
148 * @param get_path path the reply has taken
149 * @return true on success, false on failures
150 */
151bool
152GDS_CLIENTS_handle_reply (const struct GDS_DATACACHE_BlockData *bd,
153 const struct GNUNET_HashCode *query_hash,
154 unsigned int get_path_length,
155 const struct GNUNET_DHT_PathElement *get_path);
156
157
158/**
159 * Check if some client is monitoring GET messages and notify
160 * them in that case.
161 *
162 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
163 * @param type The type of data in the request.
164 * @param hop_count Hop count so far.
165 * @param path_length number of entries in path (or 0 if not recorded).
166 * @param path peers on the GET path (or NULL if not recorded).
167 * @param desired_replication_level Desired replication level.
168 * @param key Key of the requested data.
169 */
170void
171GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption options,
172 enum GNUNET_BLOCK_Type type,
173 uint32_t hop_count,
174 uint32_t desired_replication_level,
175 unsigned int path_length,
176 const struct GNUNET_DHT_PathElement *path,
177 const struct GNUNET_HashCode *key);
178
179
180/**
181 * Check if some client is monitoring GET RESP messages and notify
182 * them in that case.
183 *
184 * @param bd block details
185 * @param get_path Peers on GET path (or NULL if not recorded).
186 * @param get_path_length number of entries in @a get_path.
187 */
188void
189GDS_CLIENTS_process_get_resp (const struct GDS_DATACACHE_BlockData *bd,
190 const struct GNUNET_DHT_PathElement *get_path,
191 unsigned int get_path_length);
192
193
194/**
195 * Check if some client is monitoring PUT messages and notify
196 * them in that case. The @a path should include our own
197 * peer ID (if recorded).
198 *
199 * @param options routing options to apply
200 * @param bd details about the block
201 * @param hop_count Hop count so far.
202 * @param desired_replication_level Desired replication level.
203 */
204void
205GDS_CLIENTS_process_put (enum GNUNET_DHT_RouteOption options,
206 const struct GDS_DATACACHE_BlockData *bd,
207 uint32_t hop_count,
208 uint32_t desired_replication_level);
209
210/**
211 * Return the current NSE
212 *
213 * @return the current NSE as a logarithm
214 */
215double
216GDS_NSE_get (void);
217
218#endif
diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c
deleted file mode 100644
index fd65102b3..000000000
--- a/src/dht/gnunet-service-dht_clients.c
+++ /dev/null
@@ -1,1665 +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#include "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_protocols.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet-service-dht.h"
32#include "gnunet-service-dht_datacache.h"
33#include "gnunet-service-dht_neighbours.h"
34#include "dht.h"
35
36
37/**
38 * Enable slow sanity checks to debug issues.
39 * 0: do not check
40 * 1: check all external inputs
41 * 2: check internal computations as well
42 */
43#define SANITY_CHECKS 2
44
45/**
46 * Should routing details be logged to stderr (for debugging)?
47 */
48#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
49 __VA_ARGS__)
50
51#define LOG(kind, ...) GNUNET_log_from (kind, "dht-clients", __VA_ARGS__)
52
53
54/**
55 * Struct containing information about a client,
56 * handle to connect to it, and any pending messages
57 * that need to be sent to it.
58 */
59struct ClientHandle;
60
61
62/**
63 * Entry in the local forwarding map for a client's GET request.
64 */
65struct ClientQueryRecord
66{
67 /**
68 * The key this request was about
69 */
70 struct GNUNET_HashCode key;
71
72 /**
73 * Kept in a DLL with @e client.
74 */
75 struct ClientQueryRecord *next;
76
77 /**
78 * Kept in a DLL with @e client.
79 */
80 struct ClientQueryRecord *prev;
81
82 /**
83 * Client responsible for the request.
84 */
85 struct ClientHandle *ch;
86
87 /**
88 * Extended query (see gnunet_block_lib.h), allocated at the end of this struct.
89 */
90 const void *xquery;
91
92 /**
93 * Array of (hashes of) replies we have already seen for this request.
94 */
95 struct GNUNET_HashCode *seen_replies;
96
97 /**
98 * Pointer to this nodes heap location in the retry-heap (for fast removal)
99 */
100 struct GNUNET_CONTAINER_HeapNode *hnode;
101
102 /**
103 * What's the delay between re-try operations that we currently use for this
104 * request?
105 */
106 struct GNUNET_TIME_Relative retry_frequency;
107
108 /**
109 * What's the next time we should re-try this request?
110 */
111 struct GNUNET_TIME_Absolute retry_time;
112
113 /**
114 * The unique identifier of this request
115 */
116 uint64_t unique_id;
117
118 /**
119 * Number of bytes in xquery.
120 */
121 size_t xquery_size;
122
123 /**
124 * Number of entries in @e seen_replies.
125 */
126 unsigned int seen_replies_count;
127
128 /**
129 * Desired replication level
130 */
131 uint32_t replication;
132
133 /**
134 * Any message options for this request
135 */
136 enum GNUNET_DHT_RouteOption msg_options;
137
138 /**
139 * The type for the data for the GET request.
140 */
141 enum GNUNET_BLOCK_Type type;
142};
143
144
145/**
146 * Struct containing parameters of monitoring requests.
147 */
148struct ClientMonitorRecord
149{
150 /**
151 * Next element in DLL.
152 */
153 struct ClientMonitorRecord *next;
154
155 /**
156 * Previous element in DLL.
157 */
158 struct ClientMonitorRecord *prev;
159
160 /**
161 * Client to notify of these requests.
162 */
163 struct ClientHandle *ch;
164
165 /**
166 * Key of data of interest. All bits zero for 'all'.
167 */
168 struct GNUNET_HashCode key;
169
170 /**
171 * Type of blocks that are of interest
172 */
173 enum GNUNET_BLOCK_Type type;
174
175 /**
176 * Flag whether to notify about GET messages.
177 */
178 int16_t get;
179
180 /**
181 * Flag whether to notify about GET_REPONSE messages.
182 */
183 int16_t get_resp;
184
185 /**
186 * Flag whether to notify about PUT messages.
187 */
188 uint16_t put;
189
190};
191
192
193/**
194 * Struct containing information about a client,
195 * handle to connect to it, and any pending messages
196 * that need to be sent to it.
197 */
198struct ClientHandle
199{
200 /**
201 * Linked list of active queries of this client.
202 */
203 struct ClientQueryRecord *cqr_head;
204
205 /**
206 * Linked list of active queries of this client.
207 */
208 struct ClientQueryRecord *cqr_tail;
209
210 /**
211 * The handle to this client
212 */
213 struct GNUNET_SERVICE_Client *client;
214
215 /**
216 * The message queue to this client
217 */
218 struct GNUNET_MQ_Handle *mq;
219};
220
221
222/**
223 * Our handle to the BLOCK library.
224 */
225struct GNUNET_BLOCK_Context *GDS_block_context;
226
227/**
228 * Handle for the statistics service.
229 */
230struct GNUNET_STATISTICS_Handle *GDS_stats;
231
232/**
233 * Handle for the service.
234 */
235struct GNUNET_SERVICE_Handle *GDS_service;
236
237/**
238 * The configuration the DHT service is running with
239 */
240const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
241
242/**
243 * List of active monitoring requests.
244 */
245static struct ClientMonitorRecord *monitor_head;
246
247/**
248 * List of active monitoring requests.
249 */
250static struct ClientMonitorRecord *monitor_tail;
251
252/**
253 * Hashmap for fast key based lookup, maps keys to `struct ClientQueryRecord` entries.
254 */
255static struct GNUNET_CONTAINER_MultiHashMap *forward_map;
256
257/**
258 * Heap with all of our client's request, sorted by retry time (earliest on top).
259 */
260static struct GNUNET_CONTAINER_Heap *retry_heap;
261
262/**
263 * Task that re-transmits requests (using retry_heap).
264 */
265static struct GNUNET_SCHEDULER_Task *retry_task;
266
267
268/**
269 * Free data structures associated with the given query.
270 *
271 * @param record record to remove
272 */
273static void
274remove_client_query_record (struct ClientQueryRecord *record)
275{
276 struct ClientHandle *ch = record->ch;
277
278 GNUNET_CONTAINER_DLL_remove (ch->cqr_head,
279 ch->cqr_tail,
280 record);
281 GNUNET_assert (GNUNET_YES ==
282 GNUNET_CONTAINER_multihashmap_remove (forward_map,
283 &record->key,
284 record));
285 if (NULL != record->hnode)
286 GNUNET_CONTAINER_heap_remove_node (record->hnode);
287 GNUNET_array_grow (record->seen_replies,
288 record->seen_replies_count,
289 0);
290 GNUNET_free (record);
291}
292
293
294/**
295 * Functions with this signature are called whenever a local client is
296 * connects to us.
297 *
298 * @param cls closure (NULL for dht)
299 * @param client identification of the client
300 * @param mq message queue for talking to @a client
301 * @return our `struct ClientHandle` for @a client
302 */
303static void *
304client_connect_cb (void *cls,
305 struct GNUNET_SERVICE_Client *client,
306 struct GNUNET_MQ_Handle *mq)
307{
308 struct ClientHandle *ch;
309
310 (void) cls;
311 ch = GNUNET_new (struct ClientHandle);
312 ch->client = client;
313 ch->mq = mq;
314 return ch;
315}
316
317
318/**
319 * Functions with this signature are called whenever a client
320 * is disconnected on the network level.
321 *
322 * @param cls closure (NULL for dht)
323 * @param client identification of the client
324 * @param app_ctx our `struct ClientHandle` for @a client
325 */
326static void
327client_disconnect_cb (void *cls,
328 struct GNUNET_SERVICE_Client *client,
329 void *app_ctx)
330{
331 struct ClientHandle *ch = app_ctx;
332
333 (void) cls;
334 (void) client;
335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336 "Local client %p disconnects\n",
337 ch);
338 {
339 struct ClientMonitorRecord *next;
340
341 for (struct ClientMonitorRecord *monitor = monitor_head;
342 NULL != monitor;
343 monitor = next)
344 {
345 next = monitor->next;
346 if (monitor->ch != ch)
347 continue;
348 GNUNET_CONTAINER_DLL_remove (monitor_head,
349 monitor_tail,
350 monitor);
351 GNUNET_free (monitor);
352 }
353 }
354
355 {
356 struct ClientQueryRecord *cqr;
357
358 while (NULL != (cqr = ch->cqr_head))
359 remove_client_query_record (cqr);
360 }
361 GNUNET_free (ch);
362}
363
364
365/**
366 * Route the given request via the DHT. This includes updating
367 * the bloom filter and retransmission times, building the P2P
368 * message and initiating the routing operation.
369 *
370 * @param cqr request to transmit
371 */
372static void
373transmit_request (struct ClientQueryRecord *cqr)
374{
375 struct GNUNET_BLOCK_Group *bg;
376 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
377
378 GNUNET_STATISTICS_update (GDS_stats,
379 "# GET requests from clients injected",
380 1,
381 GNUNET_NO);
382 bg = GNUNET_BLOCK_group_create (GDS_block_context,
383 cqr->type,
384 NULL, /* raw data */
385 0, /* raw data size */
386 "seen-set-size",
387 cqr->seen_replies_count,
388 NULL);
389 GNUNET_BLOCK_group_set_seen (bg,
390 cqr->seen_replies,
391 cqr->seen_replies_count);
392 peer_bf
393 = GNUNET_CONTAINER_bloomfilter_init (NULL,
394 DHT_BLOOM_SIZE,
395 GNUNET_CONSTANTS_BLOOMFILTER_K);
396 LOG (GNUNET_ERROR_TYPE_DEBUG,
397 "Initiating GET for %s, replication %u, already have %u replies\n",
398 GNUNET_h2s (&cqr->key),
399 cqr->replication,
400 cqr->seen_replies_count);
401 GDS_NEIGHBOURS_handle_get (cqr->type,
402 cqr->msg_options,
403 cqr->replication,
404 0 /* hop count */,
405 &cqr->key,
406 cqr->xquery,
407 cqr->xquery_size,
408 bg,
409 peer_bf);
410 GNUNET_BLOCK_group_destroy (bg);
411 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
412
413 /* Exponential back-off for retries.
414 * max. is #GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD (15 min) */
415 cqr->retry_frequency = GNUNET_TIME_STD_BACKOFF (cqr->retry_frequency);
416 cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency);
417}
418
419
420/**
421 * Task that looks at the #retry_heap and transmits all of the requests
422 * on the heap that are ready for transmission. Then re-schedules
423 * itself (unless the heap is empty).
424 *
425 * @param cls unused
426 */
427static void
428transmit_next_request_task (void *cls)
429{
430 struct ClientQueryRecord *cqr;
431
432 (void) cls;
433 retry_task = NULL;
434 while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap)))
435 {
436 cqr->hnode = NULL;
437 if (! GNUNET_TIME_absolute_is_past (cqr->retry_time))
438 {
439 cqr->hnode
440 = GNUNET_CONTAINER_heap_insert (retry_heap,
441 cqr,
442 cqr->retry_time.abs_value_us);
443 retry_task
444 = GNUNET_SCHEDULER_add_at (cqr->retry_time,
445 &transmit_next_request_task,
446 NULL);
447 return;
448 }
449 transmit_request (cqr);
450 cqr->hnode
451 = GNUNET_CONTAINER_heap_insert (retry_heap,
452 cqr,
453 cqr->retry_time.abs_value_us);
454 }
455}
456
457
458/**
459 * Check DHT PUT messages from the client.
460 *
461 * @param cls the client we received this message from
462 * @param dht_msg the actual message received
463 * @return #GNUNET_OK (always)
464 */
465static enum GNUNET_GenericReturnValue
466check_dht_local_put (void *cls,
467 const struct GNUNET_DHT_ClientPutMessage *dht_msg)
468{
469 uint32_t replication_level = ntohl (dht_msg->desired_replication_level);
470
471 (void) cls;
472 if (replication_level > GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL)
473 {
474 GNUNET_break_op (0);
475 return GNUNET_SYSERR;
476 }
477 return GNUNET_OK;
478}
479
480
481/**
482 * Handler for PUT messages.
483 *
484 * @param cls the client we received this message from
485 * @param dht_msg the actual message received
486 */
487static void
488handle_dht_local_put (void *cls,
489 const struct GNUNET_DHT_ClientPutMessage *dht_msg)
490{
491 struct ClientHandle *ch = cls;
492 uint16_t size = ntohs (dht_msg->header.size);
493 enum GNUNET_DHT_RouteOption options
494 = (enum GNUNET_DHT_RouteOption) ntohl (dht_msg->options);
495 uint32_t replication_level
496 = ntohl (dht_msg->desired_replication_level);
497 struct GDS_DATACACHE_BlockData bd = {
498 .key = dht_msg->key,
499 .expiration_time = GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
500 .data = &dht_msg[1],
501 .data_size = size - sizeof (*dht_msg),
502 .type = ntohl (dht_msg->type)
503 };
504
505 LOG (GNUNET_ERROR_TYPE_DEBUG,
506 "Handling local PUT of %lu-bytes for query %s of type %u\n",
507 (unsigned long) (size - sizeof(struct GNUNET_DHT_ClientPutMessage)),
508 GNUNET_h2s (&dht_msg->key),
509 (unsigned int) bd.type);
510 if (GNUNET_OK !=
511 GNUNET_BLOCK_check_block (GDS_block_context,
512 bd.type,
513 bd.data,
514 bd.data_size))
515 {
516 GNUNET_break (0);
517 return;
518 }
519 GNUNET_STATISTICS_update (GDS_stats,
520 "# PUT requests received from clients",
521 1,
522 GNUNET_NO);
523 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
524 "CLIENT-PUT %s\n",
525 GNUNET_h2s_full (&dht_msg->key));
526 /* give to local clients */
527 GNUNET_break (GDS_CLIENTS_handle_reply (&bd,
528 &bd.key,
529 0, NULL /* get path */));
530
531 {
532 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
533
534 peer_bf
535 = GNUNET_CONTAINER_bloomfilter_init (NULL,
536 DHT_BLOOM_SIZE,
537 GNUNET_CONSTANTS_BLOOMFILTER_K);
538 /* store locally */
539 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
540 (GDS_am_closest_peer (&dht_msg->key,
541 peer_bf)))
542 GDS_DATACACHE_handle_put (&bd);
543 /* route to other peers */
544 if (GNUNET_OK !=
545 GDS_NEIGHBOURS_handle_put (&bd,
546 options,
547 replication_level,
548 0 /* hop count */,
549 peer_bf))
550 {
551 GNUNET_STATISTICS_update (GDS_stats,
552 "# Local PUT requests not routed",
553 1,
554 GNUNET_NO);
555 }
556 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
557 }
558 GDS_CLIENTS_process_put (
559 options,
560 &bd,
561 0, /* hop count */
562 replication_level);
563 GNUNET_SERVICE_client_continue (ch->client);
564}
565
566
567/**
568 * Handle a result from local datacache for a GET operation.
569 *
570 * @param cls the `struct ClientHandle` of the client doing the query
571 * @param bd details about the block that was found
572 */
573static void
574handle_local_result (void *cls,
575 const struct GDS_DATACACHE_BlockData *bd)
576{
577 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
578 "Datacache provided result for query key %s\n",
579 GNUNET_h2s (&bd->key));
580 GNUNET_break (GDS_CLIENTS_handle_reply (bd,
581 &bd->key,
582 0, NULL /* get_path */));
583}
584
585
586/**
587 * Check DHT GET messages from the client.
588 *
589 * @param cls the client we received this message from
590 * @param message the actual message received
591 * @return #GNUNET_OK (always)
592 */
593static enum GNUNET_GenericReturnValue
594check_dht_local_get (void *cls,
595 const struct GNUNET_DHT_ClientGetMessage *get)
596{
597 (void) cls;
598 (void) get;
599 /* always well-formed */
600 return GNUNET_OK;
601}
602
603
604/**
605 * Handler for DHT GET messages from the client.
606 *
607 * @param cls the client we received this message from
608 * @param message the actual message received
609 */
610static void
611handle_dht_local_get (void *cls,
612 const struct GNUNET_DHT_ClientGetMessage *get)
613{
614 struct ClientHandle *ch = cls;
615 struct ClientQueryRecord *cqr;
616 uint16_t size = ntohs (get->header.size);
617 const char *xquery = (const char *) &get[1];
618 size_t xquery_size = size - sizeof(struct GNUNET_DHT_ClientGetMessage);
619
620 LOG (GNUNET_ERROR_TYPE_DEBUG,
621 "Received GET request for %s from local client %p, xq: %.*s\n",
622 GNUNET_h2s (&get->key),
623 ch->client,
624 (int) xquery_size,
625 xquery);
626 GNUNET_STATISTICS_update (GDS_stats,
627 "# GET requests received from clients",
628 1,
629 GNUNET_NO);
630 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
631 "CLIENT-GET %s\n",
632 GNUNET_h2s_full (&get->key));
633
634 cqr = GNUNET_malloc (sizeof(struct ClientQueryRecord) + xquery_size);
635 cqr->key = get->key;
636 cqr->ch = ch;
637 cqr->xquery = (const void *) &cqr[1];
638 GNUNET_memcpy (&cqr[1],
639 xquery,
640 xquery_size);
641 cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap,
642 cqr,
643 0);
644 cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS;
645 cqr->retry_time = GNUNET_TIME_absolute_get ();
646 cqr->unique_id = get->unique_id;
647 cqr->xquery_size = xquery_size;
648 cqr->replication = ntohl (get->desired_replication_level);
649 cqr->msg_options = (enum GNUNET_DHT_RouteOption) ntohl (get->options);
650 cqr->type = ntohl (get->type);
651 GNUNET_CONTAINER_DLL_insert (ch->cqr_head,
652 ch->cqr_tail,
653 cqr);
654 GNUNET_CONTAINER_multihashmap_put (forward_map,
655 &cqr->key,
656 cqr,
657 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
658 GDS_CLIENTS_process_get (cqr->msg_options,
659 cqr->type,
660 0, /* hop count */
661 cqr->replication,
662 0, /* path length */
663 NULL,
664 &get->key);
665 /* start remote requests */
666 if (NULL != retry_task)
667 GNUNET_SCHEDULER_cancel (retry_task);
668 retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task,
669 NULL);
670 /* perform local lookup */
671 GDS_DATACACHE_handle_get (&get->key,
672 cqr->type,
673 cqr->xquery,
674 xquery_size,
675 NULL,
676 &handle_local_result,
677 ch);
678 GNUNET_SERVICE_client_continue (ch->client);
679}
680
681
682/**
683 * Closure for #find_by_unique_id().
684 */
685struct FindByUniqueIdContext
686{
687 /**
688 * Where to store the result, if found.
689 */
690 struct ClientQueryRecord *cqr;
691
692 /**
693 * Unique ID to look for.
694 */
695 uint64_t unique_id;
696};
697
698
699/**
700 * Function called for each existing DHT record for the given
701 * query. Checks if it matches the UID given in the closure
702 * and if so returns the entry as a result.
703 *
704 * @param cls the search context
705 * @param key query for the lookup (not used)
706 * @param value the `struct ClientQueryRecord`
707 * @return #GNUNET_YES to continue iteration (result not yet found)
708 */
709static enum GNUNET_GenericReturnValue
710find_by_unique_id (void *cls,
711 const struct GNUNET_HashCode *key,
712 void *value)
713{
714 struct FindByUniqueIdContext *fui_ctx = cls;
715 struct ClientQueryRecord *cqr = value;
716
717 if (cqr->unique_id != fui_ctx->unique_id)
718 return GNUNET_YES;
719 fui_ctx->cqr = cqr;
720 return GNUNET_NO;
721}
722
723
724/**
725 * Check "GET result seen" messages from the client.
726 *
727 * @param cls the client we received this message from
728 * @param message the actual message received
729 * @return #GNUNET_OK if @a seen is well-formed
730 */
731static enum GNUNET_GenericReturnValue
732check_dht_local_get_result_seen (
733 void *cls,
734 const struct GNUNET_DHT_ClientGetResultSeenMessage *seen)
735{
736 uint16_t size = ntohs (seen->header.size);
737 unsigned int hash_count =
738 (size - sizeof(*seen))
739 / sizeof(struct GNUNET_HashCode);
740
741 if (size != sizeof(*seen) + hash_count * sizeof(struct GNUNET_HashCode))
742 {
743 GNUNET_break (0);
744 return GNUNET_SYSERR;
745 }
746 return GNUNET_OK;
747}
748
749
750/**
751 * Handler for "GET result seen" messages from the client.
752 *
753 * @param cls the client we received this message from
754 * @param message the actual message received
755 */
756static void
757handle_dht_local_get_result_seen (
758 void *cls,
759 const struct GNUNET_DHT_ClientGetResultSeenMessage *seen)
760{
761 struct ClientHandle *ch = cls;
762 uint16_t size = ntohs (seen->header.size);
763 unsigned int hash_count = (size - sizeof(*seen))
764 / sizeof(struct GNUNET_HashCode);
765 const struct GNUNET_HashCode *hc = (const struct GNUNET_HashCode*) &seen[1];
766 struct FindByUniqueIdContext fui_ctx = {
767 .unique_id = seen->unique_id
768 };
769 unsigned int old_count;
770 struct ClientQueryRecord *cqr;
771
772 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
773 &seen->key,
774 &find_by_unique_id,
775 &fui_ctx);
776 if (NULL == (cqr = fui_ctx.cqr))
777 {
778 GNUNET_break (0);
779 GNUNET_SERVICE_client_drop (ch->client);
780 return;
781 }
782 /* finally, update 'seen' list */
783 old_count = cqr->seen_replies_count;
784 GNUNET_array_grow (cqr->seen_replies,
785 cqr->seen_replies_count,
786 cqr->seen_replies_count + hash_count);
787 GNUNET_memcpy (&cqr->seen_replies[old_count],
788 hc,
789 sizeof(struct GNUNET_HashCode) * hash_count);
790}
791
792
793/**
794 * Closure for #remove_by_unique_id().
795 */
796struct RemoveByUniqueIdContext
797{
798 /**
799 * Client that issued the removal request.
800 */
801 struct ClientHandle *ch;
802
803 /**
804 * Unique ID of the request.
805 */
806 uint64_t unique_id;
807};
808
809
810/**
811 * Iterator over hash map entries that frees all entries
812 * that match the given client and unique ID.
813 *
814 * @param cls unique ID and client to search for in source routes
815 * @param key current key code
816 * @param value value in the hash map, a ClientQueryRecord
817 * @return #GNUNET_YES (we should continue to iterate)
818 */
819static enum GNUNET_GenericReturnValue
820remove_by_unique_id (void *cls,
821 const struct GNUNET_HashCode *key,
822 void *value)
823{
824 const struct RemoveByUniqueIdContext *ctx = cls;
825 struct ClientQueryRecord *cqr = value;
826
827 if (cqr->unique_id != ctx->unique_id)
828 return GNUNET_YES;
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 "Removing client %p's record for key %s (by unique id)\n",
831 ctx->ch->client,
832 GNUNET_h2s (key));
833 remove_client_query_record (cqr);
834 return GNUNET_YES;
835}
836
837
838/**
839 * Handler for any generic DHT stop messages, calls the appropriate handler
840 * depending on message type (if processed locally)
841 *
842 * @param cls client we received this message from
843 * @param message the actual message received
844 *
845 */
846static void
847handle_dht_local_get_stop (
848 void *cls,
849 const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg)
850{
851 struct ClientHandle *ch = cls;
852 struct RemoveByUniqueIdContext ctx;
853
854 GNUNET_STATISTICS_update (GDS_stats,
855 "# GET STOP requests received from clients",
856 1,
857 GNUNET_NO);
858 LOG (GNUNET_ERROR_TYPE_DEBUG,
859 "Received GET STOP request for %s from local client %p\n",
860 GNUNET_h2s (&dht_stop_msg->key),
861 ch->client);
862 ctx.ch = ch;
863 ctx.unique_id = dht_stop_msg->unique_id;
864 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
865 &dht_stop_msg->key,
866 &remove_by_unique_id,
867 &ctx);
868 GNUNET_SERVICE_client_continue (ch->client);
869}
870
871
872/**
873 * Closure for #forward_reply()
874 */
875struct ForwardReplyContext
876{
877 /**
878 * Block details.
879 */
880 const struct GDS_DATACACHE_BlockData *bd;
881
882 /**
883 * GET path taken.
884 */
885 const struct GNUNET_DHT_PathElement *get_path;
886
887 /**
888 * Number of entries in @e get_path.
889 */
890 unsigned int get_path_length;
891
892};
893
894
895/**
896 * Iterator over hash map entries that send a given reply to
897 * each of the matching clients. With some tricky recycling
898 * of the buffer.
899 *
900 * @param cls the `struct ForwardReplyContext`
901 * @param query_hash hash of the query for which this may be a reply
902 * @param value value in the hash map, a ClientQueryRecord
903 * @return #GNUNET_YES (we should continue to iterate),
904 * if the result is mal-formed, #GNUNET_NO
905 */
906static enum GNUNET_GenericReturnValue
907forward_reply (void *cls,
908 const struct GNUNET_HashCode *query_hash,
909 void *value)
910{
911 struct ForwardReplyContext *frc = cls;
912 struct ClientQueryRecord *record = value;
913 struct GNUNET_MQ_Envelope *env;
914 struct GNUNET_DHT_ClientResultMessage *reply;
915 enum GNUNET_BLOCK_ReplyEvaluationResult eval;
916 bool do_free;
917 struct GNUNET_HashCode ch;
918 struct GNUNET_DHT_PathElement *paths;
919
920 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
921 "CLIENT-RESULT %s\n",
922 GNUNET_h2s_full (&frc->bd->key));
923 if ( (record->type != GNUNET_BLOCK_TYPE_ANY) &&
924 (record->type != frc->bd->type) )
925 {
926 LOG (GNUNET_ERROR_TYPE_DEBUG,
927 "Record type mismatch, not passing request for key %s to local client\n",
928 GNUNET_h2s (&frc->bd->key));
929 GNUNET_STATISTICS_update (GDS_stats,
930 "# Key match, type mismatches in REPLY to CLIENT",
931 1,
932 GNUNET_NO);
933 return GNUNET_YES; /* type mismatch */
934 }
935 if ( (0 == (record->msg_options & GNUNET_DHT_RO_FIND_APPROXIMATE)) &&
936 (0 != GNUNET_memcmp (&frc->bd->key,
937 query_hash)) )
938 {
939 GNUNET_STATISTICS_update (GDS_stats,
940 "# Inexact key match, but exact match required",
941 1,
942 GNUNET_NO);
943 return GNUNET_YES; /* type mismatch */
944 }
945 GNUNET_CRYPTO_hash (frc->bd->data,
946 frc->bd->data_size,
947 &ch);
948 for (unsigned int i = 0; i < record->seen_replies_count; i++)
949 if (0 ==
950 GNUNET_memcmp (&record->seen_replies[i],
951 &ch))
952 {
953 LOG (GNUNET_ERROR_TYPE_DEBUG,
954 "Duplicate reply, not passing request for key %s to local client\n",
955 GNUNET_h2s (&frc->bd->key));
956 GNUNET_STATISTICS_update (GDS_stats,
957 "# Duplicate REPLIES to CLIENT request dropped",
958 1,
959 GNUNET_NO);
960 return GNUNET_YES; /* duplicate */
961 }
962 eval
963 = GNUNET_BLOCK_check_reply (GDS_block_context,
964 record->type,
965 NULL,
966 &frc->bd->key,
967 record->xquery,
968 record->xquery_size,
969 frc->bd->data,
970 frc->bd->data_size);
971 LOG (GNUNET_ERROR_TYPE_DEBUG,
972 "Evaluation result is %d for key %s for local client's query\n",
973 (int) eval,
974 GNUNET_h2s (&frc->bd->key));
975 switch (eval)
976 {
977 case GNUNET_BLOCK_REPLY_OK_LAST:
978 do_free = true;
979 break;
980 case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED:
981 case GNUNET_BLOCK_REPLY_OK_MORE:
982 GNUNET_array_append (record->seen_replies,
983 record->seen_replies_count,
984 ch);
985 do_free = false;
986 break;
987 case GNUNET_BLOCK_REPLY_OK_DUPLICATE:
988 /* should be impossible to encounter here */
989 GNUNET_break (0);
990 return GNUNET_YES;
991 case GNUNET_BLOCK_REPLY_IRRELEVANT:
992 return GNUNET_YES;
993 default:
994 GNUNET_break (0);
995 return GNUNET_NO;
996 }
997 GNUNET_STATISTICS_update (GDS_stats,
998 "# RESULTS queued for clients",
999 1,
1000 GNUNET_NO);
1001 env = GNUNET_MQ_msg_extra (reply,
1002 frc->bd->data_size
1003 + (frc->get_path_length + frc->bd->put_path_length)
1004 * sizeof(struct GNUNET_DHT_PathElement),
1005 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT);
1006 reply->type = htonl (frc->bd->type);
1007 reply->get_path_length = htonl (frc->get_path_length);
1008 reply->put_path_length = htonl (frc->bd->put_path_length);
1009 reply->unique_id = record->unique_id;
1010 reply->expiration = GNUNET_TIME_absolute_hton (frc->bd->expiration_time);
1011 reply->key = *query_hash;
1012 paths = (struct GNUNET_DHT_PathElement *) &reply[1];
1013 GNUNET_memcpy (paths,
1014 frc->bd->put_path,
1015 sizeof(struct GNUNET_DHT_PathElement)
1016 * frc->bd->put_path_length);
1017 GNUNET_memcpy (&paths[frc->bd->put_path_length],
1018 frc->get_path,
1019 sizeof(struct GNUNET_DHT_PathElement)
1020 * frc->get_path_length);
1021 GNUNET_memcpy (&paths[frc->get_path_length + frc->bd->put_path_length],
1022 frc->bd->data,
1023 frc->bd->data_size);
1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1025 "Sending reply to query %s for client %p\n",
1026 GNUNET_h2s (query_hash),
1027 record->ch->client);
1028 GNUNET_MQ_send (record->ch->mq,
1029 env);
1030 if (GNUNET_YES == do_free)
1031 remove_client_query_record (record);
1032 return GNUNET_YES;
1033}
1034
1035
1036bool
1037GDS_CLIENTS_handle_reply (const struct GDS_DATACACHE_BlockData *bd,
1038 const struct GNUNET_HashCode *query_hash,
1039 unsigned int get_path_length,
1040 const struct GNUNET_DHT_PathElement *get_path)
1041{
1042 struct ForwardReplyContext frc;
1043 size_t msize = sizeof (struct GNUNET_DHT_ClientResultMessage)
1044 + bd->data_size
1045 + (get_path_length + bd->put_path_length)
1046 * sizeof(struct GNUNET_DHT_PathElement);
1047
1048 if (msize >= GNUNET_MAX_MESSAGE_SIZE)
1049 {
1050 GNUNET_break (0);
1051 return false;
1052 }
1053#if SANITY_CHECKS > 1
1054 if (0 !=
1055 GNUNET_DHT_verify_path (bd->data,
1056 bd->data_size,
1057 bd->expiration_time,
1058 bd->put_path,
1059 bd->put_path_length,
1060 get_path,
1061 get_path_length,
1062 &GDS_my_identity))
1063 {
1064 GNUNET_break (0);
1065 return false;
1066 }
1067#endif
1068 frc.bd = bd;
1069 frc.get_path = get_path;
1070 frc.get_path_length = get_path_length;
1071 LOG (GNUNET_ERROR_TYPE_DEBUG,
1072 "Forwarding reply for query hash %s with GPL %u and PPL %u to client\n",
1073 GNUNET_h2s (query_hash),
1074 get_path_length,
1075 bd->put_path_length);
1076 if (0 ==
1077 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
1078 query_hash,
1079 &forward_reply,
1080 &frc))
1081 {
1082 LOG (GNUNET_ERROR_TYPE_DEBUG,
1083 "No matching client for reply for query %s\n",
1084 GNUNET_h2s (query_hash));
1085 GNUNET_STATISTICS_update (GDS_stats,
1086 "# REPLIES ignored for CLIENTS (no match)",
1087 1,
1088 GNUNET_NO);
1089 }
1090 return true;
1091}
1092
1093
1094/* **************** HELLO logic ***************** */
1095
1096/**
1097 * Handler for HELLO GET message. Reply to client
1098 * with a URL of our HELLO.
1099 *
1100 * @param cls the client we received this message from
1101 * @param msg the actual message received
1102 *
1103 */
1104static void
1105handle_dht_local_hello_get (void *cls,
1106 const struct GNUNET_MessageHeader *msg)
1107{
1108 struct ClientHandle *ch = cls;
1109 char *url = GNUNET_HELLO_builder_to_url (GDS_my_hello,
1110 &GDS_my_private_key);
1111 size_t slen = strlen (url) + 1;
1112 struct GNUNET_MessageHeader *hdr;
1113 struct GNUNET_MQ_Envelope *env;
1114
1115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1116 "Handling request from local client for my HELLO\n");
1117 env = GNUNET_MQ_msg_extra (hdr,
1118 slen,
1119 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL);
1120 memcpy (&hdr[1],
1121 url,
1122 slen);
1123 GNUNET_free (url);
1124 GNUNET_MQ_send (ch->mq,
1125 env);
1126 GNUNET_SERVICE_client_continue (ch->client);
1127}
1128
1129
1130/**
1131 * Process a client HELLO message received from the service.
1132 *
1133 * @param cls the client we received this message from
1134 * @param hdr HELLO URL message from the service.
1135 * @return #GNUNET_OK if @a hdr is well-formed
1136 */
1137static enum GNUNET_GenericReturnValue
1138check_dht_local_hello_offer (void *cls,
1139 const struct GNUNET_MessageHeader *hdr)
1140{
1141 uint16_t len = ntohs (hdr->size);
1142 const char *buf = (const char *) &hdr[1];
1143
1144 (void) cls;
1145 if ('\0' != buf[len - sizeof (*hdr) - 1])
1146 {
1147 GNUNET_break (0);
1148 return GNUNET_SYSERR;
1149 }
1150 return GNUNET_OK;
1151}
1152
1153
1154/**
1155 * Handler for HELLO OFFER message. Try to use the
1156 * HELLO to connect to another peer.
1157 *
1158 * @param cls the client we received this message from
1159 * @param msg the actual message received
1160 */
1161static void
1162handle_dht_local_hello_offer (void *cls,
1163 const struct GNUNET_MessageHeader *msg)
1164{
1165 struct ClientHandle *ch = cls;
1166 const char *url = (const char *) &msg[1];
1167 struct GNUNET_HELLO_Builder *b;
1168 struct GNUNET_PeerIdentity pid;
1169
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171 "Local client provided HELLO URL %s\n",
1172 url);
1173 b = GNUNET_HELLO_builder_from_url (url);
1174 if (NULL == b)
1175 {
1176 GNUNET_break (0);
1177 GNUNET_SERVICE_client_drop (ch->client);
1178 return;
1179 }
1180 GNUNET_SERVICE_client_continue (ch->client);
1181 GNUNET_HELLO_builder_iterate (b,
1182 &pid,
1183 &GDS_try_connect,
1184 &pid);
1185 GNUNET_HELLO_builder_free (b);
1186}
1187
1188
1189/* ************* logic for monitors ************** */
1190
1191
1192/**
1193 * Handler for monitor start messages
1194 *
1195 * @param cls the client we received this message from
1196 * @param msg the actual message received
1197 *
1198 */
1199static void
1200handle_dht_local_monitor (void *cls,
1201 const struct GNUNET_DHT_MonitorStartStopMessage *msg)
1202{
1203 struct ClientHandle *ch = cls;
1204 struct ClientMonitorRecord *r;
1205
1206 r = GNUNET_new (struct ClientMonitorRecord);
1207 r->ch = ch;
1208 r->type = ntohl (msg->type);
1209 r->get = ntohs (msg->get);
1210 r->get_resp = ntohs (msg->get_resp);
1211 r->put = ntohs (msg->put);
1212 if (0 != ntohs (msg->filter_key))
1213 r->key = msg->key;
1214 GNUNET_CONTAINER_DLL_insert (monitor_head,
1215 monitor_tail,
1216 r);
1217 GNUNET_SERVICE_client_continue (ch->client);
1218}
1219
1220
1221/**
1222 * Handler for monitor stop messages
1223 *
1224 * @param cls the client we received this message from
1225 * @param msg the actual message received
1226 */
1227static void
1228handle_dht_local_monitor_stop (
1229 void *cls,
1230 const struct GNUNET_DHT_MonitorStartStopMessage *msg)
1231{
1232 struct ClientHandle *ch = cls;
1233
1234 GNUNET_SERVICE_client_continue (ch->client);
1235 for (struct ClientMonitorRecord *r = monitor_head;
1236 NULL != r;
1237 r = r->next)
1238 {
1239 bool keys_match;
1240
1241 keys_match =
1242 (GNUNET_is_zero (&r->key))
1243 ? (0 == ntohs (msg->filter_key))
1244 : ( (0 != ntohs (msg->filter_key)) &&
1245 (! GNUNET_memcmp (&r->key,
1246 &msg->key)) );
1247 if ( (ch == r->ch) &&
1248 (ntohl (msg->type) == r->type) &&
1249 (r->get == msg->get) &&
1250 (r->get_resp == msg->get_resp) &&
1251 (r->put == msg->put) &&
1252 keys_match)
1253 {
1254 GNUNET_CONTAINER_DLL_remove (monitor_head,
1255 monitor_tail,
1256 r);
1257 GNUNET_free (r);
1258 return; /* Delete only ONE entry */
1259 }
1260 }
1261}
1262
1263
1264/**
1265 * Function to call by #for_matching_monitors().
1266 *
1267 * @param cls closure
1268 * @param m a matching monitor
1269 */
1270typedef void
1271(*MonitorAction)(void *cls,
1272 struct ClientMonitorRecord *m);
1273
1274
1275/**
1276 * Call @a cb on all monitors that watch for blocks of @a type
1277 * and key @a key.
1278 *
1279 * @param type the type to match
1280 * @param key the key to match
1281 * @param cb function to call
1282 * @param cb_cls closure for @a cb
1283 */
1284static void
1285for_matching_monitors (enum GNUNET_BLOCK_Type type,
1286 const struct GNUNET_HashCode *key,
1287 MonitorAction cb,
1288 void *cb_cls)
1289{
1290 struct ClientHandle **cl = NULL;
1291 unsigned int cl_size = 0;
1292
1293 for (struct ClientMonitorRecord *m = monitor_head;
1294 NULL != m;
1295 m = m->next)
1296 {
1297 if ( ( (GNUNET_BLOCK_TYPE_ANY == m->type) ||
1298 (m->type == type) ) &&
1299 ( (GNUNET_is_zero (&m->key)) ||
1300 (0 ==
1301 GNUNET_memcmp (key,
1302 &m->key)) ) )
1303 {
1304 unsigned int i;
1305
1306 /* Don't send duplicates */
1307 for (i = 0; i < cl_size; i++)
1308 if (cl[i] == m->ch)
1309 break;
1310 if (i < cl_size)
1311 continue;
1312 GNUNET_array_append (cl,
1313 cl_size,
1314 m->ch);
1315 cb (cb_cls,
1316 m);
1317 }
1318 }
1319 GNUNET_free (cl);
1320}
1321
1322
1323/**
1324 * Closure for #get_action();
1325 */
1326struct GetActionContext
1327{
1328 enum GNUNET_DHT_RouteOption options;
1329 enum GNUNET_BLOCK_Type type;
1330 uint32_t hop_count;
1331 uint32_t desired_replication_level;
1332 unsigned int get_path_length;
1333 const struct GNUNET_DHT_PathElement *get_path;
1334 const struct GNUNET_HashCode *key;
1335};
1336
1337
1338/**
1339 * Function called on monitors that match a GET.
1340 * Sends the GET notification to the monitor.
1341 *
1342 * @param cls a `struct GetActionContext`
1343 * @param m a matching monitor
1344 */
1345static void
1346get_action (void *cls,
1347 struct ClientMonitorRecord *m)
1348{
1349 struct GetActionContext *gac = cls;
1350 struct GNUNET_MQ_Envelope *env;
1351 struct GNUNET_DHT_MonitorGetMessage *mmsg;
1352 struct GNUNET_DHT_PathElement *msg_path;
1353 size_t msize;
1354
1355 msize = gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement);
1356 env = GNUNET_MQ_msg_extra (mmsg,
1357 msize,
1358 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET);
1359 mmsg->options = htonl (gac->options);
1360 mmsg->type = htonl (gac->type);
1361 mmsg->hop_count = htonl (gac->hop_count);
1362 mmsg->desired_replication_level = htonl (gac->desired_replication_level);
1363 mmsg->get_path_length = htonl (gac->get_path_length);
1364 mmsg->key = *gac->key;
1365 msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1366 GNUNET_memcpy (msg_path,
1367 gac->get_path,
1368 gac->get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1369 GNUNET_MQ_send (m->ch->mq,
1370 env);
1371}
1372
1373
1374/**
1375 * Check if some client is monitoring GET messages and notify
1376 * them in that case. If tracked, @a path should include the local peer.
1377 *
1378 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
1379 * @param type The type of data in the request.
1380 * @param hop_count Hop count so far.
1381 * @param path_length number of entries in path (or 0 if not recorded).
1382 * @param path peers on the GET path (or NULL if not recorded).
1383 * @param desired_replication_level Desired replication level.
1384 * @param key Key of the requested data.
1385 */
1386void
1387GDS_CLIENTS_process_get (enum GNUNET_DHT_RouteOption options,
1388 enum GNUNET_BLOCK_Type type,
1389 uint32_t hop_count,
1390 uint32_t desired_replication_level,
1391 unsigned int path_length,
1392 const struct GNUNET_DHT_PathElement *path,
1393 const struct GNUNET_HashCode *key)
1394{
1395 struct GetActionContext gac = {
1396 .options = options,
1397 .type = type,
1398 .hop_count = hop_count,
1399 .desired_replication_level = desired_replication_level,
1400 .get_path_length = path_length,
1401 .get_path = path,
1402 .key = key
1403 };
1404
1405 for_matching_monitors (type,
1406 key,
1407 &get_action,
1408 &gac);
1409}
1410
1411
1412/**
1413 * Closure for response_action().
1414 */
1415struct ResponseActionContext
1416{
1417 const struct GDS_DATACACHE_BlockData *bd;
1418 const struct GNUNET_DHT_PathElement *get_path;
1419 unsigned int get_path_length;
1420};
1421
1422
1423/**
1424 * Function called on monitors that match a response.
1425 * Sends the response notification to the monitor.
1426 *
1427 * @param cls a `struct ResponseActionContext`
1428 * @param m a matching monitor
1429 */
1430static void
1431response_action (void *cls,
1432 struct ClientMonitorRecord *m)
1433{
1434 const struct ResponseActionContext *resp_ctx = cls;
1435 const struct GDS_DATACACHE_BlockData *bd = resp_ctx->bd;
1436
1437 struct GNUNET_MQ_Envelope *env;
1438 struct GNUNET_DHT_MonitorGetRespMessage *mmsg;
1439 struct GNUNET_DHT_PathElement *path;
1440 size_t msize;
1441
1442 msize = bd->data_size;
1443 msize += (resp_ctx->get_path_length + bd->put_path_length)
1444 * sizeof(struct GNUNET_DHT_PathElement);
1445 env = GNUNET_MQ_msg_extra (mmsg,
1446 msize,
1447 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP);
1448 mmsg->type = htonl (bd->type);
1449 mmsg->put_path_length = htonl (bd->put_path_length);
1450 mmsg->get_path_length = htonl (resp_ctx->get_path_length);
1451 mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1452 mmsg->key = bd->key;
1453 path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1454 GNUNET_memcpy (path,
1455 bd->put_path,
1456 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
1457 GNUNET_memcpy (path,
1458 resp_ctx->get_path,
1459 resp_ctx->get_path_length
1460 * sizeof(struct GNUNET_DHT_PathElement));
1461 GNUNET_memcpy (&path[resp_ctx->get_path_length],
1462 bd->data,
1463 bd->data_size);
1464 GNUNET_MQ_send (m->ch->mq,
1465 env);
1466}
1467
1468
1469void
1470GDS_CLIENTS_process_get_resp (const struct GDS_DATACACHE_BlockData *bd,
1471 const struct GNUNET_DHT_PathElement *get_path,
1472 unsigned int get_path_length)
1473{
1474 struct ResponseActionContext rac = {
1475 .bd = bd,
1476 .get_path = get_path,
1477 .get_path_length = get_path_length
1478 };
1479
1480 for_matching_monitors (bd->type,
1481 &bd->key,
1482 &response_action,
1483 &rac);
1484}
1485
1486
1487/**
1488 * Closure for put_action().
1489 */
1490struct PutActionContext
1491{
1492 const struct GDS_DATACACHE_BlockData *bd;
1493 enum GNUNET_DHT_RouteOption options;
1494 uint32_t hop_count;
1495 uint32_t desired_replication_level;
1496};
1497
1498
1499/**
1500 * Function called on monitors that match a PUT.
1501 * Sends the PUT notification to the monitor.
1502 *
1503 * @param cls a `struct PutActionContext`
1504 * @param m a matching monitor
1505 */
1506static void
1507put_action (void *cls,
1508 struct ClientMonitorRecord *m)
1509{
1510 const struct PutActionContext *put_ctx = cls;
1511 const struct GDS_DATACACHE_BlockData *bd = put_ctx->bd;
1512 struct GNUNET_MQ_Envelope *env;
1513 struct GNUNET_DHT_MonitorPutMessage *mmsg;
1514 struct GNUNET_DHT_PathElement *msg_path;
1515 size_t msize;
1516
1517 msize = bd->data_size
1518 + bd->put_path_length
1519 * sizeof(struct GNUNET_DHT_PathElement);
1520 env = GNUNET_MQ_msg_extra (mmsg,
1521 msize,
1522 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT);
1523 mmsg->options = htonl (put_ctx->options);
1524 mmsg->type = htonl (bd->type);
1525 mmsg->hop_count = htonl (put_ctx->hop_count);
1526 mmsg->desired_replication_level = htonl (put_ctx->desired_replication_level);
1527 mmsg->put_path_length = htonl (bd->put_path_length);
1528 mmsg->key = bd->key;
1529 mmsg->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1530 msg_path = (struct GNUNET_DHT_PathElement *) &mmsg[1];
1531 GNUNET_memcpy (msg_path,
1532 bd->put_path,
1533 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
1534 GNUNET_memcpy (&msg_path[bd->put_path_length],
1535 bd->data,
1536 bd->data_size);
1537 GNUNET_MQ_send (m->ch->mq,
1538 env);
1539}
1540
1541
1542void
1543GDS_CLIENTS_process_put (enum GNUNET_DHT_RouteOption options,
1544 const struct GDS_DATACACHE_BlockData *bd,
1545 uint32_t hop_count,
1546 uint32_t desired_replication_level)
1547{
1548 struct PutActionContext put_ctx = {
1549 .bd = bd,
1550 .hop_count = hop_count,
1551 .desired_replication_level = desired_replication_level,
1552 .options = options
1553 };
1554
1555 for_matching_monitors (bd->type,
1556 &bd->key,
1557 &put_action,
1558 &put_ctx);
1559}
1560
1561
1562/* ********************** Initialization logic ***************** */
1563
1564
1565/**
1566 * Initialize client subsystem.
1567 *
1568 * @param server the initialized server
1569 */
1570static void
1571GDS_CLIENTS_init (void)
1572{
1573 forward_map
1574 = GNUNET_CONTAINER_multihashmap_create (1024,
1575 GNUNET_YES);
1576 retry_heap
1577 = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1578}
1579
1580
1581/**
1582 * Shutdown client subsystem.
1583 */
1584static void
1585GDS_CLIENTS_stop (void)
1586{
1587 if (NULL != retry_task)
1588 {
1589 GNUNET_SCHEDULER_cancel (retry_task);
1590 retry_task = NULL;
1591 }
1592}
1593
1594
1595/**
1596 * Define "main" method using service macro.
1597 *
1598 * @param name name of the service, like "dht" or "xdht"
1599 * @param run name of the initializaton method for the service
1600 */
1601#define GDS_DHT_SERVICE_INIT(name, run) \
1602 GNUNET_SERVICE_MAIN \
1603 (name, \
1604 GNUNET_SERVICE_OPTION_NONE, \
1605 run, \
1606 &client_connect_cb, \
1607 &client_disconnect_cb, \
1608 NULL, \
1609 GNUNET_MQ_hd_var_size (dht_local_put, \
1610 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, \
1611 struct GNUNET_DHT_ClientPutMessage, \
1612 NULL), \
1613 GNUNET_MQ_hd_var_size (dht_local_get, \
1614 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, \
1615 struct GNUNET_DHT_ClientGetMessage, \
1616 NULL), \
1617 GNUNET_MQ_hd_fixed_size (dht_local_get_stop, \
1618 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP, \
1619 struct GNUNET_DHT_ClientGetStopMessage, \
1620 NULL), \
1621 GNUNET_MQ_hd_fixed_size (dht_local_monitor, \
1622 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START, \
1623 struct GNUNET_DHT_MonitorStartStopMessage, \
1624 NULL), \
1625 GNUNET_MQ_hd_fixed_size (dht_local_monitor_stop, \
1626 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP, \
1627 struct GNUNET_DHT_MonitorStartStopMessage, \
1628 NULL), \
1629 GNUNET_MQ_hd_var_size (dht_local_get_result_seen, \
1630 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN, \
1631 struct GNUNET_DHT_ClientGetResultSeenMessage, \
1632 NULL), \
1633 GNUNET_MQ_hd_fixed_size (dht_local_hello_get, \
1634 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_GET, \
1635 struct GNUNET_MessageHeader, \
1636 NULL), \
1637 GNUNET_MQ_hd_var_size (dht_local_hello_offer, \
1638 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL, \
1639 struct GNUNET_MessageHeader, \
1640 NULL), \
1641 GNUNET_MQ_handler_end ())
1642
1643
1644/**
1645 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1646 */
1647void __attribute__ ((destructor))
1648GDS_CLIENTS_done ()
1649{
1650 if (NULL != retry_heap)
1651 {
1652 GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap));
1653 GNUNET_CONTAINER_heap_destroy (retry_heap);
1654 retry_heap = NULL;
1655 }
1656 if (NULL != forward_map)
1657 {
1658 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map));
1659 GNUNET_CONTAINER_multihashmap_destroy (forward_map);
1660 forward_map = NULL;
1661 }
1662}
1663
1664
1665/* 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 be0a6db81..000000000
--- a/src/dht/gnunet-service-dht_datacache.c
+++ /dev/null
@@ -1,318 +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 4
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 &GDS_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_ReplyEvaluationResult 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_IRRELEVANT:
208 GNUNET_STATISTICS_update (GDS_stats,
209 "# Irrelevant RESULTS found in datacache",
210 1,
211 GNUNET_NO);
212 break;
213 }
214 return (eval == GNUNET_BLOCK_REPLY_OK_LAST) ? GNUNET_NO : GNUNET_OK;
215}
216
217
218enum GNUNET_BLOCK_ReplyEvaluationResult
219GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
220 enum GNUNET_BLOCK_Type type,
221 const void *xquery,
222 size_t xquery_size,
223 struct GNUNET_BLOCK_Group *bg,
224 GDS_DATACACHE_GetCallback gc,
225 void *gc_cls)
226{
227 struct GetRequestContext ctx = {
228 .eval = GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED,
229 .key = *key,
230 .xquery = xquery,
231 .xquery_size = xquery_size,
232 .bg = bg,
233 .gc = gc,
234 .gc_cls = gc_cls
235 };
236 unsigned int r;
237
238 if (NULL == datacache)
239 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
240 GNUNET_STATISTICS_update (GDS_stats,
241 "# GET requests given to datacache",
242 1,
243 GNUNET_NO);
244 r = GNUNET_DATACACHE_get (datacache,
245 key,
246 type,
247 &datacache_get_iterator,
248 &ctx);
249 LOG (GNUNET_ERROR_TYPE_DEBUG,
250 "DATACACHE GET for key %s completed (%d). %u results found.\n",
251 GNUNET_h2s (key),
252 ctx.eval,
253 r);
254 return ctx.eval;
255}
256
257
258enum GNUNET_BLOCK_ReplyEvaluationResult
259GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
260 enum GNUNET_BLOCK_Type type,
261 const void *xquery,
262 size_t xquery_size,
263 struct GNUNET_BLOCK_Group *bg,
264 GDS_DATACACHE_GetCallback cb,
265 void *cb_cls)
266{
267 struct GetRequestContext ctx = {
268 .eval = GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED,
269 .key = *key,
270 .xquery = xquery,
271 .xquery_size = xquery_size,
272 .bg = bg,
273 .gc = cb,
274 .gc_cls = cb_cls
275 };
276 unsigned int r;
277
278 if (NULL == datacache)
279 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
280 GNUNET_STATISTICS_update (GDS_stats,
281 "# GET closest requests given to datacache",
282 1,
283 GNUNET_NO);
284 r = GNUNET_DATACACHE_get_closest (datacache,
285 key,
286 type,
287 NUM_CLOSEST,
288 &datacache_get_iterator,
289 &ctx);
290 LOG (GNUNET_ERROR_TYPE_DEBUG,
291 "DATACACHE approximate GET for key %s completed (%d). %u results found.\n",
292 GNUNET_h2s (key),
293 ctx.eval,
294 r);
295 return ctx.eval;
296}
297
298
299void
300GDS_DATACACHE_init ()
301{
302 datacache = GNUNET_DATACACHE_create (GDS_cfg,
303 "dhtcache");
304}
305
306
307void
308GDS_DATACACHE_done ()
309{
310 if (NULL != datacache)
311 {
312 GNUNET_DATACACHE_destroy (datacache);
313 datacache = NULL;
314 }
315}
316
317
318/* 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 d860139f5..000000000
--- a/src/dht/gnunet-service-dht_datacache.h
+++ /dev/null
@@ -1,156 +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_ReplyEvaluationResult
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 type requested data type
126 * @param xquery extended query
127 * @param xquery_size number of bytes in xquery
128 * @param bg block group to use for evaluation of replies
129 * @param cb function to call with the result
130 * @param cb_cls closure for @a cb
131 * @return evaluation result for the local replies
132 */
133enum GNUNET_BLOCK_ReplyEvaluationResult
134GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
135 enum GNUNET_BLOCK_Type type,
136 const void *xquery,
137 size_t xquery_size,
138 struct GNUNET_BLOCK_Group *bg,
139 GDS_DATACACHE_GetCallback cb,
140 void *cb_cls);
141
142
143/**
144 * Initialize datacache subsystem.
145 */
146void
147GDS_DATACACHE_init (void);
148
149
150/**
151 * Shutdown datacache subsystem.
152 */
153void
154GDS_DATACACHE_done (void);
155
156#endif
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
deleted file mode 100644
index fde25936f..000000000
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ /dev/null
@@ -1,2695 +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_hello_lib.h"
32#include "gnunet_hello_uri_lib.h"
33#include "gnunet-service-dht.h"
34#include "gnunet-service-dht_neighbours.h"
35#include "gnunet-service-dht_routing.h"
36#include "dht.h"
37
38#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
39 __VA_ARGS__)
40
41/**
42 * Enable slow sanity checks to debug issues.
43 *
44 * TODO: might want to eventually implement probabilistic
45 * load-based path verification, but for now it is all or nothing
46 * based on this define.
47 *
48 * 0: do not check -- if signatures become performance critical
49 * 1: check all external inputs -- normal production for now
50 * 2: check internal computations as well -- for debugging
51 */
52#define SANITY_CHECKS 2
53
54/**
55 * How many buckets will we allow in total.
56 */
57#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
58
59/**
60 * What is the maximum number of peers in a given bucket.
61 */
62#define DEFAULT_BUCKET_SIZE 8
63
64/**
65 * Desired replication level for FIND PEER requests
66 */
67#define FIND_PEER_REPLICATION_LEVEL 4
68
69/**
70 * Maximum allowed number of pending messages per peer.
71 */
72#define MAXIMUM_PENDING_PER_PEER 64
73
74/**
75 * How long at least to wait before sending another find peer request.
76 * This is basically the frequency at which we will usually send out
77 * requests when we are 'perfectly' connected.
78 */
79#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
80 GNUNET_TIME_UNIT_MINUTES, 2)
81
82
83/**
84 * How long to additionally wait on average per #bucket_size to send out the
85 * FIND PEER requests if we did successfully connect (!) to a a new peer and
86 * added it to a bucket (as counted in #newly_found_peers). This time is
87 * Multiplied by 100 * newly_found_peers / bucket_size to get the new delay
88 * for finding peers (the #DHT_MINIMUM_FIND_PEER_INTERVAL is still added on
89 * top). Also the range in which we randomize, so the effective value
90 * is half of the number given here.
91 */
92#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
93 GNUNET_TIME_UNIT_SECONDS, 6)
94
95/**
96 * How long at most to wait for transmission of a GET request to another peer?
97 */
98#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
99
100
101GNUNET_NETWORK_STRUCT_BEGIN
102
103/**
104 * P2P PUT message
105 */
106struct PeerPutMessage
107{
108 /**
109 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
110 */
111 struct GNUNET_MessageHeader header;
112
113 /**
114 * Content type.
115 */
116 uint32_t type GNUNET_PACKED;
117
118 /**
119 * Processing options
120 */
121 uint16_t options GNUNET_PACKED;
122
123 /**
124 * Hop count
125 */
126 uint16_t hop_count GNUNET_PACKED;
127
128 /**
129 * Replication level for this message
130 */
131 uint16_t desired_replication_level GNUNET_PACKED;
132
133 /**
134 * Length of the PUT path that follows (if tracked).
135 */
136 uint16_t put_path_length GNUNET_PACKED;
137
138 /**
139 * When does the content expire?
140 */
141 struct GNUNET_TIME_AbsoluteNBO expiration_time;
142
143 /**
144 * Bloomfilter (for peer identities) to stop circular routes
145 */
146 char bloomfilter[DHT_BLOOM_SIZE];
147
148 /**
149 * The key we are storing under.
150 */
151 struct GNUNET_HashCode key;
152
153 /* put path (if tracked) */
154
155 /* Payload */
156};
157
158
159/**
160 * P2P Result message
161 */
162struct PeerResultMessage
163{
164 /**
165 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
166 */
167 struct GNUNET_MessageHeader header;
168
169 /**
170 * Content type.
171 */
172 uint32_t type GNUNET_PACKED;
173
174 /**
175 * Reserved.
176 */
177 uint32_t reserved GNUNET_PACKED;
178
179 /**
180 * Length of the PUT path that follows (if tracked).
181 */
182 uint16_t put_path_length GNUNET_PACKED;
183
184 /**
185 * Length of the GET path that follows (if tracked).
186 */
187 uint16_t get_path_length GNUNET_PACKED;
188
189 /**
190 * When does the content expire?
191 */
192 struct GNUNET_TIME_AbsoluteNBO expiration_time;
193
194 /**
195 * The key of the corresponding GET request.
196 */
197 struct GNUNET_HashCode key;
198
199 /* put path (if tracked) */
200
201 /* get path (if tracked) */
202
203 /* Payload */
204};
205
206
207/**
208 * P2P GET message
209 */
210struct PeerGetMessage
211{
212 /**
213 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
214 */
215 struct GNUNET_MessageHeader header;
216
217 /**
218 * Desired content type.
219 */
220 uint32_t type GNUNET_PACKED;
221
222 /**
223 * Processing options
224 */
225 uint16_t options GNUNET_PACKED;
226
227 /**
228 * Hop count
229 */
230 uint16_t hop_count GNUNET_PACKED;
231
232 /**
233 * Desired replication level for this request.
234 */
235 uint16_t desired_replication_level GNUNET_PACKED;
236
237 /**
238 * Size of the result filter.
239 */
240 uint16_t result_filter_size GNUNET_PACKED;
241
242 /**
243 * Bloomfilter (for peer identities) to stop circular routes
244 */
245 char bloomfilter[DHT_BLOOM_SIZE];
246
247 /**
248 * The key we are looking for.
249 */
250 struct GNUNET_HashCode key;
251
252 /* result bloomfilter */
253
254 /* xquery */
255
256};
257GNUNET_NETWORK_STRUCT_END
258
259
260/**
261 * Entry for a peer in a bucket.
262 */
263struct PeerInfo;
264
265
266/**
267 * List of targets that we can use to reach this peer.
268 */
269struct Target
270{
271 /**
272 * Kept in a DLL.
273 */
274 struct Target *next;
275
276 /**
277 * Kept in a DLL.
278 */
279 struct Target *prev;
280
281 /**
282 * Handle for sending messages to this peer.
283 */
284 struct GNUNET_DHTU_Target *utarget;
285
286 /**
287 * Underlay providing this target.
288 */
289 struct GDS_Underlay *u;
290
291 /**
292 * Peer this is a target for.
293 */
294 struct PeerInfo *pi;
295
296 /**
297 * Handle used to 'hold' the connection to this peer.
298 */
299 struct GNUNET_DHTU_PreferenceHandle *ph;
300
301 /**
302 * Set to number of messages are waiting for the transmission to finish.
303 */
304 unsigned int load;
305
306 /**
307 * Set to @a true if the target was dropped, but we could not clean
308 * up yet because @e busy was also true.
309 */
310 bool dropped;
311
312};
313
314
315/**
316 * Entry for a peer in a bucket.
317 */
318struct PeerInfo
319{
320 /**
321 * What is the identity of the peer?
322 */
323 struct GNUNET_PeerIdentity id;
324
325 /**
326 * Hash of @e id.
327 */
328 struct GNUNET_HashCode phash;
329
330 /**
331 * When does our HELLO from this peer expire?
332 */
333 struct GNUNET_TIME_Absolute hello_expiration;
334
335 /**
336 * Next peer entry (DLL)
337 */
338 struct PeerInfo *next;
339
340 /**
341 * Prev peer entry (DLL)
342 */
343 struct PeerInfo *prev;
344
345 /**
346 * Head of DLL of targets for this peer.
347 */
348 struct Target *t_head;
349
350 /**
351 * Tail of DLL of targets for this peer.
352 */
353 struct Target *t_tail;
354
355 /**
356 * Block with a HELLO of this peer.
357 */
358 void *hello;
359
360 /**
361 * Number of bytes in @e hello.
362 */
363 size_t hello_size;
364
365 /**
366 * Which bucket is this peer in?
367 */
368 int peer_bucket;
369};
370
371
372/**
373 * Peers are grouped into buckets.
374 */
375struct PeerBucket
376{
377 /**
378 * Head of DLL
379 */
380 struct PeerInfo *head;
381
382 /**
383 * Tail of DLL
384 */
385 struct PeerInfo *tail;
386
387 /**
388 * Number of peers in the bucket.
389 */
390 unsigned int peers_size;
391};
392
393
394/**
395 * Do we cache all results that we are routing in the local datacache?
396 */
397static int cache_results;
398
399/**
400 * The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
401 */
402static unsigned int closest_bucket;
403
404/**
405 * How many peers have we added since we sent out our last
406 * find peer request?
407 */
408static unsigned int newly_found_peers;
409
410/**
411 * Option for testing that disables the 'connect' function of the DHT.
412 */
413static int disable_try_connect;
414
415/**
416 * The buckets. Array of size #MAX_BUCKETS. Offset 0 means 0 bits matching.
417 */
418static struct PeerBucket k_buckets[MAX_BUCKETS];
419
420/**
421 * Hash map of all CORE-connected peers, for easy removal from
422 * #k_buckets on disconnect. Values are of type `struct PeerInfo`.
423 */
424static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
425
426/**
427 * Maximum size for each bucket.
428 */
429static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
430
431/**
432 * Task that sends FIND PEER requests.
433 */
434static struct GNUNET_SCHEDULER_Task *find_peer_task;
435
436
437/**
438 * Function called whenever we finished sending to a target.
439 * Marks the transmission as finished (and the target as ready
440 * for the next message).
441 *
442 * @param cls a `struct Target *`
443 */
444static void
445send_done_cb (void *cls)
446{
447 struct Target *t = cls;
448 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
449
450 GNUNET_assert (t->load > 0);
451 t->load--;
452 if (0 < t->load)
453 return;
454 if (t->dropped)
455 {
456 GNUNET_free (t);
457 return;
458 }
459 /* move target back to the front */
460 GNUNET_CONTAINER_DLL_remove (pi->t_head,
461 pi->t_tail,
462 t);
463 GNUNET_CONTAINER_DLL_insert (pi->t_head,
464 pi->t_tail,
465 t);
466}
467
468
469/**
470 * Send @a msg to @a pi.
471 *
472 * @param pi where to send the message
473 * @param msg message to send
474 */
475static void
476do_send (struct PeerInfo *pi,
477 const struct GNUNET_MessageHeader *msg)
478{
479 struct Target *t;
480
481 for (t = pi->t_head;
482 NULL != t;
483 t = t->next)
484 if (t->load < MAXIMUM_PENDING_PER_PEER)
485 break;
486 if (NULL == t)
487 {
488 /* all targets busy, drop message */
489 GNUNET_STATISTICS_update (GDS_stats,
490 "# messages dropped (underlays busy)",
491 1,
492 GNUNET_NO);
493 return;
494 }
495 t->load++;
496 /* rotate busy targets to the end */
497 if (MAXIMUM_PENDING_PER_PEER == t->load)
498 {
499 GNUNET_CONTAINER_DLL_remove (pi->t_head,
500 pi->t_tail,
501 t);
502 GNUNET_CONTAINER_DLL_insert_tail (pi->t_head,
503 pi->t_tail,
504 t);
505 }
506 GDS_u_send (t->u,
507 t->utarget,
508 msg,
509 ntohs (msg->size),
510 &send_done_cb,
511 t);
512}
513
514
515/**
516 * Sign that we are routing a message from @a pred to @a succ.
517 * (So the route is $PRED->us->$SUCC).
518 *
519 * @param key key of the data (not necessarily the query hash)
520 * @param data payload (the block)
521 * @param data_size number of bytes in @a data
522 * @param exp_time expiration time of @a data
523 * @param pred predecessor peer ID
524 * @param succ successor peer ID
525 * @param[out] sig where to write the signature
526 * (of purpose #GNUNET_SIGNATURE_PURPOSE_DHT_PUT_HOP)
527 */
528static void
529sign_path (const void *data,
530 size_t data_size,
531 struct GNUNET_TIME_Absolute exp_time,
532 const struct GNUNET_PeerIdentity *pred,
533 const struct GNUNET_PeerIdentity *succ,
534 struct GNUNET_CRYPTO_EddsaSignature *sig)
535{
536 struct GNUNET_DHT_HopSignature hs = {
537 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
538 .purpose.size = htonl (sizeof (hs)),
539 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
540 .pred = *pred,
541 .succ = *succ
542 };
543
544 GNUNET_CRYPTO_hash (data,
545 data_size,
546 &hs.h_data);
547 GNUNET_CRYPTO_eddsa_sign (&GDS_my_private_key,
548 &hs,
549 sig);
550}
551
552
553/**
554 * Find the optimal bucket for this key.
555 *
556 * @param hc the hashcode to compare our identity to
557 * @return the proper bucket index, or -1
558 * on error (same hashcode)
559 */
560static int
561find_bucket (const struct GNUNET_HashCode *hc)
562{
563 struct GNUNET_HashCode xor;
564 unsigned int bits;
565
566 GNUNET_CRYPTO_hash_xor (hc,
567 &GDS_my_identity_hash,
568 &xor);
569 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
570 if (bits == MAX_BUCKETS)
571 {
572 /* How can all bits match? Got my own ID? */
573 GNUNET_break (0);
574 return -1;
575 }
576 return MAX_BUCKETS - bits - 1;
577}
578
579
580/**
581 * Add each of the peers we already know to the Bloom filter of
582 * the request so that we don't get duplicate HELLOs.
583 *
584 * @param cls the `struct GNUNET_BLOCK_Group`
585 * @param key peer identity to add to the bloom filter
586 * @param value the peer information
587 * @return #GNUNET_YES (we should continue to iterate)
588 */
589static enum GNUNET_GenericReturnValue
590add_known_to_bloom (void *cls,
591 const struct GNUNET_PeerIdentity *key,
592 void *value)
593{
594 struct GNUNET_BLOCK_Group *bg = cls;
595 struct PeerInfo *pi = value;
596
597 GNUNET_BLOCK_group_set_seen (bg,
598 &pi->phash,
599 1);
600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
601 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
602 GNUNET_i2s (key));
603 return GNUNET_YES;
604}
605
606
607/**
608 * Task to send a find peer message for our own peer identifier
609 * so that we can find the closest peers in the network to ourselves
610 * and attempt to connect to them.
611 *
612 * @param cls closure for this task, NULL
613 */
614static void
615send_find_peer_message (void *cls)
616{
617 (void) cls;
618
619 /* Compute when to do this again (and if we should
620 even send a message right now) */
621 {
622 struct GNUNET_TIME_Relative next_send_time;
623 bool done_early;
624
625 find_peer_task = NULL;
626 done_early = (newly_found_peers > bucket_size);
627 /* schedule next round, taking longer if we found more peers
628 in the last round. */
629 next_send_time.rel_value_us =
630 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
631 + GNUNET_CRYPTO_random_u64 (
632 GNUNET_CRYPTO_QUALITY_WEAK,
633 GNUNET_TIME_relative_multiply (
634 DHT_AVG_FIND_PEER_INTERVAL,
635 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
636 newly_found_peers = 0;
637 GNUNET_assert (NULL == find_peer_task);
638 find_peer_task =
639 GNUNET_SCHEDULER_add_delayed (next_send_time,
640 &send_find_peer_message,
641 NULL);
642 if (done_early)
643 return;
644 }
645
646 /* actually send 'find peer' request */
647 {
648 struct GNUNET_BLOCK_Group *bg;
649 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
650
651 bg = GNUNET_BLOCK_group_create (GDS_block_context,
652 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
653 NULL,
654 0,
655 "filter-size",
656 DHT_BLOOM_SIZE,
657 NULL);
658 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
659 &add_known_to_bloom,
660 bg);
661 peer_bf
662 = GNUNET_CONTAINER_bloomfilter_init (NULL,
663 DHT_BLOOM_SIZE,
664 GNUNET_CONSTANTS_BLOOMFILTER_K);
665 if (GNUNET_OK !=
666 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
667 GNUNET_DHT_RO_FIND_APPROXIMATE
668 | GNUNET_DHT_RO_RECORD_ROUTE,
669 FIND_PEER_REPLICATION_LEVEL,
670 0, /* hop count */
671 &GDS_my_identity_hash,
672 NULL, 0, /* xquery */
673 bg,
674 peer_bf))
675 {
676 GNUNET_STATISTICS_update (GDS_stats,
677 "# Failed to initiate FIND PEER lookup",
678 1,
679 GNUNET_NO);
680 }
681 else
682 {
683 GNUNET_STATISTICS_update (GDS_stats,
684 "# FIND PEER messages initiated",
685 1,
686 GNUNET_NO);
687 }
688 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
689 GNUNET_BLOCK_group_destroy (bg);
690 }
691}
692
693
694/**
695 * The list of the first #bucket_size peers of @a bucket
696 * changed. We should thus make sure we have called 'hold'
697 * all of the first bucket_size peers!
698 *
699 * @param[in,out] bucket the bucket where the peer set changed
700 */
701static void
702update_hold (struct PeerBucket *bucket)
703{
704 unsigned int off = 0;
705
706 /* find the peer -- we just go over all of them, should
707 be hardly any more expensive than just finding the 'right'
708 one. */
709 for (struct PeerInfo *pos = bucket->head;
710 NULL != pos;
711 pos = pos->next)
712 {
713 if (off > bucket_size)
714 break; /* We only hold up to #bucket_size peers per bucket */
715 off++;
716 for (struct Target *tp = pos->t_head;
717 NULL != tp;
718 tp = tp->next)
719 if (NULL == tp->ph)
720 tp->ph = GDS_u_hold (tp->u,
721 tp->utarget);
722 }
723}
724
725
726void
727GDS_u_connect (void *cls,
728 struct GNUNET_DHTU_Target *target,
729 const struct GNUNET_PeerIdentity *pid,
730 void **ctx)
731{
732 struct GDS_Underlay *u = cls;
733 struct PeerInfo *pi;
734 struct PeerBucket *bucket;
735 bool do_hold = false;
736
737 /* Check for connect to self message */
738 if (0 == GNUNET_memcmp (&GDS_my_identity,
739 pid))
740 return;
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
742 "Connected to peer %s\n",
743 GNUNET_i2s (pid));
744 pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
745 pid);
746 if (NULL == pi)
747 {
748 GNUNET_STATISTICS_update (GDS_stats,
749 "# peers connected",
750 1,
751 GNUNET_NO);
752 pi = GNUNET_new (struct PeerInfo);
753 pi->id = *pid;
754 GNUNET_CRYPTO_hash (pid,
755 sizeof(*pid),
756 &pi->phash);
757 pi->peer_bucket = find_bucket (&pi->phash);
758 GNUNET_assert ( (pi->peer_bucket >= 0) &&
759 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
760 bucket = &k_buckets[pi->peer_bucket];
761 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
762 bucket->tail,
763 pi);
764 bucket->peers_size++;
765 closest_bucket = GNUNET_MAX (closest_bucket,
766 (unsigned int) pi->peer_bucket + 1);
767 GNUNET_assert (GNUNET_OK ==
768 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
769 &pi->id,
770 pi,
771 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
772 if (bucket->peers_size <= bucket_size)
773 {
774 newly_found_peers++;
775 do_hold = true;
776 }
777 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
778 (GNUNET_YES != disable_try_connect) )
779 {
780 /* got a first connection, good time to start with FIND PEER requests... */
781 GNUNET_assert (NULL == find_peer_task);
782 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
783 NULL);
784 }
785 }
786 {
787 struct Target *t;
788
789 t = GNUNET_new (struct Target);
790 t->u = u;
791 t->utarget = target;
792 t->pi = pi;
793 GNUNET_CONTAINER_DLL_insert (pi->t_head,
794 pi->t_tail,
795 t);
796 *ctx = t;
797
798 }
799 if (do_hold)
800 update_hold (bucket);
801}
802
803
804void
805GDS_u_disconnect (void *ctx)
806{
807 struct Target *t = ctx;
808 struct PeerInfo *pi;
809 struct PeerBucket *bucket;
810 bool was_held = false;
811
812 /* Check for disconnect from self message (on shutdown) */
813 if (NULL == t)
814 return;
815 pi = t->pi;
816 GNUNET_CONTAINER_DLL_remove (pi->t_head,
817 pi->t_tail,
818 t);
819 if (NULL != t->ph)
820 {
821 GDS_u_drop (t->u,
822 t->ph);
823 t->ph = NULL;
824 was_held = true;
825 }
826 if (t->load > 0)
827 {
828 t->dropped = true;
829 t->pi = NULL;
830 }
831 else
832 {
833 GNUNET_free (t);
834 }
835 if (NULL != pi->t_head)
836 return; /* got other connections still */
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838 "Disconnected from peer %s\n",
839 GNUNET_i2s (&pi->id));
840 GNUNET_STATISTICS_update (GDS_stats,
841 "# peers connected",
842 -1,
843 GNUNET_NO);
844 GNUNET_assert (GNUNET_YES ==
845 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
846 &pi->id,
847 pi));
848 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
849 (GNUNET_YES != disable_try_connect))
850 {
851 GNUNET_SCHEDULER_cancel (find_peer_task);
852 find_peer_task = NULL;
853 }
854 GNUNET_assert (pi->peer_bucket >= 0);
855 bucket = &k_buckets[pi->peer_bucket];
856 GNUNET_CONTAINER_DLL_remove (bucket->head,
857 bucket->tail,
858 pi);
859 GNUNET_assert (bucket->peers_size > 0);
860 bucket->peers_size--;
861 if ( (was_held) &&
862 (bucket->peers_size >= bucket_size - 1) )
863 update_hold (bucket);
864 while ( (closest_bucket > 0) &&
865 (0 == k_buckets[closest_bucket - 1].peers_size))
866 closest_bucket--;
867 GNUNET_free (pi->hello);
868 GNUNET_free (pi);
869}
870
871
872/**
873 * To how many peers should we (on average) forward the request to
874 * obtain the desired target_replication count (on average).
875 *
876 * @param hop_count number of hops the message has traversed
877 * @param target_replication the number of total paths desired
878 * @return Some number of peers to forward the message to
879 */
880static unsigned int
881get_forward_count (uint16_t hop_count,
882 uint16_t target_replication)
883{
884 uint32_t random_value;
885 uint32_t forward_count;
886 float target_value;
887 float rm1;
888
889 if (hop_count > GDS_NSE_get () * 4.0)
890 {
891 /* forcefully terminate */
892 GNUNET_STATISTICS_update (GDS_stats,
893 "# requests TTL-dropped",
894 1,
895 GNUNET_NO);
896 return 0;
897 }
898 if (hop_count > GDS_NSE_get () * 2.0)
899 {
900 /* Once we have reached our ideal number of hops, only forward to 1 peer */
901 return 1;
902 }
903 /* bound by system-wide maximum and minimum */
904 if (0 == target_replication)
905 target_replication = 1; /* 0 is verboten */
906 target_replication =
907 GNUNET_MIN (GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL,
908 target_replication);
909 rm1 = target_replication - 1.0;
910 target_value =
911 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
912
913 /* Set forward count to floor of target_value */
914 forward_count = (uint32_t) target_value;
915 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
916 target_value = target_value - forward_count;
917 random_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
918 UINT32_MAX);
919 if (random_value < (target_value * UINT32_MAX))
920 forward_count++;
921 return GNUNET_MIN (forward_count,
922 GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL);
923}
924
925
926/**
927 * Check whether my identity is closer than any known peers. If a
928 * non-null bloomfilter is given, check if this is the closest peer
929 * that hasn't already been routed to.
930 *
931 * @param key hash code to check closeness to
932 * @param bloom bloomfilter, exclude these entries from the decision
933 * @return #GNUNET_YES if node location is closest,
934 * #GNUNET_NO otherwise.
935 */
936enum GNUNET_GenericReturnValue
937GDS_am_closest_peer (const struct GNUNET_HashCode *key,
938 const struct GNUNET_CONTAINER_BloomFilter *bloom)
939{
940 if (0 == GNUNET_memcmp (&GDS_my_identity_hash,
941 key))
942 return GNUNET_YES;
943 for (int bucket_num = find_bucket (key);
944 bucket_num < closest_bucket;
945 bucket_num++)
946 {
947 unsigned int count = 0;
948
949 GNUNET_assert (bucket_num >= 0);
950 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
951 NULL != pos;
952 pos = pos->next)
953 {
954 if (count >= bucket_size)
955 break; /* we only consider first #bucket_size entries per bucket */
956 count++;
957 if ( (NULL != bloom) &&
958 (GNUNET_YES ==
959 GNUNET_CONTAINER_bloomfilter_test (bloom,
960 &pos->phash)) )
961 continue; /* Ignore filtered peers */
962 /* All peers in this bucket must be closer than us, as
963 they mismatch with our PID on the pivotal bit. So
964 because an unfiltered peer exists, we are not the
965 closest. */
966 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
967 &GDS_my_identity_hash,
968 key);
969 switch (delta)
970 {
971 case -1: /* pos closer */
972 return GNUNET_NO;
973 case 0: /* identical, impossible! */
974 GNUNET_assert (0);
975 break;
976 case 1: /* I am closer */
977 break;
978 }
979 }
980 }
981 /* No closer (unfiltered) peers found; we must be the closest! */
982 return GNUNET_YES;
983}
984
985
986/**
987 * Select a peer from the routing table that would be a good routing
988 * destination for sending a message for @a key. The resulting peer
989 * must not be in the set of @a bloom blocked peers.
990 *
991 * Note that we should not ALWAYS select the closest peer to the
992 * target, we do a "random" peer selection if the number of @a hops
993 * is below the logarithm of the network size estimate.
994 *
995 * In all cases, we only consider at most the first #bucket_size peers of any
996 * #k_buckets. The other peers in the bucket are there because GNUnet doesn't
997 * really allow the DHT to "reject" connections, but we only use the first
998 * #bucket_size, even if more exist. (The idea is to ensure that those
999 * connections are frequently used, and for others to be not used by the DHT,
1000 * and thus possibly dropped by transport due to disuse).
1001 *
1002 * @param key the key we are selecting a peer to route to
1003 * @param bloom a Bloom filter containing entries this request has seen already
1004 * @param hops how many hops has this message traversed thus far
1005 * @return Peer to route to, or NULL on error
1006 */
1007static struct PeerInfo *
1008select_peer (const struct GNUNET_HashCode *key,
1009 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1010 uint32_t hops)
1011{
1012 if (0 == closest_bucket)
1013 {
1014 GNUNET_STATISTICS_update (GDS_stats,
1015 "# Peer selection failed",
1016 1,
1017 GNUNET_NO);
1018 return NULL; /* we have zero connections */
1019 }
1020 if (hops >= GDS_NSE_get ())
1021 {
1022 /* greedy selection (closest peer that is not in Bloom filter) */
1023 struct PeerInfo *chosen = NULL;
1024 int best_bucket;
1025 int bucket_offset;
1026
1027 {
1028 struct GNUNET_HashCode xor;
1029
1030 GNUNET_CRYPTO_hash_xor (key,
1031 &GDS_my_identity_hash,
1032 &xor);
1033 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1034 }
1035 if (best_bucket >= closest_bucket)
1036 bucket_offset = closest_bucket - 1;
1037 else
1038 bucket_offset = best_bucket;
1039 while (-1 != bucket_offset)
1040 {
1041 struct PeerBucket *bucket = &k_buckets[bucket_offset];
1042 unsigned int count = 0;
1043
1044 for (struct PeerInfo *pos = bucket->head;
1045 NULL != pos;
1046 pos = pos->next)
1047 {
1048 if (count >= bucket_size)
1049 break; /* we only consider first #bucket_size entries per bucket */
1050 count++;
1051 if ( (NULL != bloom) &&
1052 (GNUNET_YES ==
1053 GNUNET_CONTAINER_bloomfilter_test (bloom,
1054 &pos->phash)) )
1055 {
1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1057 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1058 GNUNET_i2s (&pos->id),
1059 GNUNET_h2s (key));
1060 continue;
1061 }
1062 if (NULL == chosen)
1063 {
1064 /* First candidate */
1065 chosen = pos;
1066 }
1067 else
1068 {
1069 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1070 &chosen->phash,
1071 key);
1072 switch (delta)
1073 {
1074 case -1: /* pos closer */
1075 chosen = pos;
1076 break;
1077 case 0: /* identical, impossible! */
1078 GNUNET_assert (0);
1079 break;
1080 case 1: /* chosen closer */
1081 break;
1082 }
1083 }
1084 count++;
1085 } /* for all (#bucket_size) peers in bucket */
1086 if (NULL != chosen)
1087 break;
1088
1089 /* If we chose nothing in first iteration, first go through deeper
1090 buckets (best chance to find a good match), and if we still found
1091 nothing, then to shallower buckets. Terminate on any match in the
1092 current bucket, as this search order guarantees that it can only get
1093 worse as we keep going. */
1094 if (bucket_offset > best_bucket)
1095 {
1096 /* Go through more deeper buckets */
1097 bucket_offset++;
1098 if (bucket_offset == closest_bucket)
1099 {
1100 /* Can't go any deeper, if nothing selected,
1101 go for shallower buckets */
1102 bucket_offset = best_bucket - 1;
1103 }
1104 }
1105 else
1106 {
1107 /* We're either at the 'best_bucket' or already moving
1108 on to shallower buckets. */
1109 if (bucket_offset == best_bucket)
1110 bucket_offset++; /* go for deeper buckets */
1111 else
1112 bucket_offset--; /* go for shallower buckets */
1113 }
1114 } /* for applicable buckets (starting at best match) */
1115 if (NULL == chosen)
1116 {
1117 GNUNET_STATISTICS_update (GDS_stats,
1118 "# Peer selection failed",
1119 1,
1120 GNUNET_NO);
1121 return NULL;
1122 }
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "Selected peer `%s' in greedy routing for %s\n",
1125 GNUNET_i2s (&chosen->id),
1126 GNUNET_h2s (key));
1127 return chosen;
1128 } /* end of 'greedy' peer selection */
1129
1130 /* select "random" peer */
1131 /* count number of peers that are available and not filtered,
1132 but limit to at most #bucket_size peers, starting with
1133 those 'furthest' from us. */
1134 {
1135 unsigned int total = 0;
1136 unsigned int selected;
1137
1138 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1139 {
1140 struct PeerBucket *bucket = &k_buckets[bc];
1141 unsigned int count = 0;
1142
1143 for (struct PeerInfo *pos = bucket->head;
1144 NULL != pos;
1145 pos = pos->next)
1146 {
1147 count++;
1148 if (count > bucket_size)
1149 break; /* limits search to #bucket_size peers per bucket */
1150 if ( (NULL != bloom) &&
1151 (GNUNET_YES ==
1152 GNUNET_CONTAINER_bloomfilter_test (bloom,
1153 &pos->phash)) )
1154 {
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "Excluded peer `%s' due to BF match in random routing for %s\n",
1157 GNUNET_i2s (&pos->id),
1158 GNUNET_h2s (key));
1159 continue; /* Ignore filtered peers */
1160 }
1161 total++;
1162 } /* for all peers in bucket */
1163 } /* for all buckets */
1164 if (0 == total) /* No peers to select from! */
1165 {
1166 GNUNET_STATISTICS_update (GDS_stats,
1167 "# Peer selection failed",
1168 1,
1169 GNUNET_NO);
1170 return NULL;
1171 }
1172
1173 /* Now actually choose a peer */
1174 selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1175 total);
1176 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1177 {
1178 unsigned int count = 0;
1179
1180 for (struct PeerInfo *pos = k_buckets[bc].head;
1181 pos != NULL;
1182 pos = pos->next)
1183 {
1184 count++;
1185 if (count > bucket_size)
1186 break; /* limits search to #bucket_size peers per bucket */
1187
1188 if ( (NULL != bloom) &&
1189 (GNUNET_YES ==
1190 GNUNET_CONTAINER_bloomfilter_test (bloom,
1191 &pos->phash)) )
1192 continue; /* Ignore bloomfiltered peers */
1193 if (0 == selected--)
1194 {
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "Selected peer `%s' in random routing for %s\n",
1197 GNUNET_i2s (&pos->id),
1198 GNUNET_h2s (key));
1199 return pos;
1200 }
1201 } /* for peers in bucket */
1202 } /* for all buckets */
1203 } /* random peer selection scope */
1204 GNUNET_break (0);
1205 return NULL;
1206}
1207
1208
1209/**
1210 * Compute the set of peers that the given request should be
1211 * forwarded to.
1212 *
1213 * @param key routing key
1214 * @param[in,out] bloom Bloom filter excluding peers as targets,
1215 * all selected peers will be added to the Bloom filter
1216 * @param hop_count number of hops the request has traversed so far
1217 * @param target_replication desired number of replicas
1218 * @param[out] targets where to store an array of target peers (to be
1219 * free()ed by the caller)
1220 * @return number of peers returned in @a targets.
1221 */
1222static unsigned int
1223get_target_peers (const struct GNUNET_HashCode *key,
1224 struct GNUNET_CONTAINER_BloomFilter *bloom,
1225 uint16_t hop_count,
1226 uint16_t target_replication,
1227 struct PeerInfo ***targets)
1228{
1229 unsigned int target;
1230 unsigned int off;
1231 struct PeerInfo **rtargets;
1232
1233 GNUNET_assert (NULL != bloom);
1234 target = get_forward_count (hop_count,
1235 target_replication);
1236 if (0 == target)
1237 {
1238 *targets = NULL;
1239 return 0;
1240 }
1241 rtargets = GNUNET_new_array (target,
1242 struct PeerInfo *);
1243 for (off = 0; off < target; off++)
1244 {
1245 struct PeerInfo *nxt;
1246
1247 nxt = select_peer (key,
1248 bloom,
1249 hop_count);
1250 if (NULL == nxt)
1251 break;
1252 rtargets[off] = nxt;
1253 GNUNET_break (GNUNET_NO ==
1254 GNUNET_CONTAINER_bloomfilter_test (bloom,
1255 &nxt->phash));
1256 GNUNET_CONTAINER_bloomfilter_add (bloom,
1257 &nxt->phash);
1258 }
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1261 off,
1262 GNUNET_CONTAINER_multipeermap_size (all_connected_peers),
1263 (unsigned int) hop_count,
1264 GNUNET_h2s (key),
1265 target);
1266 if (0 == off)
1267 {
1268 GNUNET_free (rtargets);
1269 *targets = NULL;
1270 return 0;
1271 }
1272 *targets = rtargets;
1273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1274 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1275 GNUNET_h2s (key),
1276 off,
1277 target);
1278 return off;
1279}
1280
1281
1282/**
1283 * If we got a HELLO, consider it for our own routing table
1284 *
1285 * @param bd block data we got
1286 */
1287static void
1288hello_check (const struct GDS_DATACACHE_BlockData *bd)
1289{
1290 struct GNUNET_PeerIdentity pid;
1291 struct GNUNET_HELLO_Builder *b;
1292
1293 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO != bd->type)
1294 return;
1295
1296 b = GNUNET_HELLO_builder_from_block (bd->data,
1297 bd->data_size);
1298 if (GNUNET_YES != disable_try_connect)
1299 GNUNET_HELLO_builder_iterate (b,
1300 &pid,
1301 &GDS_try_connect,
1302 &pid);
1303 GNUNET_HELLO_builder_free (b);
1304}
1305
1306
1307enum GNUNET_GenericReturnValue
1308GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1309 enum GNUNET_DHT_RouteOption options,
1310 uint16_t desired_replication_level,
1311 uint16_t hop_count,
1312 struct GNUNET_CONTAINER_BloomFilter *bf)
1313{
1314 unsigned int target_count;
1315 struct PeerInfo **targets;
1316 size_t msize;
1317 unsigned int skip_count;
1318 unsigned int put_path_length = bd->put_path_length;
1319
1320 GNUNET_assert (NULL != bf);
1321#if SANITY_CHECKS > 1
1322 if (0 !=
1323 GNUNET_DHT_verify_path (bd->data,
1324 bd->data_size,
1325 bd->expiration_time,
1326 bd->put_path,
1327 bd->put_path_length,
1328 NULL, 0, /* get_path */
1329 &GDS_my_identity))
1330 {
1331 GNUNET_break_op (0);
1332 put_path_length = 0;
1333 }
1334#endif
1335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1336 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1337 GNUNET_i2s (&GDS_my_identity),
1338 GNUNET_h2s (&bd->key),
1339 (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1340 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1341
1342 /* if we got a HELLO, consider it for our own routing table */
1343 hello_check (bd);
1344 GNUNET_CONTAINER_bloomfilter_add (bf,
1345 &GDS_my_identity_hash);
1346 GNUNET_STATISTICS_update (GDS_stats,
1347 "# PUT requests routed",
1348 1,
1349 GNUNET_NO);
1350 target_count
1351 = get_target_peers (&bd->key,
1352 bf,
1353 hop_count,
1354 desired_replication_level,
1355 &targets);
1356 if (0 == target_count)
1357 {
1358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359 "Routing PUT for %s terminates after %u hops at %s\n",
1360 GNUNET_h2s (&bd->key),
1361 (unsigned int) hop_count,
1362 GNUNET_i2s (&GDS_my_identity));
1363 return GNUNET_NO;
1364 }
1365 msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1366 + bd->data_size;
1367 if (msize + sizeof(struct PeerPutMessage)
1368 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1369 {
1370 put_path_length = 0;
1371 msize = bd->data_size;
1372 }
1373 if (msize + sizeof(struct PeerPutMessage)
1374 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1375 {
1376 GNUNET_break (0);
1377 GNUNET_free (targets);
1378 return GNUNET_NO;
1379 }
1380 skip_count = 0;
1381 for (unsigned int i = 0; i < target_count; i++)
1382 {
1383 struct PeerInfo *target = targets[i];
1384 struct PeerPutMessage *ppm;
1385 char buf[sizeof (*ppm) + msize] GNUNET_ALIGN;
1386 struct GNUNET_DHT_PathElement *pp;
1387
1388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389 "Routing PUT for %s after %u hops to %s\n",
1390 GNUNET_h2s (&bd->key),
1391 (unsigned int) hop_count,
1392 GNUNET_i2s (&target->id));
1393 ppm = (struct PeerPutMessage *) buf;
1394 ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
1395 ppm->header.size = htons (sizeof (buf));
1396 ppm->type = htonl (bd->type);
1397 ppm->options = htons (options);
1398 ppm->hop_count = htons (hop_count + 1);
1399 ppm->desired_replication_level = htons (desired_replication_level);
1400 ppm->put_path_length = htons (put_path_length);
1401 ppm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1402 GNUNET_break (GNUNET_YES ==
1403 GNUNET_CONTAINER_bloomfilter_test (bf,
1404 &target->phash));
1405 GNUNET_assert (GNUNET_OK ==
1406 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
1407 ppm->bloomfilter,
1408 DHT_BLOOM_SIZE));
1409 ppm->key = bd->key;
1410 pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1411 GNUNET_memcpy (pp,
1412 bd->put_path,
1413 sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1414 /* 0 == put_path_length means path is not being tracked */
1415 if (0 != put_path_length)
1416 {
1417 /* Note that the signature in 'put_path' was not initialized before,
1418 so this is crucial to avoid sending garbage. */
1419 sign_path (bd->data,
1420 bd->data_size,
1421 bd->expiration_time,
1422 &pp[put_path_length - 1].pred,
1423 &target->id,
1424 &pp[put_path_length - 1].sig);
1425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1426 "Signing PUT PATH %u => %s\n",
1427 put_path_length,
1428 GNUNET_B2S (&pp[put_path_length - 1].sig));
1429 }
1430
1431 GNUNET_memcpy (&pp[put_path_length],
1432 bd->data,
1433 bd->data_size);
1434 do_send (target,
1435 &ppm->header);
1436 }
1437 GNUNET_free (targets);
1438 GNUNET_STATISTICS_update (GDS_stats,
1439 "# PUT messages queued for transmission",
1440 target_count - skip_count,
1441 GNUNET_NO);
1442 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1443}
1444
1445
1446enum GNUNET_GenericReturnValue
1447GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1448 enum GNUNET_DHT_RouteOption options,
1449 uint16_t desired_replication_level,
1450 uint16_t hop_count,
1451 const struct GNUNET_HashCode *key,
1452 const void *xquery,
1453 size_t xquery_size,
1454 struct GNUNET_BLOCK_Group *bg,
1455 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1456{
1457 unsigned int target_count;
1458 struct PeerInfo **targets;
1459 size_t msize;
1460 size_t result_filter_size;
1461 void *result_filter;
1462 unsigned int skip_count;
1463
1464 GNUNET_assert (NULL != peer_bf);
1465 GNUNET_STATISTICS_update (GDS_stats,
1466 "# GET requests routed",
1467 1,
1468 GNUNET_NO);
1469 target_count = get_target_peers (key,
1470 peer_bf,
1471 hop_count,
1472 desired_replication_level,
1473 &targets);
1474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1475 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1476 GNUNET_i2s (&GDS_my_identity),
1477 GNUNET_h2s (key),
1478 (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1479 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1480
1481 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1482 &GDS_my_identity_hash);
1483 if (0 == target_count)
1484 {
1485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1486 "Routing GET for %s terminates after %u hops at %s\n",
1487 GNUNET_h2s (key),
1488 (unsigned int) hop_count,
1489 GNUNET_i2s (&GDS_my_identity));
1490 return GNUNET_NO;
1491 }
1492 if (GNUNET_OK !=
1493 GNUNET_BLOCK_group_serialize (bg,
1494 &result_filter,
1495 &result_filter_size))
1496 {
1497 result_filter = NULL;
1498 result_filter_size = 0;
1499 }
1500 msize = xquery_size + result_filter_size;
1501 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1502 {
1503 GNUNET_break (0);
1504 GNUNET_free (result_filter);
1505 GNUNET_free (targets);
1506 return GNUNET_NO;
1507 }
1508 /* forward request */
1509 skip_count = 0;
1510 for (unsigned int i = 0; i < target_count; i++)
1511 {
1512 struct PeerInfo *target = targets[i];
1513 struct PeerGetMessage *pgm;
1514 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1515 char *rf;
1516
1517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1518 "Routing GET for %s after %u hops to %s\n",
1519 GNUNET_h2s (key),
1520 (unsigned int) hop_count,
1521 GNUNET_i2s (&target->id));
1522 pgm = (struct PeerGetMessage *) buf;
1523 pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
1524 pgm->header.size = htons (sizeof (buf));
1525 pgm->type = htonl (type);
1526 pgm->options = htons (options);
1527 pgm->hop_count = htons (hop_count + 1);
1528 pgm->desired_replication_level = htons (desired_replication_level);
1529 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1530 GNUNET_break (GNUNET_YES ==
1531 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1532 &target->phash));
1533 GNUNET_assert (GNUNET_OK ==
1534 GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf,
1535 pgm->bloomfilter,
1536 DHT_BLOOM_SIZE));
1537 pgm->key = *key;
1538 rf = (char *) &pgm[1];
1539 GNUNET_memcpy (rf,
1540 result_filter,
1541 result_filter_size);
1542 GNUNET_memcpy (&rf[result_filter_size],
1543 xquery,
1544 xquery_size);
1545 do_send (target,
1546 &pgm->header);
1547 }
1548 GNUNET_STATISTICS_update (GDS_stats,
1549 "# GET messages queued for transmission",
1550 target_count - skip_count,
1551 GNUNET_NO);
1552 GNUNET_free (targets);
1553 GNUNET_free (result_filter);
1554 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1555}
1556
1557
1558struct PeerInfo *
1559GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
1560{
1561 return GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
1562 target);
1563}
1564
1565
1566bool
1567GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1568 const struct GDS_DATACACHE_BlockData *bd,
1569 const struct GNUNET_HashCode *query_hash,
1570 unsigned int get_path_length,
1571 const struct GNUNET_DHT_PathElement *get_path)
1572{
1573 struct GNUNET_DHT_PathElement *paths;
1574 size_t msize;
1575 unsigned int ppl = bd->put_path_length;
1576
1577#if SANITY_CHECKS > 1
1578 if (0 !=
1579 GNUNET_DHT_verify_path (bd->data,
1580 bd->data_size,
1581 bd->expiration_time,
1582 bd->put_path,
1583 bd->put_path_length,
1584 get_path,
1585 get_path_length,
1586 &GDS_my_identity))
1587 {
1588 GNUNET_break_op (0);
1589 return false;
1590 }
1591#endif
1592 msize = bd->data_size + (get_path_length + ppl)
1593 * sizeof(struct GNUNET_DHT_PathElement);
1594 if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1595 (get_path_length >
1596 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1597 (ppl >
1598 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1599 (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
1600 {
1601 ppl = 0;
1602 get_path_length = 0;
1603 msize = bd->data_size + (get_path_length + ppl)
1604 * sizeof(struct GNUNET_DHT_PathElement);
1605 }
1606 if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1607 (get_path_length >
1608 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1609 (ppl >
1610 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1611 (bd->data_size > GNUNET_MAX_MESSAGE_SIZE))
1612 {
1613 GNUNET_break (0);
1614 return false;
1615 }
1616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1617 "Forwarding reply for key %s to peer %s\n",
1618 GNUNET_h2s (query_hash),
1619 GNUNET_i2s (&pi->id));
1620 GNUNET_STATISTICS_update (GDS_stats,
1621 "# RESULT messages queued for transmission",
1622 1,
1623 GNUNET_NO);
1624 {
1625 struct PeerResultMessage *prm;
1626 char buf[sizeof (*prm) + msize] GNUNET_ALIGN;
1627
1628 prm = (struct PeerResultMessage *) buf;
1629 prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1630 prm->header.size = htons (sizeof (buf));
1631 prm->type = htonl (bd->type);
1632 prm->reserved = htonl (0);
1633 prm->put_path_length = htons (ppl);
1634 prm->get_path_length = htons (get_path_length);
1635 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1636 prm->key = *query_hash;
1637 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1638 if (NULL != bd->put_path)
1639 {
1640 GNUNET_memcpy (paths,
1641 bd->put_path,
1642 ppl * sizeof(struct GNUNET_DHT_PathElement));
1643 }
1644 else
1645 {
1646 GNUNET_assert (0 == ppl);
1647 }
1648 if (NULL != get_path)
1649 {
1650 GNUNET_memcpy (&paths[ppl],
1651 get_path,
1652 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1653 }
1654 else
1655 {
1656 GNUNET_assert (0 == get_path_length);
1657 }
1658 /* 0 == get_path_length+ppl means path is not being tracked */
1659 if (0 != (get_path_length + ppl))
1660 {
1661 /* Note that the last signature in 'paths' was not initialized before,
1662 so this is crucial to avoid sending garbage. */
1663 sign_path (bd->data,
1664 bd->data_size,
1665 bd->expiration_time,
1666 &paths[ppl + get_path_length - 1].pred,
1667 &pi->id,
1668 &paths[ppl + get_path_length - 1].sig);
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670 "Signing GET PATH %u/%u of %s => %s\n",
1671 ppl,
1672 get_path_length,
1673 GNUNET_h2s (query_hash),
1674 GNUNET_B2S (&paths[ppl + get_path_length - 1].sig));
1675 }
1676 GNUNET_memcpy (&paths[ppl + get_path_length],
1677 bd->data,
1678 bd->data_size);
1679
1680#if SANITY_CHECKS > 1
1681 {
1682 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1683
1684 memcpy (xpaths,
1685 &paths[ppl],
1686 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1687 xpaths[get_path_length].pred = GDS_my_identity;
1688 if (0 !=
1689 GNUNET_DHT_verify_path (bd->data,
1690 bd->data_size,
1691 bd->expiration_time,
1692 paths,
1693 ppl,
1694 xpaths,
1695 get_path_length + 1,
1696 &pi->id))
1697 {
1698 GNUNET_break (0);
1699 return false;
1700 }
1701 }
1702#endif
1703 do_send (pi,
1704 &prm->header);
1705 }
1706 return true;
1707}
1708
1709
1710/**
1711 * Check validity of a p2p put request.
1712 *
1713 * @param cls closure with the `struct PeerInfo` of the sender
1714 * @param message message
1715 * @return #GNUNET_OK if the message is valid
1716 */
1717static enum GNUNET_GenericReturnValue
1718check_dht_p2p_put (void *cls,
1719 const struct PeerPutMessage *put)
1720{
1721 uint16_t msize = ntohs (put->header.size);
1722 uint16_t putlen = ntohs (put->put_path_length);
1723
1724 (void) cls;
1725 if ( (msize <
1726 sizeof(struct PeerPutMessage)
1727 + putlen * sizeof(struct GNUNET_DHT_PathElement)) ||
1728 (putlen >
1729 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
1730 {
1731 GNUNET_break_op (0);
1732 return GNUNET_SYSERR;
1733 }
1734 return GNUNET_OK;
1735}
1736
1737
1738/**
1739 * Core handler for p2p put requests.
1740 *
1741 * @param cls closure with the `struct Target` of the sender
1742 * @param message message
1743 */
1744static void
1745handle_dht_p2p_put (void *cls,
1746 const struct PeerPutMessage *put)
1747{
1748 struct Target *t = cls;
1749 struct PeerInfo *peer = t->pi;
1750 uint16_t msize = ntohs (put->header.size);
1751 enum GNUNET_DHT_RouteOption options
1752 = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1753 const struct GNUNET_DHT_PathElement *put_path
1754 = (const struct GNUNET_DHT_PathElement *) &put[1];
1755 uint16_t putlen
1756 = ntohs (put->put_path_length);
1757 struct GDS_DATACACHE_BlockData bd = {
1758 .key = put->key,
1759 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1760 .type = ntohl (put->type),
1761 .data_size = msize - (sizeof(*put)
1762 + putlen * sizeof(struct GNUNET_DHT_PathElement)),
1763 .data = &put_path[putlen]
1764 };
1765
1766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767 "PUT for `%s' from %s with RO (%s/%s)\n",
1768 GNUNET_h2s (&put->key),
1769 GNUNET_i2s (&peer->id),
1770 (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1771 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1772 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
1773 {
1774 GNUNET_STATISTICS_update (GDS_stats,
1775 "# Expired PUTs discarded",
1776 1,
1777 GNUNET_NO);
1778 return;
1779 }
1780 if (GNUNET_NO ==
1781 GNUNET_BLOCK_check_block (GDS_block_context,
1782 bd.type,
1783 bd.data,
1784 bd.data_size))
1785 {
1786 GNUNET_break_op (0);
1787 return;
1788 }
1789 if (0 == (options & GNUNET_DHT_RO_RECORD_ROUTE))
1790 putlen = 0;
1791 GNUNET_STATISTICS_update (GDS_stats,
1792 "# P2P PUT requests received",
1793 1,
1794 GNUNET_NO);
1795 GNUNET_STATISTICS_update (GDS_stats,
1796 "# P2P PUT bytes received",
1797 msize,
1798 GNUNET_NO);
1799 {
1800 struct GNUNET_HashCode test_key;
1801 enum GNUNET_GenericReturnValue ret;
1802
1803 ret = GNUNET_BLOCK_get_key (GDS_block_context,
1804 bd.type,
1805 bd.data,
1806 bd.data_size,
1807 &test_key);
1808 switch (ret)
1809 {
1810 case GNUNET_YES:
1811 if (0 != GNUNET_memcmp (&test_key,
1812 &bd.key))
1813 {
1814 GNUNET_break_op (0);
1815 return;
1816 }
1817 break;
1818 case GNUNET_NO:
1819 /* cannot verify, good luck */
1820 break;
1821 case GNUNET_SYSERR:
1822 /* block type not supported, good luck */
1823 break;
1824 }
1825 }
1826
1827 {
1828 struct GNUNET_CONTAINER_BloomFilter *bf;
1829 struct GNUNET_DHT_PathElement pp[putlen + 1];
1830
1831 bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter,
1832 DHT_BLOOM_SIZE,
1833 GNUNET_CONSTANTS_BLOOMFILTER_K);
1834 GNUNET_break_op (GNUNET_YES ==
1835 GNUNET_CONTAINER_bloomfilter_test (bf,
1836 &peer->phash));
1837 /* extend 'put path' by sender */
1838 bd.put_path = (const struct GNUNET_DHT_PathElement *) pp;
1839 bd.put_path_length = putlen + 1;
1840 if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
1841 {
1842 unsigned int failure_offset;
1843
1844 GNUNET_memcpy (pp,
1845 put_path,
1846 putlen * sizeof(struct GNUNET_DHT_PathElement));
1847 pp[putlen].pred = peer->id;
1848 /* zero-out signature, not valid until we actually do forward! */
1849 memset (&pp[putlen].sig,
1850 0,
1851 sizeof (pp[putlen].sig));
1852#if SANITY_CHECKS
1853 /* TODO: might want to eventually implement probabilistic
1854 load-based path verification, but for now it is all or nothing */
1855 failure_offset
1856 = GNUNET_DHT_verify_path (bd.data,
1857 bd.data_size,
1858 bd.expiration_time,
1859 pp,
1860 putlen + 1,
1861 NULL, 0, /* get_path */
1862 &GDS_my_identity);
1863#else
1864 failure_offset = 0;
1865#endif
1866 if (0 != failure_offset)
1867 {
1868 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1869 "Recorded put path invalid at offset %u, truncating\n",
1870 failure_offset);
1871 GNUNET_assert (failure_offset <= putlen);
1872 bd.put_path = &pp[failure_offset];
1873 bd.put_path_length = putlen - failure_offset;
1874 }
1875 }
1876 else
1877 {
1878 bd.put_path_length = 0;
1879 }
1880
1881 /* give to local clients */
1882 GNUNET_break (GDS_CLIENTS_handle_reply (&bd,
1883 &bd.key,
1884 0, NULL /* get path */));
1885
1886 /* store locally */
1887 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1888 (GDS_am_closest_peer (&put->key,
1889 bf)) )
1890 GDS_DATACACHE_handle_put (&bd);
1891 {
1892 enum GNUNET_GenericReturnValue forwarded;
1893
1894 /* route to other peers */
1895 forwarded
1896 = GDS_NEIGHBOURS_handle_put (&bd,
1897 options,
1898 ntohs (put->desired_replication_level),
1899 ntohs (put->hop_count),
1900 bf);
1901 /* notify monitoring clients */
1902 GDS_CLIENTS_process_put (options
1903 | ((GNUNET_OK == forwarded)
1904 ? GNUNET_DHT_RO_LAST_HOP
1905 : 0),
1906 &bd,
1907 ntohs (put->hop_count),
1908 ntohs (put->desired_replication_level));
1909 }
1910 GNUNET_CONTAINER_bloomfilter_free (bf);
1911 }
1912}
1913
1914
1915/**
1916 * We have received a request for a HELLO. Sends our
1917 * HELLO back.
1918 *
1919 * @param pi sender of the request
1920 * @param key peers close to this key are desired
1921 * @param bg group for filtering peers
1922 */
1923static void
1924handle_find_my_hello (struct PeerInfo *pi,
1925 const struct GNUNET_HashCode *query_hash,
1926 struct GNUNET_BLOCK_Group *bg)
1927{
1928 size_t block_size = 0;
1929
1930 /* TODO: consider caching our HELLO block for a bit, to
1931 avoid signing too often here... */
1932 GNUNET_break (GNUNET_NO ==
1933 GNUNET_HELLO_builder_to_block (GDS_my_hello,
1934 &GDS_my_private_key,
1935 NULL,
1936 &block_size));
1937 {
1938 char block[block_size];
1939
1940 if (GNUNET_OK !=
1941 GNUNET_HELLO_builder_to_block (GDS_my_hello,
1942 &GDS_my_private_key,
1943 block,
1944 &block_size))
1945 {
1946 GNUNET_STATISTICS_update (GDS_stats,
1947 "# FIND PEER requests ignored due to lack of HELLO",
1948 1,
1949 GNUNET_NO);
1950 }
1951 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
1952 GNUNET_BLOCK_check_reply (GDS_block_context,
1953 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1954 bg,
1955 &GDS_my_identity_hash,
1956 NULL, 0,
1957 block,
1958 block_size))
1959 {
1960 struct GDS_DATACACHE_BlockData bd = {
1961 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1962 .expiration_time
1963 = GNUNET_TIME_relative_to_absolute (
1964 GNUNET_HELLO_ADDRESS_EXPIRATION),
1965 .key = GDS_my_identity_hash,
1966 .data = block,
1967 .data_size = block_size
1968 };
1969
1970 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
1971 &bd,
1972 query_hash,
1973 0, NULL /* get path */));
1974 }
1975 else
1976 {
1977 GNUNET_STATISTICS_update (GDS_stats,
1978 "# FIND PEER requests ignored due to Bloomfilter",
1979 1,
1980 GNUNET_NO);
1981 }
1982 }
1983}
1984
1985
1986/**
1987 * We have received a request for nearby HELLOs. Sends matching
1988 * HELLOs back.
1989 *
1990 * @param pi sender of the request
1991 * @param key peers close to this key are desired
1992 * @param bg group for filtering peers
1993 */
1994static void
1995handle_find_local_hello (struct PeerInfo *pi,
1996 const struct GNUNET_HashCode *query_hash,
1997 struct GNUNET_BLOCK_Group *bg)
1998{
1999 /* Force non-random selection by hop count */
2000 struct PeerInfo *peer;
2001
2002 peer = select_peer (query_hash,
2003 NULL,
2004 GDS_NSE_get () + 1);
2005 if ( (NULL != peer->hello) &&
2006 (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
2007 (GNUNET_BLOCK_REPLY_OK_MORE ==
2008 GNUNET_BLOCK_check_reply (
2009 GDS_block_context,
2010 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2011 bg,
2012 &peer->phash,
2013 NULL, 0, /* xquery */
2014 peer->hello,
2015 peer->hello_size)) )
2016 {
2017 struct GDS_DATACACHE_BlockData bd = {
2018 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2019 .expiration_time = peer->hello_expiration,
2020 .key = peer->phash,
2021 .data = peer->hello,
2022 .data_size = peer->hello_size
2023 };
2024
2025 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
2026 &bd,
2027 query_hash,
2028 0, NULL /* get path */));
2029 }
2030}
2031
2032
2033/**
2034 * Handle an exact result from local datacache for a GET operation.
2035 *
2036 * @param cls the `struct PeerInfo` for which this is a reply
2037 * @param bd details about the block we found locally
2038 */
2039static void
2040handle_local_result (void *cls,
2041 const struct GDS_DATACACHE_BlockData *bd)
2042{
2043 struct PeerInfo *peer = cls;
2044
2045 GNUNET_break (GDS_NEIGHBOURS_handle_reply (peer,
2046 bd,
2047 &bd->key,
2048 0, NULL /* get path */));
2049}
2050
2051
2052/**
2053 * Check validity of p2p get request.
2054 *
2055 * @param cls closure with the `struct Target` of the sender
2056 * @param get the message
2057 * @return #GNUNET_OK if the message is well-formed
2058 */
2059static enum GNUNET_GenericReturnValue
2060check_dht_p2p_get (void *cls,
2061 const struct PeerGetMessage *get)
2062{
2063 uint16_t msize = ntohs (get->header.size);
2064 uint16_t result_filter_size = ntohs (get->result_filter_size);
2065
2066 (void) cls;
2067 if (msize < sizeof(*get) + result_filter_size)
2068 {
2069 GNUNET_break_op (0);
2070 return GNUNET_SYSERR;
2071 }
2072 return GNUNET_OK;
2073}
2074
2075
2076/**
2077 * Core handler for p2p get requests.
2078 *
2079 * @param cls closure with the `struct Target` of the sender
2080 * @param get the message
2081 */
2082static void
2083handle_dht_p2p_get (void *cls,
2084 const struct PeerGetMessage *get)
2085{
2086 struct Target *t = cls;
2087 struct PeerInfo *peer = t->pi;
2088 uint16_t msize = ntohs (get->header.size);
2089 uint16_t result_filter_size = ntohs (get->result_filter_size);
2090 uint16_t hop_count = ntohs (get->hop_count);
2091 enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2092 enum GNUNET_DHT_RouteOption options = (enum GNUNET_DHT_RouteOption) ntohs (
2093 get->options);
2094 enum GNUNET_BLOCK_ReplyEvaluationResult eval = GNUNET_BLOCK_REPLY_OK_MORE;
2095 const void *result_filter = (const void *) &get[1];
2096 const void *xquery = result_filter + result_filter_size;
2097 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2098
2099 /* parse and validate message */
2100 GNUNET_STATISTICS_update (GDS_stats,
2101 "# P2P GET requests received",
2102 1,
2103 GNUNET_NO);
2104 GNUNET_STATISTICS_update (GDS_stats,
2105 "# P2P GET bytes received",
2106 msize,
2107 GNUNET_NO);
2108 if (GNUNET_NO ==
2109 GNUNET_BLOCK_check_query (GDS_block_context,
2110 type,
2111 &get->key,
2112 xquery,
2113 xquery_size))
2114 {
2115 /* request invalid */
2116 GNUNET_break_op (0);
2117 return;
2118 }
2119
2120 {
2121 struct GNUNET_BLOCK_Group *bg;
2122 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2123
2124 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2125 DHT_BLOOM_SIZE,
2126 GNUNET_CONSTANTS_BLOOMFILTER_K);
2127 GNUNET_break_op (GNUNET_YES ==
2128 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2129 &peer->phash));
2130 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2131 type,
2132 result_filter,
2133 result_filter_size,
2134 "filter-size",
2135 result_filter_size,
2136 NULL);
2137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2138 "GET for %s at %s after %u hops\n",
2139 GNUNET_h2s (&get->key),
2140 GNUNET_i2s (&GDS_my_identity),
2141 (unsigned int) hop_count);
2142 /* local lookup (this may update the bg) */
2143 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2144 (GDS_am_closest_peer (&get->key,
2145 peer_bf)) )
2146 {
2147 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == type)
2148 {
2149 GNUNET_STATISTICS_update (GDS_stats,
2150 "# P2P HELLO lookup requests processed",
2151 1,
2152 GNUNET_NO);
2153 handle_find_my_hello (peer,
2154 &get->key,
2155 bg);
2156 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2157 handle_find_local_hello (peer,
2158 &get->key,
2159 bg);
2160 }
2161 else
2162 {
2163 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2164 eval = GDS_DATACACHE_get_closest (&get->key,
2165 type,
2166 xquery,
2167 xquery_size,
2168 bg,
2169 &handle_local_result,
2170 peer);
2171 else
2172 eval = GDS_DATACACHE_handle_get (&get->key,
2173 type,
2174 xquery,
2175 xquery_size,
2176 bg,
2177 &handle_local_result,
2178 peer);
2179 }
2180 }
2181 else
2182 {
2183 GNUNET_STATISTICS_update (GDS_stats,
2184 "# P2P GET requests ONLY routed",
2185 1,
2186 GNUNET_NO);
2187 }
2188
2189 /* remember request for routing replies
2190 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2191 */
2192 GDS_ROUTING_add (&peer->id,
2193 type,
2194 bg, /* bg now owned by routing, but valid at least until end of this function! */
2195 options,
2196 &get->key,
2197 xquery,
2198 xquery_size);
2199
2200 /* P2P forwarding */
2201 {
2202 bool forwarded = false;
2203 uint16_t desired_replication_level = ntohs (
2204 get->desired_replication_level);
2205
2206 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2207 forwarded = (GNUNET_OK ==
2208 GDS_NEIGHBOURS_handle_get (type,
2209 options,
2210 desired_replication_level,
2211 hop_count,
2212 &get->key,
2213 xquery,
2214 xquery_size,
2215 bg,
2216 peer_bf));
2217 GDS_CLIENTS_process_get (
2218 options
2219 | (forwarded
2220 ? 0
2221 : GNUNET_DHT_RO_LAST_HOP),
2222 type,
2223 hop_count,
2224 desired_replication_level,
2225 0,
2226 NULL,
2227 &get->key);
2228 }
2229 /* clean up; note that 'bg' is owned by routing now! */
2230 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2231 }
2232}
2233
2234
2235/**
2236 * Process a reply, after the @a get_path has been updated.
2237 *
2238 * @param bd block details
2239 * @param query_hash hash of the original query, might not match key in @a bd
2240 * @param get_path_length number of entries in @a get_path
2241 * @param get_path path the reply has taken
2242 * @return true on success
2243 */
2244static bool
2245process_reply_with_path (const struct GDS_DATACACHE_BlockData *bd,
2246 const struct GNUNET_HashCode *query_hash,
2247 unsigned int get_path_length,
2248 const struct GNUNET_DHT_PathElement *get_path)
2249{
2250 /* forward to local clients */
2251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2252 "Forwarding reply to local clients\n");
2253 if (! GDS_CLIENTS_handle_reply (bd,
2254 query_hash,
2255 get_path_length,
2256 get_path))
2257 {
2258 GNUNET_break (0);
2259 return false;
2260 }
2261 GDS_CLIENTS_process_get_resp (bd,
2262 get_path,
2263 get_path_length);
2264 if (GNUNET_YES == cache_results)
2265 {
2266 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2267 + bd->put_path_length)];
2268 struct GDS_DATACACHE_BlockData bdx = *bd;
2269
2270 GNUNET_memcpy (xput_path,
2271 bd->put_path,
2272 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
2273 GNUNET_memcpy (&xput_path[bd->put_path_length],
2274 get_path,
2275 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2276 bdx.put_path = xput_path;
2277 bdx.put_path_length += get_path_length;
2278 GDS_DATACACHE_handle_put (&bdx);
2279 }
2280 /* forward to other peers */
2281 GDS_ROUTING_process (bd,
2282 query_hash,
2283 get_path_length,
2284 get_path);
2285 return true;
2286}
2287
2288
2289/**
2290 * Check validity of p2p result message.
2291 *
2292 * @param cls closure
2293 * @param message message
2294 * @return #GNUNET_YES if the message is well-formed
2295 */
2296static enum GNUNET_GenericReturnValue
2297check_dht_p2p_result (void *cls,
2298 const struct PeerResultMessage *prm)
2299{
2300 uint16_t get_path_length = ntohs (prm->get_path_length);
2301 uint16_t put_path_length = ntohs (prm->put_path_length);
2302 uint16_t msize = ntohs (prm->header.size);
2303
2304 (void) cls;
2305 if ( (msize <
2306 sizeof(struct PeerResultMessage)
2307 + (get_path_length + put_path_length)
2308 * sizeof(struct GNUNET_DHT_PathElement)) ||
2309 (get_path_length >
2310 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2311 (put_path_length >
2312 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2313 {
2314 GNUNET_break_op (0);
2315 return GNUNET_SYSERR;
2316 }
2317 return GNUNET_OK;
2318}
2319
2320
2321/**
2322 * Core handler for p2p result messages.
2323 *
2324 * @param cls closure
2325 * @param message message
2326 */
2327static void
2328handle_dht_p2p_result (void *cls,
2329 const struct PeerResultMessage *prm)
2330{
2331 struct Target *t = cls;
2332 struct PeerInfo *peer = t->pi;
2333 uint16_t msize = ntohs (prm->header.size);
2334 uint16_t get_path_length = ntohs (prm->get_path_length);
2335 struct GDS_DATACACHE_BlockData bd = {
2336 .expiration_time = GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2337 .put_path = (const struct GNUNET_DHT_PathElement *) &prm[1],
2338 .put_path_length = ntohs (prm->put_path_length),
2339 .key = prm->key,
2340 .type = ntohl (prm->type)
2341 };
2342 const struct GNUNET_DHT_PathElement *get_path
2343 = &bd.put_path[bd.put_path_length];
2344
2345 /* parse and validate message */
2346 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2347 {
2348 GNUNET_STATISTICS_update (GDS_stats,
2349 "# Expired results discarded",
2350 1,
2351 GNUNET_NO);
2352 return;
2353 }
2354 get_path = &bd.put_path[bd.put_path_length];
2355 bd.data = (const void *) &get_path[get_path_length];
2356 bd.data_size = msize - (sizeof(struct PeerResultMessage)
2357 + (get_path_length + bd.put_path_length)
2358 * sizeof(struct GNUNET_DHT_PathElement));
2359 if (GNUNET_OK !=
2360 GNUNET_BLOCK_check_block (GDS_block_context,
2361 bd.type,
2362 bd.data,
2363 bd.data_size))
2364 {
2365 GNUNET_break_op (0);
2366 return;
2367 }
2368 GNUNET_STATISTICS_update (GDS_stats,
2369 "# P2P RESULTS received",
2370 1,
2371 GNUNET_NO);
2372 GNUNET_STATISTICS_update (GDS_stats,
2373 "# P2P RESULT bytes received",
2374 msize,
2375 GNUNET_NO);
2376 {
2377 enum GNUNET_GenericReturnValue ret;
2378
2379 ret = GNUNET_BLOCK_get_key (GDS_block_context,
2380 bd.type,
2381 bd.data,
2382 bd.data_size,
2383 &bd.key);
2384 if (GNUNET_NO == ret)
2385 bd.key = prm->key;
2386 }
2387
2388 /* if we got a HELLO, consider it for our own routing table */
2389 hello_check (&bd);
2390
2391 /* Need to append 'peer' to 'get_path' */
2392 {
2393 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2394 struct GNUNET_DHT_PathElement *gp = xget_path;
2395 unsigned int failure_offset;
2396
2397 GNUNET_memcpy (xget_path,
2398 get_path,
2399 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2400 xget_path[get_path_length].pred = peer->id;
2401 memset (&xget_path[get_path_length].sig,
2402 0,
2403 sizeof (xget_path[get_path_length].sig));
2404#if SANITY_CHECKS
2405 /* TODO: might want to eventually implement probabilistic
2406 load-based path verification, but for now it is all or nothing */
2407 failure_offset
2408 = GNUNET_DHT_verify_path (bd.data,
2409 bd.data_size,
2410 bd.expiration_time,
2411 bd.put_path,
2412 bd.put_path_length,
2413 xget_path,
2414 get_path_length + 1,
2415 &GDS_my_identity);
2416#else
2417 failure_offset = 0;
2418#endif
2419 if (0 != failure_offset)
2420 {
2421 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2422 "Recorded path invalid at offset %u, truncating\n",
2423 failure_offset);
2424 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length);
2425 if (failure_offset >= bd.put_path_length)
2426 {
2427 /* failure on get path */
2428 get_path_length -= (failure_offset - bd.put_path_length);
2429 gp = &xget_path[failure_offset - bd.put_path_length];
2430 bd.put_path_length = 0;
2431 }
2432 else
2433 {
2434 /* failure on put path */
2435 bd.put_path = &bd.put_path[failure_offset];
2436 bd.put_path_length -= failure_offset;
2437 }
2438 }
2439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2440 "Extending GET path of length %u with %s\n",
2441 get_path_length,
2442 GNUNET_i2s (&peer->id));
2443 GNUNET_break (process_reply_with_path (&bd,
2444 &prm->key,
2445 get_path_length + 1,
2446 gp));
2447 }
2448}
2449
2450
2451/**
2452 * Check validity of a p2p hello message.
2453 *
2454 * @param cls closure
2455 * @param hello message
2456 * @return #GNUNET_YES if the message is well-formed
2457 */
2458static enum GNUNET_GenericReturnValue
2459check_dht_p2p_hello (void *cls,
2460 const struct GNUNET_MessageHeader *hello)
2461{
2462 struct Target *t = cls;
2463 struct PeerInfo *peer = t->pi;
2464 enum GNUNET_GenericReturnValue ret;
2465 size_t hellob_size;
2466 void *hellob;
2467 struct GNUNET_TIME_Absolute expiration;
2468
2469 ret = GNUNET_HELLO_dht_msg_to_block (hello,
2470 &peer->id,
2471 &hellob,
2472 &hellob_size,
2473 &expiration);
2474 GNUNET_free (hellob);
2475 return ret;
2476}
2477
2478
2479/**
2480 * Core handler for p2p HELLO messages.
2481 *
2482 * @param cls closure
2483 * @param message message
2484 */
2485static void
2486handle_dht_p2p_hello (void *cls,
2487 const struct GNUNET_MessageHeader *hello)
2488{
2489 struct Target *t = cls;
2490 struct PeerInfo *peer = t->pi;
2491
2492 GNUNET_free (peer->hello);
2493 peer->hello_size = 0;
2494 GNUNET_break (GNUNET_OK ==
2495 GNUNET_HELLO_dht_msg_to_block (hello,
2496 &peer->id,
2497 &peer->hello,
2498 &peer->hello_size,
2499 &peer->hello_expiration));
2500}
2501
2502
2503void
2504GDS_u_receive (void *cls,
2505 void **tctx,
2506 void **sctx,
2507 const void *message,
2508 size_t message_size)
2509{
2510 struct Target *t = *tctx;
2511 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2512 GNUNET_MQ_hd_var_size (dht_p2p_get,
2513 GNUNET_MESSAGE_TYPE_DHT_P2P_GET,
2514 struct PeerGetMessage,
2515 t),
2516 GNUNET_MQ_hd_var_size (dht_p2p_put,
2517 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT,
2518 struct PeerPutMessage,
2519 t),
2520 GNUNET_MQ_hd_var_size (dht_p2p_result,
2521 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2522 struct PeerResultMessage,
2523 t),
2524 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2525 GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO,
2526 struct GNUNET_MessageHeader,
2527 t),
2528 GNUNET_MQ_handler_end ()
2529 };
2530 const struct GNUNET_MessageHeader *mh = message;
2531
2532 (void) cls; /* the 'struct GDS_Underlay' */
2533 (void) sctx; /* our receiver address */
2534 if (NULL == t)
2535 {
2536 /* Received message claiming to originate from myself?
2537 Ignore! */
2538 GNUNET_break_op (0);
2539 return;
2540 }
2541 if (message_size < sizeof (*mh))
2542 {
2543 GNUNET_break_op (0);
2544 return;
2545 }
2546 if (message_size != ntohs (mh->size))
2547 {
2548 GNUNET_break_op (0);
2549 return;
2550 }
2551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2552 "Handling message of type %u from peer %s\n",
2553 ntohs (mh->type),
2554 GNUNET_i2s (&t->pi->id));
2555 if (GNUNET_OK !=
2556 GNUNET_MQ_handle_message (core_handlers,
2557 mh))
2558 {
2559 GNUNET_break_op (0);
2560 return;
2561 }
2562}
2563
2564
2565/**
2566 * Callback function used to extract URIs from a builder.
2567 * Called when we should consider connecting to a peer.
2568 *
2569 * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
2570 * @param uri one of the URIs
2571 */
2572void
2573GDS_try_connect (void *cls,
2574 const char *uri)
2575{
2576 const struct GNUNET_PeerIdentity *pid = cls;
2577 struct GNUNET_HashCode phash;
2578 int peer_bucket;
2579 struct PeerBucket *bucket;
2580
2581 if (0 == GNUNET_memcmp (&GDS_my_identity,
2582 pid))
2583 {
2584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585 "Got a HELLO for my own PID, ignoring it\n");
2586 return; /* that's us! */
2587 }
2588 GNUNET_CRYPTO_hash (pid,
2589 sizeof(*pid),
2590 &phash);
2591 peer_bucket = find_bucket (&phash);
2592 GNUNET_assert ( (peer_bucket >= 0) &&
2593 ((unsigned int) peer_bucket < MAX_BUCKETS));
2594 bucket = &k_buckets[peer_bucket];
2595 if (bucket->peers_size >= bucket_size)
2596 return; /* do not care */
2597 for (struct PeerInfo *pi = bucket->head;
2598 NULL != pi;
2599 pi = pi->next)
2600 if (0 ==
2601 GNUNET_memcmp (&pi->id,
2602 pid))
2603 {
2604 /* already connected */
2605 /* TODO: maybe consider 'uri' anyway as an additional
2606 alternative address??? */
2607 return;
2608 }
2609 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2610 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2611 GNUNET_i2s (pid),
2612 uri,
2613 peer_bucket,
2614 bucket->peers_size,
2615 bucket_size);
2616 /* new peer that we like! */
2617 GDS_u_try_connect (pid,
2618 uri);
2619}
2620
2621
2622/**
2623 * Send @a msg to all peers in our buckets.
2624 *
2625 * @param msg message to broadcast
2626 */
2627void
2628GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
2629{
2630 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2631 {
2632 struct PeerBucket *bucket = &k_buckets[bc];
2633 unsigned int count = 0;
2634
2635 for (struct PeerInfo *pos = bucket->head;
2636 NULL != pos;
2637 pos = pos->next)
2638 {
2639 if (count >= bucket_size)
2640 break; /* we only consider first #bucket_size entries per bucket */
2641 count++;
2642 do_send (pos,
2643 msg);
2644 }
2645 }
2646}
2647
2648
2649enum GNUNET_GenericReturnValue
2650GDS_NEIGHBOURS_init ()
2651{
2652
2653 unsigned long long temp_config_num;
2654
2655 disable_try_connect
2656 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2657 "DHT",
2658 "DISABLE_TRY_CONNECT");
2659 if (GNUNET_OK ==
2660 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
2661 "DHT",
2662 "bucket_size",
2663 &temp_config_num))
2664 bucket_size = (unsigned int) temp_config_num;
2665 cache_results
2666 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2667 "DHT",
2668 "CACHE_RESULTS");
2669 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2670 GNUNET_YES);
2671 return GNUNET_OK;
2672}
2673
2674
2675void
2676GDS_NEIGHBOURS_done ()
2677{
2678 if (NULL == all_connected_peers)
2679 return;
2680 GNUNET_assert (0 ==
2681 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2682 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2683 all_connected_peers = NULL;
2684 GNUNET_assert (NULL == find_peer_task);
2685}
2686
2687
2688struct GNUNET_PeerIdentity *
2689GDS_NEIGHBOURS_get_id ()
2690{
2691 return &GDS_my_identity;
2692}
2693
2694
2695/* 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 4f4172f71..000000000
--- a/src/dht/gnunet-service-dht_neighbours.h
+++ /dev/null
@@ -1,228 +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_dhtu_plugin.h"
34#include "gnunet-service-dht_datacache.h"
35
36
37struct PeerInfo;
38
39/**
40 * Lookup peer by peer's identity.
41 *
42 * @param target peer to look up
43 * @return NULL if we are not connected to @a target
44 */
45struct PeerInfo *
46GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target);
47
48
49/**
50 * Perform a PUT operation. Forwards the given request to other
51 * peers. Does not store the data locally. Does not give the
52 * data to local clients. May do nothing if this is the only
53 * peer in the network (or if we are the closest peer in the
54 * network).
55 *
56 * @param bd data about the block
57 * @param options routing options
58 * @param desired_replication_level desired replication level
59 * @param hop_count how many hops has this message traversed so far
60 * @param bf Bloom filter of peers this PUT has already traversed
61 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
62 */
63enum GNUNET_GenericReturnValue
64GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
65 enum GNUNET_DHT_RouteOption options,
66 uint16_t desired_replication_level,
67 uint16_t hop_count,
68 struct GNUNET_CONTAINER_BloomFilter *bf);
69
70
71/**
72 * Perform a GET operation. Forwards the given request to other
73 * peers. Does not lookup the key locally. May do nothing if this is
74 * the only peer in the network (or if we are the closest peer in the
75 * network).
76 *
77 * @param type type of the block
78 * @param options routing options
79 * @param desired_replication_level desired replication count
80 * @param hop_count how many hops did this request traverse so far?
81 * @param key key for the content
82 * @param xquery extended query
83 * @param xquery_size number of bytes in @a xquery
84 * @param bg block group to filter replies
85 * @param peer_bf filter for peers not to select (again, updated)
86 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
87 */
88enum GNUNET_GenericReturnValue
89GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
90 enum GNUNET_DHT_RouteOption options,
91 uint16_t desired_replication_level,
92 uint16_t hop_count,
93 const struct GNUNET_HashCode *key,
94 const void *xquery,
95 size_t xquery_size,
96 struct GNUNET_BLOCK_Group *bg,
97 struct GNUNET_CONTAINER_BloomFilter *peer_bf);
98
99
100/**
101 * Handle a reply (route to origin). Only forwards the reply back to
102 * other peers waiting for it. Does not do local caching or
103 * forwarding to local clients.
104 *
105 * @param pi neighbour that should receive the block
106 * @param type type of the block
107 * @param bd details about the reply
108 * @param query_hash query that was used for the request
109 * @param get_path_length number of entries in put_path
110 * @param get_path peers this reply has traversed so far (if tracked)
111 * @return true on success
112 */
113bool
114GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
115 const struct GDS_DATACACHE_BlockData *bd,
116 const struct GNUNET_HashCode *query_hash,
117 unsigned int get_path_length,
118 const struct GNUNET_DHT_PathElement *get_path);
119
120
121/**
122 * Check whether my identity is closer than any known peers. If a
123 * non-null bloomfilter is given, check if this is the closest peer
124 * that hasn't already been routed to.
125 *
126 * @param key hash code to check closeness to
127 * @param bloom bloomfilter, exclude these entries from the decision
128 * @return #GNUNET_YES if node location is closest,
129 * #GNUNET_NO otherwise.
130 */
131enum GNUNET_GenericReturnValue
132GDS_am_closest_peer (const struct GNUNET_HashCode *key,
133 const struct GNUNET_CONTAINER_BloomFilter *bloom);
134
135
136/**
137 * Callback function used to extract URIs from a builder.
138 * Called when we should consider connecting to a peer.
139 *
140 * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
141 * @param uri one of the URIs
142 */
143void
144GDS_try_connect (void *cls,
145 const char *uri);
146
147
148/**
149 * Function to call when we connect to a peer and can henceforth transmit to
150 * that peer.
151 *
152 * @param cls the closure, must be a `struct GDS_Underlay`
153 * @param target handle to the target,
154 * pointer will remain valid until @e disconnect_cb is called
155 * @para pid peer identity,
156 * pointer will remain valid until @e disconnect_cb is called
157 * @param[out] ctx storage space for DHT to use in association with this target
158 */
159void
160GDS_u_connect (void *cls,
161 struct GNUNET_DHTU_Target *target,
162 const struct GNUNET_PeerIdentity *pid,
163 void **ctx);
164
165
166/**
167 * Function to call when we disconnected from a peer and can henceforth
168 * cannot transmit to that peer anymore.
169 *
170 * @param[in] ctx storage space used by the DHT in association with this target
171 */
172void
173GDS_u_disconnect (void *ctx);
174
175
176/**
177 * Function to call when we receive a message.
178 *
179 * @param cls the closure
180 * @param origin where the message originated from
181 * @param[in,out] tctx ctx of target address where we received the message from
182 * @param[in,out] sctx ctx of our own source address at which we received the message
183 * @param message the message we received @param message_size number of
184 * bytes in @a message
185 */
186void
187GDS_u_receive (void *cls,
188 void **tctx,
189 void **sctx,
190 const void *message,
191 size_t message_size);
192
193
194/**
195 * Send @a msg to all peers in our buckets.
196 *
197 * @param msg message to broadcast
198 */
199void
200GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg);
201
202
203/**
204 * Initialize neighbours subsystem.
205 *
206 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
207 */
208enum GNUNET_GenericReturnValue
209GDS_NEIGHBOURS_init (void);
210
211
212/**
213 * Shutdown neighbours subsystem.
214 */
215void
216GDS_NEIGHBOURS_done (void);
217
218
219/**
220 * Get the ID of the local node.
221 *
222 * @return identity of the local node
223 */
224struct GNUNET_PeerIdentity *
225GDS_NEIGHBOURS_get_id (void);
226
227
228#endif
diff --git a/src/dht/gnunet-service-dht_routing.c b/src/dht/gnunet-service-dht_routing.c
deleted file mode 100644
index 6deb5fa16..000000000
--- a/src/dht/gnunet-service-dht_routing.c
+++ /dev/null
@@ -1,431 +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#include "gnunet_block_group_lib.h"
31
32
33/**
34 * Number of requests we track at most (for routing replies).
35 * TODO: make configurable!
36 */
37#define DHT_MAX_RECENT (1024 * 128)
38
39
40/**
41 * Information we keep about all recent GET requests
42 * so that we can route replies.
43 */
44struct RecentRequest
45{
46 /**
47 * The peer this request was received from.
48 */
49 struct GNUNET_PeerIdentity peer;
50
51 /**
52 * Key of this request.
53 */
54 struct GNUNET_HashCode key;
55
56 /**
57 * Position of this node in the min heap.
58 */
59 struct GNUNET_CONTAINER_HeapNode *heap_node;
60
61 /**
62 * Block group for filtering replies.
63 */
64 struct GNUNET_BLOCK_Group *bg;
65
66 /**
67 * extended query (see gnunet_block_lib.h). Allocated at the
68 * end of this struct.
69 */
70 const void *xquery;
71
72 /**
73 * Number of bytes in xquery.
74 */
75 size_t xquery_size;
76
77 /**
78 * Type of the requested block.
79 */
80 enum GNUNET_BLOCK_Type type;
81
82 /**
83 * Request options.
84 */
85 enum GNUNET_DHT_RouteOption options;
86};
87
88
89/**
90 * Recent requests by time inserted.
91 */
92static struct GNUNET_CONTAINER_Heap *recent_heap;
93
94/**
95 * Recently seen requests by key.
96 */
97static struct GNUNET_CONTAINER_MultiHashMap *recent_map;
98
99
100/**
101 * Closure for the process() function.
102 */
103struct ProcessContext
104{
105 /**
106 * Block data.
107 */
108 const struct GDS_DATACACHE_BlockData *bd;
109
110 /**
111 * Path of the reply.
112 */
113 const struct GNUNET_DHT_PathElement *get_path;
114
115 /**
116 * Number of entries in @e get_path.
117 */
118 unsigned int get_path_length;
119
120};
121
122
123/**
124 * Forward the result to the given peer if it matches the request.
125 *
126 * @param cls the `struct ProcessContext` with the result
127 * @param query_hash the hash from the original query
128 * @param value the `struct RecentRequest` with the request
129 * @return #GNUNET_OK (continue to iterate)
130 */
131static enum GNUNET_GenericReturnValue
132process (void *cls,
133 const struct GNUNET_HashCode *query_hash,
134 void *value)
135{
136 struct ProcessContext *pc = cls;
137 struct RecentRequest *rr = value;
138 enum GNUNET_BLOCK_ReplyEvaluationResult eval;
139 unsigned int get_path_length;
140 struct GDS_DATACACHE_BlockData bdx = *pc->bd;
141
142 if ( (rr->type != GNUNET_BLOCK_TYPE_ANY) &&
143 (rr->type != pc->bd->type) )
144 return GNUNET_OK; /* type mismatch */
145 if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE))
146 {
147 get_path_length = pc->get_path_length;
148 }
149 else
150 {
151 get_path_length = 0;
152 bdx.put_path_length = 0;
153 bdx.put_path = NULL;
154 }
155 if ( (0 == (rr->options & GNUNET_DHT_RO_FIND_APPROXIMATE)) &&
156 (0 != GNUNET_memcmp (query_hash,
157 &bdx.key)) )
158 {
159 GNUNET_STATISTICS_update (GDS_stats,
160 "# Inexact matches discarded in exact search",
161 1,
162 GNUNET_NO);
163 return GNUNET_OK; /* exact search, but inexact match */
164 }
165 eval = GNUNET_BLOCK_check_reply (GDS_block_context,
166 bdx.type,
167 rr->bg,
168 &bdx.key,
169 rr->xquery,
170 rr->xquery_size,
171 bdx.data,
172 bdx.data_size);
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "Result for %s of type %d was evaluated as %d\n",
175 GNUNET_h2s (&bdx.key),
176 bdx.type,
177 eval);
178 if (GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED == eval)
179 {
180 /* If we do not know the block type, we still filter
181 exact duplicates by the block content */
182 struct GNUNET_HashCode chash;
183
184 GNUNET_CRYPTO_hash (bdx.data,
185 bdx.data_size,
186 &chash);
187 if (GNUNET_YES ==
188 GNUNET_BLOCK_GROUP_bf_test_and_set (rr->bg,
189 &chash))
190 eval = GNUNET_BLOCK_REPLY_OK_DUPLICATE;
191 else
192 eval = GNUNET_BLOCK_REPLY_OK_MORE;
193 }
194 switch (eval)
195 {
196 case GNUNET_BLOCK_REPLY_OK_MORE:
197 case GNUNET_BLOCK_REPLY_OK_LAST:
198 case GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED:
199 {
200 struct PeerInfo *pi;
201
202 GNUNET_STATISTICS_update (GDS_stats,
203 "# Good REPLIES matched against routing table",
204 1,
205 GNUNET_NO);
206 pi = GDS_NEIGHBOURS_lookup_peer (&rr->peer);
207 if (NULL == pi)
208 {
209 /* peer disconnected in the meantime, drop reply */
210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211 "No matching peer for reply for key %s\n",
212 GNUNET_h2s (query_hash));
213 return GNUNET_OK;
214 }
215 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
216 &bdx,
217 query_hash,
218 get_path_length,
219 pc->get_path));
220 }
221 break;
222 case GNUNET_BLOCK_REPLY_OK_DUPLICATE:
223 GNUNET_STATISTICS_update (GDS_stats,
224 "# Duplicate REPLIES matched against routing table",
225 1,
226 GNUNET_NO);
227 return GNUNET_OK;
228 case GNUNET_BLOCK_REPLY_IRRELEVANT:
229 GNUNET_STATISTICS_update (GDS_stats,
230 "# Irrelevant REPLIES matched against routing table",
231 1,
232 GNUNET_NO);
233 return GNUNET_OK;
234 default:
235 GNUNET_break (0);
236 return GNUNET_OK;
237 }
238 return GNUNET_OK;
239}
240
241
242/**
243 * Handle a reply (route to origin). Only forwards the reply back to
244 * other peers waiting for it. Does not do local caching or
245 * forwarding to local clients. Essentially calls
246 * GDS_NEIGHBOURS_handle_reply() for all peers that sent us a matching
247 * request recently.
248 *
249 * @param bd block details
250 * @param query_hash query used in the inquiry
251 * @param get_path_length number of entries in @a get_path
252 * @param get_path peers this reply has traversed so far (if tracked)
253 */
254void
255GDS_ROUTING_process (const struct GDS_DATACACHE_BlockData *bd,
256 const struct GNUNET_HashCode *query_hash,
257 unsigned int get_path_length,
258 const struct GNUNET_DHT_PathElement *get_path)
259{
260 struct ProcessContext pc = {
261 .bd = bd,
262 .get_path = get_path,
263 .get_path_length = get_path_length
264 };
265
266 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
267 query_hash,
268 &process,
269 &pc);
270}
271
272
273/**
274 * Remove the oldest entry from the DHT routing table. Must only
275 * be called if it is known that there is at least one entry
276 * in the heap and hashmap.
277 */
278static void
279expire_oldest_entry (void)
280{
281 struct RecentRequest *recent_req;
282
283 GNUNET_STATISTICS_update (GDS_stats,
284 "# Old entries removed from routing table",
285 1,
286 GNUNET_NO);
287 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
288 GNUNET_assert (recent_req != NULL);
289 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
290 GNUNET_BLOCK_group_destroy (recent_req->bg);
291 GNUNET_assert (GNUNET_YES ==
292 GNUNET_CONTAINER_multihashmap_remove (recent_map,
293 &recent_req->key,
294 recent_req));
295 GNUNET_free (recent_req);
296}
297
298
299/**
300 * Try to combine multiple recent requests for the same value
301 * (if they come from the same peer).
302 *
303 * @param cls the new `struct RecentRequest` (to discard upon successful combination)
304 * @param key the query
305 * @param value the existing `struct RecentRequest` (to update upon successful combination)
306 * @return #GNUNET_OK (continue to iterate),
307 * #GNUNET_SYSERR if the request was successfully combined
308 */
309static enum GNUNET_GenericReturnValue
310try_combine_recent (void *cls,
311 const struct GNUNET_HashCode *key,
312 void *value)
313{
314 struct RecentRequest *in = cls;
315 struct RecentRequest *rr = value;
316
317 if ( (0 != GNUNET_memcmp (&in->peer,
318 &rr->peer)) ||
319 (in->type != rr->type) ||
320 (in->xquery_size != rr->xquery_size) ||
321 (0 != memcmp (in->xquery,
322 rr->xquery,
323 in->xquery_size) ) )
324 return GNUNET_OK;
325 GNUNET_break (GNUNET_SYSERR !=
326 GNUNET_BLOCK_group_merge (in->bg,
327 rr->bg));
328 rr->bg = in->bg;
329 GNUNET_free (in);
330 return GNUNET_SYSERR;
331}
332
333
334/**
335 * Add a new entry to our routing table.
336 *
337 * @param sender peer that originated the request
338 * @param type type of the block
339 * @param[in] bg block group for filtering duplicate replies
340 * @param options options for processing
341 * @param key key for the content
342 * @param xquery extended query
343 * @param xquery_size number of bytes in @a xquery
344 * @param reply_bf bloomfilter to filter duplicates
345 * @param reply_bf_mutator mutator for @a reply_bf
346 */
347void
348GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
349 enum GNUNET_BLOCK_Type type,
350 struct GNUNET_BLOCK_Group *bg,
351 enum GNUNET_DHT_RouteOption options,
352 const struct GNUNET_HashCode *key,
353 const void *xquery,
354 size_t xquery_size)
355{
356 struct RecentRequest *recent_req;
357
358 while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT)
359 expire_oldest_entry ();
360 GNUNET_STATISTICS_update (GDS_stats,
361 "# Entries added to routing table",
362 1,
363 GNUNET_NO);
364 recent_req = GNUNET_malloc (sizeof(struct RecentRequest) + xquery_size);
365 recent_req->peer = *sender;
366 recent_req->key = *key;
367 recent_req->bg = bg;
368 recent_req->type = type;
369 recent_req->options = options;
370 recent_req->xquery = &recent_req[1];
371 GNUNET_memcpy (&recent_req[1],
372 xquery,
373 xquery_size);
374 recent_req->xquery_size = xquery_size;
375 if (GNUNET_SYSERR ==
376 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
377 key,
378 &try_combine_recent,
379 recent_req))
380 {
381 GNUNET_STATISTICS_update (GDS_stats,
382 "# DHT requests combined",
383 1,
384 GNUNET_NO);
385 return;
386 }
387 recent_req->heap_node
388 = GNUNET_CONTAINER_heap_insert (
389 recent_heap,
390 recent_req,
391 GNUNET_TIME_absolute_get ().abs_value_us);
392 (void) GNUNET_CONTAINER_multihashmap_put (
393 recent_map,
394 key,
395 recent_req,
396 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
397}
398
399
400/**
401 * Initialize routing subsystem.
402 */
403void
404GDS_ROUTING_init ()
405{
406 recent_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
407 recent_map = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3,
408 GNUNET_NO);
409}
410
411
412/**
413 * Shutdown routing subsystem.
414 */
415void
416GDS_ROUTING_done ()
417{
418 while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0)
419 expire_oldest_entry ();
420 GNUNET_assert (0 ==
421 GNUNET_CONTAINER_heap_get_size (recent_heap));
422 GNUNET_CONTAINER_heap_destroy (recent_heap);
423 recent_heap = NULL;
424 GNUNET_assert (0 ==
425 GNUNET_CONTAINER_multihashmap_size (recent_map));
426 GNUNET_CONTAINER_multihashmap_destroy (recent_map);
427 recent_map = NULL;
428}
429
430
431/* 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 bee16736c..000000000
--- a/src/dht/plugin_block_dht.c
+++ /dev/null
@@ -1,408 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010, 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/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_hello_uri_lib.h"
32#include "gnunet_block_plugin.h"
33#include "gnunet_block_group_lib.h"
34
35#define DEBUG_DHT GNUNET_EXTRA_LOGGING
36
37/**
38 * Number of bits we set per entry in the bloomfilter.
39 * Do not change!
40 */
41#define BLOOMFILTER_K 16
42
43
44/**
45 * Create a new block group.
46 *
47 * @param ctx block context in which the block group is created
48 * @param type type of the block for which we are creating the group
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 const void *raw_data,
59 size_t raw_data_size,
60 va_list va)
61{
62 unsigned int bf_size;
63 const char *guard;
64
65 guard = va_arg (va, const char *);
66 if (0 == strcmp (guard,
67 "seen-set-size"))
68 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va,
69 unsigned int),
70 BLOOMFILTER_K);
71 else if (0 == strcmp (guard,
72 "filter-size"))
73 bf_size = va_arg (va, unsigned int);
74 else
75 {
76 GNUNET_break (0);
77 bf_size = 8;
78 }
79 GNUNET_break (NULL == va_arg (va, const char *));
80 return GNUNET_BLOCK_GROUP_bf_create (cls,
81 bf_size,
82 BLOOMFILTER_K,
83 type,
84 raw_data,
85 raw_data_size);
86}
87
88
89/**
90 * Function called to validate a query.
91 *
92 * @param cls closure
93 * @param type block type
94 * @param query original query (hash)
95 * @param xquery extrended query data (can be NULL, depending on type)
96 * @param xquery_size number of bytes in @a xquery
97 * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not
98 */
99static enum GNUNET_GenericReturnValue
100block_plugin_dht_check_query (void *cls,
101 enum GNUNET_BLOCK_Type type,
102 const struct GNUNET_HashCode *query,
103 const void *xquery,
104 size_t xquery_size)
105{
106 switch (type)
107 {
108 case GNUNET_BLOCK_TYPE_DHT_HELLO:
109 if (0 != xquery_size)
110 {
111 GNUNET_break_op (0);
112 return GNUNET_NO;
113 }
114 return GNUNET_OK;
115 case GNUNET_BLOCK_TYPE_DHT_URL_HELLO:
116 if (0 != xquery_size)
117 {
118 GNUNET_break_op (0);
119 return GNUNET_NO;
120 }
121 return GNUNET_OK;
122 default:
123 GNUNET_break (0);
124 return GNUNET_SYSERR;
125 }
126}
127
128
129/**
130 * Function called to validate a block for storage.
131 *
132 * @param cls closure
133 * @param type block type
134 * @param block block data to validate
135 * @param block_size number of bytes in @a block
136 * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not
137 */
138static enum GNUNET_GenericReturnValue
139block_plugin_dht_check_block (void *cls,
140 enum GNUNET_BLOCK_Type type,
141 const void *block,
142 size_t block_size)
143{
144 switch (type)
145 {
146 case GNUNET_BLOCK_TYPE_DHT_HELLO:
147 {
148 const struct GNUNET_HELLO_Message *hello;
149 struct GNUNET_PeerIdentity pid;
150 const struct GNUNET_MessageHeader *msg;
151
152 if (block_size < sizeof(struct GNUNET_MessageHeader))
153 {
154 GNUNET_break_op (0);
155 return GNUNET_NO;
156 }
157 msg = block;
158 if (block_size != ntohs (msg->size))
159 {
160 GNUNET_break_op (0);
161 return GNUNET_NO;
162 }
163 hello = block;
164 if (GNUNET_OK !=
165 GNUNET_HELLO_get_id (hello,
166 &pid))
167 {
168 GNUNET_break_op (0);
169 return GNUNET_NO;
170 }
171 return GNUNET_OK;
172 }
173 case GNUNET_BLOCK_TYPE_DHT_URL_HELLO:
174 {
175 struct GNUNET_HELLO_Builder *b;
176 struct GNUNET_PeerIdentity pid;
177 struct GNUNET_HashCode h_pid;
178
179 b = GNUNET_HELLO_builder_from_block (block,
180 block_size);
181 if (NULL == b)
182 {
183 GNUNET_break (0);
184 return GNUNET_NO;
185 }
186 GNUNET_HELLO_builder_iterate (b,
187 &pid,
188 NULL, NULL);
189 GNUNET_CRYPTO_hash (&pid,
190 sizeof (pid),
191 &h_pid);
192 GNUNET_HELLO_builder_free (b);
193 return GNUNET_OK;
194 }
195 default:
196 GNUNET_break (0);
197 return GNUNET_SYSERR;
198 }
199}
200
201
202/**
203 * Function called to validate a reply to a request. Note that it is assumed
204 * that the reply has already been matched to the key (and signatures checked)
205 * as it would be done with the GetKeyFunction and the
206 * BlockEvaluationFunction.
207 *
208 * @param cls closure
209 * @param type block type
210 * @param group which block group to use for evaluation
211 * @param query original query (hash)
212 * @param xquery extrended query data (can be NULL, depending on type)
213 * @param xquery_size number of bytes in @a xquery
214 * @param reply_block response to validate
215 * @param reply_block_size number of bytes in @a reply_block
216 * @return characterization of result
217 */
218static enum GNUNET_BLOCK_ReplyEvaluationResult
219block_plugin_dht_check_reply (
220 void *cls,
221 enum GNUNET_BLOCK_Type type,
222 struct GNUNET_BLOCK_Group *group,
223 const struct GNUNET_HashCode *query,
224 const void *xquery,
225 size_t xquery_size,
226 const void *reply_block,
227 size_t reply_block_size)
228{
229 switch (type)
230 {
231 case GNUNET_BLOCK_TYPE_DHT_HELLO:
232 {
233 const struct GNUNET_MessageHeader *msg = reply_block;
234 const struct GNUNET_HELLO_Message *hello = reply_block;
235 struct GNUNET_PeerIdentity pid;
236 struct GNUNET_HashCode phash;
237
238 GNUNET_assert (reply_block_size >= sizeof(struct GNUNET_MessageHeader));
239 GNUNET_assert (reply_block_size == ntohs (msg->size));
240 GNUNET_assert (GNUNET_OK ==
241 GNUNET_HELLO_get_id (hello,
242 &pid));
243 GNUNET_CRYPTO_hash (&pid,
244 sizeof(pid),
245 &phash);
246 if (GNUNET_YES ==
247 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
248 &phash))
249 return GNUNET_BLOCK_REPLY_OK_DUPLICATE;
250 return GNUNET_BLOCK_REPLY_OK_MORE;
251 }
252 case GNUNET_BLOCK_TYPE_DHT_URL_HELLO:
253 {
254 struct GNUNET_HELLO_Builder *b;
255 struct GNUNET_PeerIdentity pid;
256 struct GNUNET_HashCode h_pid;
257
258 b = GNUNET_HELLO_builder_from_block (reply_block,
259 reply_block_size);
260 GNUNET_assert (NULL != b);
261 GNUNET_HELLO_builder_iterate (b,
262 &pid,
263 NULL, NULL);
264 GNUNET_CRYPTO_hash (&pid,
265 sizeof (pid),
266 &h_pid);
267 GNUNET_HELLO_builder_free (b);
268 if (GNUNET_YES ==
269 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
270 &h_pid))
271 return GNUNET_BLOCK_REPLY_OK_DUPLICATE;
272 return GNUNET_BLOCK_REPLY_OK_MORE;
273 }
274 default:
275 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
276 }
277}
278
279
280/**
281 * Function called to obtain the key for a block.
282 *
283 * @param cls closure
284 * @param type block type
285 * @param block block to get the key for
286 * @param block_size number of bytes @a block
287 * @param[out] key set to the key (query) for the given block
288 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
289 * (or if extracting a key from a block of this type does not work)
290 */
291static enum GNUNET_GenericReturnValue
292block_plugin_dht_get_key (void *cls,
293 enum GNUNET_BLOCK_Type type,
294 const void *block,
295 size_t block_size,
296 struct GNUNET_HashCode *key)
297{
298 switch (type)
299 {
300 case GNUNET_BLOCK_TYPE_DHT_HELLO:
301 {
302 const struct GNUNET_MessageHeader *msg;
303 const struct GNUNET_HELLO_Message *hello;
304 struct GNUNET_PeerIdentity *pid;
305
306 if (block_size < sizeof(struct GNUNET_MessageHeader))
307 {
308 GNUNET_break_op (0);
309 memset (key,
310 0,
311 sizeof (*key));
312 return GNUNET_OK;
313 }
314 msg = block;
315 if (block_size != ntohs (msg->size))
316 {
317 GNUNET_break_op (0);
318 memset (key,
319 0,
320 sizeof (*key));
321 return GNUNET_OK;
322 }
323 hello = block;
324 memset (key,
325 0,
326 sizeof(*key));
327 pid = (struct GNUNET_PeerIdentity *) key;
328 if (GNUNET_OK !=
329 GNUNET_HELLO_get_id (hello,
330 pid))
331 {
332 GNUNET_break_op (0);
333 memset (key,
334 0,
335 sizeof (*key));
336 return GNUNET_OK;
337 }
338 return GNUNET_OK;
339 }
340 case GNUNET_BLOCK_TYPE_DHT_URL_HELLO:
341 {
342 struct GNUNET_HELLO_Builder *b;
343 struct GNUNET_PeerIdentity pid;
344
345 b = GNUNET_HELLO_builder_from_block (block,
346 block_size);
347 if (NULL == b)
348 {
349 GNUNET_break (0);
350 memset (key,
351 0,
352 sizeof (*key));
353 return GNUNET_OK;
354 }
355 GNUNET_HELLO_builder_iterate (b,
356 &pid,
357 NULL, NULL);
358 GNUNET_CRYPTO_hash (&pid,
359 sizeof (pid),
360 key);
361 GNUNET_HELLO_builder_free (b);
362 return GNUNET_OK;
363 }
364 default:
365 GNUNET_break (0);
366 return GNUNET_SYSERR;
367 }
368}
369
370
371/**
372 * Entry point for the plugin.
373 */
374void *
375libgnunet_plugin_block_dht_init (void *cls)
376{
377 static enum GNUNET_BLOCK_Type types[] = {
378 GNUNET_BLOCK_TYPE_DHT_HELLO,
379 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
380 GNUNET_BLOCK_TYPE_ANY /* end of list */
381 };
382 struct GNUNET_BLOCK_PluginFunctions *api;
383
384 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
385 api->get_key = &block_plugin_dht_get_key;
386 api->check_query = &block_plugin_dht_check_query;
387 api->check_block = &block_plugin_dht_check_block;
388 api->check_reply = &block_plugin_dht_check_reply;
389 api->create_group = &block_plugin_dht_create_group;
390 api->types = types;
391 return api;
392}
393
394
395/**
396 * Exit point from the plugin.
397 */
398void *
399libgnunet_plugin_block_dht_done (void *cls)
400{
401 struct GNUNET_BLOCK_PluginFunctions *api = cls;
402
403 GNUNET_free (api);
404 return NULL;
405}
406
407
408/* 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 4830ba629..000000000
--- a/src/dht/test_dht_topo.c
+++ /dev/null
@@ -1,634 +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 query query hash
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 *query,
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 if (0 != GNUNET_memcmp (query,
363 &get_op->key))
364 {
365 /* exact search should only yield exact results */
366 GNUNET_break (0);
367 return;
368 }
369 GNUNET_CRYPTO_hash (query,
370 sizeof(*query),
371 &want);
372 if (0 != memcmp (&want,
373 data,
374 sizeof(want)))
375 {
376 GNUNET_break (0);
377 return;
378 }
379 if (0 !=
380 GNUNET_DHT_verify_path (data,
381 size,
382 exp,
383 put_path,
384 put_path_length,
385 get_path,
386 get_path_length,
387 &get_op->me))
388 {
389 GNUNET_break (0);
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
391 "Path signature (%u/%u) verification failed for peer %s!\n",
392 get_path_length,
393 put_path_length,
394 GNUNET_i2s (&get_op->me));
395 }
396 else
397 {
398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399 "Get successful\n");
400 ok--;
401 }
402 GNUNET_DHT_get_stop (get_op->get);
403 GNUNET_CONTAINER_DLL_remove (get_head,
404 get_tail,
405 get_op);
406 GNUNET_free (get_op);
407 if (NULL != get_head)
408 return;
409 /* all DHT GET operations successful; get stats! */
410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
411 "All DHT operations successful. Obtaining stats!\n");
412 ctx = stop_ops ();
413 GNUNET_assert (NULL != ctx);
414 (void) GNUNET_TESTBED_get_statistics (NUM_PEERS,
415 my_peers,
416 NULL, NULL,
417 &handle_stats,
418 &stats_finished,
419 ctx);
420}
421
422
423/**
424 * Task to put the id of each peer into the DHT.
425 *
426 * @param cls array with NUM_PEERS DHT handles
427 * @param tc Task context
428 */
429static void
430do_puts (void *cls)
431{
432 struct GNUNET_DHT_Handle **hs = cls;
433 struct GNUNET_HashCode key;
434 struct GNUNET_HashCode value;
435
436 put_task = NULL;
437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438 "Putting %u values into DHT\n",
439 NUM_PEERS);
440 for (unsigned int i = 0; i < NUM_PEERS; i++)
441 {
442 GNUNET_CRYPTO_hash (&i,
443 sizeof(i),
444 &key);
445 GNUNET_CRYPTO_hash (&key,
446 sizeof(key),
447 &value);
448 GNUNET_DHT_put (hs[i],
449 &key,
450 10U,
451 GNUNET_DHT_RO_RECORD_ROUTE
452 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
453 GNUNET_BLOCK_TYPE_TEST,
454 sizeof(value),
455 &value,
456 GNUNET_TIME_UNIT_FOREVER_ABS,
457 NULL,
458 NULL);
459 }
460 put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY,
461 &do_puts,
462 hs);
463}
464
465
466/**
467 * Callback to be called when the requested peer information is available
468 * The peer information in the callback is valid until the operation 'op' is canceled.
469 *
470 * @param cls a `struct GetOperation *`
471 * @param op the operation this callback corresponds to
472 * @param pinfo the result; will be NULL if the operation has failed
473 * @param emsg error message if the operation has failed; will be NULL if the
474 * operation is successful
475 */
476static void
477pid_cb (void *cls,
478 struct GNUNET_TESTBED_Operation *op,
479 const struct GNUNET_TESTBED_PeerInformation *pinfo,
480 const char *emsg)
481{
482 struct GetOperation *get_op = cls;
483
484 if (NULL != emsg)
485 {
486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
487 "Testbed failure: %s\n",
488 emsg);
489 GNUNET_TESTBED_operation_done (get_op->to);
490 get_op->to = NULL;
491 GNUNET_SCHEDULER_shutdown ();
492 return;
493 }
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Testbed provided PID %s\n",
496 GNUNET_i2s (pinfo->result.id));
497 get_op->me = *pinfo->result.id;
498 GNUNET_TESTBED_operation_done (get_op->to);
499 get_op->to = NULL;
500 get_op->get = GNUNET_DHT_get_start (get_op->dht,
501 GNUNET_BLOCK_TYPE_TEST,
502 &get_op->key,
503 4U, /* replication level */
504 GNUNET_DHT_RO_RECORD_ROUTE
505 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
506 NULL, /* xquery */
507 0, /* xquery bits */
508 &dht_get_handler,
509 get_op);
510}
511
512
513/**
514 * Start GET operations.
515 */
516static void
517start_get (void *cls)
518{
519 struct GNUNET_DHT_Handle **dhts = cls;
520
521 get_task = NULL;
522 for (unsigned int i = 0; i < NUM_PEERS; i++)
523 {
524 struct GNUNET_HashCode key;
525
526 GNUNET_CRYPTO_hash (&i,
527 sizeof(i),
528 &key);
529 for (unsigned int j = 0; j < NUM_PEERS; j++)
530 {
531 struct GetOperation *get_op;
532
533 get_op = GNUNET_new (struct GetOperation);
534 ok++;
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Starting GET %p\n",
537 get_op);
538 get_op->key = key;
539 get_op->dht = dhts[j];
540 get_op->to = GNUNET_TESTBED_peer_get_information (my_peers[j],
541 GNUNET_TESTBED_PIT_IDENTITY,
542 &pid_cb,
543 get_op);
544 GNUNET_CONTAINER_DLL_insert (get_head,
545 get_tail,
546 get_op);
547 }
548 }
549}
550
551
552/**
553 * Main function of the test.
554 *
555 * @param cls closure (NULL)
556 * @param ctx argument to give to #GNUNET_DHT_TEST_cleanup on test end
557 * @param num_peers number of @a peers that are running
558 * @param peers array of peers
559 * @param dhts handle to each of the DHTs of the peers
560 */
561static void
562run (void *cls,
563 struct GNUNET_DHT_TEST_Context *ctx,
564 unsigned int num_peers,
565 struct GNUNET_TESTBED_Peer **peers,
566 struct GNUNET_DHT_Handle **dhts)
567{
568 GNUNET_assert (NUM_PEERS == num_peers);
569 my_peers = peers;
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571 "Peers setup, starting test\n");
572 put_task = GNUNET_SCHEDULER_add_now (&do_puts,
573 dhts);
574 get_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
575 &start_get,
576 dhts);
577 timeout_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
578 &timeout_cb,
579 ctx);
580 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
581 ctx);
582}
583
584
585/**
586 * Main: start test
587 */
588int
589main (int xargc, char *xargv[])
590{
591 const char *cfg_filename;
592 const char *test_name;
593
594 unsetenv ("XDG_DATA_HOME");
595 unsetenv ("XDG_CONFIG_HOME");
596 unsetenv ("XDG_CACHE_HOME");
597 if (NULL != strstr (xargv[0], "test_dht_2dtorus"))
598 {
599 cfg_filename = "test_dht_2dtorus.conf";
600 test_name = "test-dht-2dtorus";
601 NUM_PEERS = 16;
602 }
603 else if (NULL != strstr (xargv[0], "test_dht_line"))
604 {
605 cfg_filename = "test_dht_line.conf";
606 test_name = "test-dht-line";
607 NUM_PEERS = 5;
608 }
609 else if (NULL != strstr (xargv[0], "test_dht_twopeer"))
610 {
611 cfg_filename = "test_dht_line.conf";
612 test_name = "test-dht-twopeer";
613 NUM_PEERS = 2;
614 }
615 else if (NULL != strstr (xargv[0], "test_dht_multipeer"))
616 {
617 cfg_filename = "test_dht_multipeer.conf";
618 test_name = "test-dht-multipeer";
619 NUM_PEERS = 10;
620 }
621 else
622 {
623 GNUNET_break (0);
624 return 1;
625 }
626 GNUNET_DHT_TEST_run (test_name,
627 cfg_filename,
628 NUM_PEERS,
629 &run, NULL);
630 return ok;
631}
632
633
634/* end of test_dht_topo.c */