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