2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
23 #include "gnunet_util_lib.h"
25 #include "gnunet_dht_service.h"
26 #include "gnunet_statistics_service.h"
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"
33 #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
36 /******************************************************************************/
37 /******************************** STRUCTS **********************************/
38 /******************************************************************************/
41 * Handle for DHT searches.
43 struct GCD_search_handle
48 struct GNUNET_DHT_GetHandle *dhtget;
51 * Provided callback to call when a path is found.
53 GCD_search_callback callback;
61 * Peer ID searched for
63 GNUNET_PEER_Id peer_id;
67 /******************************************************************************/
68 /******************************* GLOBALS ***********************************/
69 /******************************************************************************/
72 * Global handle to the statistics service.
74 extern struct GNUNET_STATISTICS_Handle *stats;
77 * Own ID (short value).
79 extern GNUNET_PEER_Id myid;
82 * Own ID (full value).
84 extern struct GNUNET_PeerIdentity my_full_id;
89 static struct GNUNET_DHT_Handle *dht_handle;
92 * How often to PUT own ID in the DHT.
94 static struct GNUNET_TIME_Relative id_announce_time;
97 * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
99 static unsigned long long dht_replication_level;
102 * Task to periodically announce itself in the network.
104 static struct GNUNET_SCHEDULER_Task * announce_id_task;
107 * Delay for the next ID announce.
109 static struct GNUNET_TIME_Relative announce_delay;
112 * GET requests to stop on shutdown.
114 static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
116 /******************************************************************************/
117 /******************************** STATIC ***********************************/
118 /******************************************************************************/
122 * Build a PeerPath from the paths returned from the DHT, reversing the paths
123 * to obtain a local peer -> destination path and interning the peer ids.
125 * @return Newly allocated and created path
127 * FIXME refactor and use build_path_from_peer_ids
129 static struct CadetPeerPath *
130 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
131 unsigned int get_path_length,
132 const struct GNUNET_PeerIdentity *put_path,
133 unsigned int put_path_length)
135 size_t size = get_path_length + put_path_length + 1;
136 struct GNUNET_PeerIdentity peers[size];
137 const struct GNUNET_PeerIdentity *peer;
138 struct CadetPeerPath *p;
139 unsigned int own_pos;
142 peers[0] = my_full_id;
143 LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length);
144 for (i = 0 ; i < get_path_length; i++)
146 peer = &get_path[get_path_length - i - 1];
147 LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer));
148 peers[i + 1] = *peer;
150 for (i = 0 ; i < put_path_length; i++)
152 peer = &put_path[put_path_length - i - 1];
153 LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer));
154 peers[i + get_path_length + 1] = *peer;
156 p = path_build_from_peer_ids (peers, size, myid, &own_pos);
162 * Function to process paths received for a new peer addition. The recorded
163 * paths form the initial tunnel, which can be optimized later.
164 * Called on each result obtained for the DHT search.
167 * @param exp when will this value expire
168 * @param key key of the result
169 * @param get_path path of the get request
170 * @param get_path_length lenght of @a get_path
171 * @param put_path path of the put request
172 * @param put_path_length length of the @a put_path
173 * @param type type of the result
174 * @param size number of bytes in data
175 * @param data pointer to the result data
178 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
179 const struct GNUNET_HashCode * key,
180 const struct GNUNET_PeerIdentity *get_path,
181 unsigned int get_path_length,
182 const struct GNUNET_PeerIdentity *put_path,
183 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
184 size_t size, const void *data)
186 struct GCD_search_handle *h = cls;
187 struct GNUNET_HELLO_Message *hello;
188 struct CadetPeerPath *p;
189 struct CadetPeer *peer;
192 p = path_build_from_dht (get_path, get_path_length,
193 put_path, put_path_length);
201 LOG (GNUNET_ERROR_TYPE_INFO,
202 "Got path from DHT: %s\n",
204 GNUNET_free_non_null (s);
206 peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
207 LOG (GNUNET_ERROR_TYPE_DEBUG,
208 "Got HELLO for %s\n",
210 h->callback (h->cls, p);
212 hello = (struct GNUNET_HELLO_Message *) data;
213 GCP_set_hello (peer, hello);
214 GCP_try_connect (peer);
219 * Periodically announce self id in the DHT
224 announce_id (void *cls)
226 struct GNUNET_HashCode phash;
227 const struct GNUNET_HELLO_Message *hello;
229 struct GNUNET_TIME_Absolute expiration;
230 struct GNUNET_TIME_Relative next_put;
232 announce_id_task = NULL;
233 LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
234 hello = GCH_get_mine ();
235 size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
236 if ( (NULL == hello) || (0 == size) )
238 /* Peerinfo gave us no hello yet, try again soon. */
239 LOG (GNUNET_ERROR_TYPE_INFO,
240 " no hello, waiting!\n");
241 GNUNET_STATISTICS_update (stats,
242 "# DHT announce skipped (no hello)",
245 expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
247 announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
251 expiration = GNUNET_HELLO_get_last_expiration (hello);
252 announce_delay = GNUNET_TIME_UNIT_SECONDS;
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Hello %p size: %u\n",
261 GNUNET_STATISTICS_update (stats,
267 GNUNET_memcpy (&phash,
269 sizeof (my_full_id));
270 GNUNET_DHT_put (dht_handle, /* DHT handle */
271 &phash, /* Key to use */
272 dht_replication_level, /* Replication level */
273 GNUNET_DHT_RO_RECORD_ROUTE
274 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
275 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
276 size, /* Size of the data */
277 (const char *) hello, /* Data itself */
278 expiration, /* Data expiration */
279 NULL, /* Continuation */
280 NULL); /* Continuation closure */
282 /* Call again in id_announce_time, unless HELLO expires first,
283 * but wait at least 1s. */
284 next_put = GNUNET_TIME_absolute_get_remaining (expiration);
285 next_put = GNUNET_TIME_relative_min (next_put,
287 next_put = GNUNET_TIME_relative_max (next_put,
288 GNUNET_TIME_UNIT_SECONDS);
289 announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put,
295 * Iterator over hash map entries and stop GET requests before disconnecting
298 * @param cls Closure (unused)
299 * @param key Current peer ID.
300 * @param value Value in the hash map (GCD_search_handle).
302 * @return #GNUNET_YES, we should continue to iterate,
309 struct GCD_search_handle *h = value;
316 /******************************************************************************/
317 /******************************** API ***********************************/
318 /******************************************************************************/
321 * Initialize the DHT subsystem.
323 * @param c Configuration.
326 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
328 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
330 GNUNET_CONFIGURATION_get_value_number (c, "CADET",
331 "DHT_REPLICATION_LEVEL",
332 &dht_replication_level))
334 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET",
335 "DHT_REPLICATION_LEVEL", "USING DEFAULT");
336 dht_replication_level = 3;
340 GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
343 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET",
344 "ID_ANNOUNCE_TIME", "MISSING");
345 GNUNET_SCHEDULER_shutdown ();
349 dht_handle = GNUNET_DHT_connect (c, 64);
350 if (NULL == dht_handle)
355 announce_delay = GNUNET_TIME_UNIT_SECONDS;
356 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
357 get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
362 * Shut down the DHT subsystem.
367 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n");
368 GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
369 GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
370 if (dht_handle != NULL)
372 GNUNET_DHT_disconnect (dht_handle);
375 if (NULL != announce_id_task)
377 GNUNET_SCHEDULER_cancel (announce_id_task);
378 announce_id_task = NULL;
382 struct GCD_search_handle *
383 GCD_search (const struct GNUNET_PeerIdentity *peer_id,
384 GCD_search_callback callback, void *cls)
386 struct GNUNET_HashCode phash;
387 struct GCD_search_handle *h;
389 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n",
390 GNUNET_i2s (peer_id));
391 GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO);
392 memset (&phash, 0, sizeof (phash));
393 GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id));
394 h = GNUNET_new (struct GCD_search_handle);
395 h->peer_id = GNUNET_PEER_intern (peer_id);
396 h->callback = callback;
398 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
399 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
400 &phash, /* key to search */
401 dht_replication_level, /* replication level */
402 GNUNET_DHT_RO_RECORD_ROUTE |
403 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
408 GNUNET_CONTAINER_multihashmap32_put (get_requests,
411 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
417 GCD_search_stop (struct GCD_search_handle *h)
419 GNUNET_break (GNUNET_OK ==
420 GNUNET_CONTAINER_multihashmap32_remove (get_requests,
422 GNUNET_DHT_get_stop (h->dhtget);