aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_xu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/plugin_transport_xu.c')
-rw-r--r--src/transport/plugin_transport_xu.c2492
1 files changed, 0 insertions, 2492 deletions
diff --git a/src/transport/plugin_transport_xu.c b/src/transport/plugin_transport_xu.c
deleted file mode 100644
index b716c6878..000000000
--- a/src/transport/plugin_transport_xu.c
+++ /dev/null
@@ -1,2492 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-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/**
22 * @file transport/plugin_transport_xu.c
23 * @brief Implementation of the XU transport protocol
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Matthias Wachs
27 */
28#include "platform.h"
29#include "plugin_transport_xu.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_fragmentation_lib.h"
33#include "gnunet_nat_service.h"
34#include "gnunet_protocols.h"
35#include "gnunet_resolver_service.h"
36#include "gnunet_signatures.h"
37#include "gnunet_constants.h"
38#include "gnunet_statistics_service.h"
39#include "gnunet_transport_service.h"
40#include "gnunet_transport_plugin.h"
41#include "transport.h"
42
43#define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__)
44
45/**
46 * After how much inactivity should a XU session time out?
47 */
48#define XU_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
49
50
51/**
52 * XU Message-Packet header (after defragmentation).
53 */
54struct XUMessage
55{
56 /**
57 * Message header.
58 */
59 struct GNUNET_MessageHeader header;
60
61 /**
62 * Always zero for now.
63 */
64 uint32_t reserved;
65
66 /**
67 * What is the identity of the sender
68 */
69 struct GNUNET_PeerIdentity sender;
70
71};
72
73
74/**
75 * Closure for #append_port().
76 */
77struct PrettyPrinterContext
78{
79 /**
80 * DLL
81 */
82 struct PrettyPrinterContext *next;
83
84 /**
85 * DLL
86 */
87 struct PrettyPrinterContext *prev;
88
89 /**
90 * Our plugin.
91 */
92 struct Plugin *plugin;
93
94 /**
95 * Resolver handle
96 */
97 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
98
99 /**
100 * Function to call with the result.
101 */
102 GNUNET_TRANSPORT_AddressStringCallback asc;
103
104 /**
105 * Clsoure for @e asc.
106 */
107 void *asc_cls;
108
109 /**
110 * Timeout task
111 */
112 struct GNUNET_SCHEDULER_Task *timeout_task;
113
114 /**
115 * Is this an IPv6 address?
116 */
117 int ipv6;
118
119 /**
120 * Options
121 */
122 uint32_t options;
123
124 /**
125 * Port to add after the IP address.
126 */
127 uint16_t port;
128
129};
130
131
132/**
133 * Session with another peer.
134 */
135struct GNUNET_ATS_Session
136{
137 /**
138 * Which peer is this session for?
139 */
140 struct GNUNET_PeerIdentity target;
141
142 /**
143 * Tokenizer for inbound messages.
144 */
145 struct GNUNET_MessageStreamTokenizer *mst;
146
147 /**
148 * Plugin this session belongs to.
149 */
150 struct Plugin *plugin;
151
152 /**
153 * Session timeout task
154 */
155 struct GNUNET_SCHEDULER_Task *timeout_task;
156
157 /**
158 * When does this session time out?
159 */
160 struct GNUNET_TIME_Absolute timeout;
161
162 /**
163 * What time did we last transmit?
164 */
165 struct GNUNET_TIME_Absolute last_transmit_time;
166
167 /**
168 * expected delay for ACKs
169 */
170 struct GNUNET_TIME_Relative last_expected_ack_delay;
171
172 /**
173 * desired delay between XU messages
174 */
175 struct GNUNET_TIME_Relative last_expected_msg_delay;
176
177 /**
178 */
179 struct GNUNET_TIME_Relative flow_delay_for_other_peer;
180 struct GNUNET_TIME_Relative flow_delay_from_other_peer;
181
182 /**
183 * Our own address.
184 */
185 struct GNUNET_HELLO_Address *address;
186
187 /**
188 * Number of bytes waiting for transmission to this peer.
189 */
190 unsigned long long bytes_in_queue;
191
192 /**
193 * Number of messages waiting for transmission to this peer.
194 */
195 unsigned int msgs_in_queue;
196
197 /**
198 * Reference counter to indicate that this session is
199 * currently being used and must not be destroyed;
200 * setting @e in_destroy will destroy it as soon as
201 * possible.
202 */
203 unsigned int rc;
204
205 /**
206 * Network type of the address.
207 */
208 enum GNUNET_NetworkType scope;
209
210 /**
211 * Is this session about to be destroyed (sometimes we cannot
212 * destroy a session immediately as below us on the stack
213 * there might be code that still uses it; in this case,
214 * @e rc is non-zero).
215 */
216 int in_destroy;
217};
218
219
220
221/**
222 * If a session monitor is attached, notify it about the new
223 * session state.
224 *
225 * @param plugin our plugin
226 * @param session session that changed state
227 * @param state new state of the session
228 */
229static void
230notify_session_monitor (struct Plugin *plugin,
231 struct GNUNET_ATS_Session *session,
232 enum GNUNET_TRANSPORT_SessionState state)
233{
234 struct GNUNET_TRANSPORT_SessionInfo info;
235
236 if (NULL == plugin->sic)
237 return;
238 if (GNUNET_YES == session->in_destroy)
239 return; /* already destroyed, just RC>0 left-over actions */
240 memset (&info,
241 0,
242 sizeof (info));
243 info.state = state;
244 info.is_inbound = GNUNET_SYSERR; /* hard to say */
245 info.num_msg_pending = session->msgs_in_queue;
246 info.num_bytes_pending = session->bytes_in_queue;
247 /* info.receive_delay remains zero as this is not supported by XU
248 (cannot selectively not receive from 'some' peer while continuing
249 to receive from others) */
250 info.session_timeout = session->timeout;
251 info.address = session->address;
252 plugin->sic (plugin->sic_cls,
253 session,
254 &info);
255}
256
257
258/**
259 * Return information about the given session to the monitor callback.
260 *
261 * @param cls the `struct Plugin` with the monitor callback (`sic`)
262 * @param peer peer we send information about
263 * @param value our `struct GNUNET_ATS_Session` to send information about
264 * @return #GNUNET_OK (continue to iterate)
265 */
266static int
267send_session_info_iter (void *cls,
268 const struct GNUNET_PeerIdentity *peer,
269 void *value)
270{
271 struct Plugin *plugin = cls;
272 struct GNUNET_ATS_Session *session = value;
273
274 (void) peer;
275 notify_session_monitor (plugin,
276 session,
277 GNUNET_TRANSPORT_SS_INIT);
278 notify_session_monitor (plugin,
279 session,
280 GNUNET_TRANSPORT_SS_UP);
281 return GNUNET_OK;
282}
283
284
285/**
286 * Begin monitoring sessions of a plugin. There can only
287 * be one active monitor per plugin (i.e. if there are
288 * multiple monitors, the transport service needs to
289 * multiplex the generated events over all of them).
290 *
291 * @param cls closure of the plugin
292 * @param sic callback to invoke, NULL to disable monitor;
293 * plugin will being by iterating over all active
294 * sessions immediately and then enter monitor mode
295 * @param sic_cls closure for @a sic
296 */
297static void
298xu_plugin_setup_monitor (void *cls,
299 GNUNET_TRANSPORT_SessionInfoCallback sic,
300 void *sic_cls)
301{
302 struct Plugin *plugin = cls;
303
304 plugin->sic = sic;
305 plugin->sic_cls = sic_cls;
306 if (NULL != sic)
307 {
308 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
309 &send_session_info_iter,
310 plugin);
311 /* signal end of first iteration */
312 sic (sic_cls,
313 NULL,
314 NULL);
315 }
316}
317
318
319/* ****************** Little Helpers ****************** */
320
321
322/**
323 * Function to free last resources associated with a session.
324 *
325 * @param s session to free
326 */
327static void
328free_session (struct GNUNET_ATS_Session *s)
329{
330 if (NULL != s->address)
331 {
332 GNUNET_HELLO_address_free (s->address);
333 s->address = NULL;
334 }
335 if (NULL != s->mst)
336 {
337 GNUNET_MST_destroy (s->mst);
338 s->mst = NULL;
339 }
340 GNUNET_free (s);
341}
342
343
344/**
345 * Function that is called to get the keepalive factor.
346 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
347 * calculate the interval between keepalive packets.
348 *
349 * @param cls closure with the `struct Plugin`
350 * @return keepalive factor
351 */
352static unsigned int
353xu_query_keepalive_factor (void *cls)
354{
355 (void) cls;
356 return 15;
357}
358
359
360/**
361 * Function obtain the network type for a session
362 *
363 * @param cls closure (`struct Plugin *`)
364 * @param session the session
365 * @return the network type
366 */
367static enum GNUNET_NetworkType
368xu_plugin_get_network (void *cls,
369 struct GNUNET_ATS_Session *session)
370{
371 (void) cls;
372 return session->scope;
373}
374
375
376/**
377 * Function obtain the network type for an address.
378 *
379 * @param cls closure (`struct Plugin *`)
380 * @param address the address
381 * @return the network type
382 */
383static enum GNUNET_NetworkType
384xu_plugin_get_network_for_address (void *cls,
385 const struct GNUNET_HELLO_Address *address)
386{
387 struct Plugin *plugin = cls;
388 size_t addrlen;
389 struct sockaddr_in a4;
390 struct sockaddr_in6 a6;
391 const struct IPv4XuAddress *u4;
392 const struct IPv6XuAddress *u6;
393 const void *sb;
394 size_t sbs;
395
396 addrlen = address->address_length;
397 if (addrlen == sizeof(struct IPv6XuAddress))
398 {
399 GNUNET_assert (NULL != address->address); /* make static analysis happy */
400 u6 = address->address;
401 memset (&a6, 0, sizeof(a6));
402#if HAVE_SOCKADDR_IN_SIN_LEN
403 a6.sin6_len = sizeof (a6);
404#endif
405 a6.sin6_family = AF_INET6;
406 a6.sin6_port = u6->u6_port;
407 GNUNET_memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr));
408 sb = &a6;
409 sbs = sizeof(a6);
410 }
411 else if (addrlen == sizeof(struct IPv4XuAddress))
412 {
413 GNUNET_assert (NULL != address->address); /* make static analysis happy */
414 u4 = address->address;
415 memset (&a4, 0, sizeof(a4));
416#if HAVE_SOCKADDR_IN_SIN_LEN
417 a4.sin_len = sizeof (a4);
418#endif
419 a4.sin_family = AF_INET;
420 a4.sin_port = u4->u4_port;
421 a4.sin_addr.s_addr = u4->ipv4_addr;
422 sb = &a4;
423 sbs = sizeof(a4);
424 }
425 else
426 {
427 GNUNET_break (0);
428 return GNUNET_NT_UNSPECIFIED;
429 }
430 return plugin->env->get_address_type (plugin->env->cls,
431 sb,
432 sbs);
433}
434
435
436/* ******************* Event loop ******************** */
437
438/**
439 * We have been notified that our readset has something to read. We don't
440 * know which socket needs to be read, so we have to check each one
441 * Then reschedule this function to be called again once more is available.
442 *
443 * @param cls the plugin handle
444 */
445static void
446xu_plugin_select_v4 (void *cls);
447
448
449/**
450 * We have been notified that our readset has something to read. We don't
451 * know which socket needs to be read, so we have to check each one
452 * Then reschedule this function to be called again once more is available.
453 *
454 * @param cls the plugin handle
455 */
456static void
457xu_plugin_select_v6 (void *cls);
458
459
460/**
461 * (re)schedule IPv4-select tasks for this plugin.
462 *
463 * @param plugin plugin to reschedule
464 */
465static void
466schedule_select_v4 (struct Plugin *plugin)
467{
468 if ( (GNUNET_YES != plugin->enable_ipv4) ||
469 (NULL == plugin->sockv4) )
470 return;
471 if (NULL != plugin->select_task_v4)
472 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
473 plugin->select_task_v4
474 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
475 plugin->sockv4,
476 &xu_plugin_select_v4,
477 plugin);
478}
479
480
481/**
482 * (re)schedule IPv6-select tasks for this plugin.
483 *
484 * @param plugin plugin to reschedule
485 */
486static void
487schedule_select_v6 (struct Plugin *plugin)
488{
489 if ( (GNUNET_YES != plugin->enable_ipv6) ||
490 (NULL == plugin->sockv6) )
491 return;
492 if (NULL != plugin->select_task_v6)
493 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
494 plugin->select_task_v6
495 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
496 plugin->sockv6,
497 &xu_plugin_select_v6,
498 plugin);
499}
500
501
502/* ******************* Address to string and back ***************** */
503
504
505/**
506 * Function called for a quick conversion of the binary address to
507 * a numeric address. Note that the caller must not free the
508 * address and that the next call to this function is allowed
509 * to override the address again.
510 *
511 * @param cls closure
512 * @param addr binary address (a `union XuAddress`)
513 * @param addrlen length of the @a addr
514 * @return string representing the same address
515 */
516const char *
517xu_address_to_string (void *cls,
518 const void *addr,
519 size_t addrlen)
520{
521 static char rbuf[INET6_ADDRSTRLEN + 10];
522 char buf[INET6_ADDRSTRLEN];
523 const void *sb;
524 struct in_addr a4;
525 struct in6_addr a6;
526 const struct IPv4XuAddress *t4;
527 const struct IPv6XuAddress *t6;
528 int af;
529 uint16_t port;
530 uint32_t options;
531
532 (void) cls;
533 if (NULL == addr)
534 {
535 GNUNET_break_op (0);
536 return NULL;
537 }
538
539 if (addrlen == sizeof(struct IPv6XuAddress))
540 {
541 t6 = addr;
542 af = AF_INET6;
543 options = ntohl (t6->options);
544 port = ntohs (t6->u6_port);
545 a6 = t6->ipv6_addr;
546 sb = &a6;
547 }
548 else if (addrlen == sizeof(struct IPv4XuAddress))
549 {
550 t4 = addr;
551 af = AF_INET;
552 options = ntohl (t4->options);
553 port = ntohs (t4->u4_port);
554 a4.s_addr = t4->ipv4_addr;
555 sb = &a4;
556 }
557 else
558 {
559 GNUNET_break_op (0);
560 return NULL;
561 }
562 inet_ntop (af,
563 sb,
564 buf,
565 INET6_ADDRSTRLEN);
566 GNUNET_snprintf (rbuf,
567 sizeof(rbuf),
568 (af == AF_INET6)
569 ? "%s.%u.[%s]:%u"
570 : "%s.%u.%s:%u",
571 PLUGIN_NAME,
572 options,
573 buf,
574 port);
575 return rbuf;
576}
577
578
579/**
580 * Function called to convert a string address to a binary address.
581 *
582 * @param cls closure (`struct Plugin *`)
583 * @param addr string address
584 * @param addrlen length of the address
585 * @param buf location to store the buffer
586 * @param added location to store the number of bytes in the buffer.
587 * If the function returns #GNUNET_SYSERR, its contents are undefined.
588 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
589 */
590static int
591xu_string_to_address (void *cls,
592 const char *addr,
593 uint16_t addrlen,
594 void **buf,
595 size_t *added)
596{
597 struct sockaddr_storage socket_address;
598 char *address;
599 char *plugin;
600 char *optionstr;
601 uint32_t options;
602
603 (void) cls;
604 /* Format tcp.options.address:port */
605 address = NULL;
606 plugin = NULL;
607 optionstr = NULL;
608
609 if ((NULL == addr) || (0 == addrlen))
610 {
611 GNUNET_break (0);
612 return GNUNET_SYSERR;
613 }
614 if ('\0' != addr[addrlen - 1])
615 {
616 GNUNET_break (0);
617 return GNUNET_SYSERR;
618 }
619 if (strlen (addr) + 1 != (size_t) addrlen)
620 {
621 GNUNET_break (0);
622 return GNUNET_SYSERR;
623 }
624 plugin = GNUNET_strdup (addr);
625 optionstr = strchr (plugin, '.');
626 if (NULL == optionstr)
627 {
628 GNUNET_break (0);
629 GNUNET_free (plugin);
630 return GNUNET_SYSERR;
631 }
632 optionstr[0] = '\0';
633 optionstr++;
634 options = atol (optionstr);
635 address = strchr (optionstr, '.');
636 if (NULL == address)
637 {
638 GNUNET_break (0);
639 GNUNET_free (plugin);
640 return GNUNET_SYSERR;
641 }
642 address[0] = '\0';
643 address++;
644
645 if (GNUNET_OK !=
646 GNUNET_STRINGS_to_address_ip (address,
647 strlen (address),
648 &socket_address))
649 {
650 GNUNET_break (0);
651 GNUNET_free (plugin);
652 return GNUNET_SYSERR;
653 }
654 GNUNET_free(plugin);
655
656 switch (socket_address.ss_family)
657 {
658 case AF_INET:
659 {
660 struct IPv4XuAddress *u4;
661 const struct sockaddr_in *in4 = (const struct sockaddr_in *) &socket_address;
662
663 u4 = GNUNET_new (struct IPv4XuAddress);
664 u4->options = htonl (options);
665 u4->ipv4_addr = in4->sin_addr.s_addr;
666 u4->u4_port = in4->sin_port;
667 *buf = u4;
668 *added = sizeof (struct IPv4XuAddress);
669 return GNUNET_OK;
670 }
671 case AF_INET6:
672 {
673 struct IPv6XuAddress *u6;
674 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) &socket_address;
675
676 u6 = GNUNET_new (struct IPv6XuAddress);
677 u6->options = htonl (options);
678 u6->ipv6_addr = in6->sin6_addr;
679 u6->u6_port = in6->sin6_port;
680 *buf = u6;
681 *added = sizeof (struct IPv6XuAddress);
682 return GNUNET_OK;
683 }
684 default:
685 GNUNET_break (0);
686 return GNUNET_SYSERR;
687 }
688}
689
690
691/**
692 * Append our port and forward the result.
693 *
694 * @param cls a `struct PrettyPrinterContext *`
695 * @param hostname result from DNS resolver
696 */
697static void
698append_port (void *cls,
699 const char *hostname)
700{
701 struct PrettyPrinterContext *ppc = cls;
702 struct Plugin *plugin = ppc->plugin;
703 char *ret;
704
705 if (NULL == hostname)
706 {
707 /* Final call, done */
708 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
709 plugin->ppc_dll_tail,
710 ppc);
711 ppc->resolver_handle = NULL;
712 ppc->asc (ppc->asc_cls,
713 NULL,
714 GNUNET_OK);
715 GNUNET_free (ppc);
716 return;
717 }
718 if (GNUNET_YES == ppc->ipv6)
719 GNUNET_asprintf (&ret,
720 "%s.%u.[%s]:%d",
721 PLUGIN_NAME,
722 ppc->options,
723 hostname,
724 ppc->port);
725 else
726 GNUNET_asprintf (&ret,
727 "%s.%u.%s:%d",
728 PLUGIN_NAME,
729 ppc->options,
730 hostname,
731 ppc->port);
732 ppc->asc (ppc->asc_cls,
733 ret,
734 GNUNET_OK);
735 GNUNET_free (ret);
736}
737
738
739/**
740 * Convert the transports address to a nice, human-readable format.
741 *
742 * @param cls closure with the `struct Plugin *`
743 * @param type name of the transport that generated the address
744 * @param addr one of the addresses of the host, NULL for the last address
745 * the specific address format depends on the transport;
746 * a `union XuAddress`
747 * @param addrlen length of the address
748 * @param numeric should (IP) addresses be displayed in numeric form?
749 * @param timeout after how long should we give up?
750 * @param asc function to call on each string
751 * @param asc_cls closure for @a asc
752 */
753static void
754xu_plugin_address_pretty_printer (void *cls,
755 const char *type,
756 const void *addr,
757 size_t addrlen,
758 int numeric,
759 struct GNUNET_TIME_Relative timeout,
760 GNUNET_TRANSPORT_AddressStringCallback asc,
761 void *asc_cls)
762{
763 struct Plugin *plugin = cls;
764 struct PrettyPrinterContext *ppc;
765 const struct sockaddr *sb;
766 size_t sbs;
767 struct sockaddr_in a4;
768 struct sockaddr_in6 a6;
769 const struct IPv4XuAddress *u4;
770 const struct IPv6XuAddress *u6;
771 uint16_t port;
772 uint32_t options;
773
774 (void) type;
775 if (addrlen == sizeof(struct IPv6XuAddress))
776 {
777 u6 = addr;
778 memset (&a6,
779 0,
780 sizeof (a6));
781 a6.sin6_family = AF_INET6;
782#if HAVE_SOCKADDR_IN_SIN_LEN
783 a6.sin6_len = sizeof (a6);
784#endif
785 a6.sin6_port = u6->u6_port;
786 a6.sin6_addr = u6->ipv6_addr;
787 port = ntohs (u6->u6_port);
788 options = ntohl (u6->options);
789 sb = (const struct sockaddr *) &a6;
790 sbs = sizeof (a6);
791 }
792 else if (addrlen == sizeof (struct IPv4XuAddress))
793 {
794 u4 = addr;
795 memset (&a4,
796 0,
797 sizeof(a4));
798 a4.sin_family = AF_INET;
799#if HAVE_SOCKADDR_IN_SIN_LEN
800 a4.sin_len = sizeof (a4);
801#endif
802 a4.sin_port = u4->u4_port;
803 a4.sin_addr.s_addr = u4->ipv4_addr;
804 port = ntohs (u4->u4_port);
805 options = ntohl (u4->options);
806 sb = (const struct sockaddr *) &a4;
807 sbs = sizeof(a4);
808 }
809 else
810 {
811 /* invalid address */
812 GNUNET_break_op (0);
813 asc (asc_cls,
814 NULL,
815 GNUNET_SYSERR);
816 asc (asc_cls,
817 NULL,
818 GNUNET_OK);
819 return;
820 }
821 ppc = GNUNET_new (struct PrettyPrinterContext);
822 ppc->plugin = plugin;
823 ppc->asc = asc;
824 ppc->asc_cls = asc_cls;
825 ppc->port = port;
826 ppc->options = options;
827 if (addrlen == sizeof (struct IPv6XuAddress))
828 ppc->ipv6 = GNUNET_YES;
829 else
830 ppc->ipv6 = GNUNET_NO;
831 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
832 plugin->ppc_dll_tail,
833 ppc);
834 ppc->resolver_handle
835 = GNUNET_RESOLVER_hostname_get (sb,
836 sbs,
837 ! numeric,
838 timeout,
839 &append_port,
840 ppc);
841}
842
843
844/**
845 * Check if the given port is plausible (must be either our listen
846 * port or our advertised port). If it is neither, we return
847 * #GNUNET_SYSERR.
848 *
849 * @param plugin global variables
850 * @param in_port port number to check
851 * @return #GNUNET_OK if port is either our open or advertised port
852 */
853static int
854check_port (const struct Plugin *plugin,
855 uint16_t in_port)
856{
857 if ( (plugin->port == in_port) ||
858 (plugin->aport == in_port) )
859 return GNUNET_OK;
860 return GNUNET_SYSERR;
861}
862
863
864/**
865 * Function that will be called to check if a binary address for this
866 * plugin is well-formed and corresponds to an address for THIS peer
867 * (as per our configuration). Naturally, if absolutely necessary,
868 * plugins can be a bit conservative in their answer, but in general
869 * plugins should make sure that the address does not redirect
870 * traffic to a 3rd party that might try to man-in-the-middle our
871 * traffic.
872 *
873 * @param cls closure, should be our handle to the Plugin
874 * @param addr pointer to a `union XuAddress`
875 * @param addrlen length of @a addr
876 * @return #GNUNET_OK if this is a plausible address for this peer
877 * and transport, #GNUNET_SYSERR if not
878 */
879static int
880xu_plugin_check_address (void *cls,
881 const void *addr,
882 size_t addrlen)
883{
884 struct Plugin *plugin = cls;
885 const struct IPv4XuAddress *v4;
886 const struct IPv6XuAddress *v6;
887
888 if (sizeof(struct IPv4XuAddress) == addrlen)
889 {
890 struct sockaddr_in s4;
891
892 v4 = (const struct IPv4XuAddress *) addr;
893 if (GNUNET_OK != check_port (plugin,
894 ntohs (v4->u4_port)))
895 return GNUNET_SYSERR;
896 memset (&s4, 0, sizeof (s4));
897 s4.sin_family = AF_INET;
898#if HAVE_SOCKADDR_IN_SIN_LEN
899 s4.sin_len = sizeof (s4);
900#endif
901 s4.sin_port = v4->u4_port;
902 s4.sin_addr.s_addr = v4->ipv4_addr;
903
904 if (GNUNET_OK !=
905 GNUNET_NAT_test_address (plugin->nat,
906 &s4,
907 sizeof (struct sockaddr_in)))
908 return GNUNET_SYSERR;
909 }
910 else if (sizeof(struct IPv6XuAddress) == addrlen)
911 {
912 struct sockaddr_in6 s6;
913
914 v6 = (const struct IPv6XuAddress *) addr;
915 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
916 return GNUNET_OK; /* plausible, if unlikely... */
917 memset (&s6, 0, sizeof (s6));
918 s6.sin6_family = AF_INET6;
919#if HAVE_SOCKADDR_IN_SIN_LEN
920 s6.sin6_len = sizeof (s6);
921#endif
922 s6.sin6_port = v6->u6_port;
923 s6.sin6_addr = v6->ipv6_addr;
924
925 if (GNUNET_OK !=
926 GNUNET_NAT_test_address (plugin->nat,
927 &s6,
928 sizeof(struct sockaddr_in6)))
929 return GNUNET_SYSERR;
930 }
931 else
932 {
933 GNUNET_break_op (0);
934 return GNUNET_SYSERR;
935 }
936 return GNUNET_OK;
937}
938
939
940/**
941 * Our external IP address/port mapping has changed.
942 *
943 * @param cls closure, the `struct Plugin`
944 * @param add_remove #GNUNET_YES to mean the new public IP address,
945 * #GNUNET_NO to mean the previous (now invalid) one
946 * @param ac address class the address belongs to
947 * @param addr either the previous or the new public IP address
948 * @param addrlen actual length of the @a addr
949 */
950static void
951xu_nat_port_map_callback (void *cls,
952 int add_remove,
953 enum GNUNET_NAT_AddressClass ac,
954 const struct sockaddr *addr,
955 socklen_t addrlen)
956{
957 struct Plugin *plugin = cls;
958 struct GNUNET_HELLO_Address *address;
959 struct IPv4XuAddress u4;
960 struct IPv6XuAddress u6;
961 void *arg;
962 size_t args;
963
964 if (GNUNET_NAT_AC_LOOPBACK == ac)
965 return;
966 if (GNUNET_NAT_AC_LAN == ac)
967 return;
968 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
969 return;
970 LOG (GNUNET_ERROR_TYPE_DEBUG,
971 (GNUNET_YES == add_remove)
972 ? "NAT notification to add address `%s'\n"
973 : "NAT notification to remove address `%s'\n",
974 GNUNET_a2s (addr,
975 addrlen));
976 /* convert 'address' to our internal format */
977 switch (addr->sa_family)
978 {
979 case AF_INET:
980 {
981 const struct sockaddr_in *i4;
982
983 GNUNET_assert (sizeof(struct sockaddr_in) == addrlen);
984 i4 = (const struct sockaddr_in *) addr;
985 if (0 == ntohs (i4->sin_port))
986 return; /* Port = 0 means unmapped, ignore these for XU. */
987 memset (&u4,
988 0,
989 sizeof(u4));
990 u4.options = htonl (plugin->myoptions);
991 u4.ipv4_addr = i4->sin_addr.s_addr;
992 u4.u4_port = i4->sin_port;
993 arg = &u4;
994 args = sizeof (struct IPv4XuAddress);
995 break;
996 }
997 case AF_INET6:
998 {
999 const struct sockaddr_in6 *i6;
1000
1001 GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen);
1002 i6 = (const struct sockaddr_in6 *) addr;
1003 if (0 == ntohs (i6->sin6_port))
1004 return; /* Port = 0 means unmapped, ignore these for XU. */
1005 memset (&u6,
1006 0,
1007 sizeof(u6));
1008 u6.options = htonl (plugin->myoptions);
1009 u6.ipv6_addr = i6->sin6_addr;
1010 u6.u6_port = i6->sin6_port;
1011 arg = &u6;
1012 args = sizeof (struct IPv6XuAddress);
1013 break;
1014 }
1015 default:
1016 GNUNET_break (0);
1017 return;
1018 }
1019 /* modify our published address list */
1020 /* TODO: use 'ac' here in the future... */
1021 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1022 PLUGIN_NAME,
1023 arg,
1024 args,
1025 GNUNET_HELLO_ADDRESS_INFO_NONE);
1026 plugin->env->notify_address (plugin->env->cls,
1027 add_remove,
1028 address);
1029 GNUNET_HELLO_address_free (address);
1030}
1031
1032
1033/* ********************* Finding sessions ******************* */
1034
1035
1036/**
1037 * Closure for #session_cmp_it().
1038 */
1039struct GNUNET_ATS_SessionCompareContext
1040{
1041 /**
1042 * Set to session matching the address.
1043 */
1044 struct GNUNET_ATS_Session *res;
1045
1046 /**
1047 * Address we are looking for.
1048 */
1049 const struct GNUNET_HELLO_Address *address;
1050};
1051
1052
1053/**
1054 * Find a session with a matching address.
1055 *
1056 * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
1057 * @param key peer identity (unused)
1058 * @param value the `struct GNUNET_ATS_Session *`
1059 * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1060 */
1061static int
1062session_cmp_it (void *cls,
1063 const struct GNUNET_PeerIdentity *key,
1064 void *value)
1065{
1066 struct GNUNET_ATS_SessionCompareContext *cctx = cls;
1067 struct GNUNET_ATS_Session *s = value;
1068
1069 (void) key;
1070 if (0 == GNUNET_HELLO_address_cmp (s->address,
1071 cctx->address))
1072 {
1073 GNUNET_assert (GNUNET_NO == s->in_destroy);
1074 cctx->res = s;
1075 return GNUNET_NO;
1076 }
1077 return GNUNET_OK;
1078}
1079
1080
1081/**
1082 * Locate an existing session the transport service is using to
1083 * send data to another peer. Performs some basic sanity checks
1084 * on the address and then tries to locate a matching session.
1085 *
1086 * @param cls the plugin
1087 * @param address the address we should locate the session by
1088 * @return the session if it exists, or NULL if it is not found
1089 */
1090static struct GNUNET_ATS_Session *
1091xu_plugin_lookup_session (void *cls,
1092 const struct GNUNET_HELLO_Address *address)
1093{
1094 struct Plugin *plugin = cls;
1095 const struct IPv6XuAddress *xu_a6;
1096 const struct IPv4XuAddress *xu_a4;
1097 struct GNUNET_ATS_SessionCompareContext cctx;
1098
1099 if (NULL == address->address)
1100 {
1101 GNUNET_break (0);
1102 return NULL;
1103 }
1104 if (sizeof(struct IPv4XuAddress) == address->address_length)
1105 {
1106 if (NULL == plugin->sockv4)
1107 return NULL;
1108 xu_a4 = (const struct IPv4XuAddress *) address->address;
1109 if (0 == xu_a4->u4_port)
1110 {
1111 GNUNET_break (0);
1112 return NULL;
1113 }
1114 }
1115 else if (sizeof(struct IPv6XuAddress) == address->address_length)
1116 {
1117 if (NULL == plugin->sockv6)
1118 return NULL;
1119 xu_a6 = (const struct IPv6XuAddress *) address->address;
1120 if (0 == xu_a6->u6_port)
1121 {
1122 GNUNET_break (0);
1123 return NULL;
1124 }
1125 }
1126 else
1127 {
1128 GNUNET_break (0);
1129 return NULL;
1130 }
1131
1132 /* check if session already exists */
1133 cctx.address = address;
1134 cctx.res = NULL;
1135 LOG (GNUNET_ERROR_TYPE_DEBUG,
1136 "Looking for existing session for peer `%s' with address `%s'\n",
1137 GNUNET_i2s (&address->peer),
1138 xu_address_to_string (plugin,
1139 address->address,
1140 address->address_length));
1141 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1142 &address->peer,
1143 &session_cmp_it,
1144 &cctx);
1145 if (NULL == cctx.res)
1146 return NULL;
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Found existing session %p\n",
1149 cctx.res);
1150 return cctx.res;
1151}
1152
1153
1154/* ********************** Timeout ****************** */
1155
1156
1157/**
1158 * Increment session timeout due to activity.
1159 *
1160 * @param s session to reschedule timeout activity for
1161 */
1162static void
1163reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1164{
1165 if (GNUNET_YES == s->in_destroy)
1166 return;
1167 GNUNET_assert (NULL != s->timeout_task);
1168 s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1169}
1170
1171
1172
1173/**
1174 * Function that will be called whenever the transport service wants to
1175 * notify the plugin that a session is still active and in use and
1176 * therefore the session timeout for this session has to be updated
1177 *
1178 * @param cls closure with the `struct Plugin`
1179 * @param peer which peer was the session for
1180 * @param session which session is being updated
1181 */
1182static void
1183xu_plugin_update_session_timeout (void *cls,
1184 const struct GNUNET_PeerIdentity *peer,
1185 struct GNUNET_ATS_Session *session)
1186{
1187 struct Plugin *plugin = cls;
1188
1189 if (GNUNET_YES !=
1190 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1191 peer,
1192 session))
1193 {
1194 GNUNET_break (0);
1195 return;
1196 }
1197 /* Reschedule session timeout */
1198 reschedule_session_timeout (session);
1199}
1200
1201
1202/* ************************* Sending ************************ */
1203
1204
1205/**
1206 * We failed to transmit a message via XU. Generate
1207 * a descriptive error message.
1208 *
1209 * @param plugin our plugin
1210 * @param sa target address we were trying to reach
1211 * @param slen number of bytes in @a sa
1212 * @param error the errno value returned from the sendto() call
1213 */
1214static void
1215analyze_send_error (struct Plugin *plugin,
1216 const struct sockaddr *sa,
1217 socklen_t slen,
1218 int error)
1219{
1220 enum GNUNET_NetworkType type;
1221
1222 type = plugin->env->get_address_type (plugin->env->cls,
1223 sa,
1224 slen);
1225 if ( ( (GNUNET_NT_LAN == type) ||
1226 (GNUNET_NT_WAN == type) ) &&
1227 ( (ENETUNREACH == errno) ||
1228 (ENETDOWN == errno) ) )
1229 {
1230 if (slen == sizeof (struct sockaddr_in))
1231 {
1232 /* IPv4: "Network unreachable" or "Network down"
1233 *
1234 * This indicates we do not have connectivity
1235 */
1236 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1237 _("XU could not transmit message to `%s': "
1238 "Network seems down, please check your network configuration\n"),
1239 GNUNET_a2s (sa,
1240 slen));
1241 }
1242 if (slen == sizeof (struct sockaddr_in6))
1243 {
1244 /* IPv6: "Network unreachable" or "Network down"
1245 *
1246 * This indicates that this system is IPv6 enabled, but does not
1247 * have a valid global IPv6 address assigned or we do not have
1248 * connectivity
1249 */
1250 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1251 _("XU could not transmit IPv6 message! "
1252 "Please check your network configuration and disable IPv6 if your "
1253 "connection does not have a global IPv6 address\n"));
1254 }
1255 }
1256 else
1257 {
1258 LOG (GNUNET_ERROR_TYPE_WARNING,
1259 "XU could not transmit message to `%s': `%s'\n",
1260 GNUNET_a2s (sa,
1261 slen),
1262 STRERROR (error));
1263 }
1264}
1265
1266
1267
1268
1269/**
1270 * Function that can be used by the transport service to transmit a
1271 * message using the plugin. Note that in the case of a peer
1272 * disconnecting, the continuation MUST be called prior to the
1273 * disconnect notification itself. This function will be called with
1274 * this peer's HELLO message to initiate a fresh connection to another
1275 * peer.
1276 *
1277 * @param cls closure
1278 * @param s which session must be used
1279 * @param msgbuf the message to transmit
1280 * @param msgbuf_size number of bytes in @a msgbuf
1281 * @param priority how important is the message (most plugins will
1282 * ignore message priority and just FIFO)
1283 * @param to how long to wait at most for the transmission (does not
1284 * require plugins to discard the message after the timeout,
1285 * just advisory for the desired delay; most plugins will ignore
1286 * this as well)
1287 * @param cont continuation to call once the message has
1288 * been transmitted (or if the transport is ready
1289 * for the next transmission call; or if the
1290 * peer disconnected...); can be NULL
1291 * @param cont_cls closure for @a cont
1292 * @return number of bytes used (on the physical network, with overheads);
1293 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1294 * and does NOT mean that the message was not transmitted (DV)
1295 */
1296static ssize_t
1297xu_plugin_send (void *cls,
1298 struct GNUNET_ATS_Session *s,
1299 const char *msgbuf,
1300 size_t msgbuf_size,
1301 unsigned int priority,
1302 struct GNUNET_TIME_Relative to,
1303 GNUNET_TRANSPORT_TransmitContinuation cont,
1304 void *cont_cls)
1305{
1306 struct Plugin *plugin = cls;
1307 size_t xumlen = msgbuf_size + sizeof(struct XUMessage);
1308 struct XUMessage *xu;
1309 char mbuf[xumlen] GNUNET_ALIGN;
1310 ssize_t sent;
1311 socklen_t slen;
1312 const struct sockaddr *a;
1313 const struct IPv4XuAddress *u4;
1314 struct sockaddr_in a4;
1315 const struct IPv6XuAddress *u6;
1316 struct sockaddr_in6 a6;
1317 struct GNUNET_NETWORK_Handle *sock;
1318
1319 (void) priority;
1320 (void) to;
1321 if ( (sizeof(struct IPv6XuAddress) == s->address->address_length) &&
1322 (NULL == plugin->sockv6) )
1323 return GNUNET_SYSERR;
1324 if ( (sizeof(struct IPv4XuAddress) == s->address->address_length) &&
1325 (NULL == plugin->sockv4) )
1326 return GNUNET_SYSERR;
1327 if (xumlen >= GNUNET_MAX_MESSAGE_SIZE)
1328 {
1329 GNUNET_break (0);
1330 return GNUNET_SYSERR;
1331 }
1332 if (GNUNET_YES !=
1333 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1334 &s->target,
1335 s))
1336 {
1337 GNUNET_break (0);
1338 return GNUNET_SYSERR;
1339 }
1340 LOG (GNUNET_ERROR_TYPE_DEBUG,
1341 "XU transmits %u-byte message to `%s' using address `%s'\n",
1342 xumlen,
1343 GNUNET_i2s (&s->target),
1344 xu_address_to_string (plugin,
1345 s->address->address,
1346 s->address->address_length));
1347 xu = (struct XUMessage *) mbuf;
1348 xu->header.size = htons (xumlen);
1349 xu->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE);
1350 xu->reserved = htonl (0);
1351 xu->sender = *plugin->env->my_identity;
1352 GNUNET_memcpy (&xu[1],
1353 msgbuf,
1354 msgbuf_size);
1355
1356 if (sizeof (struct IPv4XuAddress) == s->address->address_length)
1357 {
1358 u4 = s->address->address;
1359 memset (&a4,
1360 0,
1361 sizeof(a4));
1362 a4.sin_family = AF_INET;
1363#if HAVE_SOCKADDR_IN_SIN_LEN
1364 a4.sin_len = sizeof (a4);
1365#endif
1366 a4.sin_port = u4->u4_port;
1367 a4.sin_addr.s_addr = u4->ipv4_addr;
1368 a = (const struct sockaddr *) &a4;
1369 slen = sizeof (a4);
1370 sock = plugin->sockv4;
1371 }
1372 else if (sizeof (struct IPv6XuAddress) == s->address->address_length)
1373 {
1374 u6 = s->address->address;
1375 memset (&a6,
1376 0,
1377 sizeof(a6));
1378 a6.sin6_family = AF_INET6;
1379#if HAVE_SOCKADDR_IN_SIN_LEN
1380 a6.sin6_len = sizeof (a6);
1381#endif
1382 a6.sin6_port = u6->u6_port;
1383 a6.sin6_addr = u6->ipv6_addr;
1384 a = (const struct sockaddr *) &a6;
1385 slen = sizeof (a6);
1386 sock = plugin->sockv6;
1387 }
1388 else
1389 {
1390 GNUNET_break (0);
1391 return GNUNET_SYSERR;
1392 }
1393
1394 sent = GNUNET_NETWORK_socket_sendto (sock,
1395 mbuf,
1396 xumlen,
1397 a,
1398 slen);
1399 s->last_transmit_time
1400 = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
1401 s->last_transmit_time);
1402
1403 if (GNUNET_SYSERR == sent)
1404 {
1405 /* Failure */
1406 analyze_send_error (plugin,
1407 a,
1408 slen,
1409 errno);
1410 GNUNET_STATISTICS_update (plugin->env->stats,
1411 "# XU, total, bytes, sent, failure",
1412 sent,
1413 GNUNET_NO);
1414 GNUNET_STATISTICS_update (plugin->env->stats,
1415 "# XU, total, messages, sent, failure",
1416 1,
1417 GNUNET_NO);
1418 return GNUNET_SYSERR;
1419 }
1420 /* Success */
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "XU transmitted %u-byte message to `%s' `%s' (%d: %s)\n",
1423 (unsigned int) (msgbuf_size),
1424 GNUNET_i2s (&s->target),
1425 GNUNET_a2s (a,
1426 slen),
1427 (int ) sent,
1428 (sent < 0) ? STRERROR (errno) : "ok");
1429 GNUNET_STATISTICS_update (plugin->env->stats,
1430 "# XU, total, bytes, sent, success",
1431 sent,
1432 GNUNET_NO);
1433 GNUNET_STATISTICS_update (plugin->env->stats,
1434 "# XU, total, messages, sent, success",
1435 1,
1436 GNUNET_NO);
1437 cont (cont_cls,
1438 &s->target,
1439 GNUNET_OK,
1440 msgbuf_size,
1441 xumlen);
1442 notify_session_monitor (s->plugin,
1443 s,
1444 GNUNET_TRANSPORT_SS_UPDATE);
1445 return xumlen;
1446}
1447
1448
1449/* ********************** Receiving ********************** */
1450
1451
1452/**
1453 * Functions with this signature are called whenever we need to close
1454 * a session due to a disconnect or failure to establish a connection.
1455 *
1456 * @param cls closure with the `struct Plugin`
1457 * @param s session to close down
1458 * @return #GNUNET_OK on success
1459 */
1460static int
1461xu_disconnect_session (void *cls,
1462 struct GNUNET_ATS_Session *s)
1463{
1464 struct Plugin *plugin = cls;
1465
1466 GNUNET_assert (GNUNET_YES != s->in_destroy);
1467 LOG (GNUNET_ERROR_TYPE_DEBUG,
1468 "Session %p to peer `%s' at address %s ended\n",
1469 s,
1470 GNUNET_i2s (&s->target),
1471 xu_address_to_string (plugin,
1472 s->address->address,
1473 s->address->address_length));
1474 if (NULL != s->timeout_task)
1475 {
1476 GNUNET_SCHEDULER_cancel (s->timeout_task);
1477 s->timeout_task = NULL;
1478 }
1479 GNUNET_assert (GNUNET_YES ==
1480 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
1481 &s->target,
1482 s));
1483 s->in_destroy = GNUNET_YES;
1484 notify_session_monitor (s->plugin,
1485 s,
1486 GNUNET_TRANSPORT_SS_DONE);
1487 plugin->env->session_end (plugin->env->cls,
1488 s->address,
1489 s);
1490 GNUNET_STATISTICS_set (plugin->env->stats,
1491 "# XU sessions active",
1492 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1493 GNUNET_NO);
1494 if (0 == s->rc)
1495 free_session (s);
1496 return GNUNET_OK;
1497}
1498
1499
1500/**
1501 * Message tokenizer has broken up an incomming message. Pass it on
1502 * to the service.
1503 *
1504 * @param cls the `struct GNUNET_ATS_Session *`
1505 * @param hdr the actual message
1506 * @return #GNUNET_OK (always)
1507 */
1508static int
1509process_inbound_tokenized_messages (void *cls,
1510 const struct GNUNET_MessageHeader *hdr)
1511{
1512 struct GNUNET_ATS_Session *session = cls;
1513 struct Plugin *plugin = session->plugin;
1514
1515 if (GNUNET_YES == session->in_destroy)
1516 return GNUNET_OK;
1517 reschedule_session_timeout (session);
1518 session->flow_delay_for_other_peer
1519 = plugin->env->receive (plugin->env->cls,
1520 session->address,
1521 session,
1522 hdr);
1523 return GNUNET_OK;
1524}
1525
1526
1527/**
1528 * Destroy a session, plugin is being unloaded.
1529 *
1530 * @param cls the `struct Plugin`
1531 * @param key hash of public key of target peer
1532 * @param value a `struct PeerSession *` to clean up
1533 * @return #GNUNET_OK (continue to iterate)
1534 */
1535static int
1536disconnect_and_free_it (void *cls,
1537 const struct GNUNET_PeerIdentity *key,
1538 void *value)
1539{
1540 struct Plugin *plugin = cls;
1541
1542 (void) key;
1543 xu_disconnect_session (plugin,
1544 value);
1545 return GNUNET_OK;
1546}
1547
1548
1549/**
1550 * Disconnect from a remote node. Clean up session if we have one for
1551 * this peer.
1552 *
1553 * @param cls closure for this call (should be handle to Plugin)
1554 * @param target the peeridentity of the peer to disconnect
1555 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1556 */
1557static void
1558xu_disconnect (void *cls,
1559 const struct GNUNET_PeerIdentity *target)
1560{
1561 struct Plugin *plugin = cls;
1562
1563 LOG (GNUNET_ERROR_TYPE_DEBUG,
1564 "Disconnecting from peer `%s'\n",
1565 GNUNET_i2s (target));
1566 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1567 target,
1568 &disconnect_and_free_it,
1569 plugin);
1570}
1571
1572
1573/**
1574 * Session was idle, so disconnect it.
1575 *
1576 * @param cls the `struct GNUNET_ATS_Session` to time out
1577 */
1578static void
1579session_timeout (void *cls)
1580{
1581 struct GNUNET_ATS_Session *s = cls;
1582 struct Plugin *plugin = s->plugin;
1583 struct GNUNET_TIME_Relative left;
1584
1585 s->timeout_task = NULL;
1586 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1587 if (left.rel_value_us > 0)
1588 {
1589 /* not actually our turn yet, but let's at least update
1590 the monitor, it may think we're about to die ... */
1591 notify_session_monitor (s->plugin,
1592 s,
1593 GNUNET_TRANSPORT_SS_UPDATE);
1594 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1595 &session_timeout,
1596 s);
1597 return;
1598 }
1599 LOG (GNUNET_ERROR_TYPE_DEBUG,
1600 "Session %p was idle for %s, disconnecting\n",
1601 s,
1602 GNUNET_STRINGS_relative_time_to_string (XU_SESSION_TIME_OUT,
1603 GNUNET_YES));
1604 /* call session destroy function */
1605 xu_disconnect_session (plugin,
1606 s);
1607}
1608
1609
1610/**
1611 * Allocate a new session for the given endpoint address.
1612 * Note that this function does not inform the service
1613 * of the new session, this is the responsibility of the
1614 * caller (if needed).
1615 *
1616 * @param cls the `struct Plugin`
1617 * @param address address of the other peer to use
1618 * @param network_type network type the address belongs to
1619 * @return NULL on error, otherwise session handle
1620 */
1621static struct GNUNET_ATS_Session *
1622xu_plugin_create_session (void *cls,
1623 const struct GNUNET_HELLO_Address *address,
1624 enum GNUNET_NetworkType network_type)
1625{
1626 struct Plugin *plugin = cls;
1627 struct GNUNET_ATS_Session *s;
1628
1629 s = GNUNET_new (struct GNUNET_ATS_Session);
1630 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
1631 s);
1632 s->plugin = plugin;
1633 s->address = GNUNET_HELLO_address_copy (address);
1634 s->target = address->peer;
1635 s->last_transmit_time = GNUNET_TIME_absolute_get ();
1636 s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1637 250);
1638 s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1639 s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
1640 s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
1641 s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1642 s->timeout_task = GNUNET_SCHEDULER_add_delayed (XU_SESSION_TIME_OUT,
1643 &session_timeout,
1644 s);
1645 s->scope = network_type;
1646
1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1648 "Creating new session %p for peer `%s' address `%s'\n",
1649 s,
1650 GNUNET_i2s (&address->peer),
1651 xu_address_to_string (plugin,
1652 address->address,
1653 address->address_length));
1654 GNUNET_assert (GNUNET_OK ==
1655 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1656 &s->target,
1657 s,
1658 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1659 GNUNET_STATISTICS_set (plugin->env->stats,
1660 "# XU sessions active",
1661 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1662 GNUNET_NO);
1663 notify_session_monitor (plugin,
1664 s,
1665 GNUNET_TRANSPORT_SS_INIT);
1666 return s;
1667}
1668
1669
1670/**
1671 * Creates a new outbound session the transport service will use to
1672 * send data to the peer.
1673 *
1674 * @param cls the `struct Plugin *`
1675 * @param address the address
1676 * @return the session or NULL of max connections exceeded
1677 */
1678static struct GNUNET_ATS_Session *
1679xu_plugin_get_session (void *cls,
1680 const struct GNUNET_HELLO_Address *address)
1681{
1682 struct Plugin *plugin = cls;
1683 struct GNUNET_ATS_Session *s;
1684 enum GNUNET_NetworkType network_type = GNUNET_NT_UNSPECIFIED;
1685 const struct IPv4XuAddress *xu_v4;
1686 const struct IPv6XuAddress *xu_v6;
1687
1688 if (NULL == address)
1689 {
1690 GNUNET_break (0);
1691 return NULL;
1692 }
1693 if ( (address->address_length != sizeof(struct IPv4XuAddress)) &&
1694 (address->address_length != sizeof(struct IPv6XuAddress)) )
1695 {
1696 GNUNET_break_op (0);
1697 return NULL;
1698 }
1699 if (NULL != (s = xu_plugin_lookup_session (cls,
1700 address)))
1701 return s;
1702
1703 /* need to create new session */
1704 if (sizeof (struct IPv4XuAddress) == address->address_length)
1705 {
1706 struct sockaddr_in v4;
1707
1708 xu_v4 = (const struct IPv4XuAddress *) address->address;
1709 memset (&v4, '\0', sizeof (v4));
1710 v4.sin_family = AF_INET;
1711#if HAVE_SOCKADDR_IN_SIN_LEN
1712 v4.sin_len = sizeof (struct sockaddr_in);
1713#endif
1714 v4.sin_port = xu_v4->u4_port;
1715 v4.sin_addr.s_addr = xu_v4->ipv4_addr;
1716 network_type = plugin->env->get_address_type (plugin->env->cls,
1717 (const struct sockaddr *) &v4,
1718 sizeof (v4));
1719 }
1720 if (sizeof (struct IPv6XuAddress) == address->address_length)
1721 {
1722 struct sockaddr_in6 v6;
1723
1724 xu_v6 = (const struct IPv6XuAddress *) address->address;
1725 memset (&v6, '\0', sizeof (v6));
1726 v6.sin6_family = AF_INET6;
1727#if HAVE_SOCKADDR_IN_SIN_LEN
1728 v6.sin6_len = sizeof (struct sockaddr_in6);
1729#endif
1730 v6.sin6_port = xu_v6->u6_port;
1731 v6.sin6_addr = xu_v6->ipv6_addr;
1732 network_type = plugin->env->get_address_type (plugin->env->cls,
1733 (const struct sockaddr *) &v6,
1734 sizeof (v6));
1735 }
1736 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
1737 return xu_plugin_create_session (cls,
1738 address,
1739 network_type);
1740}
1741
1742
1743/**
1744 * We've received a XU Message. Process it (pass contents to main service).
1745 *
1746 * @param plugin plugin context
1747 * @param msg the message
1748 * @param xu_addr sender address
1749 * @param xu_addr_len number of bytes in @a xu_addr
1750 * @param network_type network type the address belongs to
1751 */
1752static void
1753process_xu_message (struct Plugin *plugin,
1754 const struct XUMessage *msg,
1755 const union XuAddress *xu_addr,
1756 size_t xu_addr_len,
1757 enum GNUNET_NetworkType network_type)
1758{
1759 struct GNUNET_ATS_Session *s;
1760 struct GNUNET_HELLO_Address *address;
1761
1762 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
1763 if (0 != ntohl (msg->reserved))
1764 {
1765 GNUNET_break_op(0);
1766 return;
1767 }
1768 if (ntohs (msg->header.size)
1769 < sizeof(struct GNUNET_MessageHeader) + sizeof(struct XUMessage))
1770 {
1771 GNUNET_break_op(0);
1772 return;
1773 }
1774
1775 address = GNUNET_HELLO_address_allocate (&msg->sender,
1776 PLUGIN_NAME,
1777 xu_addr,
1778 xu_addr_len,
1779 GNUNET_HELLO_ADDRESS_INFO_NONE);
1780 if (NULL ==
1781 (s = xu_plugin_lookup_session (plugin,
1782 address)))
1783 {
1784 s = xu_plugin_create_session (plugin,
1785 address,
1786 network_type);
1787 plugin->env->session_start (plugin->env->cls,
1788 address,
1789 s,
1790 s->scope);
1791 notify_session_monitor (plugin,
1792 s,
1793 GNUNET_TRANSPORT_SS_UP);
1794 }
1795 GNUNET_free (address);
1796
1797 s->rc++;
1798 GNUNET_MST_from_buffer (s->mst,
1799 (const char *) &msg[1],
1800 ntohs (msg->header.size) - sizeof(struct XUMessage),
1801 GNUNET_YES,
1802 GNUNET_NO);
1803 s->rc--;
1804 if ( (0 == s->rc) &&
1805 (GNUNET_YES == s->in_destroy) )
1806 free_session (s);
1807}
1808
1809
1810/**
1811 * Read and process a message from the given socket.
1812 *
1813 * @param plugin the overall plugin
1814 * @param rsock socket to read from
1815 */
1816static void
1817xu_select_read (struct Plugin *plugin,
1818 struct GNUNET_NETWORK_Handle *rsock)
1819{
1820 socklen_t fromlen;
1821 struct sockaddr_storage addr;
1822 char buf[65536] GNUNET_ALIGN;
1823 ssize_t size;
1824 const struct GNUNET_MessageHeader *msg;
1825 struct IPv4XuAddress v4;
1826 struct IPv6XuAddress v6;
1827 const struct sockaddr *sa;
1828 const struct sockaddr_in *sa4;
1829 const struct sockaddr_in6 *sa6;
1830 const union XuAddress *int_addr;
1831 size_t int_addr_len;
1832 enum GNUNET_NetworkType network_type;
1833
1834 fromlen = sizeof (addr);
1835 memset (&addr,
1836 0,
1837 sizeof(addr));
1838 size = GNUNET_NETWORK_socket_recvfrom (rsock,
1839 buf,
1840 sizeof (buf),
1841 (struct sockaddr *) &addr,
1842 &fromlen);
1843 sa = (const struct sockaddr *) &addr;
1844#if MINGW
1845 /* On SOCK_DGRAM XU sockets recvfrom might fail with a
1846 * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!)
1847 * on this socket has failed.
1848 * Quote from MSDN:
1849 * WSAECONNRESET - The virtual circuit was reset by the remote side
1850 * executing a hard or abortive close. The application should close
1851 * the socket; it is no longer usable. On a XU-datagram socket this
1852 * error indicates a previous send operation resulted in an ICMP Port
1853 * Unreachable message.
1854 */
1855 if ( (-1 == size) &&
1856 (ECONNRESET == errno) )
1857 return;
1858#endif
1859 if (-1 == size)
1860 {
1861 LOG (GNUNET_ERROR_TYPE_DEBUG,
1862 "XU failed to receive data: %s\n",
1863 STRERROR (errno));
1864 /* Connection failure or something. Not a protocol violation. */
1865 return;
1866 }
1867
1868 /* Check if this is a STUN packet */
1869 if (GNUNET_NO !=
1870 GNUNET_NAT_stun_handle_packet (plugin->nat,
1871 (const struct sockaddr *) &addr,
1872 fromlen,
1873 buf,
1874 size))
1875 return; /* was STUN, do not process further */
1876
1877 if (((size_t) size) < sizeof(struct GNUNET_MessageHeader))
1878 {
1879 LOG (GNUNET_ERROR_TYPE_WARNING,
1880 "XU got %u bytes from %s, which is not enough for a GNUnet message header\n",
1881 (unsigned int ) size,
1882 GNUNET_a2s (sa,
1883 fromlen));
1884 /* _MAY_ be a connection failure (got partial message) */
1885 /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
1886 GNUNET_break_op (0);
1887 return;
1888 }
1889
1890 msg = (const struct GNUNET_MessageHeader *) buf;
1891 LOG (GNUNET_ERROR_TYPE_DEBUG,
1892 "XU received %u-byte message from `%s' type %u\n",
1893 (unsigned int) size,
1894 GNUNET_a2s (sa,
1895 fromlen),
1896 ntohs (msg->type));
1897 if (size != ntohs (msg->size))
1898 {
1899 LOG (GNUNET_ERROR_TYPE_WARNING,
1900 "XU malformed message (size %u) header from %s\n",
1901 (unsigned int) size,
1902 GNUNET_a2s (sa,
1903 fromlen));
1904 GNUNET_break_op (0);
1905 return;
1906 }
1907 GNUNET_STATISTICS_update (plugin->env->stats,
1908 "# XU, total bytes received",
1909 size,
1910 GNUNET_NO);
1911 network_type = plugin->env->get_address_type (plugin->env->cls,
1912 sa,
1913 fromlen);
1914 switch (sa->sa_family)
1915 {
1916 case AF_INET:
1917 sa4 = (const struct sockaddr_in *) &addr;
1918 v4.options = 0;
1919 v4.ipv4_addr = sa4->sin_addr.s_addr;
1920 v4.u4_port = sa4->sin_port;
1921 int_addr = (union XuAddress *) &v4;
1922 int_addr_len = sizeof (v4);
1923 break;
1924 case AF_INET6:
1925 sa6 = (const struct sockaddr_in6 *) &addr;
1926 v6.options = 0;
1927 v6.ipv6_addr = sa6->sin6_addr;
1928 v6.u6_port = sa6->sin6_port;
1929 int_addr = (union XuAddress *) &v6;
1930 int_addr_len = sizeof (v6);
1931 break;
1932 default:
1933 GNUNET_break (0);
1934 return;
1935 }
1936
1937 switch (ntohs (msg->type))
1938 {
1939 case GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE:
1940 if (ntohs (msg->size) < sizeof(struct XUMessage))
1941 {
1942 GNUNET_break_op(0);
1943 return;
1944 }
1945 process_xu_message (plugin,
1946 (const struct XUMessage *) msg,
1947 int_addr,
1948 int_addr_len,
1949 network_type);
1950 return;
1951 default:
1952 GNUNET_break_op(0);
1953 return;
1954 }
1955}
1956
1957
1958/* ***************** Event loop (part 2) *************** */
1959
1960
1961/**
1962 * We have been notified that our readset has something to read. We don't
1963 * know which socket needs to be read, so we have to check each one
1964 * Then reschedule this function to be called again once more is available.
1965 *
1966 * @param cls the plugin handle
1967 */
1968static void
1969xu_plugin_select_v4 (void *cls)
1970{
1971 struct Plugin *plugin = cls;
1972 const struct GNUNET_SCHEDULER_TaskContext *tc;
1973
1974 plugin->select_task_v4 = NULL;
1975 if (NULL == plugin->sockv4)
1976 return;
1977 tc = GNUNET_SCHEDULER_get_task_context ();
1978 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1979 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
1980 plugin->sockv4)) )
1981 xu_select_read (plugin,
1982 plugin->sockv4);
1983 schedule_select_v4 (plugin);
1984}
1985
1986
1987/**
1988 * We have been notified that our readset has something to read. We don't
1989 * know which socket needs to be read, so we have to check each one
1990 * Then reschedule this function to be called again once more is available.
1991 *
1992 * @param cls the plugin handle
1993 */
1994static void
1995xu_plugin_select_v6 (void *cls)
1996{
1997 struct Plugin *plugin = cls;
1998 const struct GNUNET_SCHEDULER_TaskContext *tc;
1999
2000 plugin->select_task_v6 = NULL;
2001 if (NULL == plugin->sockv6)
2002 return;
2003 tc = GNUNET_SCHEDULER_get_task_context ();
2004 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
2005 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
2006 plugin->sockv6)) )
2007 xu_select_read (plugin,
2008 plugin->sockv6);
2009 schedule_select_v6 (plugin);
2010}
2011
2012
2013/* ******************* Initialization *************** */
2014
2015
2016/**
2017 * Setup the XU sockets (for IPv4 and IPv6) for the plugin.
2018 *
2019 * @param plugin the plugin to initialize
2020 * @param bind_v6 IPv6 address to bind to (can be NULL, for 'any')
2021 * @param bind_v4 IPv4 address to bind to (can be NULL, for 'any')
2022 * @return number of sockets that were successfully bound
2023 */
2024static unsigned int
2025setup_sockets (struct Plugin *plugin,
2026 const struct sockaddr_in6 *bind_v6,
2027 const struct sockaddr_in *bind_v4)
2028{
2029 int tries;
2030 unsigned int sockets_created = 0;
2031 struct sockaddr_in6 server_addrv6;
2032 struct sockaddr_in server_addrv4;
2033 const struct sockaddr *server_addr;
2034 const struct sockaddr *addrs[2];
2035 socklen_t addrlens[2];
2036 socklen_t addrlen;
2037 int eno;
2038
2039 /* Create IPv6 socket */
2040 eno = EINVAL;
2041 if (GNUNET_YES == plugin->enable_ipv6)
2042 {
2043 plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6,
2044 SOCK_DGRAM,
2045 0);
2046 if (NULL == plugin->sockv6)
2047 {
2048 LOG (GNUNET_ERROR_TYPE_INFO,
2049 _("Disabling IPv6 since it is not supported on this system!\n"));
2050 plugin->enable_ipv6 = GNUNET_NO;
2051 }
2052 else
2053 {
2054 memset (&server_addrv6,
2055 0,
2056 sizeof(struct sockaddr_in6));
2057#if HAVE_SOCKADDR_IN_SIN_LEN
2058 server_addrv6.sin6_len = sizeof (struct sockaddr_in6);
2059#endif
2060 server_addrv6.sin6_family = AF_INET6;
2061 if (NULL != bind_v6)
2062 server_addrv6.sin6_addr = bind_v6->sin6_addr;
2063 else
2064 server_addrv6.sin6_addr = in6addr_any;
2065
2066 if (0 == plugin->port) /* autodetect */
2067 server_addrv6.sin6_port
2068 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2069 33537)
2070 + 32000);
2071 else
2072 server_addrv6.sin6_port = htons (plugin->port);
2073 addrlen = sizeof (struct sockaddr_in6);
2074 server_addr = (const struct sockaddr *) &server_addrv6;
2075
2076 tries = 0;
2077 while (tries < 10)
2078 {
2079 LOG(GNUNET_ERROR_TYPE_DEBUG,
2080 "Binding to IPv6 `%s'\n",
2081 GNUNET_a2s (server_addr,
2082 addrlen));
2083 /* binding */
2084 if (GNUNET_OK ==
2085 GNUNET_NETWORK_socket_bind (plugin->sockv6,
2086 server_addr,
2087 addrlen))
2088 break;
2089 eno = errno;
2090 if (0 != plugin->port)
2091 {
2092 tries = 10; /* fail immediately */
2093 break; /* bind failed on specific port */
2094 }
2095 /* autodetect */
2096 server_addrv6.sin6_port
2097 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2098 33537)
2099 + 32000);
2100 tries++;
2101 }
2102 if (tries >= 10)
2103 {
2104 GNUNET_NETWORK_socket_close (plugin->sockv6);
2105 plugin->enable_ipv6 = GNUNET_NO;
2106 plugin->sockv6 = NULL;
2107 }
2108 else
2109 {
2110 plugin->port = ntohs (server_addrv6.sin6_port);
2111 }
2112 if (NULL != plugin->sockv6)
2113 {
2114 LOG (GNUNET_ERROR_TYPE_DEBUG,
2115 "IPv6 XU socket created listinging at %s\n",
2116 GNUNET_a2s (server_addr,
2117 addrlen));
2118 addrs[sockets_created] = server_addr;
2119 addrlens[sockets_created] = addrlen;
2120 sockets_created++;
2121 }
2122 else
2123 {
2124 LOG (GNUNET_ERROR_TYPE_WARNING,
2125 _("Failed to bind XU socket to %s: %s\n"),
2126 GNUNET_a2s (server_addr,
2127 addrlen),
2128 STRERROR (eno));
2129 }
2130 }
2131 }
2132
2133 /* Create IPv4 socket */
2134 eno = EINVAL;
2135 plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET,
2136 SOCK_DGRAM,
2137 0);
2138 if (NULL == plugin->sockv4)
2139 {
2140 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
2141 "socket");
2142 LOG (GNUNET_ERROR_TYPE_INFO,
2143 _("Disabling IPv4 since it is not supported on this system!\n"));
2144 plugin->enable_ipv4 = GNUNET_NO;
2145 }
2146 else
2147 {
2148 memset (&server_addrv4,
2149 0,
2150 sizeof(struct sockaddr_in));
2151#if HAVE_SOCKADDR_IN_SIN_LEN
2152 server_addrv4.sin_len = sizeof (struct sockaddr_in);
2153#endif
2154 server_addrv4.sin_family = AF_INET;
2155 if (NULL != bind_v4)
2156 server_addrv4.sin_addr = bind_v4->sin_addr;
2157 else
2158 server_addrv4.sin_addr.s_addr = INADDR_ANY;
2159
2160 if (0 == plugin->port)
2161 /* autodetect */
2162 server_addrv4.sin_port
2163 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2164 33537)
2165 + 32000);
2166 else
2167 server_addrv4.sin_port = htons (plugin->port);
2168
2169 addrlen = sizeof (struct sockaddr_in);
2170 server_addr = (const struct sockaddr *) &server_addrv4;
2171
2172 tries = 0;
2173 while (tries < 10)
2174 {
2175 LOG (GNUNET_ERROR_TYPE_DEBUG,
2176 "Binding to IPv4 `%s'\n",
2177 GNUNET_a2s (server_addr,
2178 addrlen));
2179
2180 /* binding */
2181 if (GNUNET_OK ==
2182 GNUNET_NETWORK_socket_bind (plugin->sockv4,
2183 server_addr,
2184 addrlen))
2185 break;
2186 eno = errno;
2187 if (0 != plugin->port)
2188 {
2189 tries = 10; /* fail */
2190 break; /* bind failed on specific port */
2191 }
2192
2193 /* autodetect */
2194 server_addrv4.sin_port
2195 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2196 33537)
2197 + 32000);
2198 tries++;
2199 }
2200 if (tries >= 10)
2201 {
2202 GNUNET_NETWORK_socket_close (plugin->sockv4);
2203 plugin->enable_ipv4 = GNUNET_NO;
2204 plugin->sockv4 = NULL;
2205 }
2206 else
2207 {
2208 plugin->port = ntohs (server_addrv4.sin_port);
2209 }
2210
2211 if (NULL != plugin->sockv4)
2212 {
2213 LOG (GNUNET_ERROR_TYPE_DEBUG,
2214 "IPv4 socket created on port %s\n",
2215 GNUNET_a2s (server_addr,
2216 addrlen));
2217 addrs[sockets_created] = server_addr;
2218 addrlens[sockets_created] = addrlen;
2219 sockets_created++;
2220 }
2221 else
2222 {
2223 LOG (GNUNET_ERROR_TYPE_ERROR,
2224 _("Failed to bind XU socket to %s: %s\n"),
2225 GNUNET_a2s (server_addr,
2226 addrlen),
2227 STRERROR (eno));
2228 }
2229 }
2230
2231 if (0 == sockets_created)
2232 {
2233 LOG (GNUNET_ERROR_TYPE_WARNING,
2234 _("Failed to open XU sockets\n"));
2235 return 0; /* No sockets created, return */
2236 }
2237 schedule_select_v4 (plugin);
2238 schedule_select_v6 (plugin);
2239 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2240 "transport-xu",
2241 IPPROTO_UDP,
2242 sockets_created,
2243 addrs,
2244 addrlens,
2245 &xu_nat_port_map_callback,
2246 NULL,
2247 plugin);
2248 return sockets_created;
2249}
2250
2251
2252/**
2253 * The exported method. Makes the core api available via a global and
2254 * returns the xu transport API.
2255 *
2256 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2257 * @return our `struct GNUNET_TRANSPORT_PluginFunctions`
2258 */
2259void *
2260libgnunet_plugin_transport_xu_init (void *cls)
2261{
2262 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2263 struct GNUNET_TRANSPORT_PluginFunctions *api;
2264 struct Plugin *p;
2265 unsigned long long port;
2266 unsigned long long aport;
2267 int enable_v6;
2268 char *bind4_address;
2269 char *bind6_address;
2270 struct sockaddr_in server_addrv4;
2271 struct sockaddr_in6 server_addrv6;
2272 unsigned int res;
2273 int have_bind4;
2274 int have_bind6;
2275
2276 if (NULL == env->receive)
2277 {
2278 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2279 initialze the plugin or the API */
2280 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2281 api->cls = NULL;
2282 api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2283 api->address_to_string = &xu_address_to_string;
2284 api->string_to_address = &xu_string_to_address;
2285 return api;
2286 }
2287
2288 /* Get port number: port == 0 : autodetect a port,
2289 * > 0 : use this port, not given : 2086 default */
2290 if (GNUNET_OK !=
2291 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2292 "transport-xu",
2293 "PORT",
2294 &port))
2295 port = 2086;
2296 if (port > 65535)
2297 {
2298 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2299 "transport-xu",
2300 "PORT",
2301 _("must be in [0,65535]"));
2302 return NULL;
2303 }
2304 if (GNUNET_OK !=
2305 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2306 "transport-xu",
2307 "ADVERTISED_PORT",
2308 &aport))
2309 aport = port;
2310 if (aport > 65535)
2311 {
2312 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2313 "transport-xu",
2314 "ADVERTISED_PORT",
2315 _("must be in [0,65535]"));
2316 return NULL;
2317 }
2318
2319 if (GNUNET_YES ==
2320 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2321 "nat",
2322 "DISABLEV6"))
2323 enable_v6 = GNUNET_NO;
2324 else
2325 enable_v6 = GNUNET_YES;
2326
2327 have_bind4 = GNUNET_NO;
2328 memset (&server_addrv4,
2329 0,
2330 sizeof (server_addrv4));
2331 if (GNUNET_YES ==
2332 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2333 "transport-xu",
2334 "BINDTO",
2335 &bind4_address))
2336 {
2337 LOG (GNUNET_ERROR_TYPE_DEBUG,
2338 "Binding XU plugin to specific address: `%s'\n",
2339 bind4_address);
2340 if (1 != inet_pton (AF_INET,
2341 bind4_address,
2342 &server_addrv4.sin_addr))
2343 {
2344 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2345 "transport-xu",
2346 "BINDTO",
2347 _("must be valid IPv4 address"));
2348 GNUNET_free (bind4_address);
2349 return NULL;
2350 }
2351 have_bind4 = GNUNET_YES;
2352 }
2353 GNUNET_free_non_null (bind4_address);
2354 have_bind6 = GNUNET_NO;
2355 memset (&server_addrv6,
2356 0,
2357 sizeof (server_addrv6));
2358 if (GNUNET_YES ==
2359 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2360 "transport-xu",
2361 "BINDTO6",
2362 &bind6_address))
2363 {
2364 LOG (GNUNET_ERROR_TYPE_DEBUG,
2365 "Binding xu plugin to specific address: `%s'\n",
2366 bind6_address);
2367 if (1 != inet_pton (AF_INET6,
2368 bind6_address,
2369 &server_addrv6.sin6_addr))
2370 {
2371 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2372 "transport-xu",
2373 "BINDTO6",
2374 _("must be valid IPv6 address"));
2375 GNUNET_free (bind6_address);
2376 return NULL;
2377 }
2378 have_bind6 = GNUNET_YES;
2379 }
2380 GNUNET_free_non_null (bind6_address);
2381
2382 p = GNUNET_new (struct Plugin);
2383 p->port = port;
2384 p->aport = aport;
2385 p->enable_ipv6 = enable_v6;
2386 p->enable_ipv4 = GNUNET_YES; /* default */
2387 p->env = env;
2388 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
2389 GNUNET_NO);
2390 res = setup_sockets (p,
2391 (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL,
2392 (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL);
2393 if ( (0 == res) ||
2394 ( (NULL == p->sockv4) &&
2395 (NULL == p->sockv6) ) )
2396 {
2397 LOG (GNUNET_ERROR_TYPE_ERROR,
2398 _("Failed to create XU network sockets\n"));
2399 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
2400 if (NULL != p->nat)
2401 GNUNET_NAT_unregister (p->nat);
2402 GNUNET_free (p);
2403 return NULL;
2404 }
2405
2406 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2407 api->cls = p;
2408 api->disconnect_session = &xu_disconnect_session;
2409 api->query_keepalive_factor = &xu_query_keepalive_factor;
2410 api->disconnect_peer = &xu_disconnect;
2411 api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2412 api->address_to_string = &xu_address_to_string;
2413 api->string_to_address = &xu_string_to_address;
2414 api->check_address = &xu_plugin_check_address;
2415 api->get_session = &xu_plugin_get_session;
2416 api->send = &xu_plugin_send;
2417 api->get_network = &xu_plugin_get_network;
2418 api->get_network_for_address = &xu_plugin_get_network_for_address;
2419 api->update_session_timeout = &xu_plugin_update_session_timeout;
2420 api->setup_monitor = &xu_plugin_setup_monitor;
2421 return api;
2422}
2423
2424
2425/**
2426 * The exported method. Makes the core api available via a global and
2427 * returns the xu transport API.
2428 *
2429 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2430 * @return NULL
2431 */
2432void *
2433libgnunet_plugin_transport_xu_done (void *cls)
2434{
2435 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2436 struct Plugin *plugin = api->cls;
2437 struct PrettyPrinterContext *cur;
2438
2439 if (NULL == plugin)
2440 {
2441 GNUNET_free (api);
2442 return NULL;
2443 }
2444 if (NULL != plugin->select_task_v4)
2445 {
2446 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
2447 plugin->select_task_v4 = NULL;
2448 }
2449 if (NULL != plugin->select_task_v6)
2450 {
2451 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
2452 plugin->select_task_v6 = NULL;
2453 }
2454 if (NULL != plugin->sockv4)
2455 {
2456 GNUNET_break (GNUNET_OK ==
2457 GNUNET_NETWORK_socket_close (plugin->sockv4));
2458 plugin->sockv4 = NULL;
2459 }
2460 if (NULL != plugin->sockv6)
2461 {
2462 GNUNET_break (GNUNET_OK ==
2463 GNUNET_NETWORK_socket_close (plugin->sockv6));
2464 plugin->sockv6 = NULL;
2465 }
2466 if (NULL != plugin->nat)
2467 {
2468 GNUNET_NAT_unregister (plugin->nat);
2469 plugin->nat = NULL;
2470 }
2471 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2472
2473 while (NULL != (cur = plugin->ppc_dll_head))
2474 {
2475 GNUNET_break (0);
2476 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2477 plugin->ppc_dll_tail,
2478 cur);
2479 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
2480 if (NULL != cur->timeout_task)
2481 {
2482 GNUNET_SCHEDULER_cancel (cur->timeout_task);
2483 cur->timeout_task = NULL;
2484 }
2485 GNUNET_free (cur);
2486 }
2487 GNUNET_free (plugin);
2488 GNUNET_free (api);
2489 return NULL;
2490}
2491
2492/* end of plugin_transport_xu.c */