aboutsummaryrefslogtreecommitdiff
path: root/src/service/dht/gnunet-service-dht.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/dht/gnunet-service-dht.c')
-rw-r--r--src/service/dht/gnunet-service-dht.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/src/service/dht/gnunet-service-dht.c b/src/service/dht/gnunet-service-dht.c
new file mode 100644
index 000000000..0689af9aa
--- /dev/null
+++ b/src/service/dht/gnunet-service-dht.c
@@ -0,0 +1,554 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 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/**
22 * @file dht/gnunet-service-dht.c
23 * @brief GNUnet DHT service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "gnunet_common.h"
28#include "platform.h"
29#include "gnunet_block_lib.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_uri_lib.h"
32#include "gnunet_dht_service.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet-service-dht.h"
35#include "gnunet-service-dht_datacache.h"
36#include "gnunet-service-dht_neighbours.h"
37#include "gnunet-service-dht_routing.h"
38
39/**
40 * How often do we broadcast our HELLO to neighbours if
41 * nothing special happens?
42 */
43#define HELLO_FREQUENCY GNUNET_TIME_UNIT_HOURS
44
45
46/**
47 * Information we keep per underlay.
48 */
49struct GDS_Underlay
50{
51
52 /**
53 * Kept in a DLL.
54 */
55 struct GDS_Underlay *next;
56
57 /**
58 * Kept in a DLL.
59 */
60 struct GDS_Underlay *prev;
61
62 /**
63 * Environment for this underlay.
64 */
65 struct GNUNET_DHTU_PluginEnvironment env;
66
67 /**
68 * Underlay API handle.
69 */
70 struct GNUNET_DHTU_PluginFunctions *dhtu;
71
72 /**
73 * current network size estimate for this underlay.
74 */
75 double network_size_estimate;
76
77 /**
78 * Name of the underlay (i.e. "gnunet" or "ip").
79 */
80 char *name;
81
82 /**
83 * Name of the library providing the underlay.
84 */
85 char *libname;
86};
87
88
89/**
90 * An address of this peer.
91 */
92struct MyAddress
93{
94 /**
95 * Kept in a DLL.
96 */
97 struct MyAddress *next;
98
99 /**
100 * Kept in a DLL.
101 */
102 struct MyAddress *prev;
103
104 /**
105 * Underlay handle for the address.
106 */
107 struct GNUNET_DHTU_Source *source;
108
109 /**
110 * Textual representation of the address.
111 */
112 char *url;
113
114 /**
115 * Underlay of this address.
116 */
117 struct GDS_Underlay *u;
118};
119
120
121/**
122 * Our HELLO
123 */
124struct GNUNET_HELLO_Builder *GDS_my_hello;
125
126/**
127 * Identity of this peer.
128 */
129struct GNUNET_PeerIdentity GDS_my_identity;
130
131/**
132 * Hash of the identity of this peer.
133 */
134struct GNUNET_HashCode GDS_my_identity_hash;
135
136/**
137 * Our private key.
138 */
139struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key;
140
141/**
142 * Task broadcasting our HELLO.
143 */
144static struct GNUNET_SCHEDULER_Task *hello_task;
145
146/**
147 * Handles for the DHT underlays.
148 */
149static struct GDS_Underlay *u_head;
150
151/**
152 * Handles for the DHT underlays.
153 */
154static struct GDS_Underlay *u_tail;
155
156/**
157 * Head of addresses of this peer.
158 */
159static struct MyAddress *a_head;
160
161/**
162 * Tail of addresses of this peer.
163 */
164static struct MyAddress *a_tail;
165
166/**
167 * log of the current network size estimate, used as the point where
168 * we switch between random and deterministic routing.
169 */
170static double log_of_network_size_estimate;
171
172
173/**
174 * Callback that is called when network size estimate is updated.
175 *
176 * @param cls a `struct GDS_Underlay`
177 * @param timestamp time when the estimate was received from the server (or created by the server)
178 * @param logestimate the log(Base 2) value of the current network size estimate
179 * @param std_dev standard deviation for the estimate
180 *
181 */
182static void
183update_network_size_estimate (void *cls,
184 struct GNUNET_TIME_Absolute timestamp,
185 double logestimate,
186 double std_dev)
187{
188 struct GDS_Underlay *u = cls;
189 double sum = 0.0;
190
191 GNUNET_STATISTICS_update (GDS_stats,
192 "# Network size estimates received",
193 1,
194 GNUNET_NO);
195 /* do not allow estimates < 0.5 */
196 u->network_size_estimate = pow (2.0,
197 GNUNET_MAX (0.5,
198 logestimate));
199 for (struct GDS_Underlay *p = u_head; NULL != p; p = p->next)
200 sum += p->network_size_estimate;
201 if (sum <= 2.0)
202 log_of_network_size_estimate = 0.5;
203 else
204 log_of_network_size_estimate = log2 (sum);
205}
206
207
208/**
209 * Return the current NSE
210 *
211 * @return the current NSE as a logarithm
212 */
213double
214GDS_NSE_get (void)
215{
216 return log_of_network_size_estimate;
217}
218
219
220#include "gnunet-service-dht_clients.c"
221
222
223/**
224 * Task run periodically to broadcast our HELLO.
225 *
226 * @param cls NULL
227 */
228static void
229broadcast_hello (void *cls)
230{
231 struct GNUNET_MessageHeader *hello;
232
233 (void) cls;
234 /* TODO: randomize! */
235 hello_task = GNUNET_SCHEDULER_add_delayed (HELLO_FREQUENCY,
236 &broadcast_hello,
237 NULL);
238 hello = GNUNET_HELLO_builder_to_dht_hello_msg (GDS_my_hello,
239 &GDS_my_private_key,
240 GNUNET_TIME_UNIT_ZERO);
241 if (NULL == hello)
242 {
243 GNUNET_break (0);
244 return;
245 }
246 GDS_NEIGHBOURS_broadcast (hello);
247 GNUNET_free (hello);
248}
249
250
251/**
252 * Function to call with new addresses of this peer.
253 *
254 * @param cls the closure
255 * @param address address under which we are likely reachable,
256 * pointer will remain valid until @e address_del_cb is called; to be used for HELLOs. Example: "ip+udp://$PID/1.1.1.1:2086/"
257 * @param source handle for sending from this address, NULL if we can only receive
258 * @param[out] ctx storage space for DHT to use in association with this address
259 */
260static void
261u_address_add (void *cls,
262 const char *address,
263 struct GNUNET_DHTU_Source *source,
264 void **ctx)
265{
266 struct GDS_Underlay *u = cls;
267 struct MyAddress *a;
268 enum GNUNET_GenericReturnValue add_success;
269
270 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
271 "Underlay adds address %s for this peer\n",
272 address);
273 if (GNUNET_OK != (add_success = GNUNET_HELLO_builder_add_address (
274 GDS_my_hello,
275 address)))
276 {
277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
278 "Adding address `%s' from underlay %s\n",
279 address,
280 GNUNET_NO == add_success ? "not done" : "failed");
281 return;
282 }
283 a = GNUNET_new (struct MyAddress);
284 a->source = source;
285 a->url = GNUNET_strdup (address);
286 a->u = u;
287 GNUNET_CONTAINER_DLL_insert (a_head,
288 a_tail,
289 a);
290 *ctx = a;
291
292 if (NULL != hello_task)
293 GNUNET_SCHEDULER_cancel (hello_task);
294 hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
295 NULL);
296}
297
298
299/**
300 * Function to call with expired addresses of this peer.
301 *
302 * @param[in] ctx storage space used by the DHT in association with this address
303 */
304static void
305u_address_del (void *ctx)
306{
307 struct MyAddress *a = ctx;
308
309 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
310 "Underlay deletes address %s for this peer\n",
311 a->url);
312 GNUNET_HELLO_builder_del_address (GDS_my_hello,
313 a->url);
314 GNUNET_CONTAINER_DLL_remove (a_head,
315 a_tail,
316 a);
317 GNUNET_free (a->url);
318 GNUNET_free (a);
319 if (NULL != hello_task)
320 GNUNET_SCHEDULER_cancel (hello_task);
321 hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
322 NULL);
323}
324
325
326void
327GDS_u_try_connect (const struct GNUNET_PeerIdentity *pid,
328 const char *address)
329{
330 for (struct GDS_Underlay *u = u_head;
331 NULL != u;
332 u = u->next)
333 u->dhtu->try_connect (u->dhtu->cls,
334 pid,
335 address);
336}
337
338
339void
340GDS_u_send (struct GDS_Underlay *u,
341 struct GNUNET_DHTU_Target *target,
342 const void *msg,
343 size_t msg_size,
344 GNUNET_SCHEDULER_TaskCallback finished_cb,
345 void *finished_cb_cls)
346{
347 u->dhtu->send (u->dhtu->cls,
348 target,
349 msg,
350 msg_size,
351 finished_cb,
352 finished_cb_cls);
353}
354
355
356void
357GDS_u_drop (struct GDS_Underlay *u,
358 struct GNUNET_DHTU_PreferenceHandle *ph)
359{
360 u->dhtu->drop (ph);
361}
362
363
364struct GNUNET_DHTU_PreferenceHandle *
365GDS_u_hold (struct GDS_Underlay *u,
366 struct GNUNET_DHTU_Target *target)
367{
368 return u->dhtu->hold (u->dhtu->cls,
369 target);
370}
371
372
373/**
374 * Task run during shutdown.
375 *
376 * @param cls unused
377 */
378static void
379shutdown_task (void *cls)
380{
381 struct GDS_Underlay *u;
382
383 while (NULL != (u = u_head))
384 {
385 GNUNET_PLUGIN_unload (u->libname,
386 u->dhtu);
387 GNUNET_CONTAINER_DLL_remove (u_head,
388 u_tail,
389 u);
390 GNUNET_free (u->name);
391 GNUNET_free (u->libname);
392 GNUNET_free (u);
393 }
394 GDS_NEIGHBOURS_done ();
395 GDS_DATACACHE_done ();
396 GDS_ROUTING_done ();
397 if (NULL != GDS_block_context)
398 {
399 GNUNET_BLOCK_context_destroy (GDS_block_context);
400 GDS_block_context = NULL;
401 }
402 GDS_CLIENTS_stop ();
403 if (NULL != GDS_stats)
404 {
405 GNUNET_STATISTICS_destroy (GDS_stats,
406 GNUNET_YES);
407 GDS_stats = NULL;
408 }
409 if (NULL != GDS_my_hello)
410 {
411 GNUNET_HELLO_builder_free (GDS_my_hello);
412 GDS_my_hello = NULL;
413 }
414 if (NULL != hello_task)
415 {
416 GNUNET_SCHEDULER_cancel (hello_task);
417 hello_task = NULL;
418 }
419}
420
421
422/**
423 * Function iterating over all configuration sections.
424 * Loads plugins for enabled DHT underlays.
425 *
426 * @param cls NULL
427 * @param section configuration section to inspect
428 */
429static void
430load_underlay (void *cls,
431 const char *section)
432{
433 struct GDS_Underlay *u;
434 char *libname;
435
436 (void) cls;
437 if (0 != strncasecmp (section,
438 "dhtu-",
439 strlen ("dhtu-")))
440 return;
441 if (GNUNET_YES !=
442 GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
443 section,
444 "ENABLED"))
445 return;
446 section += strlen ("dhtu-");
447 u = GNUNET_new (struct GDS_Underlay);
448 u->env.cls = u;
449 u->env.cfg = GDS_cfg;
450 u->env.address_add_cb = &u_address_add;
451 u->env.address_del_cb = &u_address_del;
452 u->env.network_size_cb = &update_network_size_estimate;
453 u->env.connect_cb = &GDS_u_connect;
454 u->env.disconnect_cb = &GDS_u_disconnect;
455 u->env.receive_cb = &GDS_u_receive;
456 GNUNET_asprintf (&libname,
457 "libgnunet_plugin_dhtu_%s",
458 section);
459 u->dhtu = GNUNET_PLUGIN_load (libname,
460 &u->env);
461 if (NULL == u->dhtu)
462 {
463 GNUNET_free (libname);
464 GNUNET_free (u);
465 return;
466 }
467 u->libname = libname;
468 u->name = GNUNET_strdup (section);
469 GNUNET_CONTAINER_DLL_insert (u_head,
470 u_tail,
471 u);
472}
473
474
475/**
476 * Process dht requests.
477 *
478 * @param cls closure
479 * @param c configuration to use
480 * @param service the initialized service
481 */
482static void
483run (void *cls,
484 const struct GNUNET_CONFIGURATION_Handle *c,
485 struct GNUNET_SERVICE_Handle *service)
486{
487 GDS_cfg = c;
488 GDS_service = service;
489 {
490 char *keyfile;
491
492 if (GNUNET_OK !=
493 GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
494 "PEER",
495 "PRIVATE_KEY",
496 &keyfile))
497 {
498 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
499 "PEER",
500 "PRIVATE_KEY");
501 GNUNET_SCHEDULER_shutdown ();
502 return;
503 }
504 if (GNUNET_SYSERR ==
505 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
506 GNUNET_YES,
507 &GDS_my_private_key))
508 {
509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
510 "Failed to setup peer's private key\n");
511 GNUNET_free (keyfile);
512 GNUNET_SCHEDULER_shutdown ();
513 return;
514 }
515 GNUNET_free (keyfile);
516 }
517 GNUNET_CRYPTO_eddsa_key_get_public (&GDS_my_private_key,
518 &GDS_my_identity.public_key);
519 GDS_my_hello = GNUNET_HELLO_builder_new (&GDS_my_identity);
520 GNUNET_CRYPTO_hash (&GDS_my_identity,
521 sizeof(struct GNUNET_PeerIdentity),
522 &GDS_my_identity_hash);
523 GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
524 GDS_stats = GNUNET_STATISTICS_create ("dht",
525 GDS_cfg);
526 GDS_CLIENTS_init ();
527 GDS_ROUTING_init ();
528 GDS_DATACACHE_init ();
529 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
530 NULL);
531 if (GNUNET_OK !=
532 GDS_NEIGHBOURS_init ())
533 {
534 GNUNET_SCHEDULER_shutdown ();
535 return;
536 }
537 GNUNET_CONFIGURATION_iterate_sections (GDS_cfg,
538 &load_underlay,
539 NULL);
540 if (NULL == u_head)
541 {
542 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
543 "No DHT underlays configured!\n");
544 GNUNET_SCHEDULER_shutdown ();
545 return;
546 }
547}
548
549
550/* Finally, define the main method */
551GDS_DHT_SERVICE_INIT ("dht", &run);
552
553
554/* end of gnunet-service-dht.c */