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 "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
45 /** DHT_GET handle. */
46 struct GNUNET_DHT_GetHandle *dhtget;
48 /** Provided callback to call when a path is found. */
49 GCD_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 * FIXME refactor and use build_path_from_peer_ids
116 static struct CadetPeerPath *
117 path_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)
122 size_t size = get_path_length + put_path_length;
123 struct GNUNET_PeerIdentity peers[size];
124 const struct GNUNET_PeerIdentity *peer;
125 struct CadetPeerPath *p;
126 unsigned int own_pos;
129 LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length);
130 for (i = 0 ; i < get_path_length; i++)
132 peer = &get_path[get_path_length - i - 1];
133 LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer));
136 for (i = 0 ; i < put_path_length; i++)
138 peer = &put_path[put_path_length - i - 1];
139 LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer));
140 peers[i + get_path_length] = *peer;
142 p = path_build_from_peer_ids (peers, size, myid, &own_pos);
148 * Function to process paths received for a new peer addition. The recorded
149 * paths form the initial tunnel, which can be optimized later.
150 * Called on each result obtained for the DHT search.
153 * @param exp when will this value expire
154 * @param key key of the result
155 * @param get_path path of the get request
156 * @param get_path_length lenght of get_path
157 * @param put_path path of the put request
158 * @param put_path_length length of the put_path
159 * @param type type of the result
160 * @param size number of bytes in data
161 * @param data pointer to the result data
164 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
165 const struct GNUNET_HashCode * key,
166 const struct GNUNET_PeerIdentity *get_path,
167 unsigned int get_path_length,
168 const struct GNUNET_PeerIdentity *put_path,
169 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
170 size_t size, const void *data)
172 struct GCD_search_handle *h = cls;
173 struct GNUNET_HELLO_Message *hello;
174 struct CadetPeerPath *p;
175 struct CadetPeer *peer;
178 p = path_build_from_dht (get_path, get_path_length,
179 put_path, put_path_length);
181 LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
182 GNUNET_free_non_null (s);
183 peer = GCP_get_short (p->peers[p->length - 1]);
184 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GCP_2s (peer));
185 h->callback (h->cls, p);
187 hello = (struct GNUNET_HELLO_Message *) data;
188 GCP_set_hello (peer, hello);
189 GCP_try_connect (peer);
195 * Periodically announce self id in the DHT
198 * @param tc task context
201 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
203 struct GNUNET_HashCode phash;
204 const struct GNUNET_HELLO_Message *hello;
206 struct GNUNET_TIME_Absolute expiration;
207 struct GNUNET_TIME_Relative retry_time;
209 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
211 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
214 LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
217 * - Set data expiration in function of X
220 hello = GCH_get_mine ();
221 if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
223 /* Peerinfo gave us no hello yet, try again in a second. */
224 announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
226 LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n");
229 expiration = GNUNET_HELLO_get_last_expiration (hello);
230 retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
232 LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
233 memset (&phash, 0, sizeof (phash));
234 memcpy (&phash, &my_full_id, sizeof (my_full_id));
235 GNUNET_DHT_put (dht_handle, /* DHT handle */
236 &phash, /* Key to use */
237 dht_replication_level, /* Replication level */
238 GNUNET_DHT_RO_RECORD_ROUTE
239 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
240 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
241 size, /* Size of the data */
242 (const char *) hello, /* Data itself */
243 expiration, /* Data expiration */
244 retry_time, /* Retry time */
245 NULL, /* Continuation */
246 NULL); /* Continuation closure */
248 GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
252 * Iterator over hash map entries and stop GET requests before disconnecting
255 * @param cls Closure (unused)
256 * @param key Current peer ID.
257 * @param value Value in the hash map (GCD_search_handle).
259 * @return #GNUNET_YES, we should continue to iterate,
266 struct GCD_search_handle *h = value;
273 /******************************************************************************/
274 /******************************** API ***********************************/
275 /******************************************************************************/
278 * Initialize the DHT subsystem.
280 * @param c Configuration.
283 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
285 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
287 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DHT_REPLICATION_LEVEL",
288 &dht_replication_level))
290 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
291 "CADET", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
292 dht_replication_level = 3;
296 GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
299 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
300 "CADET", "ID_ANNOUNCE_TIME", "MISSING");
301 GNUNET_SCHEDULER_shutdown ();
305 dht_handle = GNUNET_DHT_connect (c, 64);
306 if (NULL == dht_handle)
311 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
312 get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
317 * Shut down the DHT subsystem.
322 GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
323 GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
324 if (dht_handle != NULL)
326 GNUNET_DHT_disconnect (dht_handle);
329 if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
331 GNUNET_SCHEDULER_cancel (announce_id_task);
332 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
336 struct GCD_search_handle *
337 GCD_search (const struct GNUNET_PeerIdentity *peer_id,
338 GCD_search_callback callback, void *cls)
340 struct GNUNET_HashCode phash;
341 struct GCD_search_handle *h;
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
345 memset (&phash, 0, sizeof (phash));
346 memcpy (&phash, peer_id, sizeof (*peer_id));
347 h = GNUNET_new (struct GCD_search_handle);
348 h->peer_id = GNUNET_PEER_intern (peer_id);
349 h->callback = callback;
351 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
352 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
353 &phash, /* key to search */
354 dht_replication_level, /* replication level */
355 GNUNET_DHT_RO_RECORD_ROUTE |
356 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
359 &dht_get_id_handler, h);
360 GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
361 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
366 GCD_search_stop (struct GCD_search_handle *h)
368 GNUNET_break (GNUNET_OK ==
369 GNUNET_CONTAINER_multihashmap32_remove (get_requests,
371 GNUNET_DHT_get_stop (h->dhtget);