starting re-implementation of CADET service
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_dht.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2017 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  * @file cadet/gnunet-service-cadet-new_dht.c
22  * @brief Information we track per peer.
23  * @author Bartlomiej Polot
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dht_service.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet-service-cadet-new.h"
32 #include "gnunet-service-cadet-new_dht.h"
33 #include "gnunet-service-cadet-new_hello.h"
34 #include "gnunet-service-cadet-new_peer.h"
35 #include "gnunet-service-cadet-new_paths.h"
36
37 #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
38
39
40 /**
41  * Handle for DHT searches.
42  */
43 struct GCD_search_handle
44 {
45   /**
46    * DHT_GET handle.
47    */
48   struct GNUNET_DHT_GetHandle *dhtget;
49
50   /**
51    * Provided callback to call when a path is found.
52    */
53   GCD_search_callback callback;
54
55   /**
56    * Provided closure.
57    */
58   void *cls;
59
60 };
61
62
63 /**
64  * Handle to use DHT.
65  */
66 static struct GNUNET_DHT_Handle *dht_handle;
67
68 /**
69  * How often to PUT own ID in the DHT.
70  */
71 static struct GNUNET_TIME_Relative id_announce_time;
72
73 /**
74  * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
75  */
76 static unsigned long long dht_replication_level;
77
78 /**
79  * Task to periodically announce itself in the network.
80  */
81 static struct GNUNET_SCHEDULER_Task *announce_id_task;
82
83 /**
84  * Delay for the next ID announce.
85  */
86 static struct GNUNET_TIME_Relative announce_delay;
87
88
89
90 /**
91  * Function to process paths received for a new peer addition. The recorded
92  * paths form the initial tunnel, which can be optimized later.
93  * Called on each result obtained for the DHT search.
94  *
95  * @param cls closure
96  * @param exp when will this value expire
97  * @param key key of the result
98  * @param get_path path of the get request
99  * @param get_path_length lenght of @a get_path
100  * @param put_path path of the put request
101  * @param put_path_length length of the @a put_path
102  * @param type type of the result
103  * @param size number of bytes in data
104  * @param data pointer to the result data
105  */
106 static void
107 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
108                     const struct GNUNET_HashCode *key,
109                     const struct GNUNET_PeerIdentity *get_path,
110                     unsigned int get_path_length,
111                     const struct GNUNET_PeerIdentity *put_path,
112                     unsigned int put_path_length,
113                     enum GNUNET_BLOCK_Type type,
114                     size_t size,
115                     const void *data)
116 {
117   struct GCD_search_handle *h = cls;
118   const struct GNUNET_HELLO_Message *hello = data;
119   struct CadetPeerPath *p;
120   struct CadetPeer *peer;
121
122   p = GCPP_path_from_dht (get_path,
123                           get_path_length,
124                           put_path,
125                           put_path_length);
126   h->callback (h->cls, p);
127   GCPP_path_destroy (p);
128
129   if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
130        (ntohs (hello->header.size) == size) &&
131        (size == GNUNET_HELLO_size (hello)) )
132   {
133     peer = GCP_get (&put_path[0],
134                     GNUNET_YES);
135     LOG (GNUNET_ERROR_TYPE_DEBUG,
136          "Got HELLO for %s\n",
137          GCP_2s (peer));
138     GCP_set_hello (peer,
139                    hello);
140   }
141 }
142
143
144 /**
145  * Periodically announce self id in the DHT
146  *
147  * @param cls closure
148  */
149 static void
150 announce_id (void *cls)
151 {
152   struct GNUNET_HashCode phash;
153   const struct GNUNET_HELLO_Message *hello;
154   size_t size;
155   struct GNUNET_TIME_Absolute expiration;
156   struct GNUNET_TIME_Relative next_put;
157
158   hello = GCH_get_mine ();
159   size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
160   if (0 == size)
161   {
162     expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
163                                            announce_delay);
164     announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
165   }
166   else
167   {
168     expiration = GNUNET_HELLO_get_last_expiration (hello);
169     announce_delay = GNUNET_TIME_UNIT_SECONDS;
170   }
171
172   /* Call again in id_announce_time, unless HELLO expires first,
173    * but wait at least 1s. */
174   next_put
175     = GNUNET_TIME_absolute_get_remaining (expiration);
176   next_put
177     = GNUNET_TIME_relative_min (next_put,
178                                 id_announce_time);
179   next_put
180     = GNUNET_TIME_relative_max (next_put,
181                                 GNUNET_TIME_UNIT_SECONDS);
182   announce_id_task
183     = GNUNET_SCHEDULER_add_delayed (next_put,
184                                     &announce_id,
185                                     cls);
186   GNUNET_STATISTICS_update (stats,
187                             "# DHT announce",
188                             1,
189                             GNUNET_NO);
190   memset (&phash,
191           0,
192           sizeof (phash));
193   GNUNET_memcpy (&phash,
194                  &my_full_id,
195                  sizeof (my_full_id));
196   LOG (GNUNET_ERROR_TYPE_DEBUG,
197        "Announcing my HELLO (%u bytes) in the DHT\n",
198        size);
199   GNUNET_DHT_put (dht_handle,   /* DHT handle */
200                   &phash,       /* Key to use */
201                   dht_replication_level,     /* Replication level */
202                   GNUNET_DHT_RO_RECORD_ROUTE
203                   | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
204                   GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
205                   size,  /* Size of the data */
206                   (const char *) hello, /* Data itself */
207                   expiration,  /* Data expiration */
208                   NULL,         /* Continuation */
209                   NULL);        /* Continuation closure */
210 }
211
212
213 /**
214  * Initialize the DHT subsystem.
215  *
216  * @param c Configuration.
217  */
218 void
219 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
220 {
221   LOG (GNUNET_ERROR_TYPE_DEBUG,
222        "init\n");
223   if (GNUNET_OK !=
224       GNUNET_CONFIGURATION_get_value_number (c,
225                                              "CADET",
226                                              "DHT_REPLICATION_LEVEL",
227                                              &dht_replication_level))
228   {
229     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
230                                "CADET",
231                                "DHT_REPLICATION_LEVEL",
232                                "USING DEFAULT");
233     dht_replication_level = 3;
234   }
235
236   if (GNUNET_OK !=
237       GNUNET_CONFIGURATION_get_value_time (c,
238                                            "CADET",
239                                            "ID_ANNOUNCE_TIME",
240                                            &id_announce_time))
241   {
242     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
243                                "CADET",
244                                "ID_ANNOUNCE_TIME",
245                                "MISSING");
246     GNUNET_SCHEDULER_shutdown ();
247     return;
248   }
249
250   dht_handle = GNUNET_DHT_connect (c,
251                                    64);
252   GNUNET_break (NULL != dht_handle);
253   announce_delay = GNUNET_TIME_UNIT_SECONDS;
254   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id,
255                                                NULL);
256 }
257
258
259 /**
260  * Shut down the DHT subsystem.
261  */
262 void
263 GCD_shutdown (void)
264 {
265   if (NULL != dht_handle)
266   {
267     GNUNET_DHT_disconnect (dht_handle);
268     dht_handle = NULL;
269   }
270   if (NULL != announce_id_task)
271   {
272     GNUNET_SCHEDULER_cancel (announce_id_task);
273     announce_id_task = NULL;
274   }
275 }
276
277
278 /**
279  * Search DHT for paths to @a peeR_id
280  *
281  * @param peer_id peer to search for
282  * @param callback function to call with results
283  * @param callback_cls closure for @a callback
284  * @return handle to abort search
285  */
286 struct GCD_search_handle *
287 GCD_search (const struct GNUNET_PeerIdentity *peer_id,
288             GCD_search_callback callback,
289             void *callback_cls)
290 {
291   struct GNUNET_HashCode phash;
292   struct GCD_search_handle *h;
293
294   LOG (GNUNET_ERROR_TYPE_DEBUG,
295        "Starting DHT GET for peer %s\n",
296        GNUNET_i2s (peer_id));
297   GNUNET_STATISTICS_update (stats,
298                             "# DHT search",
299                             1,
300                             GNUNET_NO);
301   memset (&phash,
302           0,
303           sizeof (phash));
304   GNUNET_memcpy (&phash,
305                  peer_id,
306                  sizeof (*peer_id));
307
308   h = GNUNET_new (struct GCD_search_handle);
309   h->callback = callback;
310   h->cls = callback_cls;
311   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
312                                     GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
313                                     &phash,     /* key to search */
314                                     dht_replication_level, /* replication level */
315                                     GNUNET_DHT_RO_RECORD_ROUTE |
316                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
317                                     NULL,       /* xquery */
318                                     0,     /* xquery bits */
319                                     &dht_get_id_handler,
320                                     h);
321   return h;
322 }
323
324
325 /**
326  * Stop DHT search started with #GCD_search().
327  *
328  * @param h handle to search to stop
329  */
330 void
331 GCD_search_stop (struct GCD_search_handle *h)
332 {
333   GNUNET_DHT_get_stop (h->dhtget);
334   GNUNET_free (h);
335 }
336
337 /* end of gnunet-service-cadet_dht.c */