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