aboutsummaryrefslogtreecommitdiff
path: root/src/dhtu
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhtu')
-rw-r--r--src/dhtu/.gitignore1
-rw-r--r--src/dhtu/Makefile.am82
-rw-r--r--src/dhtu/dhtu.conf7
-rw-r--r--src/dhtu/plugin_dhtu_gnunet.c635
-rw-r--r--src/dhtu/plugin_dhtu_ip.c1172
-rw-r--r--src/dhtu/test_dhtu_ip.c45
-rw-r--r--src/dhtu/testing_dhtu_cmd_send.c119
7 files changed, 0 insertions, 2061 deletions
diff --git a/src/dhtu/.gitignore b/src/dhtu/.gitignore
deleted file mode 100644
index 21f1a7c9b..000000000
--- a/src/dhtu/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
1test_dhtu_ip
diff --git a/src/dhtu/Makefile.am b/src/dhtu/Makefile.am
deleted file mode 100644
index 4d210b71f..000000000
--- a/src/dhtu/Makefile.am
+++ /dev/null
@@ -1,82 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage -O0
10 XLIBS = -lgcov
11endif
12
13pkgcfg_DATA = \
14 dhtu.conf
15
16plugin_LTLIBRARIES = \
17 libgnunet_plugin_dhtu_gnunet.la
18
19if !OPENBSD
20plugin_LTLIBRARIES += libgnunet_plugin_dhtu_ip.la
21
22libgnunet_plugin_dhtu_ip_la_SOURCES = \
23 plugin_dhtu_ip.c
24libgnunet_plugin_dhtu_ip_la_LIBADD = \
25 $(top_builddir)/src/util/libgnunetutil.la \
26 $(XLIBS) \
27 $(LTLIBINTL)
28libgnunet_plugin_dhtu_ip_la_LDFLAGS = \
29 $(GN_PLUGIN_LDFLAGS)
30endif
31
32
33libgnunet_plugin_dhtu_gnunet_la_SOURCES = \
34 plugin_dhtu_gnunet.c
35libgnunet_plugin_dhtu_gnunet_la_LIBADD = \
36 $(top_builddir)/src/ats/libgnunetats.la \
37 $(top_builddir)/src/core/libgnunetcore.la \
38 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
39 $(top_builddir)/src/transport/libgnunettransport.la \
40 $(top_builddir)/src/hello/libgnunethello.la \
41 $(top_builddir)/src/nse/libgnunetnse.la \
42 $(top_builddir)/src/util/libgnunetutil.la \
43 $(XLIBS) \
44 $(LTLIBINTL)
45libgnunet_plugin_dhtu_gnunet_la_LDFLAGS = \
46 $(GN_PLUGIN_LDFLAGS)
47
48
49lib_LTLIBRARIES = \
50 libgnunettestingdhtu.la
51
52libgnunettestingdhtu_la_SOURCES = \
53 testing_dhtu_cmd_send.c
54libgnunettestingdhtu_la_LIBADD = \
55 $(top_builddir)/src/testing/libgnunettesting.la \
56 $(top_builddir)/src/arm/libgnunetarm.la \
57 $(top_builddir)/src/util/libgnunetutil.la \
58 $(LTLIBINTL)
59libgnunettestingdhtu_la_LDFLAGS = \
60 $(GN_LIB_LDFLAGS) \
61 -version-info 0:0:0
62
63
64
65test_dhtu_ip_SOURCES = \
66 test_dhtu_ip.c
67test_dhtu_ip_LDADD = \
68 $(top_builddir)/src/testing/libgnunettesting.la \
69 $(top_builddir)/src/arm/libgnunetarm.la \
70 $(top_builddir)/src/util/libgnunetutil.la
71
72check_PROGRAMS = \
73 test_dhtu_ip
74
75EXTRA_DIST = \
76 dhtu.conf
77
78if ENABLE_TEST_RUN
79AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
80TESTS = \
81 $(check_PROGRAMS)
82endif
diff --git a/src/dhtu/dhtu.conf b/src/dhtu/dhtu.conf
deleted file mode 100644
index ea5ade752..000000000
--- a/src/dhtu/dhtu.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1[dhtu-gnunet]
2ENABLED = YES
3
4[dhtu-ip]
5ENABLED = NO
6NSE = 4
7UDP_PORT = 6666
diff --git a/src/dhtu/plugin_dhtu_gnunet.c b/src/dhtu/plugin_dhtu_gnunet.c
deleted file mode 100644
index b072be2be..000000000
--- a/src/dhtu/plugin_dhtu_gnunet.c
+++ /dev/null
@@ -1,635 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 * @author Christian Grothoff
23 *
24 * @file plugin_dhtu_gnunet.c
25 * @brief plain IP based DHT network underlay
26 */
27#include "platform.h"
28#include "gnunet_dhtu_plugin.h"
29#include "gnunet_ats_service.h"
30#include "gnunet_core_service.h"
31#include "gnunet_transport_service.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_peerinfo_service.h"
34#include "gnunet_nse_service.h"
35
36
37/**
38 * Handle for a HELLO we're offering the transport.
39 */
40struct HelloHandle
41{
42 /**
43 * Kept in a DLL.
44 */
45 struct HelloHandle *next;
46
47 /**
48 * Kept in a DLL.
49 */
50 struct HelloHandle *prev;
51
52 /**
53 * Our plugin.
54 */
55 struct Plugin *plugin;
56
57 /**
58 * Offer handle.
59 */
60 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
61
62};
63
64
65/**
66 * Opaque handle that the underlay offers for our address to be used when
67 * sending messages to another peer.
68 */
69struct GNUNET_DHTU_Source
70{
71
72 /**
73 * Application context for this source.
74 */
75 void *app_ctx;
76
77};
78
79
80/**
81 * Opaque handle that the underlay offers for the target peer when sending
82 * messages to another peer.
83 */
84struct GNUNET_DHTU_Target
85{
86
87 /**
88 * Application context for this target.
89 */
90 void *app_ctx;
91
92 /**
93 * Our plugin with its environment.
94 */
95 struct Plugin *plugin;
96
97 /**
98 * CORE MQ to send messages to this peer.
99 */
100 struct GNUNET_MQ_Handle *mq;
101
102 /**
103 * Head of preferences expressed for this target.
104 */
105 struct GNUNET_DHTU_PreferenceHandle *ph_head;
106
107 /**
108 * Tail of preferences expressed for this target.
109 */
110 struct GNUNET_DHTU_PreferenceHandle *ph_tail;
111
112 /**
113 * ATS preference handle for this peer, or NULL.
114 */
115 struct GNUNET_ATS_ConnectivitySuggestHandle *csh;
116
117 /**
118 * Identity of this peer.
119 */
120 struct GNUNET_PeerIdentity pid;
121
122 /**
123 * Preference counter, length of the @a ph_head DLL.
124 */
125 unsigned int ph_count;
126
127};
128
129
130/**
131 * Opaque handle expressing a preference of the DHT to
132 * keep a particular target connected.
133 */
134struct GNUNET_DHTU_PreferenceHandle
135{
136 /**
137 * Kept in a DLL.
138 */
139 struct GNUNET_DHTU_PreferenceHandle *next;
140
141 /**
142 * Kept in a DLL.
143 */
144 struct GNUNET_DHTU_PreferenceHandle *prev;
145
146 /**
147 * Target a preference was expressed for.
148 */
149 struct GNUNET_DHTU_Target *target;
150};
151
152
153/**
154 * Closure for all plugin functions.
155 */
156struct Plugin
157{
158
159 /**
160 * Our "source" address. Traditional CORE API does not tell us which source
161 * it is, so they are all identical.
162 */
163 struct GNUNET_DHTU_Source src;
164
165 /**
166 * Callbacks into the DHT.
167 */
168 struct GNUNET_DHTU_PluginEnvironment *env;
169
170 /**
171 * Handle to the CORE service.
172 */
173 struct GNUNET_CORE_Handle *core;
174
175 /**
176 * Handle to ATS service.
177 */
178 struct GNUNET_ATS_ConnectivityHandle *ats;
179
180 /**
181 * Handle to the NSE service.
182 */
183 struct GNUNET_NSE_Handle *nse;
184
185 /**
186 * Watching for our address to change.
187 */
188 struct GNUNET_PEERINFO_NotifyContext *nc;
189
190 /**
191 * Hellos we are offering to transport.
192 */
193 struct HelloHandle *hh_head;
194
195 /**
196 * Hellos we are offering to transport.
197 */
198 struct HelloHandle *hh_tail;
199
200 /**
201 * Identity of this peer.
202 */
203 struct GNUNET_PeerIdentity my_identity;
204
205};
206
207
208/**
209 * Function called once a hello offer is completed.
210 *
211 * @param cls a `struct HelloHandle`
212 */
213static void
214hello_offered_cb (void *cls)
215{
216 struct HelloHandle *hh = cls;
217 struct Plugin *plugin = hh->plugin;
218
219 GNUNET_CONTAINER_DLL_remove (plugin->hh_head,
220 plugin->hh_tail,
221 hh);
222 GNUNET_free (hh);
223}
224
225
226#include "../peerinfo-tool/gnunet-peerinfo_plugins.c"
227
228
229/**
230 * Request creation of a session with a peer at the given @a address.
231 *
232 * @param cls closure (internal context for the plugin)
233 * @param pid target identity of the peer to connect to
234 * @param address target address to connect to
235 */
236static void
237gnunet_try_connect (void *cls,
238 const struct GNUNET_PeerIdentity *pid,
239 const char *address)
240{
241 struct Plugin *plugin = cls;
242 struct GNUNET_HELLO_Message *hello = NULL;
243 struct HelloHandle *hh;
244 struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
245
246 (void) pid; /* will be needed with future address URIs */
247 if (GNUNET_OK !=
248 GNUNET_HELLO_parse_uri (address,
249 &pubkey,
250 &hello,
251 &GPI_plugins_find))
252 return;
253 hh = GNUNET_new (struct HelloHandle);
254 hh->plugin = plugin;
255 GNUNET_CONTAINER_DLL_insert (plugin->hh_head,
256 plugin->hh_tail,
257 hh);
258 hh->ohh = GNUNET_TRANSPORT_offer_hello (plugin->env->cfg,
259 &hello->header,
260 &hello_offered_cb,
261 hh);
262 GNUNET_free (hello);
263}
264
265
266/**
267 * Request underlay to keep the connection to @a target alive if possible.
268 * Hold may be called multiple times to express a strong preference to
269 * keep a connection, say because a @a target is in multiple tables.
270 *
271 * @param cls closure
272 * @param target connection to keep alive
273 */
274static struct GNUNET_DHTU_PreferenceHandle *
275gnunet_hold (void *cls,
276 struct GNUNET_DHTU_Target *target)
277{
278 struct Plugin *plugin = cls;
279 struct GNUNET_DHTU_PreferenceHandle *ph;
280
281 ph = GNUNET_new (struct GNUNET_DHTU_PreferenceHandle);
282 ph->target = target;
283 GNUNET_CONTAINER_DLL_insert (target->ph_head,
284 target->ph_tail,
285 ph);
286 target->ph_count++;
287 if (NULL != target->csh)
288 GNUNET_ATS_connectivity_suggest_cancel (target->csh);
289 target->csh
290 = GNUNET_ATS_connectivity_suggest (plugin->ats,
291 &target->pid,
292 target->ph_count);
293 return ph;
294}
295
296
297/**
298 * Do no long request underlay to keep the connection alive.
299 *
300 * @param cls closure
301 * @param target connection to keep alive
302 */
303static void
304gnunet_drop (struct GNUNET_DHTU_PreferenceHandle *ph)
305{
306 struct GNUNET_DHTU_Target *target = ph->target;
307 struct Plugin *plugin = target->plugin;
308
309 GNUNET_CONTAINER_DLL_remove (target->ph_head,
310 target->ph_tail,
311 ph);
312 target->ph_count--;
313 GNUNET_free (ph);
314 if (NULL != target->csh)
315 GNUNET_ATS_connectivity_suggest_cancel (target->csh);
316 if (0 == target->ph_count)
317 target->csh = NULL;
318 else
319 target->csh
320 = GNUNET_ATS_connectivity_suggest (plugin->ats,
321 &target->pid,
322 target->ph_count);
323}
324
325
326/**
327 * Send message to some other participant over the network. Note that
328 * sending is not guaranteeing that the other peer actually received the
329 * message. For any given @a target, the DHT must wait for the @a
330 * finished_cb to be called before calling send() again.
331 *
332 * @param cls closure (internal context for the plugin)
333 * @param target receiver identification
334 * @param msg message
335 * @param msg_size number of bytes in @a msg
336 * @param finished_cb function called once transmission is done
337 * (not called if @a target disconnects, then only the
338 * disconnect_cb is called).
339 * @param finished_cb_cls closure for @a finished_cb
340 */
341static void
342gnunet_send (void *cls,
343 struct GNUNET_DHTU_Target *target,
344 const void *msg,
345 size_t msg_size,
346 GNUNET_SCHEDULER_TaskCallback finished_cb,
347 void *finished_cb_cls)
348{
349 struct GNUNET_MQ_Envelope *env;
350 struct GNUNET_MessageHeader *cmsg;
351
352 env = GNUNET_MQ_msg_extra (cmsg,
353 msg_size,
354 GNUNET_MESSAGE_TYPE_DHT_CORE);
355 GNUNET_MQ_notify_sent (env,
356 finished_cb,
357 finished_cb_cls);
358 memcpy (&cmsg[1],
359 msg,
360 msg_size);
361 GNUNET_MQ_send (target->mq,
362 env);
363}
364
365
366/**
367 * Method called whenever a given peer connects.
368 *
369 * @param cls closure
370 * @param peer peer identity this notification is about
371 * @return closure associated with @a peer. given to mq callbacks and
372 * #GNUNET_CORE_DisconnectEventHandler
373 */
374static void *
375core_connect_cb (void *cls,
376 const struct GNUNET_PeerIdentity *peer,
377 struct GNUNET_MQ_Handle *mq)
378{
379 struct Plugin *plugin = cls;
380 struct GNUNET_DHTU_Target *target;
381
382 target = GNUNET_new (struct GNUNET_DHTU_Target);
383 target->plugin = plugin;
384 target->mq = mq;
385 target->pid = *peer;
386 plugin->env->connect_cb (plugin->env->cls,
387 target,
388 &target->pid,
389 &target->app_ctx);
390 return target;
391}
392
393
394/**
395 * Method called whenever a peer disconnects.
396 *
397 * @param cls closure
398 * @param peer peer identity this notification is about
399 * @param peer_cls closure associated with peer. given in
400 * #GNUNET_CORE_ConnectEventHandler
401 */
402static void
403core_disconnect_cb (void *cls,
404 const struct GNUNET_PeerIdentity *peer,
405 void *peer_cls)
406{
407 struct Plugin *plugin = cls;
408 struct GNUNET_DHTU_Target *target = peer_cls;
409
410 plugin->env->disconnect_cb (target->app_ctx);
411 if (NULL != target->csh)
412 GNUNET_ATS_connectivity_suggest_cancel (target->csh);
413 GNUNET_free (target);
414}
415
416
417/**
418 * Find the @a hello for our identity and then pass
419 * it to the DHT as a URL. Note that we only
420 * add addresses, never remove them, due to limitations
421 * of the current peerinfo/core/transport APIs.
422 * This will change with TNG.
423 *
424 * @param cls a `struct Plugin`
425 * @param peer id of the peer, NULL for last call
426 * @param hello hello message for the peer (can be NULL)
427 * @param error message
428 */
429static void
430peerinfo_cb (void *cls,
431 const struct GNUNET_PeerIdentity *peer,
432 const struct GNUNET_HELLO_Message *hello,
433 const char *err_msg)
434{
435 struct Plugin *plugin = cls;
436 char *addr;
437
438 if (NULL == hello)
439 return;
440 if (NULL == peer)
441 return;
442 if (0 !=
443 GNUNET_memcmp (peer,
444 &plugin->my_identity))
445 return;
446 addr = GNUNET_HELLO_compose_uri (hello,
447 &GPI_plugins_find);
448 if (NULL == addr)
449 return;
450 plugin->env->address_add_cb (plugin->env->cls,
451 addr,
452 &plugin->src,
453 &plugin->src.app_ctx);
454 GNUNET_free (addr);
455}
456
457
458/**
459 * Function called after #GNUNET_CORE_connect has succeeded (or failed
460 * for good). Note that the private key of the peer is intentionally
461 * not exposed here; if you need it, your process should try to read
462 * the private key file directly (which should work if you are
463 * authorized...). Implementations of this function must not call
464 * #GNUNET_CORE_disconnect (other than by scheduling a new task to
465 * do this later).
466 *
467 * @param cls closure
468 * @param my_identity ID of this peer, NULL if we failed
469 */
470static void
471core_init_cb (void *cls,
472 const struct GNUNET_PeerIdentity *my_identity)
473{
474 struct Plugin *plugin = cls;
475
476 plugin->my_identity = *my_identity;
477 plugin->nc = GNUNET_PEERINFO_notify (plugin->env->cfg,
478 GNUNET_NO,
479 &peerinfo_cb,
480 plugin);
481}
482
483
484/**
485 * Anything goes, always return #GNUNET_OK.
486 *
487 * @param cls unused
488 * @param msg message to check
489 * @return #GNUNET_OK if all is fine
490 */
491static int
492check_core_message (void *cls,
493 const struct GNUNET_MessageHeader *msg)
494{
495 (void) cls;
496 (void) msg;
497 return GNUNET_OK;
498}
499
500
501/**
502 * Handle message from CORE for the DHT. Passes it to the
503 * DHT logic.
504 *
505 * @param cls a `struct GNUNET_DHTU_Target` of the sender
506 * @param msg the message we received
507 */
508static void
509handle_core_message (void *cls,
510 const struct GNUNET_MessageHeader *msg)
511{
512 struct GNUNET_DHTU_Target *origin = cls;
513 struct Plugin *plugin = origin->plugin;
514
515 plugin->env->receive_cb (plugin->env->cls,
516 &origin->app_ctx,
517 &plugin->src.app_ctx,
518 &msg[1],
519 ntohs (msg->size) - sizeof (*msg));
520}
521
522
523/**
524 * Callback to call when network size estimate is updated.
525 *
526 * @param cls closure
527 * @param timestamp time when the estimate was received from the server (or created by the server)
528 * @param logestimate the log(Base 2) value of the current network size estimate
529 * @param std_dev standard deviation for the estimate
530 */
531static void
532nse_cb (void *cls,
533 struct GNUNET_TIME_Absolute timestamp,
534 double logestimate,
535 double std_dev)
536{
537 struct Plugin *plugin = cls;
538
539 plugin->env->network_size_cb (plugin->env->cls,
540 timestamp,
541 logestimate,
542 std_dev);
543}
544
545
546/**
547 * Exit point from the plugin.
548 *
549 * @param cls closure (our `struct Plugin`)
550 * @return NULL
551 */
552void *
553libgnunet_plugin_dhtu_gnunet_done (void *cls)
554{
555 struct GNUNET_DHTU_PluginFunctions *api = cls;
556 struct Plugin *plugin = api->cls;
557 struct HelloHandle *hh;
558
559 while (NULL != (hh = plugin->hh_head))
560 {
561 GNUNET_CONTAINER_DLL_remove (plugin->hh_head,
562 plugin->hh_tail,
563 hh);
564 GNUNET_TRANSPORT_offer_hello_cancel (hh->ohh);
565 GNUNET_free (hh);
566 }
567 if (NULL != plugin->nse)
568 GNUNET_NSE_disconnect (plugin->nse);
569 plugin->env->network_size_cb (plugin->env->cls,
570 GNUNET_TIME_UNIT_FOREVER_ABS,
571 0.0,
572 0.0);
573 if (NULL != plugin->core)
574 GNUNET_CORE_disconnect (plugin->core);
575 if (NULL != plugin->ats)
576 GNUNET_ATS_connectivity_done (plugin->ats);
577 if (NULL != plugin->nc)
578 GNUNET_PEERINFO_notify_cancel (plugin->nc);
579 GPI_plugins_unload ();
580 GNUNET_free (plugin);
581 GNUNET_free (api);
582 return NULL;
583}
584
585
586/**
587 * Entry point for the plugin.
588 *
589 * @param cls closure (the `struct GNUNET_DHTU_PluginEnvironment`)
590 * @return the plugin's API
591 */
592void *
593libgnunet_plugin_dhtu_gnunet_init (void *cls)
594{
595 struct GNUNET_DHTU_PluginEnvironment *env = cls;
596 struct GNUNET_DHTU_PluginFunctions *api;
597 struct Plugin *plugin;
598 struct GNUNET_MQ_MessageHandler handlers[] = {
599 GNUNET_MQ_hd_var_size (core_message,
600 GNUNET_MESSAGE_TYPE_DHT_CORE,
601 struct GNUNET_MessageHeader,
602 NULL),
603 GNUNET_MQ_handler_end ()
604 };
605
606 plugin = GNUNET_new (struct Plugin);
607 plugin->env = env;
608 api = GNUNET_new (struct GNUNET_DHTU_PluginFunctions);
609 api->cls = plugin;
610 api->try_connect = &gnunet_try_connect;
611 api->hold = &gnunet_hold;
612 api->drop = &gnunet_drop;
613 api->send = &gnunet_send;
614 plugin->ats = GNUNET_ATS_connectivity_init (env->cfg);
615 plugin->core = GNUNET_CORE_connect (env->cfg,
616 plugin,
617 &core_init_cb,
618 &core_connect_cb,
619 &core_disconnect_cb,
620 handlers);
621 plugin->nse = GNUNET_NSE_connect (env->cfg,
622 &nse_cb,
623 plugin);
624 if ( (NULL == plugin->ats) ||
625 (NULL == plugin->core) ||
626 (NULL == plugin->nse) )
627 {
628 GNUNET_break (0);
629 GNUNET_free (api);
630 libgnunet_plugin_dhtu_gnunet_done (plugin);
631 return NULL;
632 }
633 GPI_plugins_load (env->cfg);
634 return api;
635}
diff --git a/src/dhtu/plugin_dhtu_ip.c b/src/dhtu/plugin_dhtu_ip.c
deleted file mode 100644
index 612d2c119..000000000
--- a/src/dhtu/plugin_dhtu_ip.c
+++ /dev/null
@@ -1,1172 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021, 2022 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 * @author Christian Grothoff
23 *
24 * @file plugin_dhtu_ip.c
25 * @brief plain IP based DHT network underlay
26 */
27#include "platform.h"
28#include "gnunet_dhtu_plugin.h"
29
30/**
31 * How frequently should we re-scan our local interfaces for IPs?
32 */
33#define SCAN_FREQ GNUNET_TIME_UNIT_MINUTES
34
35/**
36 * Maximum number of concurrently active destinations to support.
37 */
38#define MAX_DESTS 256
39
40
41/**
42 * Opaque handle that the underlay offers for our address to be used when
43 * sending messages to another peer.
44 */
45struct GNUNET_DHTU_Source
46{
47
48 /**
49 * Kept in a DLL.
50 */
51 struct GNUNET_DHTU_Source *next;
52
53 /**
54 * Kept in a DLL.
55 */
56 struct GNUNET_DHTU_Source *prev;
57
58 /**
59 * Application context for this source.
60 */
61 void *app_ctx;
62
63 /**
64 * Address in URL form ("ip+udp://$PID/$IP:$PORT")
65 */
66 char *address;
67
68 /**
69 * My actual address.
70 */
71 struct sockaddr_storage addr;
72
73 /**
74 * Number of bytes in @a addr.
75 */
76 socklen_t addrlen;
77
78 /**
79 * Last generation this address was observed.
80 */
81 unsigned int scan_generation;
82
83};
84
85
86/**
87 * Opaque handle that the underlay offers for the target peer when sending
88 * messages to another peer.
89 */
90struct GNUNET_DHTU_Target
91{
92
93 /**
94 * Kept in a DLL.
95 */
96 struct GNUNET_DHTU_Target *next;
97
98 /**
99 * Kept in a DLL.
100 */
101 struct GNUNET_DHTU_Target *prev;
102
103 /**
104 * Application context for this target.
105 */
106 void *app_ctx;
107
108 /**
109 * Head of preferences expressed for this target.
110 */
111 struct GNUNET_DHTU_PreferenceHandle *ph_head;
112
113 /**
114 * Tail of preferences expressed for this target.
115 */
116 struct GNUNET_DHTU_PreferenceHandle *ph_tail;
117
118 /**
119 * Peer's identity.
120 */
121 struct GNUNET_PeerIdentity pid;
122
123 /**
124 * Target IP address.
125 */
126 struct sockaddr_storage addr;
127
128 /**
129 * Number of bytes in @a addr.
130 */
131 socklen_t addrlen;
132
133 /**
134 * Preference counter, length of the @a ph_head DLL.
135 */
136 unsigned int ph_count;
137
138};
139
140/**
141 * Opaque handle expressing a preference of the DHT to
142 * keep a particular target connected.
143 */
144struct GNUNET_DHTU_PreferenceHandle
145{
146 /**
147 * Kept in a DLL.
148 */
149 struct GNUNET_DHTU_PreferenceHandle *next;
150
151 /**
152 * Kept in a DLL.
153 */
154 struct GNUNET_DHTU_PreferenceHandle *prev;
155
156 /**
157 * Target a preference was expressed for.
158 */
159 struct GNUNET_DHTU_Target *target;
160};
161
162
163/**
164 * Closure for all plugin functions.
165 */
166struct Plugin
167{
168 /**
169 * Callbacks into the DHT.
170 */
171 struct GNUNET_DHTU_PluginEnvironment *env;
172
173 /**
174 * Head of sources where we receive traffic.
175 */
176 struct GNUNET_DHTU_Source *src_head;
177
178 /**
179 * Tail of sources where we receive traffic.
180 */
181 struct GNUNET_DHTU_Source *src_tail;
182
183 /**
184 * Head of destinations that are active. Sorted by
185 * last use, with latest used at the head.
186 */
187 struct GNUNET_DHTU_Target *dst_head;
188
189 /**
190 * Tail of destinations that are active.
191 */
192 struct GNUNET_DHTU_Target *dst_tail;
193
194 /**
195 * Map from hashes of sockaddrs to targets.
196 */
197 struct GNUNET_CONTAINER_MultiHashMap *dsts;
198
199 /**
200 * Task that scans for IP address changes.
201 */
202 struct GNUNET_SCHEDULER_Task *scan_task;
203
204 /**
205 * Task that reads incoming UDP packets.
206 */
207 struct GNUNET_SCHEDULER_Task *read_task;
208
209 /**
210 * Port we bind to.
211 */
212 char *port;
213
214 /**
215 * My UDP socket.
216 */
217 struct GNUNET_NETWORK_Handle *sock;
218
219 /**
220 * My identity.
221 */
222 struct GNUNET_PeerIdentity my_id;
223
224 /**
225 * How often have we scanned for IPs?
226 */
227 unsigned int scan_generation;
228
229 /**
230 * Port as a 16-bit value.
231 */
232 uint16_t port16;
233};
234
235
236/**
237 * Create a target to which we may send traffic.
238 *
239 * @param plugin our plugin
240 * @param pid presumed identity of the target
241 * @param addr target address
242 * @param addrlen number of bytes in @a addr
243 * @return new target object
244 */
245static struct GNUNET_DHTU_Target *
246create_target (struct Plugin *plugin,
247 const struct GNUNET_PeerIdentity *pid,
248 const struct sockaddr *addr,
249 socklen_t addrlen)
250{
251 struct GNUNET_DHTU_Target *dst;
252
253 if (MAX_DESTS <=
254 GNUNET_CONTAINER_multihashmap_size (plugin->dsts))
255 {
256 struct GNUNET_HashCode key;
257
258 dst = NULL;
259 for (struct GNUNET_DHTU_Target *pos = plugin->dst_head;
260 NULL != pos;
261 pos = pos->next)
262 {
263 /* >= here assures we remove oldest entries first */
264 if ( (NULL == dst) ||
265 (dst->ph_count >= pos->ph_count) )
266 dst = pos;
267 }
268 GNUNET_assert (NULL != dst);
269 plugin->env->disconnect_cb (dst->app_ctx);
270 GNUNET_CRYPTO_hash (&dst->addr,
271 dst->addrlen,
272 &key);
273 GNUNET_assert (GNUNET_YES ==
274 GNUNET_CONTAINER_multihashmap_remove (plugin->dsts,
275 &key,
276 dst));
277 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
278 plugin->dst_tail,
279 dst);
280 GNUNET_assert (NULL == dst->ph_head);
281 GNUNET_free (dst);
282 }
283 dst = GNUNET_new (struct GNUNET_DHTU_Target);
284 dst->addrlen = addrlen;
285 dst->pid = *pid;
286 memcpy (&dst->addr,
287 addr,
288 addrlen);
289 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
290 plugin->dst_tail,
291 dst);
292 plugin->env->connect_cb (plugin->env->cls,
293 dst,
294 &dst->pid,
295 &dst->app_ctx);
296 return dst;
297}
298
299
300/**
301 * Find target matching @a addr. If none exists,
302 * create one!
303 *
304 * @param plugin the plugin handle
305 * @param pid presumed identity of the target
306 * @param src source target is from, or NULL if unknown
307 * @param addr socket address to find
308 * @param addrlen number of bytes in @a addr
309 * @return matching target object
310 */
311static struct GNUNET_DHTU_Target *
312find_target (struct Plugin *plugin,
313 const struct GNUNET_PeerIdentity *pid,
314 const void *addr,
315 size_t addrlen)
316{
317 struct GNUNET_HashCode key;
318 struct GNUNET_DHTU_Target *dst;
319
320 GNUNET_CRYPTO_hash (addr,
321 addrlen,
322 &key);
323 dst = GNUNET_CONTAINER_multihashmap_get (plugin->dsts,
324 &key);
325 if (NULL == dst)
326 {
327 dst = create_target (plugin,
328 pid,
329 (const struct sockaddr *) addr,
330 addrlen);
331 GNUNET_assert (GNUNET_YES ==
332 GNUNET_CONTAINER_multihashmap_put (
333 plugin->dsts,
334 &key,
335 dst,
336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
337 }
338 else
339 {
340 /* move to head of DLL */
341 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
342 plugin->dst_tail,
343 dst);
344 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
345 plugin->dst_tail,
346 dst);
347
348 }
349 return dst;
350}
351
352
353/**
354 * Request creation of a session with a peer at the given @a address.
355 *
356 * @param cls closure (internal context for the plugin)
357 * @param pid identity of the target peer
358 * @param address target address to connect to
359 */
360static void
361ip_try_connect (void *cls,
362 const struct GNUNET_PeerIdentity *pid,
363 const char *address)
364{
365 struct Plugin *plugin = cls;
366 char *colon;
367 const char *port;
368 char *addr;
369 struct addrinfo hints = {
370 .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV
371 };
372 struct addrinfo *result = NULL;
373
374 if (0 !=
375 strncmp (address,
376 "ip+",
377 strlen ("ip+")))
378 return;
379 address += strlen ("ip+");
380 if (0 !=
381 strncmp (address,
382 "udp://",
383 strlen ("udp://")))
384 return;
385 address += strlen ("udp://");
386 addr = GNUNET_strdup (address);
387 colon = strchr (addr, ':');
388 if (NULL == colon)
389 {
390 port = plugin->port;
391 }
392 else
393 {
394 *colon = '\0';
395 port = colon + 1;
396 }
397 if (0 !=
398 getaddrinfo (addr,
399 port,
400 &hints,
401 &result))
402 {
403 GNUNET_break (0);
404 GNUNET_free (addr);
405 return;
406 }
407 GNUNET_free (addr);
408 (void) find_target (plugin,
409 pid,
410 result->ai_addr,
411 result->ai_addrlen);
412 freeaddrinfo (result);
413}
414
415
416/**
417 * Request underlay to keep the connection to @a target alive if possible.
418 * Hold may be called multiple times to express a strong preference to
419 * keep a connection, say because a @a target is in multiple tables.
420 *
421 * @param cls closure
422 * @param target connection to keep alive
423 */
424static struct GNUNET_DHTU_PreferenceHandle *
425ip_hold (void *cls,
426 struct GNUNET_DHTU_Target *target)
427{
428 struct GNUNET_DHTU_PreferenceHandle *ph;
429
430 ph = GNUNET_new (struct GNUNET_DHTU_PreferenceHandle);
431 ph->target = target;
432 GNUNET_CONTAINER_DLL_insert (target->ph_head,
433 target->ph_tail,
434 ph);
435 target->ph_count++;
436 return ph;
437}
438
439
440/**
441 * Do no long request underlay to keep the connection alive.
442 *
443 * @param cls closure
444 * @param target connection to keep alive
445 */
446static void
447ip_drop (struct GNUNET_DHTU_PreferenceHandle *ph)
448{
449 struct GNUNET_DHTU_Target *target = ph->target;
450
451 GNUNET_CONTAINER_DLL_remove (target->ph_head,
452 target->ph_tail,
453 ph);
454 target->ph_count--;
455 GNUNET_free (ph);
456}
457
458
459/**
460 * Send message to some other participant over the network. Note that
461 * sending is not guaranteeing that the other peer actually received the
462 * message. For any given @a target, the DHT must wait for the @a
463 * finished_cb to be called before calling send() again.
464 *
465 * @param cls closure (internal context for the plugin)
466 * @param target receiver identification
467 * @param msg message
468 * @param msg_size number of bytes in @a msg
469 * @param finished_cb function called once transmission is done
470 * (not called if @a target disconnects, then only the
471 * disconnect_cb is called).
472 * @param finished_cb_cls closure for @a finished_cb
473 */
474static void
475ip_send (void *cls,
476 struct GNUNET_DHTU_Target *target,
477 const void *msg,
478 size_t msg_size,
479 GNUNET_SCHEDULER_TaskCallback finished_cb,
480 void *finished_cb_cls)
481{
482 struct Plugin *plugin = cls;
483 char buf[sizeof (plugin->my_id) + msg_size];
484
485 memcpy (buf,
486 &plugin->my_id,
487 sizeof (plugin->my_id));
488 memcpy (&buf[sizeof (plugin->my_id)],
489 msg,
490 msg_size);
491 GNUNET_NETWORK_socket_sendto (plugin->sock,
492 buf,
493 sizeof (buf),
494 (const struct sockaddr *) &target->addr,
495 target->addrlen);
496 finished_cb (finished_cb_cls);
497}
498
499
500/**
501 * Create a new source on which we may be receiving traffic.
502 *
503 * @param plugin our plugin
504 * @param addr our address
505 * @param addrlen number of bytes in @a addr
506 * @return new source object
507 */
508static struct GNUNET_DHTU_Source *
509create_source (struct Plugin *plugin,
510 const struct sockaddr *addr,
511 socklen_t addrlen)
512{
513 struct GNUNET_DHTU_Source *src;
514
515 src = GNUNET_new (struct GNUNET_DHTU_Source);
516 src->addrlen = addrlen;
517 memcpy (&src->addr,
518 addr,
519 addrlen);
520 src->scan_generation = plugin->scan_generation;
521 switch (addr->sa_family)
522 {
523 case AF_INET:
524 {
525 const struct sockaddr_in *s4 = (const struct sockaddr_in *) addr;
526 char buf[INET_ADDRSTRLEN];
527
528 GNUNET_assert (sizeof (struct sockaddr_in) == addrlen);
529 GNUNET_asprintf (&src->address,
530 "ip+udp://%s:%u",
531 inet_ntop (AF_INET,
532 &s4->sin_addr,
533 buf,
534 sizeof (buf)),
535 ntohs (s4->sin_port));
536 }
537 break;
538 case AF_INET6:
539 {
540 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) addr;
541 char buf[INET6_ADDRSTRLEN];
542
543 GNUNET_assert (sizeof (struct sockaddr_in6) == addrlen);
544 GNUNET_asprintf (&src->address,
545 "ip+udp://[%s]:%u",
546 inet_ntop (AF_INET6,
547 &s6->sin6_addr,
548 buf,
549 sizeof (buf)),
550 ntohs (s6->sin6_port));
551 }
552 break;
553 default:
554 GNUNET_break (0);
555 GNUNET_free (src);
556 return NULL;
557 }
558 GNUNET_CONTAINER_DLL_insert (plugin->src_head,
559 plugin->src_tail,
560 src);
561 plugin->env->address_add_cb (plugin->env->cls,
562 src->address,
563 src,
564 &src->app_ctx);
565 return src;
566}
567
568
569/**
570 * Compare two addresses excluding the ports for equality. Only compares IP
571 * address. Must only be called on AF_INET or AF_INET6 addresses.
572 *
573 * @param a1 address to compare
574 * @param a2 address to compare
575 * @param alen number of bytes in @a a1 and @a a2
576 * @return 0 if @a a1 == @a a2.
577 */
578static int
579addrcmp_np (const struct sockaddr *a1,
580 const struct sockaddr *a2,
581 size_t alen)
582{
583 GNUNET_assert (a1->sa_family == a2->sa_family);
584 switch (a1->sa_family)
585 {
586 case AF_INET:
587 GNUNET_assert (sizeof (struct sockaddr_in) == alen);
588 {
589 const struct sockaddr_in *s1 = (const struct sockaddr_in *) a1;
590 const struct sockaddr_in *s2 = (const struct sockaddr_in *) a2;
591
592 if (s1->sin_addr.s_addr != s2->sin_addr.s_addr)
593 return 1;
594 break;
595 }
596 case AF_INET6:
597 GNUNET_assert (sizeof (struct sockaddr_in6) == alen);
598 {
599 const struct sockaddr_in6 *s1 = (const struct sockaddr_in6 *) a1;
600 const struct sockaddr_in6 *s2 = (const struct sockaddr_in6 *) a2;
601
602 if (0 != GNUNET_memcmp (&s1->sin6_addr,
603 &s2->sin6_addr))
604 return 1;
605 break;
606 }
607 default:
608 GNUNET_assert (0);
609 }
610 return 0;
611}
612
613
614/**
615 * Compare two addresses for equality. Only
616 * compares IP address and port. Must only be
617 * called on AF_INET or AF_INET6 addresses.
618 *
619 * @param a1 address to compare
620 * @param a2 address to compare
621 * @param alen number of bytes in @a a1 and @a a2
622 * @return 0 if @a a1 == @a a2.
623 */
624static int
625addrcmp (const struct sockaddr *a1,
626 const struct sockaddr *a2,
627 size_t alen)
628{
629 GNUNET_assert (a1->sa_family == a2->sa_family);
630 switch (a1->sa_family)
631 {
632 case AF_INET:
633 GNUNET_assert (sizeof (struct sockaddr_in) == alen);
634 {
635 const struct sockaddr_in *s1 = (const struct sockaddr_in *) a1;
636 const struct sockaddr_in *s2 = (const struct sockaddr_in *) a2;
637
638 if (s1->sin_port != s2->sin_port)
639 return 1;
640 if (s1->sin_addr.s_addr != s2->sin_addr.s_addr)
641 return 1;
642 break;
643 }
644 case AF_INET6:
645 GNUNET_assert (sizeof (struct sockaddr_in6) == alen);
646 {
647 const struct sockaddr_in6 *s1 = (const struct sockaddr_in6 *) a1;
648 const struct sockaddr_in6 *s2 = (const struct sockaddr_in6 *) a2;
649
650 if (s1->sin6_port != s2->sin6_port)
651 return 1;
652 if (0 != GNUNET_memcmp (&s1->sin6_addr,
653 &s2->sin6_addr))
654 return 1;
655 break;
656 }
657 default:
658 GNUNET_assert (0);
659 }
660 return 0;
661}
662
663
664/**
665 * Callback function invoked for each interface found.
666 *
667 * @param cls closure
668 * @param name name of the interface (can be NULL for unknown)
669 * @param isDefault is this presumably the default interface
670 * @param addr address of this interface (can be NULL for unknown or unassigned)
671 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
672 * @param netmask the network mask (can be NULL for unknown or unassigned)
673 * @param addrlen length of the address
674 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
675 */
676static enum GNUNET_GenericReturnValue
677process_ifcs (void *cls,
678 const char *name,
679 int isDefault,
680 const struct sockaddr *addr,
681 const struct sockaddr *broadcast_addr,
682 const struct sockaddr *netmask,
683 socklen_t addrlen)
684{
685 struct Plugin *plugin = cls;
686 struct GNUNET_DHTU_Source *src;
687
688 for (src = plugin->src_head;
689 NULL != src;
690 src = src->next)
691 {
692 if ( (addrlen == src->addrlen) &&
693 (0 == addrcmp_np (addr,
694 (const struct sockaddr *) &src->addr,
695 addrlen)) )
696 {
697 src->scan_generation = plugin->scan_generation;
698 return GNUNET_OK;
699 }
700 }
701 switch (addr->sa_family)
702 {
703 case AF_INET:
704 {
705 struct sockaddr_in v4;
706
707 GNUNET_assert (sizeof(v4) == addrlen);
708 memcpy (&v4,
709 addr,
710 addrlen);
711 v4.sin_port = htons (plugin->port16);
712 (void) create_source (plugin,
713 (const struct sockaddr *) &v4,
714 sizeof (v4));
715 break;
716 }
717 case AF_INET6:
718 {
719 struct sockaddr_in6 v6;
720
721 GNUNET_assert (sizeof(v6) == addrlen);
722 memcpy (&v6,
723 addr,
724 addrlen);
725 v6.sin6_port = htons (plugin->port16);
726 (void) create_source (plugin,
727 (const struct sockaddr *) &v6,
728 sizeof (v6));
729 break;
730 }
731 }
732 return GNUNET_OK;
733}
734
735
736/**
737 * Scan network interfaces for IP address changes.
738 *
739 * @param cls a `struct Plugin`
740 */
741static void
742scan (void *cls)
743{
744 struct Plugin *plugin = cls;
745 struct GNUNET_DHTU_Source *next;
746
747 plugin->scan_generation++;
748 GNUNET_OS_network_interfaces_list (&process_ifcs,
749 plugin);
750 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
751 NULL != src;
752 src = next)
753 {
754 next = src->next;
755 if (src->scan_generation >= plugin->scan_generation)
756 continue;
757 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
758 plugin->src_tail,
759 src);
760 plugin->env->address_del_cb (src->app_ctx);
761 GNUNET_free (src->address);
762 GNUNET_free (src);
763 }
764 plugin->scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
765 &scan,
766 plugin);
767}
768
769
770/**
771 * Find our source matching @a addr. If none exists,
772 * create one!
773 *
774 * @param plugin the plugin handle
775 * @param addr socket address to find
776 * @param addrlen number of bytes in @a addr
777 * @return matching source object
778 */
779static struct GNUNET_DHTU_Source *
780find_source (struct Plugin *plugin,
781 const void *addr,
782 size_t addrlen)
783{
784 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
785 NULL != src;
786 src = src->next)
787 {
788 if ( (addrlen == src->addrlen) &&
789 (0 == addrcmp (addr,
790 (const struct sockaddr *) &src->addr,
791 addrlen)) )
792 return src;
793 }
794
795 return create_source (plugin,
796 (const struct sockaddr *) addr,
797 addrlen);
798}
799
800
801/**
802 * UDP socket is ready to receive. Read.
803 *
804 * @param cls our `struct Plugin *`
805 */
806static void
807read_cb (void *cls)
808{
809 struct Plugin *plugin = cls;
810 ssize_t ret;
811 const struct GNUNET_PeerIdentity *pid;
812 char buf[65536] GNUNET_ALIGN;
813 struct sockaddr_storage sa;
814 struct iovec iov = {
815 .iov_base = buf,
816 .iov_len = sizeof (buf)
817 };
818 char ctl[128];
819 struct msghdr mh = {
820 .msg_name = &sa,
821 .msg_namelen = sizeof (sa),
822 .msg_iov = &iov,
823 .msg_iovlen = 1,
824 .msg_control = ctl,
825 .msg_controllen = sizeof (ctl)
826 };
827 struct GNUNET_DHTU_Target *dst = NULL;
828 struct GNUNET_DHTU_Source *src = NULL;
829
830 ret = recvmsg (GNUNET_NETWORK_get_fd (plugin->sock),
831 &mh,
832 MSG_DONTWAIT);
833 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
834 GNUNET_TIME_UNIT_FOREVER_REL,
835 plugin->sock,
836 &read_cb,
837 plugin);
838 if (ret < 0)
839 return; /* read failure, hopefully EAGAIN */
840 if (ret < sizeof (*pid))
841 {
842 GNUNET_break_op (0);
843 return;
844 }
845 /* find IP where we received message */
846 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mh);
847 NULL != cmsg;
848 cmsg = CMSG_NXTHDR (&mh,
849 cmsg))
850 {
851 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
852 "Got CMSG level %u (%d/%d), type %u (%d/%d)\n",
853 cmsg->cmsg_level,
854 (cmsg->cmsg_level == IPPROTO_IP),
855 (cmsg->cmsg_level == IPPROTO_IPV6),
856 cmsg->cmsg_type,
857 (cmsg->cmsg_type == IP_PKTINFO),
858 (cmsg->cmsg_type == IPV6_PKTINFO));
859 if ( (cmsg->cmsg_level == IPPROTO_IP) &&
860 (cmsg->cmsg_type == IP_PKTINFO) )
861 {
862 if (CMSG_LEN (sizeof (struct in_pktinfo)) ==
863 cmsg->cmsg_len)
864 {
865 struct in_pktinfo pi;
866
867 memcpy (&pi,
868 CMSG_DATA (cmsg),
869 sizeof (pi));
870 {
871 struct sockaddr_in sa = {
872 .sin_family = AF_INET,
873 .sin_addr = pi.ipi_addr,
874 .sin_port = htons (plugin->port16)
875 };
876
877 src = find_source (plugin,
878 &sa,
879 sizeof (sa));
880 /* For sources we discovered by reading,
881 force the generation far into the future */
882 src->scan_generation = plugin->scan_generation + 60;
883 }
884 break;
885 }
886 else
887 GNUNET_break (0);
888 }
889 if ( (cmsg->cmsg_level == IPPROTO_IPV6) &&
890 (cmsg->cmsg_type == IPV6_PKTINFO) )
891 {
892 if (CMSG_LEN (sizeof (struct in6_pktinfo)) ==
893 cmsg->cmsg_len)
894 {
895 struct in6_pktinfo pi;
896
897 memcpy (&pi,
898 CMSG_DATA (cmsg),
899 sizeof (pi));
900 {
901 struct sockaddr_in6 sa = {
902 .sin6_family = AF_INET6,
903 .sin6_addr = pi.ipi6_addr,
904 .sin6_port = htons (plugin->port16),
905 .sin6_scope_id = pi.ipi6_ifindex
906 };
907
908 src = find_source (plugin,
909 &sa,
910 sizeof (sa));
911 /* For sources we discovered by reading,
912 force the generation far into the future */
913 src->scan_generation = plugin->scan_generation + 60;
914 break;
915 }
916 }
917 else
918 GNUNET_break (0);
919 }
920 }
921 if (NULL == src)
922 {
923 GNUNET_break (0);
924 return;
925 }
926 pid = (const struct GNUNET_PeerIdentity *) buf;
927 dst = find_target (plugin,
928 pid,
929 &sa,
930 mh.msg_namelen);
931 if (NULL == dst)
932 {
933 GNUNET_break (0);
934 return;
935 }
936 plugin->env->receive_cb (plugin->env->cls,
937 &dst->app_ctx,
938 &src->app_ctx,
939 &buf[sizeof(*pid)],
940 ret - sizeof (*pid));
941}
942
943
944/**
945 * Entry point for the plugin.
946 *
947 * @param cls closure (the `struct GNUNET_DHTU_PluginEnvironment`)
948 * @return the plugin's API
949 */
950void *
951libgnunet_plugin_dhtu_ip_init (void *cls)
952{
953 struct GNUNET_DHTU_PluginEnvironment *env = cls;
954 struct GNUNET_DHTU_PluginFunctions *api;
955 struct Plugin *plugin;
956 char *port;
957 unsigned int nport;
958 int sock;
959 int af;
960 unsigned long long nse;
961
962 if (GNUNET_OK !=
963 GNUNET_CONFIGURATION_get_value_number (env->cfg,
964 "DHTU-IP",
965 "NSE",
966 &nse))
967 {
968 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
969 "DHTU-IP",
970 "NSE");
971 return NULL;
972 }
973 if (GNUNET_OK !=
974 GNUNET_CONFIGURATION_get_value_string (env->cfg,
975 "DHTU-IP",
976 "UDP_PORT",
977 &port))
978 {
979 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
980 "DHTU-IP",
981 "UDP_PORT");
982 return NULL;
983 }
984 {
985 char dummy;
986
987 if ( (1 != sscanf (port,
988 "%u%c",
989 &nport,
990 &dummy)) ||
991 (nport > UINT16_MAX) )
992 {
993 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
994 "DHTU-IP",
995 "UDP_PORT",
996 "must be number below 65536");
997 GNUNET_free (port);
998 return NULL;
999 }
1000 }
1001 plugin = GNUNET_new (struct Plugin);
1002 plugin->env = env;
1003 plugin->port = port;
1004 plugin->port16 = (uint16_t) nport;
1005 if (GNUNET_OK !=
1006 GNUNET_CRYPTO_get_peer_identity (env->cfg,
1007 &plugin->my_id))
1008 {
1009 GNUNET_free (plugin);
1010 return NULL;
1011 }
1012 af = AF_INET6;
1013 sock = socket (af,
1014 SOCK_DGRAM,
1015 IPPROTO_UDP);
1016 if (-1 == sock)
1017 {
1018 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1019 "socket");
1020 GNUNET_free (plugin->port);
1021 GNUNET_free (plugin);
1022 return NULL;
1023 }
1024 switch (af)
1025 {
1026 case AF_INET:
1027 {
1028 int on = 1;
1029
1030 if (0 !=
1031 setsockopt (sock,
1032 IPPROTO_IP,
1033 IP_PKTINFO,
1034 &on,
1035 sizeof (on)))
1036 {
1037 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1038 "setsockopt");
1039 }
1040 }
1041 {
1042 struct sockaddr_in sa = {
1043 .sin_family = AF_INET,
1044 .sin_port = htons ((uint16_t) nport)
1045 };
1046
1047 if (0 !=
1048 bind (sock,
1049 (const struct sockaddr *) &sa,
1050 sizeof (sa)))
1051 {
1052 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1053 "socket");
1054 GNUNET_break (0 ==
1055 close (sock));
1056 GNUNET_free (plugin->port);
1057 GNUNET_free (plugin);
1058 return NULL;
1059 }
1060 }
1061 break;
1062 case AF_INET6:
1063 {
1064 int on = 1;
1065
1066 if (0 !=
1067 setsockopt (sock,
1068 IPPROTO_IPV6,
1069 IPV6_RECVPKTINFO,
1070 &on,
1071 sizeof (on)))
1072 {
1073 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1074 "setsockopt");
1075 }
1076 }
1077 {
1078 struct sockaddr_in6 sa = {
1079 .sin6_family = AF_INET6,
1080 .sin6_port = htons ((uint16_t) nport)
1081 };
1082
1083 if (0 !=
1084 bind (sock,
1085 (const struct sockaddr *) &sa,
1086 sizeof (sa)))
1087 {
1088 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1089 "socket");
1090 GNUNET_break (0 ==
1091 close (sock));
1092 GNUNET_free (plugin->port);
1093 GNUNET_free (plugin);
1094 return NULL;
1095 }
1096 }
1097 break;
1098 }
1099 plugin->dsts = GNUNET_CONTAINER_multihashmap_create (128,
1100 GNUNET_NO);
1101 plugin->sock = GNUNET_NETWORK_socket_box_native (sock);
1102 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
1103 GNUNET_TIME_UNIT_FOREVER_REL,
1104 plugin->sock,
1105 &read_cb,
1106 plugin);
1107 env->network_size_cb (env->cls,
1108 GNUNET_TIME_UNIT_ZERO_ABS,
1109 log (nse) / log (2),
1110 -1.0 /* stddev */);
1111 plugin->scan_task = GNUNET_SCHEDULER_add_now (&scan,
1112 plugin);
1113 api = GNUNET_new (struct GNUNET_DHTU_PluginFunctions);
1114 api->cls = plugin;
1115 api->try_connect = &ip_try_connect;
1116 api->hold = &ip_hold;
1117 api->drop = &ip_drop;
1118 api->send = &ip_send;
1119 return api;
1120}
1121
1122
1123/**
1124 * Exit point from the plugin.
1125 *
1126 * @param cls closure (our `struct Plugin`)
1127 * @return NULL
1128 */
1129void *
1130libgnunet_plugin_dhtu_ip_done (void *cls)
1131{
1132 struct GNUNET_DHTU_PluginFunctions *api = cls;
1133 struct Plugin *plugin = api->cls;
1134 struct GNUNET_DHTU_Source *src;
1135 struct GNUNET_DHTU_Target *dst;
1136
1137 while (NULL != (dst = plugin->dst_head))
1138 {
1139 plugin->env->disconnect_cb (dst->app_ctx);
1140 GNUNET_assert (NULL == dst->ph_head);
1141 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
1142 plugin->dst_tail,
1143 dst);
1144 GNUNET_free (dst);
1145 }
1146 while (NULL != (src = plugin->src_head))
1147 {
1148 plugin->env->address_del_cb (src->app_ctx);
1149 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
1150 plugin->src_tail,
1151 src);
1152 GNUNET_free (src->address);
1153 GNUNET_free (src);
1154 }
1155 plugin->env->network_size_cb (plugin->env->cls,
1156 GNUNET_TIME_UNIT_FOREVER_ABS,
1157 0.0,
1158 0.0);
1159 GNUNET_CONTAINER_multihashmap_destroy (plugin->dsts);
1160 if (NULL != plugin->read_task)
1161 {
1162 GNUNET_SCHEDULER_cancel (plugin->read_task);
1163 plugin->read_task = NULL;
1164 }
1165 GNUNET_SCHEDULER_cancel (plugin->scan_task);
1166 GNUNET_break (GNUNET_OK ==
1167 GNUNET_NETWORK_socket_close (plugin->sock));
1168 GNUNET_free (plugin->port);
1169 GNUNET_free (plugin);
1170 GNUNET_free (api);
1171 return NULL;
1172}
diff --git a/src/dhtu/test_dhtu_ip.c b/src/dhtu/test_dhtu_ip.c
deleted file mode 100644
index 030b17b5f..000000000
--- a/src/dhtu/test_dhtu_ip.c
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 dhtu/test_dhtu_ip.c
23 * @brief Test case for the DHTU implementation for IP
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_testing_netjail_lib.h"
28#include "gnunet_util_lib.h"
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
31
32#define CONFIG_FILE "test_dhtu_ip.conf"
33
34
35int
36main (int argc,
37 char *const *argv)
38{
39 struct GNUNET_TESTING_Command commands[] = {
40 GNUNET_TESTING_cmd_end ()
41 };
42
43 return GNUNET_TESTING_main (commands,
44 TIMEOUT);
45}
diff --git a/src/dhtu/testing_dhtu_cmd_send.c b/src/dhtu/testing_dhtu_cmd_send.c
deleted file mode 100644
index fe8e1c18a..000000000
--- a/src/dhtu/testing_dhtu_cmd_send.c
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 testing/testing_dhtu_cmd_send.c
23 * @brief use DHTU to send a message
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29
30
31/**
32 * State for the 'send' command.
33 */
34struct SendState
35{
36
37 /**
38 * Mandatory context for async commands.
39 */
40 struct GNUNET_TESTING_AsyncContext ac;
41
42};
43
44
45/**
46 *
47 *
48 * @param cls a `struct SendState`
49 */
50static void
51send_cleanup (void *cls)
52{
53 struct SendState *ss = cls;
54
55 GNUNET_free (ss);
56}
57
58
59/**
60 * Return trains of the ``send`` command.
61 *
62 * @param cls closure.
63 * @param[out] ret result
64 * @param trait name of the trait.
65 * @param index index number of the object to offer.
66 * @return #GNUNET_OK on success.
67 * #GNUNET_NO if no trait was found
68 */
69static enum GNUNET_GenericReturnValue
70send_traits (void *cls,
71 const void **ret,
72 const char *trait,
73 unsigned int index)
74{
75 return GNUNET_NO;
76}
77
78
79/**
80 * Run the 'send' command.
81 *
82 * @param cls closure.
83 * @param is interpreter state.
84 */
85static void
86send_run (void *cls,
87 struct GNUNET_TESTING_Interpreter *is)
88{
89 struct SendState *ss = cls;
90
91#if 0
92 other_cmd = GNUNET_TESTING_interpreter_lookup_command (ss->other_label);
93 GNUNET_TESTING_get_trait_XXX (other_cmd,
94 &data);
95#endif
96 GNUNET_TESTING_async_finish (&ss->ac);
97}
98
99
100struct GNUNET_TESTING_Command
101GNUNET_TESTING_DHTU_cmd_send (const char *label)
102{
103 struct SendState *ss;
104
105 ss = GNUNET_new (struct SendState);
106
107 {
108 struct GNUNET_TESTING_Command cmd = {
109 .cls = ss,
110 .label = label,
111 .run = &send_run,
112 .ac = &ss->ac,
113 .cleanup = &send_cleanup,
114 .traits = &send_traits
115 };
116
117 return cmd;
118 }
119}