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