Update plibc header
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_dht.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21
22 #include "platform.h"
23 #include "gnunet_util_lib.h"
24
25 #include "gnunet_dht_service.h"
26
27 #include "mesh_path.h"
28 #include "gnunet-service-mesh_dht.h"
29 #include "gnunet-service-mesh_peer.h"
30
31 #define MESH_DEBUG_DHT          GNUNET_NO
32
33 #if MESH_DEBUG_DHT
34 #define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
35 #else
36 #define DEBUG_DHT(...)
37 #endif
38
39 #define LOG (level, ...) GNUNET_log_from ("mesh-dht", level, __VA_ARGS__)
40
41
42
43 /**
44  * Callback called on each path found over the DHT.
45  *
46  * @param cls Closure.
47  * @param path An unchecked, unoptimized path to the target node.
48  *             After callback will no longer be valid!
49  */
50 typedef void (*GMD_search_callback) (void *cls,
51                                      const struct MeshPeerPath *path);
52
53 /******************************************************************************/
54 /********************************   STRUCTS  **********************************/
55 /******************************************************************************/
56
57 /**
58  * Handle for DHT searches.
59  */
60 struct GMD_search_handle
61 {
62   /** DHT_GET handle. */
63   struct GNUNET_DHT_GetHandle *dhtget;
64
65   /** Provided callback to call when a path is found. */
66   GMD_search_callback callback;
67
68   /** Provided closure. */
69   void *cls;
70 };
71
72
73 /******************************************************************************/
74 /*******************************   GLOBALS  ***********************************/
75 /******************************************************************************/
76
77 /**
78  * Handle to use DHT.
79  */
80 static struct GNUNET_DHT_Handle *dht_handle;
81
82 /**
83  * How often to PUT own ID in the DHT.
84  */
85 static struct GNUNET_TIME_Relative id_announce_time;
86
87 /**
88  * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
89  */
90 static unsigned long long dht_replication_level;
91
92 /**
93  * Task to periodically announce itself in the network.
94  */
95 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
96
97 /**
98  * Own ID (short value).
99  */
100 static GNUNET_PEER_Id short_id;
101
102 /**
103  * Own ID (full value).
104  */
105 static struct GNUNET_PeerIdentity *full_id;
106
107 /**
108  * Own private key.
109  */
110 static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
111
112
113 /******************************************************************************/
114 /********************************   STATIC  ***********************************/
115 /******************************************************************************/
116
117
118 /**
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.
121  *
122  * @return Newly allocated and created path
123  */
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)
129 {
130   struct MeshPeerPath *p;
131   GNUNET_PEER_Id id;
132   int i;
133
134   p = path_new (1);
135   p->peers[0] = myid;
136   GNUNET_PEER_change_rc (myid, 1);
137   i = get_path_length;
138   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", i);
139   for (i--; i >= 0; i--)
140   {
141     id = GNUNET_PEER_intern (&get_path[i]);
142     if (p->length > 0 && id == p->peers[p->length - 1])
143     {
144       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
145       GNUNET_PEER_change_rc (id, -1);
146     }
147     else
148     {
149       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from GET: %s.\n",
150                   GNUNET_i2s (&get_path[i]));
151       p->length++;
152       p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
153       p->peers[p->length - 1] = id;
154     }
155   }
156   i = put_path_length;
157   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   PUT has %d hops.\n", i);
158   for (i--; i >= 0; i--)
159   {
160     id = GNUNET_PEER_intern (&put_path[i]);
161     if (id == myid)
162     {
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.
165        */
166       path_destroy (p);
167       p = path_new (0);
168     }
169     if (p->length > 0 && id == p->peers[p->length - 1])
170     {
171       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
172       GNUNET_PEER_change_rc (id, -1);
173     }
174     else
175     {
176       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from PUT: %s.\n",
177                   GNUNET_i2s (&put_path[i]));
178       p->length++;
179       p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
180       p->peers[p->length - 1] = id;
181     }
182   }
183 #if MESH_DEBUG
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",
191               p->length);
192   for (i = 0; i < p->length; i++)
193   {
194     struct GNUNET_PeerIdentity peer_id;
195
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));
199   }
200 #endif
201   return p;
202 }
203
204
205 /**
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.
209  *
210  * @param cls closure
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
220  */
221 static void
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)
229 {
230   struct GMD_search_handle *h = cls;
231   struct MeshPeerPath *p;
232
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);
237   path_destroy (p);
238   return;
239 }
240
241
242 /**
243  * Periodically announce self id in the DHT
244  *
245  * @param cls closure
246  * @param tc task context
247  */
248 static void
249 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
250 {
251   struct PBlock block;
252   struct GNUNET_HashCode phash;
253
254   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
255   {
256     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
257     return;
258   }
259   /* TODO
260    * - Set data expiration in function of X
261    * - Adapt X to churn
262    */
263   DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (id));
264
265   block.id = *full_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 */
278   announce_id_task =
279       GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
280 }
281
282
283 /******************************************************************************/
284 /********************************    API    ***********************************/
285 /******************************************************************************/
286
287 /**
288  * Initialize the DHT subsystem.
289  *
290  * @param c Configuration.
291  * @param peer_id Local peer ID (must remain valid during all execution time).
292  */
293 void
294 GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
295           struct GNUNET_PeerIdentity *peer_id)
296 {
297   full_id = peer_id;
298   if (GNUNET_OK !=
299       GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
300                                              &dht_replication_level))
301   {
302     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
303                                "MESH", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
304     dht_replication_level = 3;
305   }
306
307   if (GNUNET_OK !=
308       GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
309                                            &id_announce_time))
310   {
311     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
312                                "MESH", "ID_ANNOUNCE_TIME", "MISSING");
313     GNUNET_SCHEDULER_shutdown ();
314     return;
315   }
316
317   dht_handle = GNUNET_DHT_connect (c, 64);
318   if (NULL == dht_handle)
319   {
320     GNUNET_break (0);
321   }
322
323   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
324 }
325
326
327 /**
328  * Shut down the DHT subsystem.
329  */
330 void
331 GMD_shutdown(void )
332 {
333   if (dht_handle != NULL)
334   {
335     GNUNET_DHT_disconnect (dht_handle);
336     dht_handle = NULL;
337   }
338   if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
339   {
340     GNUNET_SCHEDULER_cancel (announce_id_task);
341     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
342   }
343 }
344
345 struct GMD_search_handle *
346 GMD_search (const struct GNUNET_PeerIdentity *peer_id,
347             GMD_search_callback callback, void *cls)
348 {
349   struct GNUNET_HashCode phash;
350   struct GMD_search_handle *h;
351
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);
356   h->cls = cls;
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,
363                                     NULL,       /* xquery */
364                                     0,     /* xquery bits */
365                                     &dht_get_id_handler, h);
366   return h;
367 }
368
369 void
370 GMD_search_stop (struct GMD_search_handle *h)
371 {
372   GNUNET_DHT_get_stop (h->dhtget);
373   GNUNET_free (h);
374 }