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"
27 #include "mesh_path.h"
28 #include "gnunet-service-mesh_dht.h"
29 #include "gnunet-service-mesh_peer.h"
31 #define MESH_DEBUG_DHT GNUNET_NO
34 #define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
36 #define DEBUG_DHT(...)
39 #define LOG (level, ...) GNUNET_log_from ("mesh-dht", level, __VA_ARGS__)
44 * Callback called on each path found over the DHT.
47 * @param path An unchecked, unoptimized path to the target node.
48 * After callback will no longer be valid!
50 typedef void (*GMD_search_callback) (void *cls,
51 const struct MeshPeerPath *path);
53 /******************************************************************************/
54 /******************************** STRUCTS **********************************/
55 /******************************************************************************/
58 * Handle for DHT searches.
60 struct GMD_search_handle
62 /** DHT_GET handle. */
63 struct GNUNET_DHT_GetHandle *dhtget;
65 /** Provided callback to call when a path is found. */
66 GMD_search_callback callback;
68 /** Provided closure. */
73 /******************************************************************************/
74 /******************************* GLOBALS ***********************************/
75 /******************************************************************************/
80 static struct GNUNET_DHT_Handle *dht_handle;
83 * How often to PUT own ID in the DHT.
85 static struct GNUNET_TIME_Relative id_announce_time;
88 * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
90 static unsigned long long dht_replication_level;
93 * Task to periodically announce itself in the network.
95 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
98 * Own ID (short value).
100 static GNUNET_PEER_Id short_id;
103 * Own ID (full value).
105 static struct GNUNET_PeerIdentity *full_id;
110 static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
113 /******************************************************************************/
114 /******************************** STATIC ***********************************/
115 /******************************************************************************/
119 * Build a PeerPath from the paths returned from the DHT, reversing the paths
120 * to obtain a local peer -> destination path and interning the peer ids.
122 * @return Newly allocated and created path
124 static struct MeshPeerPath *
125 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
126 unsigned int get_path_length,
127 const struct GNUNET_PeerIdentity *put_path,
128 unsigned int put_path_length)
130 struct MeshPeerPath *p;
136 GNUNET_PEER_change_rc (myid, 1);
138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
139 for (i--; i >= 0; i--)
141 id = GNUNET_PEER_intern (&get_path[i]);
142 if (p->length > 0 && id == p->peers[p->length - 1])
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
145 GNUNET_PEER_change_rc (id, -1);
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
150 GNUNET_i2s (&get_path[i]));
152 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
153 p->peers[p->length - 1] = id;
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
158 for (i--; i >= 0; i--)
160 id = GNUNET_PEER_intern (&put_path[i]);
163 /* PUT path went through us, so discard the path up until now and start
164 * from here to get a much shorter (and loop-free) path.
169 if (p->length > 0 && id == p->peers[p->length - 1])
171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
172 GNUNET_PEER_change_rc (id, -1);
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
177 GNUNET_i2s (&put_path[i]));
179 p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
180 p->peers[p->length - 1] = id;
184 if (get_path_length > 0)
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
186 GNUNET_i2s (&get_path[0]));
187 if (put_path_length > 0)
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
189 GNUNET_i2s (&put_path[0]));
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
192 for (i = 0; i < p->length; i++)
194 struct GNUNET_PeerIdentity peer_id;
196 GNUNET_PEER_resolve (p->peers[i], &peer_id);
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
198 GNUNET_i2s (&peer_id));
206 * Function to process paths received for a new peer addition. The recorded
207 * paths form the initial tunnel, which can be optimized later.
208 * Called on each result obtained for the DHT search.
211 * @param exp when will this value expire
212 * @param key key of the result
213 * @param get_path path of the get request
214 * @param get_path_length lenght of get_path
215 * @param put_path path of the put request
216 * @param put_path_length length of the put_path
217 * @param type type of the result
218 * @param size number of bytes in data
219 * @param data pointer to the result data
222 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
223 const struct GNUNET_HashCode * key,
224 const struct GNUNET_PeerIdentity *get_path,
225 unsigned int get_path_length,
226 const struct GNUNET_PeerIdentity *put_path,
227 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
228 size_t size, const void *data)
230 struct GMD_search_handle *h = cls;
231 struct MeshPeerPath *p;
233 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got results!\n");
234 p = path_build_from_dht (get_path, get_path_length,
235 put_path, put_path_length);
236 h->callback (h->cls, p);
243 * Periodically announce self id in the DHT
246 * @param tc task context
249 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
252 struct GNUNET_HashCode phash;
254 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
256 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
260 * - Set data expiration in function of X
263 DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (id));
266 GNUNET_CRYPTO_hash (full_id, sizeof (struct GNUNET_PeerIdentity), &phash);
267 GNUNET_DHT_put (dht_handle, /* DHT handle */
268 &phash, /* Key to use */
269 dht_replication_level, /* Replication level */
270 GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
271 GNUNET_BLOCK_TYPE_MESH_PEER, /* Block type */
272 sizeof (block), /* Size of the data */
273 (const char *) &block, /* Data itself */
274 GNUNET_TIME_UNIT_FOREVER_ABS, /* Data expiration */
275 GNUNET_TIME_UNIT_FOREVER_REL, /* Retry time */
276 NULL, /* Continuation */
277 NULL); /* Continuation closure */
279 GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
283 /******************************************************************************/
284 /******************************** API ***********************************/
285 /******************************************************************************/
288 * Initialize the DHT subsystem.
290 * @param c Configuration.
291 * @param peer_id Local peer ID (must remain valid during all execution time).
294 GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
295 struct GNUNET_PeerIdentity *peer_id)
299 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
300 &dht_replication_level))
302 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
303 "MESH", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
304 dht_replication_level = 3;
308 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
311 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
312 "MESH", "ID_ANNOUNCE_TIME", "MISSING");
313 GNUNET_SCHEDULER_shutdown ();
317 dht_handle = GNUNET_DHT_connect (c, 64);
318 if (NULL == dht_handle)
323 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
328 * Shut down the DHT subsystem.
333 if (dht_handle != NULL)
335 GNUNET_DHT_disconnect (dht_handle);
338 if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
340 GNUNET_SCHEDULER_cancel (announce_id_task);
341 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
345 struct GMD_search_handle *
346 GMD_search (const struct GNUNET_PeerIdentity *peer_id,
347 GMD_search_callback callback, void *cls)
349 struct GNUNET_HashCode phash;
350 struct GMD_search_handle *h;
352 LOG (GNUNET_ERROR_TYPE_DEBUG,
353 " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
354 GNUNET_CRYPTO_hash (peer_id, sizeof (struct GNUNET_PeerIdentity), &phash);
355 h = GNUNET_new (struct GMD_search_handle);
357 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
358 GNUNET_BLOCK_TYPE_MESH_PEER, /* type */
359 &phash, /* key to search */
360 dht_replication_level, /* replication level */
361 GNUNET_DHT_RO_RECORD_ROUTE |
362 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
365 &dht_get_id_handler, h);
370 GMD_search_stop (struct GMD_search_handle *h)
372 GNUNET_DHT_get_stop (h->dhtget);