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