2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 #include "gnunet_util_lib.h"
25 #include "gnunet_dht_service.h"
26 #include "gnunet_statistics_service.h"
28 #include "block_mesh.h"
29 #include "mesh_path.h"
30 #include "gnunet-service-mesh_dht.h"
31 #include "gnunet-service-mesh_peer.h"
33 #define LOG(level, ...) GNUNET_log_from (level,"mesh-dht",__VA_ARGS__)
36 /******************************************************************************/
37 /******************************** STRUCTS **********************************/
38 /******************************************************************************/
41 * Handle for DHT searches.
43 struct GMD_search_handle
45 /** DHT_GET handle. */
46 struct GNUNET_DHT_GetHandle *dhtget;
48 /** Provided callback to call when a path is found. */
49 GMD_search_callback callback;
51 /** Provided closure. */
54 /** Peer ID searched for */
55 GNUNET_PEER_Id peer_id;
59 /******************************************************************************/
60 /******************************* GLOBALS ***********************************/
61 /******************************************************************************/
64 * Global handle to the statistics service.
66 extern struct GNUNET_STATISTICS_Handle *stats;
69 * Own ID (short value).
71 extern GNUNET_PEER_Id myid;
74 * Own ID (full value).
76 extern struct GNUNET_PeerIdentity my_full_id;
81 static struct GNUNET_DHT_Handle *dht_handle;
84 * How often to PUT own ID in the DHT.
86 static struct GNUNET_TIME_Relative id_announce_time;
89 * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
91 static unsigned long long dht_replication_level;
94 * Task to periodically announce itself in the network.
96 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
99 * GET requests to stop on shutdown.
101 static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
103 /******************************************************************************/
104 /******************************** STATIC ***********************************/
105 /******************************************************************************/
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.
112 * @return Newly allocated and created path
114 static struct MeshPeerPath *
115 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
116 unsigned int get_path_length,
117 const struct GNUNET_PeerIdentity *put_path,
118 unsigned int put_path_length)
120 struct MeshPeerPath *p;
126 GNUNET_PEER_change_rc (myid, 1);
128 LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
129 for (i--; i >= 0; i--)
131 id = GNUNET_PEER_intern (&get_path[i]);
132 if (p->length > 0 && id == p->peers[p->length - 1])
134 LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
135 GNUNET_PEER_change_rc (id, -1);
139 LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
140 GNUNET_i2s (&get_path[i]));
142 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
143 p->peers[p->length - 1] = id;
147 LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
148 for (i--; i >= 0; i--)
150 id = GNUNET_PEER_intern (&put_path[i]);
153 /* PUT path went through us, so discard the path up until now and start
154 * from here to get a much shorter (and loop-free) path.
159 if (p->length > 0 && id == p->peers[p->length - 1])
161 LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
162 GNUNET_PEER_change_rc (id, -1);
166 LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
167 GNUNET_i2s (&put_path[i]));
169 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
170 p->peers[p->length - 1] = id;
174 if (get_path_length > 0)
175 LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
176 GNUNET_i2s (&get_path[0]));
177 if (put_path_length > 0)
178 LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
179 GNUNET_i2s (&put_path[0]));
180 LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
182 for (i = 0; i < p->length; i++)
184 struct GNUNET_PeerIdentity peer_id;
186 GNUNET_PEER_resolve (p->peers[i], &peer_id);
187 LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
188 GNUNET_i2s (&peer_id));
196 * Function to process paths received for a new peer addition. The recorded
197 * paths form the initial tunnel, which can be optimized later.
198 * Called on each result obtained for the DHT search.
201 * @param exp when will this value expire
202 * @param key key of the result
203 * @param get_path path of the get request
204 * @param get_path_length lenght of get_path
205 * @param put_path path of the put request
206 * @param put_path_length length of the put_path
207 * @param type type of the result
208 * @param size number of bytes in data
209 * @param data pointer to the result data
212 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
213 const struct GNUNET_HashCode * key,
214 const struct GNUNET_PeerIdentity *get_path,
215 unsigned int get_path_length,
216 const struct GNUNET_PeerIdentity *put_path,
217 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
218 size_t size, const void *data)
220 struct GMD_search_handle *h = cls;
221 struct MeshPeerPath *p;
223 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got results!\n");
224 p = path_build_from_dht (get_path, get_path_length,
225 put_path, put_path_length);
226 h->callback (h->cls, p);
233 * Periodically announce self id in the DHT
236 * @param tc task context
239 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
242 struct GNUNET_HashCode phash;
244 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
246 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
251 * - Set data expiration in function of X
254 block.id = my_full_id;
255 GNUNET_CRYPTO_hash (&my_full_id, sizeof (struct GNUNET_PeerIdentity), &phash);
256 GNUNET_DHT_put (dht_handle, /* DHT handle */
257 &phash, /* Key to use */
258 dht_replication_level, /* Replication level */
259 GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
260 GNUNET_BLOCK_TYPE_MESH_PEER, /* Block type */
261 sizeof (block), /* Size of the data */
262 (const char *) &block, /* Data itself */
263 GNUNET_TIME_UNIT_FOREVER_ABS, /* Data expiration */
264 GNUNET_TIME_UNIT_FOREVER_REL, /* Retry time */
265 NULL, /* Continuation */
266 NULL); /* Continuation closure */
268 GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
272 * Iterator over hash map entries and stop GET requests before disconnecting
275 * @param cls Closure (unused)
276 * @param key Current peer ID.
277 * @param value Value in the hash map (GMD_search_handle).
279 * @return #GNUNET_YES, we should continue to iterate,
286 struct GMD_search_handle *h = value;
293 /******************************************************************************/
294 /******************************** API ***********************************/
295 /******************************************************************************/
298 * Initialize the DHT subsystem.
300 * @param c Configuration.
303 GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
305 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
307 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
308 &dht_replication_level))
310 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
311 "MESH", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
312 dht_replication_level = 3;
316 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
319 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
320 "MESH", "ID_ANNOUNCE_TIME", "MISSING");
321 GNUNET_SCHEDULER_shutdown ();
325 dht_handle = GNUNET_DHT_connect (c, 64);
326 if (NULL == dht_handle)
331 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
332 get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
337 * Shut down the DHT subsystem.
342 GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
343 GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
344 if (dht_handle != NULL)
346 GNUNET_DHT_disconnect (dht_handle);
349 if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
351 GNUNET_SCHEDULER_cancel (announce_id_task);
352 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
356 struct GMD_search_handle *
357 GMD_search (const struct GNUNET_PeerIdentity *peer_id,
358 GMD_search_callback callback, void *cls)
360 struct GNUNET_HashCode phash;
361 struct GMD_search_handle *h;
363 LOG (GNUNET_ERROR_TYPE_DEBUG,
364 " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
365 GNUNET_CRYPTO_hash (peer_id, sizeof (struct GNUNET_PeerIdentity), &phash);
366 h = GNUNET_new (struct GMD_search_handle);
367 h->peer_id = GNUNET_PEER_intern (peer_id);
368 h->callback = callback;
370 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
371 GNUNET_BLOCK_TYPE_MESH_PEER, /* type */
372 &phash, /* key to search */
373 dht_replication_level, /* replication level */
374 GNUNET_DHT_RO_RECORD_ROUTE |
375 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
378 &dht_get_id_handler, h);
379 GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
380 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
385 GMD_search_stop (struct GMD_search_handle *h)
387 GNUNET_break (GNUNET_OK ==
388 GNUNET_CONTAINER_multihashmap32_remove (get_requests,
390 GNUNET_DHT_get_stop (h->dhtget);