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