- fix main mesh file
[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 /********************************   STRUCTS  **********************************/
44 /******************************************************************************/
45
46 /**
47  * Handle for DHT searches.
48  */
49 struct GMD_search_handle
50 {
51   /** DHT_GET handle. */
52   struct GNUNET_DHT_GetHandle *dhtget;
53
54   /** Provided callback to call when a path is found. */
55   GMD_search_callback callback;
56
57   /** Provided closure. */
58   void *cls;
59 };
60
61
62 /******************************************************************************/
63 /*******************************   GLOBALS  ***********************************/
64 /******************************************************************************/
65
66 /**
67  * Handle to use DHT.
68  */
69 static struct GNUNET_DHT_Handle *dht_handle;
70
71 /**
72  * How often to PUT own ID in the DHT.
73  */
74 static struct GNUNET_TIME_Relative id_announce_time;
75
76 /**
77  * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
78  */
79 static unsigned long long dht_replication_level;
80
81 /**
82  * Task to periodically announce itself in the network.
83  */
84 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
85
86 /**
87  * Own ID (short value).
88  */
89 static GNUNET_PEER_Id short_id;
90
91 /**
92  * Own ID (full value).
93  */
94 static struct GNUNET_PeerIdentity *full_id;
95
96 /**
97  * Own private key.
98  */
99 static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
100
101
102 /******************************************************************************/
103 /********************************   STATIC  ***********************************/
104 /******************************************************************************/
105
106
107 /**
108  * Build a PeerPath from the paths returned from the DHT, reversing the paths
109  * to obtain a local peer -> destination path and interning the peer ids.
110  *
111  * @return Newly allocated and created path
112  */
113 static struct MeshPeerPath *
114 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
115                      unsigned int get_path_length,
116                      const struct GNUNET_PeerIdentity *put_path,
117                      unsigned int put_path_length)
118 {
119   struct MeshPeerPath *p;
120   GNUNET_PEER_Id id;
121   int i;
122
123   p = path_new (1);
124   p->peers[0] = myid;
125   GNUNET_PEER_change_rc (myid, 1);
126   i = get_path_length;
127   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", i);
128   for (i--; i >= 0; i--)
129   {
130     id = GNUNET_PEER_intern (&get_path[i]);
131     if (p->length > 0 && id == p->peers[p->length - 1])
132     {
133       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
134       GNUNET_PEER_change_rc (id, -1);
135     }
136     else
137     {
138       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from GET: %s.\n",
139                   GNUNET_i2s (&get_path[i]));
140       p->length++;
141       p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
142       p->peers[p->length - 1] = id;
143     }
144   }
145   i = put_path_length;
146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   PUT has %d hops.\n", i);
147   for (i--; i >= 0; i--)
148   {
149     id = GNUNET_PEER_intern (&put_path[i]);
150     if (id == myid)
151     {
152       /* PUT path went through us, so discard the path up until now and start
153        * from here to get a much shorter (and loop-free) path.
154        */
155       path_destroy (p);
156       p = path_new (0);
157     }
158     if (p->length > 0 && id == p->peers[p->length - 1])
159     {
160       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
161       GNUNET_PEER_change_rc (id, -1);
162     }
163     else
164     {
165       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from PUT: %s.\n",
166                   GNUNET_i2s (&put_path[i]));
167       p->length++;
168       p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
169       p->peers[p->length - 1] = id;
170     }
171   }
172 #if MESH_DEBUG
173   if (get_path_length > 0)
174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   (first of GET: %s)\n",
175                 GNUNET_i2s (&get_path[0]));
176   if (put_path_length > 0)
177     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   (first of PUT: %s)\n",
178                 GNUNET_i2s (&put_path[0]));
179   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   In total: %d hops\n",
180               p->length);
181   for (i = 0; i < p->length; i++)
182   {
183     struct GNUNET_PeerIdentity peer_id;
184
185     GNUNET_PEER_resolve (p->peers[i], &peer_id);
186     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "       %u: %s\n", p->peers[i],
187                 GNUNET_i2s (&peer_id));
188   }
189 #endif
190   return p;
191 }
192
193
194 /**
195  * Function to process paths received for a new peer addition. The recorded
196  * paths form the initial tunnel, which can be optimized later.
197  * Called on each result obtained for the DHT search.
198  *
199  * @param cls closure
200  * @param exp when will this value expire
201  * @param key key of the result
202  * @param get_path path of the get request
203  * @param get_path_length lenght of get_path
204  * @param put_path path of the put request
205  * @param put_path_length length of the put_path
206  * @param type type of the result
207  * @param size number of bytes in data
208  * @param data pointer to the result data
209  */
210 static void
211 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
212                     const struct GNUNET_HashCode * key,
213                     const struct GNUNET_PeerIdentity *get_path,
214                     unsigned int get_path_length,
215                     const struct GNUNET_PeerIdentity *put_path,
216                     unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
217                     size_t size, const void *data)
218 {
219   struct GMD_search_handle *h = cls;
220   struct MeshPeerPath *p;
221
222   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got results!\n");
223   p = path_build_from_dht (get_path, get_path_length,
224                            put_path, put_path_length);
225   h->callback (h->cls, p);
226   path_destroy (p);
227   return;
228 }
229
230
231 /**
232  * Periodically announce self id in the DHT
233  *
234  * @param cls closure
235  * @param tc task context
236  */
237 static void
238 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
239 {
240   struct PBlock block;
241   struct GNUNET_HashCode phash;
242
243   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
244   {
245     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
246     return;
247   }
248   /* TODO
249    * - Set data expiration in function of X
250    * - Adapt X to churn
251    */
252   DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (id));
253
254   block.id = *full_id;
255   GNUNET_CRYPTO_hash (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 */
267   announce_id_task =
268       GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
269 }
270
271
272 /******************************************************************************/
273 /********************************    API    ***********************************/
274 /******************************************************************************/
275
276 /**
277  * Initialize the DHT subsystem.
278  *
279  * @param c Configuration.
280  * @param peer_id Local peer ID (must remain valid during all execution time).
281  */
282 void
283 GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
284           struct GNUNET_PeerIdentity *peer_id)
285 {
286   full_id = peer_id;
287   if (GNUNET_OK !=
288       GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
289                                              &dht_replication_level))
290   {
291     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
292                                "MESH", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
293     dht_replication_level = 3;
294   }
295
296   if (GNUNET_OK !=
297       GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
298                                            &id_announce_time))
299   {
300     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
301                                "MESH", "ID_ANNOUNCE_TIME", "MISSING");
302     GNUNET_SCHEDULER_shutdown ();
303     return;
304   }
305
306   dht_handle = GNUNET_DHT_connect (c, 64);
307   if (NULL == dht_handle)
308   {
309     GNUNET_break (0);
310   }
311
312   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
313 }
314
315
316 /**
317  * Shut down the DHT subsystem.
318  */
319 void
320 GMD_shutdown(void )
321 {
322   if (dht_handle != NULL)
323   {
324     GNUNET_DHT_disconnect (dht_handle);
325     dht_handle = NULL;
326   }
327   if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
328   {
329     GNUNET_SCHEDULER_cancel (announce_id_task);
330     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
331   }
332 }
333
334 struct GMD_search_handle *
335 GMD_search (const struct GNUNET_PeerIdentity *peer_id,
336             GMD_search_callback callback, void *cls)
337 {
338   struct GNUNET_HashCode phash;
339   struct GMD_search_handle *h;
340
341   LOG (GNUNET_ERROR_TYPE_DEBUG,
342        "  Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
343   GNUNET_CRYPTO_hash (peer_id, sizeof (struct GNUNET_PeerIdentity), &phash);
344   h = GNUNET_new (struct GMD_search_handle);
345   h->cls = cls;
346   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
347                                     GNUNET_BLOCK_TYPE_MESH_PEER, /* type */
348                                     &phash,     /* key to search */
349                                     dht_replication_level, /* replication level */
350                                     GNUNET_DHT_RO_RECORD_ROUTE |
351                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
352                                     NULL,       /* xquery */
353                                     0,     /* xquery bits */
354                                     &dht_get_id_handler, h);
355   return h;
356 }
357
358 void
359 GMD_search_stop (struct GMD_search_handle *h)
360 {
361   GNUNET_DHT_get_stop (h->dhtget);
362   GNUNET_free (h);
363 }