aboutsummaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-service-cadet_dht.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cadet/gnunet-service-cadet_dht.c')
-rw-r--r--src/cadet/gnunet-service-cadet_dht.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c
new file mode 100644
index 000000000..b187e3cd9
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -0,0 +1,423 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21
22#include "platform.h"
23#include "gnunet_util_lib.h"
24
25#include "gnunet_dht_service.h"
26#include "gnunet_statistics_service.h"
27
28#include "cadet_path.h"
29#include "gnunet-service-cadet_dht.h"
30#include "gnunet-service-cadet_peer.h"
31#include "gnunet-service-cadet_hello.h"
32
33#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
34
35
36/******************************************************************************/
37/******************************** STRUCTS **********************************/
38/******************************************************************************/
39
40/**
41 * Handle for DHT searches.
42 */
43struct GMD_search_handle
44{
45 /** DHT_GET handle. */
46 struct GNUNET_DHT_GetHandle *dhtget;
47
48 /** Provided callback to call when a path is found. */
49 GMD_search_callback callback;
50
51 /** Provided closure. */
52 void *cls;
53
54 /** Peer ID searched for */
55 GNUNET_PEER_Id peer_id;
56};
57
58
59/******************************************************************************/
60/******************************* GLOBALS ***********************************/
61/******************************************************************************/
62
63/**
64 * Global handle to the statistics service.
65 */
66extern struct GNUNET_STATISTICS_Handle *stats;
67
68/**
69 * Own ID (short value).
70 */
71extern GNUNET_PEER_Id myid;
72
73/**
74 * Own ID (full value).
75 */
76extern struct GNUNET_PeerIdentity my_full_id;
77
78/**
79 * Handle to use DHT.
80 */
81static struct GNUNET_DHT_Handle *dht_handle;
82
83/**
84 * How often to PUT own ID in the DHT.
85 */
86static struct GNUNET_TIME_Relative id_announce_time;
87
88/**
89 * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
90 */
91static unsigned long long dht_replication_level;
92
93/**
94 * Task to periodically announce itself in the network.
95 */
96static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
97
98/**
99 * GET requests to stop on shutdown.
100 */
101static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
102
103/******************************************************************************/
104/******************************** STATIC ***********************************/
105/******************************************************************************/
106
107
108/**
109 * Build a PeerPath from the paths returned from the DHT, reversing the paths
110 * to obtain a local peer -> destination path and interning the peer ids.
111 *
112 * @return Newly allocated and created path
113 *
114 * FIXME refactor and use build_path_from_peer_ids
115 */
116static struct CadetPeerPath *
117path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
118 unsigned int get_path_length,
119 const struct GNUNET_PeerIdentity *put_path,
120 unsigned int put_path_length)
121{
122 struct CadetPeerPath *p;
123 GNUNET_PEER_Id id;
124 int i;
125
126 p = path_new (1);
127 p->peers[0] = myid;
128 GNUNET_PEER_change_rc (myid, 1);
129 i = get_path_length;
130 LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
131 for (i--; i >= 0; i--)
132 {
133 id = GNUNET_PEER_intern (&get_path[i]);
134 if (p->length > 0 && id == p->peers[p->length - 1])
135 {
136 LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
137 GNUNET_PEER_change_rc (id, -1);
138 }
139 else
140 {
141 LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
142 GNUNET_i2s (&get_path[i]));
143 p->length++;
144 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
145 p->peers[p->length - 1] = id;
146 }
147 }
148 i = put_path_length;
149 LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
150 for (i--; i >= 0; i--)
151 {
152 id = GNUNET_PEER_intern (&put_path[i]);
153 if (id == myid)
154 {
155 /* PUT path went through us, so discard the path up until now and start
156 * from here to get a much shorter (and loop-free) path.
157 */
158 path_destroy (p);
159 p = path_new (0);
160 }
161 if (p->length > 0 && id == p->peers[p->length - 1])
162 {
163 LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
164 GNUNET_PEER_change_rc (id, -1);
165 }
166 else
167 {
168 LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
169 GNUNET_i2s (&put_path[i]));
170 p->length++;
171 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
172 p->peers[p->length - 1] = id;
173 }
174 }
175#if CADET_DEBUG
176 if (get_path_length > 0)
177 LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
178 GNUNET_i2s (&get_path[0]));
179 if (put_path_length > 0)
180 LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
181 GNUNET_i2s (&put_path[0]));
182 LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
183 p->length);
184 for (i = 0; i < p->length; i++)
185 {
186 struct GNUNET_PeerIdentity peer_id;
187
188 GNUNET_PEER_resolve (p->peers[i], &peer_id);
189 LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
190 GNUNET_i2s (&peer_id));
191 }
192#endif
193 return p;
194}
195
196
197/**
198 * Function to process paths received for a new peer addition. The recorded
199 * paths form the initial tunnel, which can be optimized later.
200 * Called on each result obtained for the DHT search.
201 *
202 * @param cls closure
203 * @param exp when will this value expire
204 * @param key key of the result
205 * @param get_path path of the get request
206 * @param get_path_length lenght of get_path
207 * @param put_path path of the put request
208 * @param put_path_length length of the put_path
209 * @param type type of the result
210 * @param size number of bytes in data
211 * @param data pointer to the result data
212 */
213static void
214dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
215 const struct GNUNET_HashCode * key,
216 const struct GNUNET_PeerIdentity *get_path,
217 unsigned int get_path_length,
218 const struct GNUNET_PeerIdentity *put_path,
219 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
220 size_t size, const void *data)
221{
222 struct GMD_search_handle *h = cls;
223 struct GNUNET_HELLO_Message *hello;
224 struct CadetPeerPath *p;
225 struct CadetPeer *peer;
226 char *s;
227
228 p = path_build_from_dht (get_path, get_path_length,
229 put_path, put_path_length);
230 s = path_2s (p);
231 LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
232 GNUNET_free_non_null (s);
233 peer = GMP_get_short (p->peers[p->length - 1]);
234 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer));
235 h->callback (h->cls, p);
236 path_destroy (p);
237 hello = (struct GNUNET_HELLO_Message *) data;
238 GMP_set_hello (peer, hello);
239 GMP_try_connect (peer);
240 return;
241}
242
243
244/**
245 * Periodically announce self id in the DHT
246 *
247 * @param cls closure
248 * @param tc task context
249 */
250static void
251announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
252{
253 struct GNUNET_HashCode phash;
254 const struct GNUNET_HELLO_Message *hello;
255 size_t size;
256 struct GNUNET_TIME_Absolute expiration;
257 struct GNUNET_TIME_Relative retry_time;
258
259 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
260 {
261 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
262 return;
263 }
264 LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
265
266 /* TODO
267 * - Set data expiration in function of X
268 * - Adapt X to churn
269 */
270 hello = GMH_get_mine ();
271 if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
272 {
273 /* Peerinfo gave us no hello yet, try again in a second. */
274 announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
275 &announce_id, cls);
276 LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n");
277 return;
278 }
279 expiration = GNUNET_HELLO_get_last_expiration (hello);
280 retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
281
282 LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
283 memset (&phash, 0, sizeof (phash));
284 memcpy (&phash, &my_full_id, sizeof (my_full_id));
285 GNUNET_DHT_put (dht_handle, /* DHT handle */
286 &phash, /* Key to use */
287 dht_replication_level, /* Replication level */
288 GNUNET_DHT_RO_RECORD_ROUTE
289 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
290 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
291 size, /* Size of the data */
292 (const char *) hello, /* Data itself */
293 expiration, /* Data expiration */
294 retry_time, /* Retry time */
295 NULL, /* Continuation */
296 NULL); /* Continuation closure */
297 announce_id_task =
298 GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
299}
300
301/**
302 * Iterator over hash map entries and stop GET requests before disconnecting
303 * from the DHT.
304 *
305 * @param cls Closure (unused)
306 * @param key Current peer ID.
307 * @param value Value in the hash map (GMD_search_handle).
308 *
309 * @return #GNUNET_YES, we should continue to iterate,
310 */
311int
312stop_get (void *cls,
313 uint32_t key,
314 void *value)
315{
316 struct GMD_search_handle *h = value;
317
318 GMD_search_stop (h);
319 return GNUNET_YES;
320}
321
322
323/******************************************************************************/
324/******************************** API ***********************************/
325/******************************************************************************/
326
327/**
328 * Initialize the DHT subsystem.
329 *
330 * @param c Configuration.
331 */
332void
333GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
334{
335 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
336 if (GNUNET_OK !=
337 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DHT_REPLICATION_LEVEL",
338 &dht_replication_level))
339 {
340 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
341 "CADET", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
342 dht_replication_level = 3;
343 }
344
345 if (GNUNET_OK !=
346 GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
347 &id_announce_time))
348 {
349 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
350 "CADET", "ID_ANNOUNCE_TIME", "MISSING");
351 GNUNET_SCHEDULER_shutdown ();
352 return;
353 }
354
355 dht_handle = GNUNET_DHT_connect (c, 64);
356 if (NULL == dht_handle)
357 {
358 GNUNET_break (0);
359 }
360
361 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
362 get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
363}
364
365
366/**
367 * Shut down the DHT subsystem.
368 */
369void
370GMD_shutdown (void)
371{
372 GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
373 GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
374 if (dht_handle != NULL)
375 {
376 GNUNET_DHT_disconnect (dht_handle);
377 dht_handle = NULL;
378 }
379 if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
380 {
381 GNUNET_SCHEDULER_cancel (announce_id_task);
382 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
383 }
384}
385
386struct GMD_search_handle *
387GMD_search (const struct GNUNET_PeerIdentity *peer_id,
388 GMD_search_callback callback, void *cls)
389{
390 struct GNUNET_HashCode phash;
391 struct GMD_search_handle *h;
392
393 LOG (GNUNET_ERROR_TYPE_DEBUG,
394 " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
395 memset (&phash, 0, sizeof (phash));
396 memcpy (&phash, peer_id, sizeof (*peer_id));
397 h = GNUNET_new (struct GMD_search_handle);
398 h->peer_id = GNUNET_PEER_intern (peer_id);
399 h->callback = callback;
400 h->cls = cls;
401 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
402 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
403 &phash, /* key to search */
404 dht_replication_level, /* replication level */
405 GNUNET_DHT_RO_RECORD_ROUTE |
406 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
407 NULL, /* xquery */
408 0, /* xquery bits */
409 &dht_get_id_handler, h);
410 GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
411 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
412 return h;
413}
414
415void
416GMD_search_stop (struct GMD_search_handle *h)
417{
418 GNUNET_break (GNUNET_OK ==
419 GNUNET_CONTAINER_multihashmap32_remove (get_requests,
420 h->peer_id, h));
421 GNUNET_DHT_get_stop (h->dhtget);
422 GNUNET_free (h);
423}