2 This file is part of GNUnet
3 Copyright (C) 2010-2017 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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
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"
43 #define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__)
46 * After how much inactivity should a XU session time out?
48 #define XU_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
52 * XU Message-Packet header (after defragmentation).
59 struct GNUNET_MessageHeader header;
62 * Always zero for now.
67 * What is the identity of the sender
69 struct GNUNET_PeerIdentity sender;
75 * Closure for #append_port().
77 struct PrettyPrinterContext
82 struct PrettyPrinterContext *next;
87 struct PrettyPrinterContext *prev;
92 struct Plugin *plugin;
97 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
100 * Function to call with the result.
102 GNUNET_TRANSPORT_AddressStringCallback asc;
105 * Clsoure for @e asc.
112 struct GNUNET_SCHEDULER_Task *timeout_task;
115 * Is this an IPv6 address?
125 * Port to add after the IP address.
133 * Session with another peer.
135 struct GNUNET_ATS_Session
138 * Which peer is this session for?
140 struct GNUNET_PeerIdentity target;
143 * Tokenizer for inbound messages.
145 struct GNUNET_MessageStreamTokenizer *mst;
148 * Plugin this session belongs to.
150 struct Plugin *plugin;
153 * Session timeout task
155 struct GNUNET_SCHEDULER_Task *timeout_task;
158 * When does this session time out?
160 struct GNUNET_TIME_Absolute timeout;
163 * What time did we last transmit?
165 struct GNUNET_TIME_Absolute last_transmit_time;
168 * expected delay for ACKs
170 struct GNUNET_TIME_Relative last_expected_ack_delay;
173 * desired delay between XU messages
175 struct GNUNET_TIME_Relative last_expected_msg_delay;
179 struct GNUNET_TIME_Relative flow_delay_for_other_peer;
180 struct GNUNET_TIME_Relative flow_delay_from_other_peer;
185 struct GNUNET_HELLO_Address *address;
188 * Number of bytes waiting for transmission to this peer.
190 unsigned long long bytes_in_queue;
193 * Number of messages waiting for transmission to this peer.
195 unsigned int msgs_in_queue;
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
206 * Network type of the address.
208 enum GNUNET_NetworkType scope;
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).
222 * If a session monitor is attached, notify it about the new
225 * @param plugin our plugin
226 * @param session session that changed state
227 * @param state new state of the session
230 notify_session_monitor (struct Plugin *plugin,
231 struct GNUNET_ATS_Session *session,
232 enum GNUNET_TRANSPORT_SessionState state)
234 struct GNUNET_TRANSPORT_SessionInfo info;
236 if (NULL == plugin->sic)
238 if (GNUNET_YES == session->in_destroy)
239 return; /* already destroyed, just RC>0 left-over actions */
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,
259 * Return information about the given session to the monitor callback.
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)
267 send_session_info_iter (void *cls,
268 const struct GNUNET_PeerIdentity *peer,
271 struct Plugin *plugin = cls;
272 struct GNUNET_ATS_Session *session = value;
275 notify_session_monitor (plugin,
277 GNUNET_TRANSPORT_SS_INIT);
278 notify_session_monitor (plugin,
280 GNUNET_TRANSPORT_SS_UP);
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).
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
298 xu_plugin_setup_monitor (void *cls,
299 GNUNET_TRANSPORT_SessionInfoCallback sic,
302 struct Plugin *plugin = cls;
305 plugin->sic_cls = sic_cls;
308 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
309 &send_session_info_iter,
311 /* signal end of first iteration */
319 /* ****************** Little Helpers ****************** */
323 * Function to free last resources associated with a session.
325 * @param s session to free
328 free_session (struct GNUNET_ATS_Session *s)
330 if (NULL != s->address)
332 GNUNET_HELLO_address_free (s->address);
337 GNUNET_MST_destroy (s->mst);
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.
349 * @param cls closure with the `struct Plugin`
350 * @return keepalive factor
353 xu_query_keepalive_factor (void *cls)
361 * Function obtain the network type for a session
363 * @param cls closure (`struct Plugin *`)
364 * @param session the session
365 * @return the network type
367 static enum GNUNET_NetworkType
368 xu_plugin_get_network (void *cls,
369 struct GNUNET_ATS_Session *session)
372 return session->scope;
377 * Function obtain the network type for an address.
379 * @param cls closure (`struct Plugin *`)
380 * @param address the address
381 * @return the network type
383 static enum GNUNET_NetworkType
384 xu_plugin_get_network_for_address (void *cls,
385 const struct GNUNET_HELLO_Address *address)
387 struct Plugin *plugin = cls;
389 struct sockaddr_in a4;
390 struct sockaddr_in6 a6;
391 const struct IPv4XuAddress *u4;
392 const struct IPv6XuAddress *u6;
396 addrlen = address->address_length;
397 if (addrlen == sizeof(struct IPv6XuAddress))
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);
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));
411 else if (addrlen == sizeof(struct IPv4XuAddress))
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);
419 a4.sin_family = AF_INET;
420 a4.sin_port = u4->u4_port;
421 a4.sin_addr.s_addr = u4->ipv4_addr;
428 return GNUNET_NT_UNSPECIFIED;
430 return plugin->env->get_address_type (plugin->env->cls,
436 /* ******************* Event loop ******************** */
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.
443 * @param cls the plugin handle
446 xu_plugin_select_v4 (void *cls);
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.
454 * @param cls the plugin handle
457 xu_plugin_select_v6 (void *cls);
461 * (re)schedule IPv4-select tasks for this plugin.
463 * @param plugin plugin to reschedule
466 schedule_select_v4 (struct Plugin *plugin)
468 if ( (GNUNET_YES != plugin->enable_ipv4) ||
469 (NULL == plugin->sockv4) )
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,
476 &xu_plugin_select_v4,
482 * (re)schedule IPv6-select tasks for this plugin.
484 * @param plugin plugin to reschedule
487 schedule_select_v6 (struct Plugin *plugin)
489 if ( (GNUNET_YES != plugin->enable_ipv6) ||
490 (NULL == plugin->sockv6) )
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,
497 &xu_plugin_select_v6,
502 /* ******************* Address to string and back ***************** */
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.
512 * @param addr binary address (a `union XuAddress`)
513 * @param addrlen length of the @a addr
514 * @return string representing the same address
517 xu_address_to_string (void *cls,
521 static char rbuf[INET6_ADDRSTRLEN + 10];
522 char buf[INET6_ADDRSTRLEN];
526 const struct IPv4XuAddress *t4;
527 const struct IPv6XuAddress *t6;
539 if (addrlen == sizeof(struct IPv6XuAddress))
543 options = ntohl (t6->options);
544 port = ntohs (t6->u6_port);
548 else if (addrlen == sizeof(struct IPv4XuAddress))
552 options = ntohl (t4->options);
553 port = ntohs (t4->u4_port);
554 a4.s_addr = t4->ipv4_addr;
566 GNUNET_snprintf (rbuf,
580 * Function called to convert a string address to a binary address.
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
591 xu_string_to_address (void *cls,
597 struct sockaddr_storage socket_address;
604 /* Format tcp.options.address:port */
609 if ((NULL == addr) || (0 == addrlen))
612 return GNUNET_SYSERR;
614 if ('\0' != addr[addrlen - 1])
617 return GNUNET_SYSERR;
619 if (strlen (addr) + 1 != (size_t) addrlen)
622 return GNUNET_SYSERR;
624 plugin = GNUNET_strdup (addr);
625 optionstr = strchr (plugin, '.');
626 if (NULL == optionstr)
629 GNUNET_free (plugin);
630 return GNUNET_SYSERR;
634 options = atol (optionstr);
635 address = strchr (optionstr, '.');
639 GNUNET_free (plugin);
640 return GNUNET_SYSERR;
646 GNUNET_STRINGS_to_address_ip (address,
651 GNUNET_free (plugin);
652 return GNUNET_SYSERR;
656 switch (socket_address.ss_family)
660 struct IPv4XuAddress *u4;
661 const struct sockaddr_in *in4 = (const struct sockaddr_in *) &socket_address;
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;
668 *added = sizeof (struct IPv4XuAddress);
673 struct IPv6XuAddress *u6;
674 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) &socket_address;
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;
681 *added = sizeof (struct IPv6XuAddress);
686 return GNUNET_SYSERR;
692 * Append our port and forward the result.
694 * @param cls a `struct PrettyPrinterContext *`
695 * @param hostname result from DNS resolver
698 append_port (void *cls,
699 const char *hostname)
701 struct PrettyPrinterContext *ppc = cls;
702 struct Plugin *plugin = ppc->plugin;
705 if (NULL == hostname)
707 /* Final call, done */
708 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
709 plugin->ppc_dll_tail,
711 ppc->resolver_handle = NULL;
712 ppc->asc (ppc->asc_cls,
718 if (GNUNET_YES == ppc->ipv6)
719 GNUNET_asprintf (&ret,
726 GNUNET_asprintf (&ret,
732 ppc->asc (ppc->asc_cls,
740 * Convert the transports address to a nice, human-readable format.
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
754 xu_plugin_address_pretty_printer (void *cls,
759 struct GNUNET_TIME_Relative timeout,
760 GNUNET_TRANSPORT_AddressStringCallback asc,
763 struct Plugin *plugin = cls;
764 struct PrettyPrinterContext *ppc;
765 const struct sockaddr *sb;
767 struct sockaddr_in a4;
768 struct sockaddr_in6 a6;
769 const struct IPv4XuAddress *u4;
770 const struct IPv6XuAddress *u6;
775 if (addrlen == sizeof(struct IPv6XuAddress))
781 a6.sin6_family = AF_INET6;
782 #if HAVE_SOCKADDR_IN_SIN_LEN
783 a6.sin6_len = sizeof (a6);
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;
792 else if (addrlen == sizeof (struct IPv4XuAddress))
798 a4.sin_family = AF_INET;
799 #if HAVE_SOCKADDR_IN_SIN_LEN
800 a4.sin_len = sizeof (a4);
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;
811 /* invalid address */
821 ppc = GNUNET_new (struct PrettyPrinterContext);
822 ppc->plugin = plugin;
824 ppc->asc_cls = asc_cls;
826 ppc->options = options;
827 if (addrlen == sizeof (struct IPv6XuAddress))
828 ppc->ipv6 = GNUNET_YES;
830 ppc->ipv6 = GNUNET_NO;
831 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
832 plugin->ppc_dll_tail,
835 = GNUNET_RESOLVER_hostname_get (sb,
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
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
854 check_port (const struct Plugin *plugin,
857 if ( (plugin->port == in_port) ||
858 (plugin->aport == in_port) )
860 return GNUNET_SYSERR;
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
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
880 xu_plugin_check_address (void *cls,
884 struct Plugin *plugin = cls;
885 const struct IPv4XuAddress *v4;
886 const struct IPv6XuAddress *v6;
888 if (sizeof(struct IPv4XuAddress) == addrlen)
890 struct sockaddr_in s4;
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);
901 s4.sin_port = v4->u4_port;
902 s4.sin_addr.s_addr = v4->ipv4_addr;
905 GNUNET_NAT_test_address (plugin->nat,
907 sizeof (struct sockaddr_in)))
908 return GNUNET_SYSERR;
910 else if (sizeof(struct IPv6XuAddress) == addrlen)
912 struct sockaddr_in6 s6;
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);
922 s6.sin6_port = v6->u6_port;
923 s6.sin6_addr = v6->ipv6_addr;
926 GNUNET_NAT_test_address (plugin->nat,
928 sizeof(struct sockaddr_in6)))
929 return GNUNET_SYSERR;
934 return GNUNET_SYSERR;
941 * Our external IP address/port mapping has changed.
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
951 xu_nat_port_map_callback (void *cls,
953 enum GNUNET_NAT_AddressClass ac,
954 const struct sockaddr *addr,
957 struct Plugin *plugin = cls;
958 struct GNUNET_HELLO_Address *address;
959 struct IPv4XuAddress u4;
960 struct IPv6XuAddress u6;
964 if (GNUNET_NAT_AC_LOOPBACK == ac)
966 if (GNUNET_NAT_AC_LAN == ac)
968 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
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",
976 /* convert 'address' to our internal format */
977 switch (addr->sa_family)
981 const struct sockaddr_in *i4;
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. */
990 u4.options = htonl (plugin->myoptions);
991 u4.ipv4_addr = i4->sin_addr.s_addr;
992 u4.u4_port = i4->sin_port;
994 args = sizeof (struct IPv4XuAddress);
999 const struct sockaddr_in6 *i6;
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. */
1008 u6.options = htonl (plugin->myoptions);
1009 u6.ipv6_addr = i6->sin6_addr;
1010 u6.u6_port = i6->sin6_port;
1012 args = sizeof (struct IPv6XuAddress);
1019 /* modify our published address list */
1020 /* TODO: use 'ac' here in the future... */
1021 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1025 GNUNET_HELLO_ADDRESS_INFO_NONE);
1026 plugin->env->notify_address (plugin->env->cls,
1029 GNUNET_HELLO_address_free (address);
1033 /* ********************* Finding sessions ******************* */
1037 * Closure for #session_cmp_it().
1039 struct GNUNET_ATS_SessionCompareContext
1042 * Set to session matching the address.
1044 struct GNUNET_ATS_Session *res;
1047 * Address we are looking for.
1049 const struct GNUNET_HELLO_Address *address;
1054 * Find a session with a matching address.
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
1062 session_cmp_it (void *cls,
1063 const struct GNUNET_PeerIdentity *key,
1066 struct GNUNET_ATS_SessionCompareContext *cctx = cls;
1067 struct GNUNET_ATS_Session *s = value;
1070 if (0 == GNUNET_HELLO_address_cmp (s->address,
1073 GNUNET_assert (GNUNET_NO == s->in_destroy);
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.
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
1090 static struct GNUNET_ATS_Session *
1091 xu_plugin_lookup_session (void *cls,
1092 const struct GNUNET_HELLO_Address *address)
1094 struct Plugin *plugin = cls;
1095 const struct IPv6XuAddress *xu_a6;
1096 const struct IPv4XuAddress *xu_a4;
1097 struct GNUNET_ATS_SessionCompareContext cctx;
1099 if (NULL == address->address)
1104 if (sizeof(struct IPv4XuAddress) == address->address_length)
1106 if (NULL == plugin->sockv4)
1108 xu_a4 = (const struct IPv4XuAddress *) address->address;
1109 if (0 == xu_a4->u4_port)
1115 else if (sizeof(struct IPv6XuAddress) == address->address_length)
1117 if (NULL == plugin->sockv6)
1119 xu_a6 = (const struct IPv6XuAddress *) address->address;
1120 if (0 == xu_a6->u6_port)
1132 /* check if session already exists */
1133 cctx.address = address;
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,
1140 address->address_length));
1141 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1145 if (NULL == cctx.res)
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Found existing session %p\n",
1154 /* ********************** Timeout ****************** */
1158 * Increment session timeout due to activity.
1160 * @param s session to reschedule timeout activity for
1163 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1165 if (GNUNET_YES == s->in_destroy)
1167 GNUNET_assert (NULL != s->timeout_task);
1168 s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
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
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
1183 xu_plugin_update_session_timeout (void *cls,
1184 const struct GNUNET_PeerIdentity *peer,
1185 struct GNUNET_ATS_Session *session)
1187 struct Plugin *plugin = cls;
1190 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1197 /* Reschedule session timeout */
1198 reschedule_session_timeout (session);
1202 /* ************************* Sending ************************ */
1206 * We failed to transmit a message via XU. Generate
1207 * a descriptive error message.
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
1215 analyze_send_error (struct Plugin *plugin,
1216 const struct sockaddr *sa,
1220 enum GNUNET_NetworkType type;
1222 type = plugin->env->get_address_type (plugin->env->cls,
1225 if ( ( (GNUNET_NT_LAN == type) ||
1226 (GNUNET_NT_WAN == type) ) &&
1227 ( (ENETUNREACH == errno) ||
1228 (ENETDOWN == errno) ) )
1230 if (slen == sizeof (struct sockaddr_in))
1232 /* IPv4: "Network unreachable" or "Network down"
1234 * This indicates we do not have connectivity
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"),
1242 if (slen == sizeof (struct sockaddr_in6))
1244 /* IPv6: "Network unreachable" or "Network down"
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
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"));
1258 LOG (GNUNET_ERROR_TYPE_WARNING,
1259 "XU could not transmit message to `%s': `%s'\n",
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
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
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)
1297 xu_plugin_send (void *cls,
1298 struct GNUNET_ATS_Session *s,
1301 unsigned int priority,
1302 struct GNUNET_TIME_Relative to,
1303 GNUNET_TRANSPORT_TransmitContinuation cont,
1306 struct Plugin *plugin = cls;
1307 size_t xumlen = msgbuf_size + sizeof(struct XUMessage);
1308 struct XUMessage *xu;
1309 char mbuf[xumlen] GNUNET_ALIGN;
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;
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)
1330 return GNUNET_SYSERR;
1333 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1338 return GNUNET_SYSERR;
1340 LOG (GNUNET_ERROR_TYPE_DEBUG,
1341 "XU transmits %u-byte message to `%s' using address `%s'\n",
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],
1356 if (sizeof (struct IPv4XuAddress) == s->address->address_length)
1358 u4 = s->address->address;
1362 a4.sin_family = AF_INET;
1363 #if HAVE_SOCKADDR_IN_SIN_LEN
1364 a4.sin_len = sizeof (a4);
1366 a4.sin_port = u4->u4_port;
1367 a4.sin_addr.s_addr = u4->ipv4_addr;
1368 a = (const struct sockaddr *) &a4;
1370 sock = plugin->sockv4;
1372 else if (sizeof (struct IPv6XuAddress) == s->address->address_length)
1374 u6 = s->address->address;
1378 a6.sin6_family = AF_INET6;
1379 #if HAVE_SOCKADDR_IN_SIN_LEN
1380 a6.sin6_len = sizeof (a6);
1382 a6.sin6_port = u6->u6_port;
1383 a6.sin6_addr = u6->ipv6_addr;
1384 a = (const struct sockaddr *) &a6;
1386 sock = plugin->sockv6;
1391 return GNUNET_SYSERR;
1394 sent = GNUNET_NETWORK_socket_sendto (sock,
1399 s->last_transmit_time
1400 = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
1401 s->last_transmit_time);
1403 if (GNUNET_SYSERR == sent)
1406 analyze_send_error (plugin,
1410 GNUNET_STATISTICS_update (plugin->env->stats,
1411 "# XU, total, bytes, sent, failure",
1414 GNUNET_STATISTICS_update (plugin->env->stats,
1415 "# XU, total, messages, sent, failure",
1418 return GNUNET_SYSERR;
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),
1428 (sent < 0) ? STRERROR (errno) : "ok");
1429 GNUNET_STATISTICS_update (plugin->env->stats,
1430 "# XU, total, bytes, sent, success",
1433 GNUNET_STATISTICS_update (plugin->env->stats,
1434 "# XU, total, messages, sent, success",
1442 notify_session_monitor (s->plugin,
1444 GNUNET_TRANSPORT_SS_UPDATE);
1449 /* ********************** Receiving ********************** */
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.
1456 * @param cls closure with the `struct Plugin`
1457 * @param s session to close down
1458 * @return #GNUNET_OK on success
1461 xu_disconnect_session (void *cls,
1462 struct GNUNET_ATS_Session *s)
1464 struct Plugin *plugin = cls;
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",
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)
1476 GNUNET_SCHEDULER_cancel (s->timeout_task);
1477 s->timeout_task = NULL;
1479 GNUNET_assert (GNUNET_YES ==
1480 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
1483 s->in_destroy = GNUNET_YES;
1484 notify_session_monitor (s->plugin,
1486 GNUNET_TRANSPORT_SS_DONE);
1487 plugin->env->session_end (plugin->env->cls,
1490 GNUNET_STATISTICS_set (plugin->env->stats,
1491 "# XU sessions active",
1492 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1501 * Message tokenizer has broken up an incomming message. Pass it on
1504 * @param cls the `struct GNUNET_ATS_Session *`
1505 * @param hdr the actual message
1506 * @return #GNUNET_OK (always)
1509 process_inbound_tokenized_messages (void *cls,
1510 const struct GNUNET_MessageHeader *hdr)
1512 struct GNUNET_ATS_Session *session = cls;
1513 struct Plugin *plugin = session->plugin;
1515 if (GNUNET_YES == session->in_destroy)
1517 reschedule_session_timeout (session);
1518 session->flow_delay_for_other_peer
1519 = plugin->env->receive (plugin->env->cls,
1528 * Destroy a session, plugin is being unloaded.
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)
1536 disconnect_and_free_it (void *cls,
1537 const struct GNUNET_PeerIdentity *key,
1540 struct Plugin *plugin = cls;
1543 xu_disconnect_session (plugin,
1550 * Disconnect from a remote node. Clean up session if we have one for
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
1558 xu_disconnect (void *cls,
1559 const struct GNUNET_PeerIdentity *target)
1561 struct Plugin *plugin = cls;
1563 LOG (GNUNET_ERROR_TYPE_DEBUG,
1564 "Disconnecting from peer `%s'\n",
1565 GNUNET_i2s (target));
1566 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1568 &disconnect_and_free_it,
1574 * Session was idle, so disconnect it.
1576 * @param cls the `struct GNUNET_ATS_Session` to time out
1579 session_timeout (void *cls)
1581 struct GNUNET_ATS_Session *s = cls;
1582 struct Plugin *plugin = s->plugin;
1583 struct GNUNET_TIME_Relative left;
1585 s->timeout_task = NULL;
1586 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1587 if (left.rel_value_us > 0)
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,
1593 GNUNET_TRANSPORT_SS_UPDATE);
1594 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1599 LOG (GNUNET_ERROR_TYPE_DEBUG,
1600 "Session %p was idle for %s, disconnecting\n",
1602 GNUNET_STRINGS_relative_time_to_string (XU_SESSION_TIME_OUT,
1604 /* call session destroy function */
1605 xu_disconnect_session (plugin,
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).
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
1621 static struct GNUNET_ATS_Session *
1622 xu_plugin_create_session (void *cls,
1623 const struct GNUNET_HELLO_Address *address,
1624 enum GNUNET_NetworkType network_type)
1626 struct Plugin *plugin = cls;
1627 struct GNUNET_ATS_Session *s;
1629 s = GNUNET_new (struct GNUNET_ATS_Session);
1630 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
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,
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,
1645 s->scope = network_type;
1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1648 "Creating new session %p for peer `%s' address `%s'\n",
1650 GNUNET_i2s (&address->peer),
1651 xu_address_to_string (plugin,
1653 address->address_length));
1654 GNUNET_assert (GNUNET_OK ==
1655 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1658 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1659 GNUNET_STATISTICS_set (plugin->env->stats,
1660 "# XU sessions active",
1661 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1663 notify_session_monitor (plugin,
1665 GNUNET_TRANSPORT_SS_INIT);
1671 * Creates a new outbound session the transport service will use to
1672 * send data to the peer.
1674 * @param cls the `struct Plugin *`
1675 * @param address the address
1676 * @return the session or NULL of max connections exceeded
1678 static struct GNUNET_ATS_Session *
1679 xu_plugin_get_session (void *cls,
1680 const struct GNUNET_HELLO_Address *address)
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;
1688 if (NULL == address)
1693 if ( (address->address_length != sizeof(struct IPv4XuAddress)) &&
1694 (address->address_length != sizeof(struct IPv6XuAddress)) )
1696 GNUNET_break_op (0);
1699 if (NULL != (s = xu_plugin_lookup_session (cls,
1703 /* need to create new session */
1704 if (sizeof (struct IPv4XuAddress) == address->address_length)
1706 struct sockaddr_in v4;
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);
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,
1720 if (sizeof (struct IPv6XuAddress) == address->address_length)
1722 struct sockaddr_in6 v6;
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);
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,
1736 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
1737 return xu_plugin_create_session (cls,
1744 * We've received a XU Message. Process it (pass contents to main service).
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
1753 process_xu_message (struct Plugin *plugin,
1754 const struct XUMessage *msg,
1755 const union XuAddress *xu_addr,
1757 enum GNUNET_NetworkType network_type)
1759 struct GNUNET_ATS_Session *s;
1760 struct GNUNET_HELLO_Address *address;
1762 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
1763 if (0 != ntohl (msg->reserved))
1768 if (ntohs (msg->header.size)
1769 < sizeof(struct GNUNET_MessageHeader) + sizeof(struct XUMessage))
1775 address = GNUNET_HELLO_address_allocate (&msg->sender,
1779 GNUNET_HELLO_ADDRESS_INFO_NONE);
1781 (s = xu_plugin_lookup_session (plugin,
1784 s = xu_plugin_create_session (plugin,
1787 plugin->env->session_start (plugin->env->cls,
1791 notify_session_monitor (plugin,
1793 GNUNET_TRANSPORT_SS_UP);
1795 GNUNET_free (address);
1798 GNUNET_MST_from_buffer (s->mst,
1799 (const char *) &msg[1],
1800 ntohs (msg->header.size) - sizeof(struct XUMessage),
1804 if ( (0 == s->rc) &&
1805 (GNUNET_YES == s->in_destroy) )
1811 * Read and process a message from the given socket.
1813 * @param plugin the overall plugin
1814 * @param rsock socket to read from
1817 xu_select_read (struct Plugin *plugin,
1818 struct GNUNET_NETWORK_Handle *rsock)
1821 struct sockaddr_storage addr;
1822 char buf[65536] GNUNET_ALIGN;
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;
1834 fromlen = sizeof (addr);
1838 size = GNUNET_NETWORK_socket_recvfrom (rsock,
1841 (struct sockaddr *) &addr,
1843 sa = (const struct sockaddr *) &addr;
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.
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.
1855 if ( (-1 == size) &&
1856 (ECONNRESET == errno) )
1861 LOG (GNUNET_ERROR_TYPE_DEBUG,
1862 "XU failed to receive data: %s\n",
1864 /* Connection failure or something. Not a protocol violation. */
1868 /* Check if this is a STUN packet */
1870 GNUNET_NAT_stun_handle_packet (plugin->nat,
1871 (const struct sockaddr *) &addr,
1875 return; /* was STUN, do not process further */
1877 if (((size_t) size) < sizeof(struct GNUNET_MessageHeader))
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,
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);
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,
1897 if (size != ntohs (msg->size))
1899 LOG (GNUNET_ERROR_TYPE_WARNING,
1900 "XU malformed message (size %u) header from %s\n",
1901 (unsigned int) size,
1904 GNUNET_break_op (0);
1907 GNUNET_STATISTICS_update (plugin->env->stats,
1908 "# XU, total bytes received",
1911 network_type = plugin->env->get_address_type (plugin->env->cls,
1914 switch (sa->sa_family)
1917 sa4 = (const struct sockaddr_in *) &addr;
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);
1925 sa6 = (const struct sockaddr_in6 *) &addr;
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);
1937 switch (ntohs (msg->type))
1939 case GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE:
1940 if (ntohs (msg->size) < sizeof(struct XUMessage))
1945 process_xu_message (plugin,
1946 (const struct XUMessage *) msg,
1958 /* ***************** Event loop (part 2) *************** */
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.
1966 * @param cls the plugin handle
1969 xu_plugin_select_v4 (void *cls)
1971 struct Plugin *plugin = cls;
1972 const struct GNUNET_SCHEDULER_TaskContext *tc;
1974 plugin->select_task_v4 = NULL;
1975 if (NULL == plugin->sockv4)
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,
1981 xu_select_read (plugin,
1983 schedule_select_v4 (plugin);
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.
1992 * @param cls the plugin handle
1995 xu_plugin_select_v6 (void *cls)
1997 struct Plugin *plugin = cls;
1998 const struct GNUNET_SCHEDULER_TaskContext *tc;
2000 plugin->select_task_v6 = NULL;
2001 if (NULL == plugin->sockv6)
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,
2007 xu_select_read (plugin,
2009 schedule_select_v6 (plugin);
2013 /* ******************* Initialization *************** */
2017 * Setup the XU sockets (for IPv4 and IPv6) for the plugin.
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
2025 setup_sockets (struct Plugin *plugin,
2026 const struct sockaddr_in6 *bind_v6,
2027 const struct sockaddr_in *bind_v4)
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];
2039 /* Create IPv6 socket */
2041 if (GNUNET_YES == plugin->enable_ipv6)
2043 plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6,
2046 if (NULL == plugin->sockv6)
2048 LOG (GNUNET_ERROR_TYPE_INFO,
2049 _("Disabling IPv6 since it is not supported on this system!\n"));
2050 plugin->enable_ipv6 = GNUNET_NO;
2054 memset (&server_addrv6,
2056 sizeof(struct sockaddr_in6));
2057 #if HAVE_SOCKADDR_IN_SIN_LEN
2058 server_addrv6.sin6_len = sizeof (struct sockaddr_in6);
2060 server_addrv6.sin6_family = AF_INET6;
2061 if (NULL != bind_v6)
2062 server_addrv6.sin6_addr = bind_v6->sin6_addr;
2064 server_addrv6.sin6_addr = in6addr_any;
2066 if (0 == plugin->port) /* autodetect */
2067 server_addrv6.sin6_port
2068 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2072 server_addrv6.sin6_port = htons (plugin->port);
2073 addrlen = sizeof (struct sockaddr_in6);
2074 server_addr = (const struct sockaddr *) &server_addrv6;
2079 LOG(GNUNET_ERROR_TYPE_DEBUG,
2080 "Binding to IPv6 `%s'\n",
2081 GNUNET_a2s (server_addr,
2085 GNUNET_NETWORK_socket_bind (plugin->sockv6,
2090 if (0 != plugin->port)
2092 tries = 10; /* fail immediately */
2093 break; /* bind failed on specific port */
2096 server_addrv6.sin6_port
2097 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2104 GNUNET_NETWORK_socket_close (plugin->sockv6);
2105 plugin->enable_ipv6 = GNUNET_NO;
2106 plugin->sockv6 = NULL;
2110 plugin->port = ntohs (server_addrv6.sin6_port);
2112 if (NULL != plugin->sockv6)
2114 LOG (GNUNET_ERROR_TYPE_DEBUG,
2115 "IPv6 XU socket created listinging at %s\n",
2116 GNUNET_a2s (server_addr,
2118 addrs[sockets_created] = server_addr;
2119 addrlens[sockets_created] = addrlen;
2124 LOG (GNUNET_ERROR_TYPE_WARNING,
2125 _("Failed to bind XU socket to %s: %s\n"),
2126 GNUNET_a2s (server_addr,
2133 /* Create IPv4 socket */
2135 plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET,
2138 if (NULL == plugin->sockv4)
2140 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
2142 LOG (GNUNET_ERROR_TYPE_INFO,
2143 _("Disabling IPv4 since it is not supported on this system!\n"));
2144 plugin->enable_ipv4 = GNUNET_NO;
2148 memset (&server_addrv4,
2150 sizeof(struct sockaddr_in));
2151 #if HAVE_SOCKADDR_IN_SIN_LEN
2152 server_addrv4.sin_len = sizeof (struct sockaddr_in);
2154 server_addrv4.sin_family = AF_INET;
2155 if (NULL != bind_v4)
2156 server_addrv4.sin_addr = bind_v4->sin_addr;
2158 server_addrv4.sin_addr.s_addr = INADDR_ANY;
2160 if (0 == plugin->port)
2162 server_addrv4.sin_port
2163 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2167 server_addrv4.sin_port = htons (plugin->port);
2169 addrlen = sizeof (struct sockaddr_in);
2170 server_addr = (const struct sockaddr *) &server_addrv4;
2175 LOG (GNUNET_ERROR_TYPE_DEBUG,
2176 "Binding to IPv4 `%s'\n",
2177 GNUNET_a2s (server_addr,
2182 GNUNET_NETWORK_socket_bind (plugin->sockv4,
2187 if (0 != plugin->port)
2189 tries = 10; /* fail */
2190 break; /* bind failed on specific port */
2194 server_addrv4.sin_port
2195 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2202 GNUNET_NETWORK_socket_close (plugin->sockv4);
2203 plugin->enable_ipv4 = GNUNET_NO;
2204 plugin->sockv4 = NULL;
2208 plugin->port = ntohs (server_addrv4.sin_port);
2211 if (NULL != plugin->sockv4)
2213 LOG (GNUNET_ERROR_TYPE_DEBUG,
2214 "IPv4 socket created on port %s\n",
2215 GNUNET_a2s (server_addr,
2217 addrs[sockets_created] = server_addr;
2218 addrlens[sockets_created] = addrlen;
2223 LOG (GNUNET_ERROR_TYPE_ERROR,
2224 _("Failed to bind XU socket to %s: %s\n"),
2225 GNUNET_a2s (server_addr,
2231 if (0 == sockets_created)
2233 LOG (GNUNET_ERROR_TYPE_WARNING,
2234 _("Failed to open XU sockets\n"));
2235 return 0; /* No sockets created, return */
2237 schedule_select_v4 (plugin);
2238 schedule_select_v6 (plugin);
2239 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2245 &xu_nat_port_map_callback,
2248 return sockets_created;
2253 * The exported method. Makes the core api available via a global and
2254 * returns the xu transport API.
2256 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2257 * @return our `struct GNUNET_TRANSPORT_PluginFunctions`
2260 libgnunet_plugin_transport_xu_init (void *cls)
2262 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2263 struct GNUNET_TRANSPORT_PluginFunctions *api;
2265 unsigned long long port;
2266 unsigned long long aport;
2268 char *bind4_address;
2269 char *bind6_address;
2270 struct sockaddr_in server_addrv4;
2271 struct sockaddr_in6 server_addrv6;
2276 if (NULL == env->receive)
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);
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;
2288 /* Get port number: port == 0 : autodetect a port,
2289 * > 0 : use this port, not given : 2086 default */
2291 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2298 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2301 _("must be in [0,65535]"));
2305 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2312 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2315 _("must be in [0,65535]"));
2320 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2323 enable_v6 = GNUNET_NO;
2325 enable_v6 = GNUNET_YES;
2327 have_bind4 = GNUNET_NO;
2328 memset (&server_addrv4,
2330 sizeof (server_addrv4));
2332 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2337 LOG (GNUNET_ERROR_TYPE_DEBUG,
2338 "Binding XU plugin to specific address: `%s'\n",
2340 if (1 != inet_pton (AF_INET,
2342 &server_addrv4.sin_addr))
2344 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2347 _("must be valid IPv4 address"));
2348 GNUNET_free (bind4_address);
2351 have_bind4 = GNUNET_YES;
2353 GNUNET_free_non_null (bind4_address);
2354 have_bind6 = GNUNET_NO;
2355 memset (&server_addrv6,
2357 sizeof (server_addrv6));
2359 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2364 LOG (GNUNET_ERROR_TYPE_DEBUG,
2365 "Binding xu plugin to specific address: `%s'\n",
2367 if (1 != inet_pton (AF_INET6,
2369 &server_addrv6.sin6_addr))
2371 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2374 _("must be valid IPv6 address"));
2375 GNUNET_free (bind6_address);
2378 have_bind6 = GNUNET_YES;
2380 GNUNET_free_non_null (bind6_address);
2382 p = GNUNET_new (struct Plugin);
2385 p->enable_ipv6 = enable_v6;
2386 p->enable_ipv4 = GNUNET_YES; /* default */
2388 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
2390 res = setup_sockets (p,
2391 (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL,
2392 (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL);
2394 ( (NULL == p->sockv4) &&
2395 (NULL == p->sockv6) ) )
2397 LOG (GNUNET_ERROR_TYPE_ERROR,
2398 _("Failed to create XU network sockets\n"));
2399 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
2401 GNUNET_NAT_unregister (p->nat);
2406 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
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;
2426 * The exported method. Makes the core api available via a global and
2427 * returns the xu transport API.
2429 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2433 libgnunet_plugin_transport_xu_done (void *cls)
2435 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2436 struct Plugin *plugin = api->cls;
2437 struct PrettyPrinterContext *cur;
2444 if (NULL != plugin->select_task_v4)
2446 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
2447 plugin->select_task_v4 = NULL;
2449 if (NULL != plugin->select_task_v6)
2451 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
2452 plugin->select_task_v6 = NULL;
2454 if (NULL != plugin->sockv4)
2456 GNUNET_break (GNUNET_OK ==
2457 GNUNET_NETWORK_socket_close (plugin->sockv4));
2458 plugin->sockv4 = NULL;
2460 if (NULL != plugin->sockv6)
2462 GNUNET_break (GNUNET_OK ==
2463 GNUNET_NETWORK_socket_close (plugin->sockv6));
2464 plugin->sockv6 = NULL;
2466 if (NULL != plugin->nat)
2468 GNUNET_NAT_unregister (plugin->nat);
2471 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2473 while (NULL != (cur = plugin->ppc_dll_head))
2476 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2477 plugin->ppc_dll_tail,
2479 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
2480 if (NULL != cur->timeout_task)
2482 GNUNET_SCHEDULER_cancel (cur->timeout_task);
2483 cur->timeout_task = NULL;
2487 GNUNET_free (plugin);
2492 /* end of plugin_transport_xu.c */