9b11ebf181c88df46592d8f3d9514a491533b4b7
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_dht.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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  */
43 struct GCD_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   GCD_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  */
66 extern struct GNUNET_STATISTICS_Handle *stats;
67
68 /**
69  * Own ID (short value).
70  */
71 extern GNUNET_PEER_Id myid;
72
73 /**
74  * Own ID (full value).
75  */
76 extern struct GNUNET_PeerIdentity my_full_id;
77
78 /**
79  * Handle to use DHT.
80  */
81 static struct GNUNET_DHT_Handle *dht_handle;
82
83 /**
84  * How often to PUT own ID in the DHT.
85  */
86 static struct GNUNET_TIME_Relative id_announce_time;
87
88 /**
89  * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
90  */
91 static unsigned long long dht_replication_level;
92
93 /**
94  * Task to periodically announce itself in the network.
95  */
96 static struct GNUNET_SCHEDULER_Task * announce_id_task;
97
98 /**
99  * Delay for the next ID announce.
100  */
101 static struct GNUNET_TIME_Relative announce_delay;
102
103 /**
104  * GET requests to stop on shutdown.
105  */
106 static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
107
108 /******************************************************************************/
109 /********************************   STATIC  ***********************************/
110 /******************************************************************************/
111
112
113 /**
114  * Build a PeerPath from the paths returned from the DHT, reversing the paths
115  * to obtain a local peer -> destination path and interning the peer ids.
116  *
117  * @return Newly allocated and created path
118  *
119  * FIXME refactor and use build_path_from_peer_ids
120  */
121 static struct CadetPeerPath *
122 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
123                      unsigned int get_path_length,
124                      const struct GNUNET_PeerIdentity *put_path,
125                      unsigned int put_path_length)
126 {
127   size_t size = get_path_length + put_path_length + 1;
128   struct GNUNET_PeerIdentity peers[size];
129   const struct GNUNET_PeerIdentity *peer;
130   struct CadetPeerPath *p;
131   unsigned int own_pos;
132   int i;
133
134   peers[0] = my_full_id;
135   LOG (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", get_path_length);
136   for (i = 0 ; i < get_path_length; i++)
137   {
138     peer = &get_path[get_path_length - i - 1];
139     LOG (GNUNET_ERROR_TYPE_DEBUG, "   From GET: %s\n", GNUNET_i2s (peer));
140     peers[i + 1] = *peer;
141   }
142   for (i = 0 ; i < put_path_length; i++)
143   {
144     peer = &put_path[put_path_length - i - 1];
145     LOG (GNUNET_ERROR_TYPE_DEBUG, "   From PUT: %s\n", GNUNET_i2s (peer));
146     peers[i + get_path_length + 1] = *peer;
147   }
148   p = path_build_from_peer_ids (peers, size, myid, &own_pos);
149   return p;
150 }
151
152
153 /**
154  * Function to process paths received for a new peer addition. The recorded
155  * paths form the initial tunnel, which can be optimized later.
156  * Called on each result obtained for the DHT search.
157  *
158  * @param cls closure
159  * @param exp when will this value expire
160  * @param key key of the result
161  * @param get_path path of the get request
162  * @param get_path_length lenght of @a get_path
163  * @param put_path path of the put request
164  * @param put_path_length length of the @a put_path
165  * @param type type of the result
166  * @param size number of bytes in data
167  * @param data pointer to the result data
168  */
169 static void
170 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
171                     const struct GNUNET_HashCode * key,
172                     const struct GNUNET_PeerIdentity *get_path,
173                     unsigned int get_path_length,
174                     const struct GNUNET_PeerIdentity *put_path,
175                     unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
176                     size_t size, const void *data)
177 {
178   struct GCD_search_handle *h = cls;
179   struct GNUNET_HELLO_Message *hello;
180   struct CadetPeerPath *p;
181   struct CadetPeer *peer;
182   char *s;
183
184   p = path_build_from_dht (get_path, get_path_length,
185                            put_path, put_path_length);
186   if (NULL == p)
187   {
188     GNUNET_break_op (0);
189     return;
190   }
191
192   s = path_2s (p);
193   LOG (GNUNET_ERROR_TYPE_INFO,
194        "Got path from DHT: %s\n",
195        s);
196   GNUNET_free_non_null (s);
197
198   peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
199   LOG (GNUNET_ERROR_TYPE_DEBUG,
200        "Got HELLO for %s\n",
201        GCP_2s (peer));
202   h->callback (h->cls, p);
203   path_destroy (p);
204   hello = (struct GNUNET_HELLO_Message *) data;
205   GCP_set_hello (peer, hello);
206   GCP_try_connect (peer);
207 }
208
209
210 /**
211  * Periodically announce self id in the DHT
212  *
213  * @param cls closure
214  */
215 static void
216 announce_id (void *cls)
217 {
218   struct GNUNET_HashCode phash;
219   const struct GNUNET_HELLO_Message *hello;
220   size_t size;
221   struct GNUNET_TIME_Absolute expiration;
222   struct GNUNET_TIME_Relative next_put;
223
224   announce_id_task = NULL;
225   LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
226   hello = GCH_get_mine ();
227   size = NULL != hello ? GNUNET_HELLO_size (hello) : 0;
228   if (NULL == hello || 0 == size)
229   {
230     /* Peerinfo gave us no hello yet, try again soon. */
231     LOG (GNUNET_ERROR_TYPE_INFO, "  no hello, waiting!\n");
232     GNUNET_STATISTICS_update (stats, "# DHT announce skipped (no hello)",
233                               1, GNUNET_NO);
234     expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
235                                            announce_delay);
236     announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
237   }
238   else
239   {
240     expiration = GNUNET_HELLO_get_last_expiration (hello);
241     announce_delay = GNUNET_TIME_UNIT_SECONDS;
242   }
243
244   LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
245   GNUNET_STATISTICS_update (stats, "# DHT announce",
246                             1, GNUNET_NO);
247   memset (&phash, 0, sizeof (phash));
248   GNUNET_memcpy (&phash, &my_full_id, sizeof (my_full_id));
249   GNUNET_DHT_put (dht_handle,   /* DHT handle */
250                   &phash,       /* Key to use */
251                   dht_replication_level,     /* Replication level */
252                   GNUNET_DHT_RO_RECORD_ROUTE
253                   | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
254                   GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
255                   size,  /* Size of the data */
256                   (const char *) hello, /* Data itself */
257                   expiration,  /* Data expiration */
258                   NULL,         /* Continuation */
259                   NULL);        /* Continuation closure */
260
261   /* Call again in id_announce_time, unless HELLO expires first,
262    * but wait at least 1s. */
263   next_put = GNUNET_TIME_absolute_get_remaining (expiration);
264   next_put = GNUNET_TIME_relative_min (next_put, id_announce_time);
265   next_put = GNUNET_TIME_relative_max (next_put, GNUNET_TIME_UNIT_SECONDS);
266   announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put, &announce_id, cls);
267 }
268
269 /**
270  * Iterator over hash map entries and stop GET requests before disconnecting
271  * from the DHT.
272  *
273  * @param cls Closure (unused)
274  * @param key Current peer ID.
275  * @param value Value in the hash map (GCD_search_handle).
276  *
277  * @return #GNUNET_YES, we should continue to iterate,
278  */
279 int
280 stop_get (void *cls,
281           uint32_t key,
282           void *value)
283 {
284   struct GCD_search_handle *h = value;
285
286   GCD_search_stop (h);
287   return GNUNET_YES;
288 }
289
290
291 /******************************************************************************/
292 /********************************    API    ***********************************/
293 /******************************************************************************/
294
295 /**
296  * Initialize the DHT subsystem.
297  *
298  * @param c Configuration.
299  */
300 void
301 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
302 {
303   LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
304   if (GNUNET_OK !=
305       GNUNET_CONFIGURATION_get_value_number (c, "CADET",
306                                              "DHT_REPLICATION_LEVEL",
307                                              &dht_replication_level))
308   {
309     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET",
310                                "DHT_REPLICATION_LEVEL", "USING DEFAULT");
311     dht_replication_level = 3;
312   }
313
314   if (GNUNET_OK !=
315       GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
316                                            &id_announce_time))
317   {
318     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET",
319                                "ID_ANNOUNCE_TIME", "MISSING");
320     GNUNET_SCHEDULER_shutdown ();
321     return;
322   }
323
324   dht_handle = GNUNET_DHT_connect (c, 64);
325   if (NULL == dht_handle)
326   {
327     GNUNET_break (0);
328   }
329
330   announce_delay = GNUNET_TIME_UNIT_SECONDS;
331   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
332   get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
333 }
334
335
336 /**
337  * Shut down the DHT subsystem.
338  */
339 void
340 GCD_shutdown (void)
341 {
342   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n");
343   GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
344   GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
345   if (dht_handle != NULL)
346   {
347     GNUNET_DHT_disconnect (dht_handle);
348     dht_handle = NULL;
349   }
350   if (NULL != announce_id_task)
351   {
352     GNUNET_SCHEDULER_cancel (announce_id_task);
353     announce_id_task = NULL;
354   }
355 }
356
357 struct GCD_search_handle *
358 GCD_search (const struct GNUNET_PeerIdentity *peer_id,
359             GCD_search_callback callback, void *cls)
360 {
361   struct GNUNET_HashCode phash;
362   struct GCD_search_handle *h;
363
364   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n",
365        GNUNET_i2s (peer_id));
366   GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO);
367   memset (&phash, 0, sizeof (phash));
368   GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id));
369   h = GNUNET_new (struct GCD_search_handle);
370   h->peer_id = GNUNET_PEER_intern (peer_id);
371   h->callback = callback;
372   h->cls = cls;
373   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
374                                     GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
375                                     &phash,     /* key to search */
376                                     dht_replication_level, /* replication level */
377                                     GNUNET_DHT_RO_RECORD_ROUTE |
378                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
379                                     NULL,       /* xquery */
380                                     0,     /* xquery bits */
381                                     &dht_get_id_handler, h);
382   GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
383                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
384   return h;
385 }
386
387
388 void
389 GCD_search_stop (struct GCD_search_handle *h)
390 {
391   GNUNET_break (GNUNET_OK ==
392                 GNUNET_CONTAINER_multihashmap32_remove (get_requests,
393                                                         h->peer_id, h));
394   GNUNET_DHT_get_stop (h->dhtget);
395   GNUNET_free (h);
396 }