fixed broken api calls in test; fixed broken protocol
[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 (GNUNET_TIME_UNIT_MILLISECONDS, 500)
44
45 /**
46  * How long do we wait after we get an updated HELLO before publishing?
47  * Allows for the HELLO to be updated again quickly, for example in
48  * case multiple addresses changed and we got a partial update.
49  */
50 #define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
51
52
53 #define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
54
55
56 /**
57  * Handle for DHT searches.
58  */
59 struct GCD_search_handle
60 {
61   /**
62    * DHT_GET handle.
63    */
64   struct GNUNET_DHT_GetHandle *dhtget;
65
66 };
67
68
69 /**
70  * Handle to use DHT.
71  */
72 static struct GNUNET_DHT_Handle *dht_handle;
73
74 /**
75  * How often to PUT own ID in the DHT.
76  */
77 static struct GNUNET_TIME_Relative id_announce_time;
78
79 /**
80  * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
81  */
82 static unsigned long long dht_replication_level;
83
84 /**
85  * Task to periodically announce itself in the network.
86  */
87 static struct GNUNET_SCHEDULER_Task *announce_id_task;
88
89 /**
90  * Delay for the next ID announce.
91  */
92 static struct GNUNET_TIME_Relative announce_delay;
93
94
95 /**
96  * Function to process paths received for a new peer addition. The recorded
97  * paths form the initial tunnel, which can be optimized later.
98  * Called on each result obtained for the DHT search.
99  *
100  * @param cls closure
101  * @param exp when will this value expire
102  * @param key key of the result
103  * @param get_path path of the get request
104  * @param get_path_length lenght of @a get_path
105  * @param put_path path of the put request
106  * @param put_path_length length of the @a put_path
107  * @param type type of the result
108  * @param size number of bytes in data
109  * @param data pointer to the result data
110  */
111 static void
112 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
113                     const struct GNUNET_HashCode *key,
114                     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                     enum GNUNET_BLOCK_Type type,
119                     size_t size,
120                     const void *data)
121 {
122   const struct GNUNET_HELLO_Message *hello = data;
123   struct CadetPeer *peer;
124
125   GCPP_try_path_from_dht (get_path,
126                           get_path_length,
127                           put_path,
128                           put_path_length);
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  * Function called by the HELLO subsystem whenever OUR hello
215  * changes. Re-triggers the DHT PUT immediately.
216  */
217 void
218 GCD_hello_update ()
219 {
220   if (NULL == announce_id_task)
221     return; /* too early */
222   GNUNET_SCHEDULER_cancel (announce_id_task);
223   announce_id_task
224     = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
225                                     &announce_id,
226                                     NULL);
227 }
228
229
230 /**
231  * Initialize the DHT subsystem.
232  *
233  * @param c Configuration.
234  */
235 void
236 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
237 {
238   if (GNUNET_OK !=
239       GNUNET_CONFIGURATION_get_value_number (c,
240                                              "CADET",
241                                              "DHT_REPLICATION_LEVEL",
242                                              &dht_replication_level))
243   {
244     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
245                                "CADET",
246                                "DHT_REPLICATION_LEVEL",
247                                "USING DEFAULT");
248     dht_replication_level = 3;
249   }
250
251   if (GNUNET_OK !=
252       GNUNET_CONFIGURATION_get_value_time (c,
253                                            "CADET",
254                                            "ID_ANNOUNCE_TIME",
255                                            &id_announce_time))
256   {
257     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
258                                "CADET",
259                                "ID_ANNOUNCE_TIME",
260                                "MISSING");
261     GNUNET_SCHEDULER_shutdown ();
262     return;
263   }
264
265   dht_handle = GNUNET_DHT_connect (c,
266                                    64);
267   GNUNET_break (NULL != dht_handle);
268   announce_delay = GNUNET_TIME_UNIT_SECONDS;
269   announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
270                                                    &announce_id,
271                                                    NULL);
272 }
273
274
275 /**
276  * Shut down the DHT subsystem.
277  */
278 void
279 GCD_shutdown (void)
280 {
281   if (NULL != dht_handle)
282   {
283     GNUNET_DHT_disconnect (dht_handle);
284     dht_handle = NULL;
285   }
286   if (NULL != announce_id_task)
287   {
288     GNUNET_SCHEDULER_cancel (announce_id_task);
289     announce_id_task = NULL;
290   }
291 }
292
293
294 /**
295  * Search DHT for paths to @a peeR_id
296  *
297  * @param peer_id peer to search for
298  * @return handle to abort search
299  */
300 struct GCD_search_handle *
301 GCD_search (const struct GNUNET_PeerIdentity *peer_id)
302 {
303   struct GNUNET_HashCode phash;
304   struct GCD_search_handle *h;
305
306   GNUNET_STATISTICS_update (stats,
307                             "# DHT search",
308                             1,
309                             GNUNET_NO);
310   memset (&phash,
311           0,
312           sizeof (phash));
313   GNUNET_memcpy (&phash,
314                  peer_id,
315                  sizeof (*peer_id));
316
317   h = GNUNET_new (struct GCD_search_handle);
318   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
319                                     GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
320                                     &phash,     /* key to search */
321                                     dht_replication_level, /* replication level */
322                                     GNUNET_DHT_RO_RECORD_ROUTE |
323                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
324                                     NULL,       /* xquery */
325                                     0,     /* xquery bits */
326                                     &dht_get_id_handler,
327                                     h);
328   LOG (GNUNET_ERROR_TYPE_DEBUG,
329        "Starting DHT GET for peer %s (%p)\n",
330        GNUNET_i2s (peer_id),
331        h);
332   return h;
333 }
334
335
336 /**
337  * Stop DHT search started with #GCD_search().
338  *
339  * @param h handle to search to stop
340  */
341 void
342 GCD_search_stop (struct GCD_search_handle *h)
343 {
344   LOG (GNUNET_ERROR_TYPE_DEBUG,
345        "Stopping DHT GET %p\n",
346        h);
347   GNUNET_DHT_get_stop (h->dhtget);
348   GNUNET_free (h);
349 }
350
351 /* end of gnunet-service-cadet_dht.c */