aboutsummaryrefslogtreecommitdiff
path: root/src/dhtu/plugin_dhtu_ip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhtu/plugin_dhtu_ip.c')
-rw-r--r--src/dhtu/plugin_dhtu_ip.c1076
1 files changed, 0 insertions, 1076 deletions
diff --git a/src/dhtu/plugin_dhtu_ip.c b/src/dhtu/plugin_dhtu_ip.c
deleted file mode 100644
index 8593a69ef..000000000
--- a/src/dhtu/plugin_dhtu_ip.c
+++ /dev/null
@@ -1,1076 +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_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://$IP:$PORT")
65 */
66 char *address;
67
68 /**
69 * Hash of the IP address.
70 */
71 struct GNUNET_DHTU_Hash id;
72
73 /**
74 * My actual address.
75 */
76 struct sockaddr_storage addr;
77
78 /**
79 * Number of bytes in @a addr.
80 */
81 socklen_t addrlen;
82
83 /**
84 * Last generation this address was observed.
85 */
86 unsigned int scan_generation;
87
88};
89
90
91/**
92 * Opaque handle that the underlay offers for the target peer when sending
93 * messages to another peer.
94 */
95struct GNUNET_DHTU_Target
96{
97
98 /**
99 * Kept in a DLL.
100 */
101 struct GNUNET_DHTU_Target *next;
102
103 /**
104 * Kept in a DLL.
105 */
106 struct GNUNET_DHTU_Target *prev;
107
108 /**
109 * Application context for this target.
110 */
111 void *app_ctx;
112
113 /**
114 * Hash of the IP address.
115 */
116 struct GNUNET_DHTU_Hash id;
117
118 /**
119 * Head of preferences expressed for this target.
120 */
121 struct GNUNET_DHTU_PreferenceHandle *ph_head;
122
123 /**
124 * Tail of preferences expressed for this target.
125 */
126 struct GNUNET_DHTU_PreferenceHandle *ph_tail;
127
128 /**
129 * Target IP address.
130 */
131 struct sockaddr_storage addr;
132
133 /**
134 * Number of bytes in @a addr.
135 */
136 socklen_t addrlen;
137
138 /**
139 * Preference counter, length of the @a ph_head DLL.
140 */
141 unsigned int ph_count;
142
143};
144
145/**
146 * Opaque handle expressing a preference of the DHT to
147 * keep a particular target connected.
148 */
149struct GNUNET_DHTU_PreferenceHandle
150{
151 /**
152 * Kept in a DLL.
153 */
154 struct GNUNET_DHTU_PreferenceHandle *next;
155
156 /**
157 * Kept in a DLL.
158 */
159 struct GNUNET_DHTU_PreferenceHandle *prev;
160
161 /**
162 * Target a preference was expressed for.
163 */
164 struct GNUNET_DHTU_Target *target;
165};
166
167
168/**
169 * Closure for all plugin functions.
170 */
171struct Plugin
172{
173 /**
174 * Callbacks into the DHT.
175 */
176 struct GNUNET_DHTU_PluginEnvironment *env;
177
178 /**
179 * Head of sources where we receive traffic.
180 */
181 struct GNUNET_DHTU_Source *src_head;
182
183 /**
184 * Tail of sources where we receive traffic.
185 */
186 struct GNUNET_DHTU_Source *src_tail;
187
188 /**
189 * Head of destinations that are active. Sorted by
190 * last use, with latest used at the head.
191 */
192 struct GNUNET_DHTU_Target *dst_head;
193
194 /**
195 * Tail of destinations that are active.
196 */
197 struct GNUNET_DHTU_Target *dst_tail;
198
199 /**
200 * Map from hashes of sockaddrs to targets.
201 */
202 struct GNUNET_CONTAINER_MultiHashMap *dsts;
203
204 /**
205 * Task that scans for IP address changes.
206 */
207 struct GNUNET_SCHEDULER_Task *scan_task;
208
209 /**
210 * Task that reads incoming UDP packets.
211 */
212 struct GNUNET_SCHEDULER_Task *read_task;
213
214 /**
215 * Port we bind to.
216 */
217 char *port;
218
219 /**
220 * How often have we scanned for IPs?
221 */
222 unsigned int scan_generation;
223
224 /**
225 * My UDP socket.
226 */
227 struct GNUNET_NETWORK_Handle *sock;
228};
229
230
231/**
232 * Use our private key to sign a message.
233 *
234 * @param cls closure
235 * @param pk our private key to sign with
236 * @param purpose what to sign
237 * @param[out] signature, allocated on heap and returned
238 * @return -1 on error, otherwise number of bytes in @a sig
239 */
240static ssize_t
241ip_sign (void *cls,
242 const struct GNUNET_DHTU_PrivateKey *pk,
243 const struct GNUNET_DHTU_SignaturePurpose *purpose,
244 void **sig)
245{
246 return 0;
247}
248
249
250/**
251 * Verify signature in @a sig over @a purpose.
252 *
253 * @param cls closure
254 * @param pk public key to verify signature of
255 * @param purpose what was being signed
256 * @param sig signature data
257 * @param sig_size number of bytes in @a sig
258 * @return #GNUNET_OK if signature is valid
259 * #GNUNET_NO if signatures are not supported
260 * #GNUNET_SYSERR if signature is invalid
261 */
262static enum GNUNET_GenericReturnValue
263ip_verify (void *cls,
264 const struct GNUNET_DHTU_PublicKey *pk,
265 const struct GNUNET_DHTU_SignaturePurpose *purpose,
266 const void *sig,
267 size_t sig_size)
268{
269 return GNUNET_NO;
270}
271
272
273/**
274 * Create a target to which we may send traffic.
275 *
276 * @param plugin our plugin
277 * @param addr target address
278 * @param addrlen number of bytes in @a addr
279 * @return new target object
280 */
281static struct GNUNET_DHTU_Target *
282create_target (struct Plugin *plugin,
283 const struct sockaddr *addr,
284 socklen_t addrlen)
285{
286 static struct GNUNET_DHTU_PublicKey pk;
287 struct GNUNET_DHTU_Target *dst;
288
289 if (MAX_DESTS >
290 GNUNET_CONTAINER_multihashmap_size (plugin->dsts))
291 {
292 struct GNUNET_HashCode key;
293
294 dst = NULL;
295 for (struct GNUNET_DHTU_Target *pos = plugin->dst_head;
296 NULL != pos;
297 pos = pos->next)
298 {
299 /* >= here assures we remove oldest entries first */
300 if ( (NULL == dst) ||
301 (dst->ph_count >= pos->ph_count) )
302 dst = pos;
303 }
304 GNUNET_assert (NULL != dst);
305 plugin->env->disconnect_cb (dst->app_ctx);
306 GNUNET_CRYPTO_hash (&dst->addr,
307 dst->addrlen,
308 &key);
309 GNUNET_assert (GNUNET_YES ==
310 GNUNET_CONTAINER_multihashmap_remove (plugin->dsts,
311 &key,
312 dst));
313 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
314 plugin->dst_tail,
315 dst);
316 GNUNET_assert (NULL == dst->ph_head);
317 GNUNET_free (dst);
318 }
319 pk.size = htons (sizeof (pk));
320 dst = GNUNET_new (struct GNUNET_DHTU_Target);
321 dst->addrlen = addrlen;
322 memcpy (&dst->addr,
323 addr,
324 addrlen);
325 switch (addr->sa_family)
326 {
327 case AF_INET:
328 {
329 const struct sockaddr_in *s4 = (const struct sockaddr_in *) addr;
330
331 GNUNET_assert (sizeof (struct sockaddr_in) == addrlen);
332 GNUNET_CRYPTO_hash (&s4->sin_addr,
333 sizeof (struct in_addr),
334 &dst->id.hc);
335 }
336 break;
337 case AF_INET6:
338 {
339 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) addr;
340
341 GNUNET_assert (sizeof (struct sockaddr_in6) == addrlen);
342 GNUNET_CRYPTO_hash (&s6->sin6_addr,
343 sizeof (struct in6_addr),
344 &dst->id.hc);
345 }
346 break;
347 default:
348 GNUNET_break (0);
349 GNUNET_free (dst);
350 return NULL;
351 }
352 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
353 plugin->dst_tail,
354 dst);
355 plugin->env->connect_cb (plugin->env->cls,
356 &pk,
357 &dst->id,
358 dst,
359 &dst->app_ctx);
360 return dst;
361}
362
363
364/**
365 * Find target matching @a addr. If none exists,
366 * create one!
367 *
368 * @param plugin the plugin handle
369 * @param src source target is from, or NULL if unknown
370 * @param addr socket address to find
371 * @param addrlen number of bytes in @a addr
372 * @return matching target object
373 */
374static struct GNUNET_DHTU_Target *
375find_target (struct Plugin *plugin,
376 const void *addr,
377 size_t addrlen)
378{
379 struct GNUNET_HashCode key;
380 struct GNUNET_DHTU_Target *dst;
381
382 GNUNET_CRYPTO_hash (addr,
383 addrlen,
384 &key);
385 dst = GNUNET_CONTAINER_multihashmap_get (plugin->dsts,
386 &key);
387 if (NULL == dst)
388 {
389 dst = create_target (plugin,
390 (const struct sockaddr *) addr,
391 addrlen);
392 GNUNET_assert (GNUNET_YES ==
393 GNUNET_CONTAINER_multihashmap_put (
394 plugin->dsts,
395 &key,
396 dst,
397 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
398 }
399 else
400 {
401 /* move to head of DLL */
402 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
403 plugin->dst_tail,
404 dst);
405 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
406 plugin->dst_tail,
407 dst);
408
409 }
410 return dst;
411}
412
413
414/**
415 * Request creation of a session with a peer at the given @a address.
416 *
417 * @param cls closure (internal context for the plugin)
418 * @param address target address to connect to
419 */
420static void
421ip_try_connect (void *cls,
422 const char *address)
423{
424 struct Plugin *plugin = cls;
425 char *colon;
426 const char *port;
427 char *addr;
428 struct addrinfo hints = {
429 .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV
430 };
431 struct addrinfo *result = NULL;
432
433 if (0 !=
434 strncmp (address,
435 "ip+",
436 strlen ("ip+")))
437 {
438 GNUNET_break (0);
439 return;
440 }
441 address += strlen ("ip+");
442 if (0 !=
443 strncmp (address,
444 "udp://",
445 strlen ("udp://")))
446 {
447 GNUNET_break (0);
448 return;
449 }
450 address += strlen ("udp://");
451 addr = GNUNET_strdup (address);
452 colon = strchr (addr, ':');
453 if (NULL == colon)
454 {
455 port = plugin->port;
456 }
457 else
458 {
459 *colon = '\0';
460 port = colon + 1;
461 }
462 if (0 !=
463 getaddrinfo (addr,
464 port,
465 &hints,
466 &result))
467 {
468 GNUNET_break (0);
469 GNUNET_free (addr);
470 return;
471 }
472 GNUNET_free (addr);
473 (void) find_target (plugin,
474 result->ai_addr,
475 result->ai_addrlen);
476 freeaddrinfo (result);
477}
478
479
480/**
481 * Request underlay to keep the connection to @a target alive if possible.
482 * Hold may be called multiple times to express a strong preference to
483 * keep a connection, say because a @a target is in multiple tables.
484 *
485 * @param cls closure
486 * @param target connection to keep alive
487 */
488static struct GNUNET_DHTU_PreferenceHandle *
489ip_hold (void *cls,
490 struct GNUNET_DHTU_Target *target)
491{
492 struct GNUNET_DHTU_PreferenceHandle *ph;
493
494 ph = GNUNET_new (struct GNUNET_DHTU_PreferenceHandle);
495 ph->target = target;
496 GNUNET_CONTAINER_DLL_insert (target->ph_head,
497 target->ph_tail,
498 ph);
499 target->ph_count++;
500 return ph;
501}
502
503
504/**
505 * Do no long request underlay to keep the connection alive.
506 *
507 * @param cls closure
508 * @param target connection to keep alive
509 */
510static void
511ip_drop (struct GNUNET_DHTU_PreferenceHandle *ph)
512{
513 struct GNUNET_DHTU_Target *target = ph->target;
514
515 GNUNET_CONTAINER_DLL_remove (target->ph_head,
516 target->ph_tail,
517 ph);
518 target->ph_count--;
519 GNUNET_free (ph);
520}
521
522
523/**
524 * Send message to some other participant over the network. Note that
525 * sending is not guaranteeing that the other peer actually received the
526 * message. For any given @a target, the DHT must wait for the @a
527 * finished_cb to be called before calling send() again.
528 *
529 * @param cls closure (internal context for the plugin)
530 * @param target receiver identification
531 * @param msg message
532 * @param msg_size number of bytes in @a msg
533 * @param finished_cb function called once transmission is done
534 * (not called if @a target disconnects, then only the
535 * disconnect_cb is called).
536 * @param finished_cb_cls closure for @a finished_cb
537 */
538static void
539ip_send (void *cls,
540 struct GNUNET_DHTU_Target *target,
541 const void *msg,
542 size_t msg_size,
543 GNUNET_SCHEDULER_TaskCallback finished_cb,
544 void *finished_cb_cls)
545{
546 struct Plugin *plugin = cls;
547
548 GNUNET_NETWORK_socket_sendto (plugin->sock,
549 msg,
550 msg_size,
551 (const struct sockaddr *) &target->addr,
552 target->addrlen);
553 finished_cb (finished_cb_cls);
554}
555
556
557/**
558 * Create a new source on which we may be receiving traffic.
559 *
560 * @param plugin our plugin
561 * @param addr our address
562 * @param addrlen number of bytes in @a addr
563 * @return new source object
564 */
565static struct GNUNET_DHTU_Source *
566create_source (struct Plugin *plugin,
567 const struct sockaddr *addr,
568 socklen_t addrlen)
569{
570 struct GNUNET_DHTU_Source *src;
571
572 src = GNUNET_new (struct GNUNET_DHTU_Source);
573 src->addrlen = addrlen;
574 memcpy (&src->addr,
575 addr,
576 addrlen);
577 src->scan_generation = plugin->scan_generation;
578 switch (addr->sa_family)
579 {
580 case AF_INET:
581 {
582 const struct sockaddr_in *s4 = (const struct sockaddr_in *) addr;
583 char buf[INET_ADDRSTRLEN];
584
585 GNUNET_assert (sizeof (struct sockaddr_in) == addrlen);
586 GNUNET_CRYPTO_hash (&s4->sin_addr,
587 sizeof (struct in_addr),
588 &src->id.hc);
589 GNUNET_asprintf (&src->address,
590 "ip+udp://%s:%u",
591 inet_ntop (AF_INET,
592 &s4->sin_addr,
593 buf,
594 sizeof (buf)),
595 ntohs (s4->sin_port));
596 }
597 break;
598 case AF_INET6:
599 {
600 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) addr;
601 char buf[INET6_ADDRSTRLEN];
602
603 GNUNET_assert (sizeof (struct sockaddr_in6) == addrlen);
604 GNUNET_CRYPTO_hash (&s6->sin6_addr,
605 sizeof (struct in6_addr),
606 &src->id.hc);
607 GNUNET_asprintf (&src->address,
608 "ip+udp://[%s]:%u",
609 inet_ntop (AF_INET6,
610 &s6->sin6_addr,
611 buf,
612 sizeof (buf)),
613 ntohs (s6->sin6_port));
614 }
615 break;
616 default:
617 GNUNET_break (0);
618 GNUNET_free (src);
619 return NULL;
620 }
621 GNUNET_CONTAINER_DLL_insert (plugin->src_head,
622 plugin->src_tail,
623 src);
624 plugin->env->address_add_cb (plugin->env->cls,
625 &src->id,
626 NULL, /* no key */
627 src->address,
628 src,
629 &src->app_ctx);
630 return src;
631}
632
633
634/**
635 * Callback function invoked for each interface found.
636 *
637 * @param cls closure
638 * @param name name of the interface (can be NULL for unknown)
639 * @param isDefault is this presumably the default interface
640 * @param addr address of this interface (can be NULL for unknown or unassigned)
641 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
642 * @param netmask the network mask (can be NULL for unknown or unassigned)
643 * @param addrlen length of the address
644 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
645 */
646static int
647process_ifcs (void *cls,
648 const char *name,
649 int isDefault,
650 const struct sockaddr *addr,
651 const struct sockaddr *broadcast_addr,
652 const struct sockaddr *netmask,
653 socklen_t addrlen)
654{
655 struct Plugin *plugin = cls;
656 struct GNUNET_DHTU_Source *src;
657
658 for (src = plugin->src_head;
659 NULL != src;
660 src = src->next)
661 {
662 if ( (addrlen == src->addrlen) &&
663 (0 == memcmp (addr,
664 &src->addr,
665 addrlen)) )
666 {
667 src->scan_generation = plugin->scan_generation;
668 return GNUNET_OK;
669 }
670 }
671 (void) create_source (plugin,
672 addr,
673 addrlen);
674 return GNUNET_OK;
675}
676
677
678/**
679 * Scan network interfaces for IP address changes.
680 *
681 * @param cls a `struct Plugin`
682 */
683static void
684scan (void *cls)
685{
686 struct Plugin *plugin = cls;
687 struct GNUNET_DHTU_Source *next;
688
689 plugin->scan_generation++;
690 GNUNET_OS_network_interfaces_list (&process_ifcs,
691 plugin);
692 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
693 NULL != src;
694 src = next)
695 {
696 next = src->next;
697 if (src->scan_generation == plugin->scan_generation)
698 continue;
699 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
700 plugin->src_tail,
701 src);
702 plugin->env->address_del_cb (src->app_ctx);
703 GNUNET_free (src->address);
704 GNUNET_free (src);
705 }
706 plugin->scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
707 &scan,
708 plugin);
709}
710
711
712/**
713 * Find our source matching @a addr. If none exists,
714 * create one!
715 *
716 * @param plugin the plugin handle
717 * @param addr socket address to find
718 * @param addrlen number of bytes in @a addr
719 * @return matching source object
720 */
721static struct GNUNET_DHTU_Source *
722find_source (struct Plugin *plugin,
723 const void *addr,
724 size_t addrlen)
725{
726 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
727 NULL != src;
728 src = src->next)
729 {
730 if ( (addrlen == src->addrlen) &&
731 (0 == memcmp (addr,
732 &src->addr,
733 addrlen)) )
734 return src;
735 }
736
737 return create_source (plugin,
738 (const struct sockaddr *) addr,
739 addrlen);
740}
741
742
743/**
744 * UDP socket is ready to receive. Read.
745 *
746 * @param cls our `struct Plugin *`
747 */
748static void
749read_cb (void *cls)
750{
751 struct Plugin *plugin = cls;
752 ssize_t ret;
753 char buf[65536];
754 struct sockaddr_storage sa;
755 struct iovec iov = {
756 .iov_base = buf,
757 .iov_len = sizeof (buf)
758 };
759 char ctl[128];
760 struct msghdr mh = {
761 .msg_name = &sa,
762 .msg_namelen = sizeof (sa),
763 .msg_iov = &iov,
764 .msg_iovlen = 1,
765 .msg_control = ctl,
766 .msg_controllen = sizeof (ctl)
767 };
768
769 ret = recvmsg (GNUNET_NETWORK_get_fd (plugin->sock),
770 &mh,
771 MSG_DONTWAIT);
772 if (ret >= 0)
773 {
774 struct GNUNET_DHTU_Target *dst = NULL;
775 struct GNUNET_DHTU_Source *src = NULL;
776 struct cmsghdr *cmsg;
777
778 /* find IP where we received message */
779 for (cmsg = CMSG_FIRSTHDR (&mh);
780 NULL != cmsg;
781 cmsg = CMSG_NXTHDR (&mh,
782 cmsg))
783 {
784 if ( (cmsg->cmsg_level == IPPROTO_IP) &&
785 (cmsg->cmsg_type == IP_PKTINFO) )
786 {
787 if (CMSG_LEN (sizeof (struct in_pktinfo)) ==
788 cmsg->cmsg_len)
789 {
790 struct in_pktinfo pi;
791
792 memcpy (&pi,
793 CMSG_DATA (cmsg),
794 sizeof (pi));
795 {
796 struct sockaddr_in sa = {
797 .sin_family = AF_INET,
798 .sin_addr = pi.ipi_addr
799 };
800
801 src = find_source (plugin,
802 &sa,
803 sizeof (sa));
804 }
805 break;
806 }
807 else
808 GNUNET_break (0);
809 }
810 if ( (cmsg->cmsg_level == IPPROTO_IPV6) &&
811 (cmsg->cmsg_type == IPV6_RECVPKTINFO) )
812 {
813 if (CMSG_LEN (sizeof (struct in6_pktinfo)) ==
814 cmsg->cmsg_len)
815 {
816 struct in6_pktinfo pi;
817
818 memcpy (&pi,
819 CMSG_DATA (cmsg),
820 sizeof (pi));
821 {
822 struct sockaddr_in6 sa = {
823 .sin6_family = AF_INET6,
824 .sin6_addr = pi.ipi6_addr,
825 .sin6_scope_id = pi.ipi6_ifindex
826 };
827
828 src = find_source (plugin,
829 &sa,
830 sizeof (sa));
831 break;
832 }
833 }
834 else
835 GNUNET_break (0);
836 }
837 }
838 dst = find_target (plugin,
839 &sa,
840 mh.msg_namelen);
841 if ( (NULL == src) ||
842 (NULL == dst) )
843 {
844 GNUNET_break (0);
845 }
846 else
847 {
848 plugin->env->receive_cb (plugin->env->cls,
849 dst->app_ctx,
850 src->app_ctx,
851 buf,
852 ret);
853 }
854 }
855 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
856 GNUNET_TIME_UNIT_FOREVER_REL,
857 plugin->sock,
858 &read_cb,
859 plugin);
860}
861
862
863/**
864 * Entry point for the plugin.
865 *
866 * @param cls closure (the `struct GNUNET_DHTU_PluginEnvironment`)
867 * @return the plugin's API
868 */
869void *
870libgnunet_plugin_dhtu_ip_init (void *cls)
871{
872 struct GNUNET_DHTU_PluginEnvironment *env = cls;
873 struct GNUNET_DHTU_PluginFunctions *api;
874 struct Plugin *plugin;
875 char *port;
876 unsigned int nport;
877 int sock;
878 int af;
879 unsigned long long nse;
880
881 if (GNUNET_OK !=
882 GNUNET_CONFIGURATION_get_value_number (env->cfg,
883 "DHTU-IP",
884 "NSE",
885 &nse))
886 {
887 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
888 "DHTU-IP",
889 "NSE");
890 return NULL;
891 }
892 if (GNUNET_OK !=
893 GNUNET_CONFIGURATION_get_value_string (env->cfg,
894 "DHTU-IP",
895 "UDP_PORT",
896 &port))
897 {
898 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
899 "DHTU-IP",
900 "UDP_PORT");
901 return NULL;
902 }
903 {
904 char dummy;
905
906 if ( (1 != sscanf (port,
907 "%u%c",
908 &nport,
909 &dummy)) ||
910 (nport > UINT16_MAX) )
911 {
912 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
913 "DHTU-IP",
914 "UDP_PORT",
915 "must be number below 65536");
916 GNUNET_free (port);
917 return NULL;
918 }
919 }
920 plugin = GNUNET_new (struct Plugin);
921 plugin->env = env;
922 plugin->port = port;
923 af = AF_INET6;
924 sock = socket (af,
925 SOCK_DGRAM,
926 IPPROTO_UDP);
927 if (-1 == sock)
928 {
929 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
930 "socket");
931 GNUNET_free (plugin->port);
932 GNUNET_free (plugin);
933 return NULL;
934 }
935 switch (af)
936 {
937 case AF_INET:
938 {
939 int on = 1;
940
941 if (0 !=
942 setsockopt (sock,
943 IPPROTO_IP,
944 IP_PKTINFO,
945 &on,
946 sizeof (on)))
947 {
948 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
949 "setsockopt");
950 }
951 }
952 {
953 struct sockaddr_in sa = {
954 .sin_family = AF_INET,
955 .sin_port = htons ((uint16_t) nport)
956 };
957
958 if (0 !=
959 bind (sock,
960 (const struct sockaddr *) &sa,
961 sizeof (sa)))
962 {
963 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
964 "socket");
965 GNUNET_break (0 ==
966 close (sock));
967 GNUNET_free (plugin->port);
968 GNUNET_free (plugin);
969 return NULL;
970 }
971 }
972 break;
973 case AF_INET6:
974 {
975 int on = 1;
976
977 if (0 !=
978 setsockopt (sock,
979 IPPROTO_IPV6,
980 IPV6_RECVPKTINFO,
981 &on,
982 sizeof (on)))
983 {
984 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
985 "setsockopt");
986 }
987 }
988 {
989 struct sockaddr_in6 sa = {
990 .sin6_family = AF_INET6,
991 .sin6_port = htons ((uint16_t) nport)
992 };
993
994 if (0 !=
995 bind (sock,
996 (const struct sockaddr *) &sa,
997 sizeof (sa)))
998 {
999 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1000 "socket");
1001 GNUNET_break (0 ==
1002 close (sock));
1003 GNUNET_free (plugin->port);
1004 GNUNET_free (plugin);
1005 return NULL;
1006 }
1007 }
1008 break;
1009 }
1010 plugin->dsts = GNUNET_CONTAINER_multihashmap_create (128,
1011 GNUNET_NO);
1012 plugin->sock = GNUNET_NETWORK_socket_box_native (sock);
1013 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
1014 GNUNET_TIME_UNIT_FOREVER_REL,
1015 plugin->sock,
1016 &read_cb,
1017 plugin);
1018 env->network_size_cb (env->cls,
1019 GNUNET_TIME_UNIT_ZERO_ABS,
1020 log (nse) / log (2),
1021 -1.0 /* stddev */);
1022 plugin->scan_task = GNUNET_SCHEDULER_add_now (&scan,
1023 plugin);
1024 api = GNUNET_new (struct GNUNET_DHTU_PluginFunctions);
1025 api->cls = plugin;
1026 api->sign = &ip_sign;
1027 api->verify = &ip_verify;
1028 api->try_connect = &ip_try_connect;
1029 api->hold = &ip_hold;
1030 api->drop = &ip_drop;
1031 api->send = &ip_send;
1032 return api;
1033}
1034
1035
1036/**
1037 * Exit point from the plugin.
1038 *
1039 * @param cls closure (our `struct Plugin`)
1040 * @return NULL
1041 */
1042void *
1043libgnunet_plugin_dhtu_ip_done (void *cls)
1044{
1045 struct GNUNET_DHTU_PluginFunctions *api = cls;
1046 struct Plugin *plugin = api->cls;
1047 struct GNUNET_DHTU_Source *src;
1048 struct GNUNET_DHTU_Target *dst;
1049
1050 while (NULL != (dst = plugin->dst_head))
1051 {
1052 plugin->env->disconnect_cb (dst->app_ctx);
1053 GNUNET_assert (NULL == dst->ph_head);
1054 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
1055 plugin->dst_tail,
1056 dst);
1057 GNUNET_free (dst);
1058 }
1059 while (NULL != (src = plugin->src_head))
1060 {
1061 plugin->env->address_del_cb (src->app_ctx);
1062 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
1063 plugin->src_tail,
1064 src);
1065 GNUNET_free (src->address);
1066 GNUNET_free (src);
1067 }
1068 GNUNET_CONTAINER_multihashmap_destroy (plugin->dsts);
1069 GNUNET_SCHEDULER_cancel (plugin->scan_task);
1070 GNUNET_break (0 ==
1071 GNUNET_NETWORK_socket_close (plugin->sock));
1072 GNUNET_free (plugin->port);
1073 GNUNET_free (plugin);
1074 GNUNET_free (api);
1075 return NULL;
1076}