2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file transport/plugin_transport_tcp.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
26 #include "gnunet_hello_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "transport.h"
38 #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__)
40 #define PLUGIN_NAME "tcp"
43 * How long until we give up on establishing an NAT connection?
46 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
48 GNUNET_NETWORK_STRUCT_BEGIN
52 * Initial handshake message for a session.
57 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
59 struct GNUNET_MessageHeader header;
62 * Identity of the node connecting (TCP client)
64 struct GNUNET_PeerIdentity clientIdentity;
69 * Basically a WELCOME message, but with the purpose
70 * of giving the waiting peer a client handle to use
72 struct TCP_NAT_ProbeMessage
75 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
77 struct GNUNET_MessageHeader header;
80 * Identity of the sender of the message.
82 struct GNUNET_PeerIdentity clientIdentity;
85 GNUNET_NETWORK_STRUCT_END
88 * Context for sending a NAT probe via TCP.
90 struct TCPProbeContext
94 * Active probes are kept in a DLL.
96 struct TCPProbeContext *next;
99 * Active probes are kept in a DLL.
101 struct TCPProbeContext *prev;
106 struct GNUNET_CONNECTION_Handle *sock;
109 * Message to be sent.
111 struct TCP_NAT_ProbeMessage message;
114 * Handle to the transmission.
116 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
119 * Transport plugin handle.
121 struct Plugin *plugin;
125 * Bits in the `options` field of TCP addresses.
127 enum TcpAddressOptions
133 TCP_OPTIONS_NONE = 0,
136 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
138 TCP_OPTIONS_RESERVED = 1,
141 * Enable TCP Stealth-style port knocking.
143 TCP_OPTIONS_TCP_STEALTH = 2
146 GNUNET_NETWORK_STRUCT_BEGIN
149 * Network format for IPv4 addresses.
151 struct IPv4TcpAddress
154 * Optional options and flags for this address,
155 * see `enum TcpAddressOptions`
157 uint32_t options GNUNET_PACKED;
160 * IPv4 address, in network byte order.
162 uint32_t ipv4_addr GNUNET_PACKED;
165 * Port number, in network byte order.
167 uint16_t t4_port GNUNET_PACKED;
172 * Network format for IPv6 addresses.
174 struct IPv6TcpAddress
177 * Optional flags for this address
178 * see `enum TcpAddressOptions`
180 uint32_t options GNUNET_PACKED;
185 struct in6_addr ipv6_addr GNUNET_PACKED;
188 * Port number, in network byte order.
190 uint16_t t6_port GNUNET_PACKED;
193 GNUNET_NETWORK_STRUCT_END
196 * Encapsulation of all of the state of the plugin.
201 * Information kept for each message that is yet to
204 struct PendingMessage
208 * This is a doubly-linked list.
210 struct PendingMessage *next;
213 * This is a doubly-linked list.
215 struct PendingMessage *prev;
218 * The pending message
223 * Continuation function to call once the message
224 * has been sent. Can be NULL if there is no
225 * continuation to call.
227 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
230 * Closure for @e transmit_cont.
232 void *transmit_cont_cls;
235 * Timeout value for the pending message.
237 struct GNUNET_TIME_Absolute timeout;
240 * So that the gnunet-service-transport can group messages together,
241 * these pending messages need to accept a message buffer and size
242 * instead of just a `struct GNUNET_MessageHeader`.
249 * Session handle for TCP connections.
251 struct GNUNET_ATS_Session
254 * To whom are we talking to (set to our identity
255 * if we are still waiting for the welcome message)
257 struct GNUNET_PeerIdentity target;
260 * Pointer to the global plugin struct.
262 struct Plugin *plugin;
265 * The client (used to identify this connection)
267 struct GNUNET_SERVER_Client *client;
270 * Task cleaning up a NAT client connection establishment attempt;
272 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
275 * Messages currently pending for transmission
276 * to this peer, if any.
278 struct PendingMessage *pending_messages_head;
281 * Messages currently pending for transmission
282 * to this peer, if any.
284 struct PendingMessage *pending_messages_tail;
287 * Handle for pending transmission request.
289 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
292 * Address of the other peer.
294 struct GNUNET_HELLO_Address *address;
297 * ID of task used to delay receiving more to throttle sender.
299 struct GNUNET_SCHEDULER_Task *receive_delay_task;
302 * Session timeout task
304 struct GNUNET_SCHEDULER_Task *timeout_task;
307 * When will this session time out?
309 struct GNUNET_TIME_Absolute timeout;
312 * When will we continue to read from the socket?
313 * (used to enforce inbound quota).
315 struct GNUNET_TIME_Absolute receive_delay;
318 * Last activity on this connection. Used to select preferred
321 struct GNUNET_TIME_Absolute last_activity;
324 * Number of bytes waiting for transmission to this peer.
326 unsigned long long bytes_in_queue;
329 * Number of messages waiting for transmission to this peer.
331 unsigned int msgs_in_queue;
334 * Network type of the address.
336 enum GNUNET_ATS_Network_Type scope;
339 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
341 int expecting_welcome;
344 * Was this session created using NAT traversal?
352 * Context for address to string conversion, closure
353 * for #append_port().
355 struct PrettyPrinterContext
360 struct PrettyPrinterContext *next;
365 struct PrettyPrinterContext *prev;
370 struct Plugin *plugin;
375 struct GNUNET_SCHEDULER_Task *timeout_task;
380 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
383 * Function to call with the result.
385 GNUNET_TRANSPORT_AddressStringCallback asc;
388 * Clsoure for @e asc.
403 * Port to add after the IP address.
410 * Encapsulation of all of the state of the plugin.
417 struct GNUNET_TRANSPORT_PluginEnvironment *env;
422 struct GNUNET_CONNECTION_Handle *lsock;
425 * Our handle to the NAT module.
427 struct GNUNET_NAT_Handle *nat;
430 * Map from peer identities to sessions for the given peer.
432 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
435 * Handle to the network service.
437 struct GNUNET_SERVICE_Context *service;
440 * Handle to the server for this service.
442 struct GNUNET_SERVER_Handle *server;
445 * Copy of the handler array where the closures are
446 * set to this struct's instance.
448 struct GNUNET_SERVER_MessageHandler *handlers;
451 * Map of peers we have tried to contact behind a NAT
453 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
456 * List of active TCP probes.
458 struct TCPProbeContext *probe_head;
461 * List of active TCP probes.
463 struct TCPProbeContext *probe_tail;
466 * Function to call about session status changes.
468 GNUNET_TRANSPORT_SessionInfoCallback sic;
471 * Closure for @e sic.
476 * ID of task used to update our addresses when one expires.
478 struct GNUNET_SCHEDULER_Task *address_update_task;
481 * Running pretty printers: head
483 struct PrettyPrinterContext *ppc_dll_head;
486 * Running pretty printers: tail
488 struct PrettyPrinterContext *ppc_dll_tail;
491 * Welcome message used by this peer.
493 struct WelcomeMessage my_welcome;
496 * How many more TCP sessions are we allowed to open right now?
498 unsigned long long max_connections;
501 * How many more TCP sessions do we have right now?
503 unsigned long long cur_connections;
511 * Port that we are actually listening on.
516 * Port that the user said we would have visible to the
524 /* begin of ancient copy-and-pasted code that should be
525 specialized for TCP ...*/
527 * Add the given UNIX domain path as an address to the
528 * list (as the first entry).
530 * @param saddrs array to update
531 * @param saddrlens where to store the address length
532 * @param unixpath path to add
533 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
534 * parameter is ignore on systems other than LINUX
537 add_unixpath (struct sockaddr **saddrs,
538 socklen_t *saddrlens,
539 const char *unixpath,
543 struct sockaddr_un *un;
545 un = GNUNET_new (struct sockaddr_un);
546 un->sun_family = AF_UNIX;
547 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
549 if (GNUNET_YES == abstract)
550 un->sun_path[0] = '\0';
552 #if HAVE_SOCKADDR_UN_SUN_LEN
553 un->sun_len = (u_char) sizeof (struct sockaddr_un);
555 *saddrs = (struct sockaddr *) un;
556 *saddrlens = sizeof (struct sockaddr_un);
558 /* this function should never be called
559 * unless AF_UNIX is defined! */
566 * Get the list of addresses that a server for the given service
569 * @param service_name name of the service
570 * @param cfg configuration (which specifies the addresses)
571 * @param addrs set (call by reference) to an array of pointers to the
572 * addresses the server should bind to and listen on; the
573 * array will be NULL-terminated (on success)
574 * @param addr_lens set (call by reference) to an array of the lengths
575 * of the respective `struct sockaddr` struct in the @a addrs
577 * @return number of addresses found on success,
578 * #GNUNET_SYSERR if the configuration
579 * did not specify reasonable finding information or
580 * if it specified a hostname that could not be resolved;
581 * #GNUNET_NO if the number of addresses configured is
582 * zero (in this case, `*addrs` and `*addr_lens` will be
586 get_server_addresses (const char *service_name,
587 const struct GNUNET_CONFIGURATION_Handle *cfg,
588 struct sockaddr ***addrs,
589 socklen_t ** addr_lens)
592 struct GNUNET_NETWORK_Handle *desc;
593 unsigned long long port;
595 struct addrinfo hints;
596 struct addrinfo *res;
597 struct addrinfo *pos;
598 struct addrinfo *next;
603 struct sockaddr **saddrs;
604 socklen_t *saddrlens;
610 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
614 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
615 return GNUNET_SYSERR;
618 disablev6 = GNUNET_NO;
622 /* probe IPv6 support */
623 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
626 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
629 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
630 return GNUNET_SYSERR;
632 LOG (GNUNET_ERROR_TYPE_INFO,
633 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
634 service_name, STRERROR (errno));
635 disablev6 = GNUNET_YES;
639 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
645 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
648 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
651 LOG (GNUNET_ERROR_TYPE_ERROR,
652 _("Require valid port number for service `%s' in configuration!\n"),
657 LOG (GNUNET_ERROR_TYPE_ERROR,
658 _("Require valid port number for service `%s' in configuration!\n"),
660 return GNUNET_SYSERR;
664 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
666 GNUNET_break (GNUNET_OK ==
667 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
668 "BINDTO", &hostname));
674 abstract = GNUNET_NO;
677 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
679 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
681 (0 < strlen (unixpath)))
683 /* probe UNIX support */
684 struct sockaddr_un s_un;
686 if (strlen (unixpath) >= sizeof (s_un.sun_path))
688 LOG (GNUNET_ERROR_TYPE_WARNING,
689 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
690 (unsigned long long) sizeof (s_un.sun_path));
691 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
692 LOG (GNUNET_ERROR_TYPE_INFO,
693 _("Using `%s' instead\n"),
697 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
699 "USE_ABSTRACT_SOCKETS");
700 if (GNUNET_SYSERR == abstract)
701 abstract = GNUNET_NO;
703 if ((GNUNET_YES != abstract)
705 GNUNET_DISK_directory_create_for_file (unixpath)))
706 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
710 if (NULL != unixpath)
712 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
715 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
718 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
719 GNUNET_free_non_null (hostname);
720 GNUNET_free (unixpath);
721 return GNUNET_SYSERR;
723 LOG (GNUNET_ERROR_TYPE_INFO,
724 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
727 GNUNET_free (unixpath);
732 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
738 if ((0 == port) && (NULL == unixpath))
740 LOG (GNUNET_ERROR_TYPE_ERROR,
741 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
743 GNUNET_free_non_null (hostname);
744 return GNUNET_SYSERR;
748 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
749 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
750 add_unixpath (saddrs, saddrlens, unixpath, abstract);
751 GNUNET_free_non_null (unixpath);
752 GNUNET_free_non_null (hostname);
754 *addr_lens = saddrlens;
758 if (NULL != hostname)
760 LOG (GNUNET_ERROR_TYPE_DEBUG,
761 "Resolving `%s' since that is where `%s' will bind to.\n",
764 memset (&hints, 0, sizeof (struct addrinfo));
766 hints.ai_family = AF_INET;
767 hints.ai_protocol = IPPROTO_TCP;
768 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
771 LOG (GNUNET_ERROR_TYPE_ERROR,
772 _("Failed to resolve `%s': %s\n"),
775 GNUNET_free (hostname);
776 GNUNET_free_non_null (unixpath);
777 return GNUNET_SYSERR;
781 while (NULL != (pos = next))
784 if ((disablev6) && (pos->ai_family == AF_INET6))
790 LOG (GNUNET_ERROR_TYPE_ERROR,
791 _("Failed to find %saddress for `%s'.\n"),
792 disablev6 ? "IPv4 " : "",
795 GNUNET_free (hostname);
796 GNUNET_free_non_null (unixpath);
797 return GNUNET_SYSERR;
800 if (NULL != unixpath)
802 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
803 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
805 if (NULL != unixpath)
807 add_unixpath (saddrs, saddrlens, unixpath, abstract);
811 while (NULL != (pos = next))
814 if ((disablev6) && (AF_INET6 == pos->ai_family))
816 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
817 continue; /* not TCP */
818 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
820 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
821 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
822 if (AF_INET == pos->ai_family)
824 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
825 saddrlens[i] = pos->ai_addrlen;
826 saddrs[i] = GNUNET_malloc (saddrlens[i]);
827 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
828 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
832 GNUNET_assert (AF_INET6 == pos->ai_family);
833 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
834 saddrlens[i] = pos->ai_addrlen;
835 saddrs[i] = GNUNET_malloc (saddrlens[i]);
836 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
837 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
841 GNUNET_free (hostname);
847 /* will bind against everything, just set port */
852 if (NULL != unixpath)
855 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
856 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
857 if (NULL != unixpath)
859 add_unixpath (saddrs, saddrlens, unixpath, abstract);
862 saddrlens[i] = sizeof (struct sockaddr_in);
863 saddrs[i] = GNUNET_malloc (saddrlens[i]);
864 #if HAVE_SOCKADDR_IN_SIN_LEN
865 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
867 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
868 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
874 if (NULL != unixpath)
876 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
877 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
879 if (NULL != unixpath)
881 add_unixpath (saddrs, saddrlens, unixpath, abstract);
884 saddrlens[i] = sizeof (struct sockaddr_in6);
885 saddrs[i] = GNUNET_malloc (saddrlens[i]);
886 #if HAVE_SOCKADDR_IN_SIN_LEN
887 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
889 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
890 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
892 saddrlens[i] = sizeof (struct sockaddr_in);
893 saddrs[i] = GNUNET_malloc (saddrlens[i]);
894 #if HAVE_SOCKADDR_IN_SIN_LEN
895 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
897 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
898 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
901 GNUNET_free_non_null (unixpath);
903 *addr_lens = saddrlens;
906 /* end ancient copy-and-paste */
910 * If a session monitor is attached, notify it about the new
913 * @param plugin our plugin
914 * @param session session that changed state
915 * @param state new state of the session
918 notify_session_monitor (struct Plugin *plugin,
919 struct GNUNET_ATS_Session *session,
920 enum GNUNET_TRANSPORT_SessionState state)
922 struct GNUNET_TRANSPORT_SessionInfo info;
924 if (NULL == plugin->sic)
926 memset (&info, 0, sizeof (info));
928 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
929 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
930 info.num_msg_pending = session->msgs_in_queue;
931 info.num_bytes_pending = session->bytes_in_queue;
932 if (NULL != session->receive_delay_task)
933 info.receive_delay = session->receive_delay;
934 info.session_timeout = session->timeout;
935 info.address = session->address;
936 plugin->sic (plugin->sic_cls,
943 * Our external IP address/port mapping has changed.
945 * @param cls closure, the `struct Plugin`
946 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
947 * the previous (now invalid) one
948 * @param ac address class the address belongs to
949 * @param addr either the previous or the new public IP address
950 * @param addrlen actual length of @a addr
953 tcp_nat_port_map_callback (void *cls,
955 enum GNUNET_NAT_AddressClass ac,
956 const struct sockaddr *addr,
959 struct Plugin *plugin = cls;
960 struct GNUNET_HELLO_Address *address;
961 struct IPv4TcpAddress t4;
962 struct IPv6TcpAddress t6;
966 LOG (GNUNET_ERROR_TYPE_INFO,
967 "NAT notification to %s address `%s'\n",
968 (GNUNET_YES == add_remove) ? "add" : "remove",
969 GNUNET_a2s (addr, addrlen));
970 /* convert 'addr' to our internal format */
971 switch (addr->sa_family)
974 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
975 memset (&t4, 0, sizeof(t4));
976 t4.options = htonl (plugin->myoptions);
977 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
978 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
983 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
984 memset (&t6, 0, sizeof(t6));
985 GNUNET_memcpy (&t6.ipv6_addr,
986 &((struct sockaddr_in6 *) addr)->sin6_addr,
987 sizeof(struct in6_addr));
988 t6.options = htonl (plugin->myoptions);
989 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
997 /* modify our published address list */
998 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
999 (args == sizeof (struct IPv6TcpAddress)));
1000 /* TODO: use 'ac' here in the future... */
1001 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1005 GNUNET_HELLO_ADDRESS_INFO_NONE);
1006 plugin->env->notify_address (plugin->env->cls,
1009 GNUNET_HELLO_address_free (address);
1014 * Function called for a quick conversion of the binary address to
1015 * a numeric address. Note that the caller must not free the
1016 * address and that the next call to this function is allowed
1017 * to override the address again.
1019 * @param cls closure (`struct Plugin*`)
1020 * @param addr binary address
1021 * @param addrlen length of @a addr
1022 * @return string representing the same address
1025 tcp_plugin_address_to_string (void *cls,
1029 static char rbuf[INET6_ADDRSTRLEN + 12];
1030 char buf[INET6_ADDRSTRLEN];
1034 const struct IPv4TcpAddress *t4;
1035 const struct IPv6TcpAddress *t6;
1042 case sizeof(struct IPv6TcpAddress):
1045 port = ntohs (t6->t6_port);
1046 options = ntohl (t6->options);
1047 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1050 case sizeof(struct IPv4TcpAddress):
1053 port = ntohs (t4->t4_port);
1054 options = ntohl (t4->options);
1055 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1059 LOG (GNUNET_ERROR_TYPE_WARNING,
1060 _("Unexpected address length: %u bytes\n"),
1061 (unsigned int) addrlen);
1064 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1066 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1070 GNUNET_snprintf (rbuf, sizeof(rbuf),
1071 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1081 * Function called to convert a string address to
1084 * @param cls closure (`struct Plugin*`)
1085 * @param addr string address
1086 * @param addrlen length of the address
1087 * @param buf location to store the buffer
1088 * @param added location to store the number of bytes in the buffer.
1089 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1090 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1093 tcp_plugin_string_to_address (void *cls,
1099 struct sockaddr_storage socket_address;
1105 /* Format tcp.options.address:port */
1109 if ((NULL == addr) || (0 == addrlen))
1112 return GNUNET_SYSERR;
1114 if ('\0' != addr[addrlen - 1])
1117 return GNUNET_SYSERR;
1119 if (strlen (addr) != addrlen - 1)
1122 return GNUNET_SYSERR;
1124 plugin = GNUNET_strdup (addr);
1125 optionstr = strchr (plugin, '.');
1126 if (NULL == optionstr)
1129 GNUNET_free(plugin);
1130 return GNUNET_SYSERR;
1132 optionstr[0] = '\0';
1134 options = atol (optionstr);
1135 address = strchr (optionstr, '.');
1136 if (NULL == address)
1139 GNUNET_free(plugin);
1140 return GNUNET_SYSERR;
1146 GNUNET_STRINGS_to_address_ip (address,
1151 GNUNET_free(plugin);
1152 return GNUNET_SYSERR;
1155 GNUNET_free(plugin);
1156 switch (socket_address.ss_family)
1160 struct IPv4TcpAddress *t4;
1161 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1162 t4 = GNUNET_new (struct IPv4TcpAddress);
1163 t4->options = htonl (options);
1164 t4->ipv4_addr = in4->sin_addr.s_addr;
1165 t4->t4_port = in4->sin_port;
1167 *added = sizeof(struct IPv4TcpAddress);
1172 struct IPv6TcpAddress *t6;
1173 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1174 t6 = GNUNET_new (struct IPv6TcpAddress);
1175 t6->options = htonl (options);
1176 t6->ipv6_addr = in6->sin6_addr;
1177 t6->t6_port = in6->sin6_port;
1179 *added = sizeof(struct IPv6TcpAddress);
1183 return GNUNET_SYSERR;
1189 * Find the session handle for the given client.
1190 * Currently uses both the hashmap and the client
1191 * context, as the client context is new and the
1192 * logic still needs to be tested.
1194 * @param plugin the plugin
1195 * @param client which client to find the session handle for
1196 * @return NULL if no matching session exists
1198 static struct GNUNET_ATS_Session *
1199 lookup_session_by_client (struct Plugin *plugin,
1200 struct GNUNET_SERVER_Client *client)
1202 return GNUNET_SERVER_client_get_user_context (client,
1203 struct GNUNET_ATS_Session);
1208 * Functions with this signature are called whenever we need
1209 * to close a session due to a disconnect or failure to
1210 * establish a connection.
1212 * @param cls the `struct Plugin`
1213 * @param session session to close down
1214 * @return #GNUNET_OK on success
1217 tcp_plugin_disconnect_session (void *cls,
1218 struct GNUNET_ATS_Session *session)
1220 struct Plugin *plugin = cls;
1221 struct PendingMessage *pm;
1223 LOG (GNUNET_ERROR_TYPE_DEBUG,
1224 "Disconnecting session of peer `%s' address `%s'\n",
1225 GNUNET_i2s (&session->target),
1226 tcp_plugin_address_to_string (session->plugin,
1227 session->address->address,
1228 session->address->address_length));
1230 if (NULL != session->timeout_task)
1232 GNUNET_SCHEDULER_cancel (session->timeout_task);
1233 session->timeout_task = NULL;
1234 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1238 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1242 GNUNET_STATISTICS_update (session->plugin->env->stats,
1243 gettext_noop ("# TCP sessions active"),
1249 GNUNET_assert (GNUNET_YES ==
1250 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1254 if (NULL != session->client)
1255 GNUNET_SERVER_client_set_user_context (session->client,
1258 /* clean up state */
1259 if (NULL != session->transmit_handle)
1261 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1262 session->transmit_handle = NULL;
1264 session->plugin->env->session_end (session->plugin->env->cls,
1268 if (NULL != session->nat_connection_timeout)
1270 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1271 session->nat_connection_timeout = NULL;
1274 while (NULL != (pm = session->pending_messages_head))
1276 LOG (GNUNET_ERROR_TYPE_DEBUG,
1277 (NULL != pm->transmit_cont)
1278 ? "Could not deliver message to `%s' at %s.\n"
1279 : "Could not deliver message to `%s' at %s, notifying.\n",
1280 GNUNET_i2s (&session->target),
1281 tcp_plugin_address_to_string (session->plugin,
1282 session->address->address,
1283 session->address->address_length));
1284 GNUNET_STATISTICS_update (session->plugin->env->stats,
1285 gettext_noop ("# bytes currently in TCP buffers"),
1286 -(int64_t) pm->message_size, GNUNET_NO);
1287 GNUNET_STATISTICS_update (session->plugin->env->stats,
1288 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1291 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1292 session->pending_messages_tail,
1294 GNUNET_assert (0 < session->msgs_in_queue);
1295 session->msgs_in_queue--;
1296 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1297 session->bytes_in_queue -= pm->message_size;
1298 if (NULL != pm->transmit_cont)
1299 pm->transmit_cont (pm->transmit_cont_cls,
1306 GNUNET_assert (0 == session->msgs_in_queue);
1307 GNUNET_assert (0 == session->bytes_in_queue);
1308 notify_session_monitor (session->plugin,
1310 GNUNET_TRANSPORT_SS_DONE);
1312 if (NULL != session->receive_delay_task)
1314 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1315 session->receive_delay_task = NULL;
1317 if (NULL != session->client)
1319 GNUNET_SERVER_client_disconnect (session->client);
1320 session->client = NULL;
1322 GNUNET_HELLO_address_free (session->address);
1323 GNUNET_assert (NULL == session->transmit_handle);
1324 GNUNET_free (session);
1330 * Function that is called to get the keepalive factor.
1331 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1332 * calculate the interval between keepalive packets.
1334 * @param cls closure with the `struct Plugin`
1335 * @return keepalive factor
1338 tcp_plugin_query_keepalive_factor (void *cls)
1345 * Session was idle for too long, so disconnect it
1347 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1350 session_timeout (void *cls)
1352 struct GNUNET_ATS_Session *s = cls;
1353 struct GNUNET_TIME_Relative left;
1355 s->timeout_task = NULL;
1356 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1357 if (0 != left.rel_value_us)
1359 /* not actually our turn yet, but let's at least update
1360 the monitor, it may think we're about to die ... */
1361 notify_session_monitor (s->plugin,
1363 GNUNET_TRANSPORT_SS_UPDATE);
1364 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1369 LOG (GNUNET_ERROR_TYPE_DEBUG,
1370 "Session %p was idle for %s, disconnecting\n",
1372 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1374 /* call session destroy function */
1375 tcp_plugin_disconnect_session (s->plugin,
1381 * Increment session timeout due to activity.
1383 * @param s session to increment timeout for
1386 reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1388 GNUNET_assert (NULL != s->timeout_task);
1389 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1394 * Create a new session. Also queues a welcome message.
1396 * @param plugin the plugin
1397 * @param address the address to create the session for
1398 * @param scope network scope the address is from
1399 * @param client client to use, reference counter must have already been increased
1400 * @param is_nat this a NAT session, we should wait for a client to
1401 * connect to us from an address, then assign that to
1403 * @return new session object
1405 static struct GNUNET_ATS_Session *
1406 create_session (struct Plugin *plugin,
1407 const struct GNUNET_HELLO_Address *address,
1408 enum GNUNET_ATS_Network_Type scope,
1409 struct GNUNET_SERVER_Client *client,
1412 struct GNUNET_ATS_Session *session;
1413 struct PendingMessage *pm;
1415 if (GNUNET_YES != is_nat)
1416 GNUNET_assert (NULL != client);
1418 GNUNET_assert (NULL == client);
1420 LOG (GNUNET_ERROR_TYPE_DEBUG,
1421 "Creating new session for peer `%s' at address %s\n",
1422 GNUNET_i2s (&address->peer),
1423 tcp_plugin_address_to_string (plugin,
1425 address->address_length));
1426 session = GNUNET_new (struct GNUNET_ATS_Session);
1427 session->last_activity = GNUNET_TIME_absolute_get ();
1428 session->plugin = plugin;
1429 session->is_nat = is_nat;
1432 session->client = client;
1433 GNUNET_SERVER_client_set_user_context (client,
1436 session->address = GNUNET_HELLO_address_copy (address);
1437 session->target = address->peer;
1438 session->expecting_welcome = GNUNET_YES;
1439 session->scope = scope;
1440 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1441 sizeof (struct WelcomeMessage));
1442 pm->msg = (const char *) &pm[1];
1443 pm->message_size = sizeof(struct WelcomeMessage);
1444 GNUNET_memcpy (&pm[1],
1445 &plugin->my_welcome,
1446 sizeof(struct WelcomeMessage));
1447 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1448 GNUNET_STATISTICS_update (plugin->env->stats,
1449 gettext_noop ("# bytes currently in TCP buffers"),
1452 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1453 session->pending_messages_tail,
1455 session->msgs_in_queue++;
1456 session->bytes_in_queue += pm->message_size;
1457 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1458 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1461 notify_session_monitor (session->plugin,
1463 GNUNET_TRANSPORT_SS_INIT);
1464 if (GNUNET_YES != is_nat)
1466 GNUNET_STATISTICS_update (plugin->env->stats,
1467 gettext_noop ("# TCP sessions active"),
1470 notify_session_monitor (session->plugin,
1472 GNUNET_TRANSPORT_SS_UP);
1476 notify_session_monitor (session->plugin,
1478 GNUNET_TRANSPORT_SS_HANDSHAKE);
1485 * If we have pending messages, ask the server to
1486 * transmit them (schedule the respective tasks, etc.)
1488 * @param session for which session should we do this
1491 process_pending_messages (struct GNUNET_ATS_Session *session);
1495 * Function called to notify a client about the socket
1496 * being ready to queue more data. "buf" will be
1497 * NULL and "size" zero if the socket was closed for
1498 * writing in the meantime.
1500 * @param cls closure
1501 * @param size number of bytes available in @a buf
1502 * @param buf where the callee should write the message
1503 * @return number of bytes written to @a buf
1506 do_transmit (void *cls,
1510 struct GNUNET_ATS_Session *session = cls;
1511 struct GNUNET_PeerIdentity pid;
1512 struct Plugin *plugin;
1513 struct PendingMessage *pos;
1514 struct PendingMessage *hd;
1515 struct PendingMessage *tl;
1516 struct GNUNET_TIME_Absolute now;
1520 session->transmit_handle = NULL;
1521 plugin = session->plugin;
1524 LOG (GNUNET_ERROR_TYPE_DEBUG,
1525 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1526 GNUNET_i2s (&session->target));
1527 /* timeout; cancel all messages that have already expired */
1531 now = GNUNET_TIME_absolute_get ();
1532 while ( (NULL != (pos = session->pending_messages_head)) &&
1533 (pos->timeout.abs_value_us <= now.abs_value_us) )
1535 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1536 session->pending_messages_tail,
1538 GNUNET_assert (0 < session->msgs_in_queue);
1539 session->msgs_in_queue--;
1540 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1541 session->bytes_in_queue -= pos->message_size;
1542 LOG (GNUNET_ERROR_TYPE_DEBUG,
1543 "Failed to transmit %u byte message to `%s'.\n",
1545 GNUNET_i2s (&session->target));
1546 ret += pos->message_size;
1547 GNUNET_CONTAINER_DLL_insert_after (hd,
1552 /* do this call before callbacks (so that if callbacks destroy
1553 * session, they have a chance to cancel actions done by this
1555 process_pending_messages (session);
1556 pid = session->target;
1557 /* no do callbacks and do not use session again since
1558 * the callbacks may abort the session */
1559 while (NULL != (pos = hd))
1561 GNUNET_CONTAINER_DLL_remove (hd,
1564 if (NULL != pos->transmit_cont)
1565 pos->transmit_cont (pos->transmit_cont_cls,
1572 GNUNET_STATISTICS_update (plugin->env->stats,
1573 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
1575 GNUNET_STATISTICS_update (plugin->env->stats,
1576 gettext_noop ("# bytes discarded by TCP (timeout)"),
1580 notify_session_monitor (session->plugin,
1582 GNUNET_TRANSPORT_SS_UPDATE);
1585 /* copy all pending messages that would fit */
1590 while (NULL != (pos = session->pending_messages_head))
1592 if (ret + pos->message_size > size)
1594 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1595 session->pending_messages_tail,
1597 GNUNET_assert (0 < session->msgs_in_queue);
1598 session->msgs_in_queue--;
1599 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1600 session->bytes_in_queue -= pos->message_size;
1601 GNUNET_assert(size >= pos->message_size);
1602 LOG (GNUNET_ERROR_TYPE_DEBUG,
1603 "Transmitting message of type %u size %u to peer %s at %s\n",
1604 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
1606 GNUNET_i2s (&session->target),
1607 tcp_plugin_address_to_string (session->plugin,
1608 session->address->address,
1609 session->address->address_length));
1610 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
1611 GNUNET_memcpy (cbuf,
1614 cbuf += pos->message_size;
1615 ret += pos->message_size;
1616 size -= pos->message_size;
1617 GNUNET_CONTAINER_DLL_insert_tail (hd,
1621 notify_session_monitor (session->plugin,
1623 GNUNET_TRANSPORT_SS_UPDATE);
1624 /* schedule 'continuation' before callbacks so that callbacks that
1625 * cancel everything don't cause us to use a session that no longer
1627 process_pending_messages (session);
1628 session->last_activity = GNUNET_TIME_absolute_get ();
1629 pid = session->target;
1630 /* we'll now call callbacks that may cancel the session; hence
1631 * we should not use 'session' after this point */
1632 while (NULL != (pos = hd))
1634 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
1635 if (NULL != pos->transmit_cont)
1636 pos->transmit_cont (pos->transmit_cont_cls,
1640 pos->message_size); /* FIXME: include TCP overhead */
1643 GNUNET_assert (NULL == hd);
1644 GNUNET_assert (NULL == tl);
1645 GNUNET_STATISTICS_update (plugin->env->stats,
1646 gettext_noop ("# bytes currently in TCP buffers"),
1649 GNUNET_STATISTICS_update (plugin->env->stats,
1650 gettext_noop ("# bytes transmitted via TCP"),
1658 * If we have pending messages, ask the server to
1659 * transmit them (schedule the respective tasks, etc.)
1661 * @param session for which session should we do this
1664 process_pending_messages (struct GNUNET_ATS_Session *session)
1666 struct PendingMessage *pm;
1668 GNUNET_assert (NULL != session->client);
1669 if (NULL != session->transmit_handle)
1671 if (NULL == (pm = session->pending_messages_head))
1674 session->transmit_handle
1675 = GNUNET_SERVER_notify_transmit_ready (session->client,
1677 GNUNET_TIME_absolute_get_remaining (pm->timeout),
1684 * Function that can be used by the transport service to transmit
1685 * a message using the plugin. Note that in the case of a
1686 * peer disconnecting, the continuation MUST be called
1687 * prior to the disconnect notification itself. This function
1688 * will be called with this peer's HELLO message to initiate
1689 * a fresh connection to another peer.
1691 * @param cls closure
1692 * @param session which session must be used
1693 * @param msgbuf the message to transmit
1694 * @param msgbuf_size number of bytes in @a msgbuf
1695 * @param priority how important is the message (most plugins will
1696 * ignore message priority and just FIFO)
1697 * @param to how long to wait at most for the transmission (does not
1698 * require plugins to discard the message after the timeout,
1699 * just advisory for the desired delay; most plugins will ignore
1701 * @param cont continuation to call once the message has
1702 * been transmitted (or if the transport is ready
1703 * for the next transmission call; or if the
1704 * peer disconnected...); can be NULL
1705 * @param cont_cls closure for @a cont
1706 * @return number of bytes used (on the physical network, with overheads);
1707 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1708 * and does NOT mean that the message was not transmitted (DV)
1711 tcp_plugin_send (void *cls,
1712 struct GNUNET_ATS_Session *session,
1715 unsigned int priority,
1716 struct GNUNET_TIME_Relative to,
1717 GNUNET_TRANSPORT_TransmitContinuation cont,
1720 struct Plugin * plugin = cls;
1721 struct PendingMessage *pm;
1723 /* create new message entry */
1724 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1725 pm->msg = (const char *) &pm[1];
1726 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
1727 pm->message_size = msgbuf_size;
1728 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
1729 pm->transmit_cont = cont;
1730 pm->transmit_cont_cls = cont_cls;
1732 LOG (GNUNET_ERROR_TYPE_DEBUG,
1733 "Asked to transmit %u bytes to `%s', added message to list.\n",
1735 GNUNET_i2s (&session->target));
1738 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
1742 GNUNET_assert (NULL != session->client);
1743 GNUNET_SERVER_client_set_timeout (session->client,
1744 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1745 GNUNET_STATISTICS_update (plugin->env->stats,
1746 gettext_noop ("# bytes currently in TCP buffers"),
1750 /* append pm to pending_messages list */
1751 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1752 session->pending_messages_tail,
1754 notify_session_monitor (session->plugin,
1756 GNUNET_TRANSPORT_SS_UPDATE);
1757 session->msgs_in_queue++;
1758 session->bytes_in_queue += pm->message_size;
1759 process_pending_messages (session);
1763 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
1767 LOG (GNUNET_ERROR_TYPE_DEBUG,
1768 "This NAT WAIT session for peer `%s' is not yet ready!\n",
1769 GNUNET_i2s (&session->target));
1770 GNUNET_STATISTICS_update (plugin->env->stats,
1771 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
1773 /* append pm to pending_messages list */
1774 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
1775 session->pending_messages_tail,
1777 session->msgs_in_queue++;
1778 session->bytes_in_queue += pm->message_size;
1779 notify_session_monitor (session->plugin,
1781 GNUNET_TRANSPORT_SS_HANDSHAKE);
1784 LOG (GNUNET_ERROR_TYPE_ERROR,
1785 "Invalid session %p\n",
1795 return GNUNET_SYSERR; /* session does not exist here */
1800 * Closure for #session_lookup_it().
1802 struct GNUNET_ATS_SessionItCtx
1805 * Address we are looking for.
1807 const struct GNUNET_HELLO_Address *address;
1810 * Where to store the session (if we found it).
1812 struct GNUNET_ATS_Session *result;
1818 * Look for a session by address.
1820 * @param cls the `struct GNUNET_ATS_SessionItCtx`
1822 * @param value a `struct GNUNET_ATS_Session`
1823 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
1826 session_lookup_it (void *cls,
1827 const struct GNUNET_PeerIdentity *key,
1830 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
1831 struct GNUNET_ATS_Session *session = value;
1834 GNUNET_HELLO_address_cmp (si_ctx->address,
1837 si_ctx->result = session;
1843 * Task cleaning up a NAT connection attempt after timeout
1845 * @param cls the `struct GNUNET_ATS_Session`
1848 nat_connect_timeout (void *cls)
1850 struct GNUNET_ATS_Session *session = cls;
1852 session->nat_connection_timeout = NULL;
1853 LOG (GNUNET_ERROR_TYPE_DEBUG,
1854 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
1855 GNUNET_i2s (&session->target),
1856 tcp_plugin_address_to_string (session->plugin,
1857 session->address->address,
1858 session->address->address_length));
1859 tcp_plugin_disconnect_session (session->plugin,
1865 * Function that will be called whenever the transport service wants to
1866 * notify the plugin that a session is still active and in use and
1867 * therefore the session timeout for this session has to be updated
1869 * @param cls closure
1870 * @param peer which peer was the session for
1871 * @param session which session is being updated
1874 tcp_plugin_update_session_timeout (void *cls,
1875 const struct GNUNET_PeerIdentity *peer,
1876 struct GNUNET_ATS_Session *session)
1878 reschedule_session_timeout (session);
1883 * Task to signal the server that we can continue
1884 * receiving from the TCP client now.
1886 * @param cls the `struct GNUNET_ATS_Session *`
1889 delayed_done (void *cls)
1891 struct GNUNET_ATS_Session *session = cls;
1893 session->receive_delay_task = NULL;
1894 reschedule_session_timeout (session);
1895 GNUNET_SERVER_receive_done (session->client,
1901 * Function that will be called whenever the transport service wants to
1902 * notify the plugin that the inbound quota changed and that the plugin
1903 * should update it's delay for the next receive value
1905 * @param cls closure
1906 * @param peer which peer was the session for
1907 * @param session which session is being updated
1908 * @param delay new delay to use for receiving
1911 tcp_plugin_update_inbound_delay (void *cls,
1912 const struct GNUNET_PeerIdentity *peer,
1913 struct GNUNET_ATS_Session *session,
1914 struct GNUNET_TIME_Relative delay)
1916 if (NULL == session->receive_delay_task)
1918 LOG (GNUNET_ERROR_TYPE_DEBUG,
1919 "New inbound delay %s\n",
1920 GNUNET_STRINGS_relative_time_to_string (delay,
1922 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
1923 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1924 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
1931 * Create a new session to transmit data to the target
1932 * This session will used to send data to this peer and the plugin will
1933 * notify us by calling the env->session_end function
1935 * @param cls closure
1936 * @param address the address to use
1937 * @return the session if the address is valid, NULL otherwise
1939 static struct GNUNET_ATS_Session *
1940 tcp_plugin_get_session (void *cls,
1941 const struct GNUNET_HELLO_Address *address)
1943 struct Plugin *plugin = cls;
1944 struct GNUNET_ATS_Session *session = NULL;
1948 struct GNUNET_CONNECTION_Handle *sa;
1949 struct sockaddr_in a4;
1950 struct sockaddr_in6 a6;
1951 const struct IPv4TcpAddress *t4;
1952 const struct IPv6TcpAddress *t6;
1953 unsigned int options;
1954 enum GNUNET_ATS_Network_Type net_type;
1955 unsigned int is_natd = GNUNET_NO;
1958 struct GNUNET_NETWORK_Handle *s;
1961 addrlen = address->address_length;
1962 LOG (GNUNET_ERROR_TYPE_DEBUG,
1963 "Trying to get session for `%s' address of peer `%s'\n",
1964 tcp_plugin_address_to_string (plugin,
1966 address->address_length),
1967 GNUNET_i2s (&address->peer));
1969 if (GNUNET_HELLO_address_check_option (address,
1970 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1976 /* look for existing session */
1978 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
1981 struct GNUNET_ATS_SessionItCtx si_ctx;
1983 si_ctx.address = address;
1984 si_ctx.result = NULL;
1985 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
1989 if (NULL != si_ctx.result)
1991 session = si_ctx.result;
1992 LOG (GNUNET_ERROR_TYPE_DEBUG,
1993 "Found existing session for `%s' address `%s'\n",
1994 GNUNET_i2s (&address->peer),
1995 tcp_plugin_address_to_string (plugin,
1997 address->address_length));
2000 /* This is a bit of a hack, limiting TCP to never allow more than
2001 one TCP connection to any given peer at the same time.
2002 Without this, peers sometimes disagree about which of the TCP
2003 connections they should use, causing one side to believe that
2004 they transmit successfully, while the other receives nothing. */
2005 return NULL; /* Refuse to have more than one TCP connection per
2006 peer pair at the same time. */
2009 if (addrlen == sizeof(struct IPv6TcpAddress))
2011 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2012 t6 = address->address;
2013 options = t6->options;
2015 memset (&a6, 0, sizeof(a6));
2016 #if HAVE_SOCKADDR_IN_SIN_LEN
2017 a6.sin6_len = sizeof (a6);
2019 a6.sin6_family = AF_INET6;
2020 a6.sin6_port = t6->t6_port;
2021 if (t6->t6_port == 0)
2022 is_natd = GNUNET_YES;
2023 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2027 else if (addrlen == sizeof(struct IPv4TcpAddress))
2029 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2030 t4 = address->address;
2031 options = t4->options;
2033 memset (&a4, 0, sizeof(a4));
2034 #if HAVE_SOCKADDR_IN_SIN_LEN
2035 a4.sin_len = sizeof (a4);
2037 a4.sin_family = AF_INET;
2038 a4.sin_port = t4->t4_port;
2039 if (t4->t4_port == 0)
2040 is_natd = GNUNET_YES;
2041 a4.sin_addr.s_addr = t4->ipv4_addr;
2047 GNUNET_STATISTICS_update (plugin->env->stats,
2048 gettext_noop ("# requests to create session with invalid address"),
2054 net_type = plugin->env->get_address_type (plugin->env->cls,
2057 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2059 if ( (is_natd == GNUNET_YES) &&
2060 (addrlen == sizeof(struct IPv6TcpAddress)) )
2062 /* NAT client only works with IPv4 addresses */
2066 if (plugin->cur_connections >= plugin->max_connections)
2072 if ( (is_natd == GNUNET_YES) &&
2074 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2077 /* Only do one NAT punch attempt per peer identity */
2081 if ( (is_natd == GNUNET_YES) &&
2082 (NULL != plugin->nat) &&
2084 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2087 struct sockaddr_in local_sa;
2089 LOG (GNUNET_ERROR_TYPE_DEBUG,
2090 "Found valid IPv4 NAT address (creating session)!\n");
2091 session = create_session (plugin,
2096 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2097 &nat_connect_timeout,
2099 GNUNET_assert (GNUNET_OK ==
2100 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2103 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2105 LOG (GNUNET_ERROR_TYPE_DEBUG,
2106 "Created NAT WAIT connection to `%s' at `%s'\n",
2107 GNUNET_i2s (&session->target),
2108 GNUNET_a2s (sb, sbs));
2112 local_sa.sin_family = AF_INET;
2113 local_sa.sin_port = htons (plugin->open_port);
2114 /* We leave sin_address at 0, let the kernel figure it out,
2115 even if our bind() is more specific. (May want to reconsider
2118 GNUNET_NAT_request_reversal (plugin->nat,
2122 LOG (GNUNET_ERROR_TYPE_DEBUG,
2123 "Running NAT client for `%s' at `%s' failed\n",
2124 GNUNET_i2s (&session->target),
2125 GNUNET_a2s (sb, sbs));
2126 tcp_plugin_disconnect_session (plugin,
2131 /* create new outbound session */
2132 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2135 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2138 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2145 GNUNET_NETWORK_socket_setsockopt (s,
2149 sizeof (struct GNUNET_PeerIdentity))) ||
2151 GNUNET_NETWORK_socket_setsockopt (s,
2153 TCP_STEALTH_INTEGRITY,
2154 &plugin->my_welcome,
2155 sizeof (struct WelcomeMessage))) )
2157 /* TCP STEALTH not supported by kernel */
2158 GNUNET_break (GNUNET_OK ==
2159 GNUNET_NETWORK_socket_close (s));
2164 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2173 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2177 LOG (GNUNET_ERROR_TYPE_DEBUG,
2178 "Failed to create connection to `%s' at `%s'\n",
2179 GNUNET_i2s (&address->peer),
2180 GNUNET_a2s (sb, sbs));
2183 LOG (GNUNET_ERROR_TYPE_DEBUG,
2184 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2185 GNUNET_i2s (&address->peer),
2186 GNUNET_a2s (sb, sbs));
2188 session = create_session (plugin,
2191 GNUNET_SERVER_connect_socket (plugin->server,
2194 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2197 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2198 /* Send TCP Welcome */
2199 process_pending_messages (session);
2206 * We have been asked to destroy all connections to a particular peer.
2207 * This function is called on each applicable session and must tear it
2210 * @param cls the `struct Plugin *`
2211 * @param key the peer which the session belongs to (unused)
2212 * @param value the `struct GNUNET_ATS_Session`
2213 * @return #GNUNET_YES (continue to iterate)
2216 session_disconnect_it (void *cls,
2217 const struct GNUNET_PeerIdentity *key,
2220 struct Plugin *plugin = cls;
2221 struct GNUNET_ATS_Session *session = value;
2223 GNUNET_STATISTICS_update (session->plugin->env->stats,
2224 gettext_noop ("# transport-service disconnect requests for TCP"),
2227 tcp_plugin_disconnect_session (plugin,
2234 * Function that can be called to force a disconnect from the
2235 * specified neighbour. This should also cancel all previously
2236 * scheduled transmissions. Obviously the transmission may have been
2237 * partially completed already, which is OK. The plugin is supposed
2238 * to close the connection (if applicable) and no longer call the
2239 * transmit continuation(s).
2241 * Finally, plugin MUST NOT call the services's receive function to
2242 * notify the service that the connection to the specified target was
2243 * closed after a getting this call.
2245 * @param cls closure
2246 * @param target peer for which the last transmission is
2250 tcp_plugin_disconnect (void *cls,
2251 const struct GNUNET_PeerIdentity *target)
2253 struct Plugin *plugin = cls;
2255 LOG (GNUNET_ERROR_TYPE_DEBUG,
2256 "Disconnecting peer `%s'\n",
2257 GNUNET_i2s (target));
2258 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2260 &session_disconnect_it,
2262 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2264 &session_disconnect_it,
2270 * We are processing an address pretty printing request and finished
2271 * the IP resolution (if applicable). Append our port and forward the
2272 * result. If called with @a hostname NULL, we are done and should
2273 * clean up the pretty printer (otherwise, there might be multiple
2274 * hostnames for the IP address and we might receive more).
2276 * @param cls the `struct PrettyPrinterContext *`
2277 * @param hostname hostname part of the address
2280 append_port (void *cls,
2281 const char *hostname)
2283 struct PrettyPrinterContext *ppc = cls;
2284 struct Plugin *plugin = ppc->plugin;
2287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2288 "append_port called with hostname `%s'\n",
2290 if (NULL == hostname)
2292 /* Final call, done */
2293 ppc->resolver_handle = NULL;
2294 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2295 plugin->ppc_dll_tail,
2297 ppc->asc (ppc->asc_cls,
2303 if (GNUNET_YES == ppc->ipv6)
2304 GNUNET_asprintf (&ret,
2311 GNUNET_asprintf (&ret,
2317 ppc->asc (ppc->asc_cls,
2325 * Convert the transports address to a nice, human-readable format.
2327 * @param cls closure with the `struct Plugin`
2328 * @param type name of the transport that generated the address
2329 * @param addr one of the addresses of the host, NULL for the last address
2330 * the specific address format depends on the transport
2331 * @param addrlen length of the @a addr
2332 * @param numeric should (IP) addresses be displayed in numeric form?
2333 * @param timeout after how long should we give up?
2334 * @param asc function to call on each string
2335 * @param asc_cls closure for @a asc
2338 tcp_plugin_address_pretty_printer (void *cls,
2343 struct GNUNET_TIME_Relative timeout,
2344 GNUNET_TRANSPORT_AddressStringCallback asc,
2347 struct Plugin *plugin = cls;
2348 struct PrettyPrinterContext *ppc;
2351 struct sockaddr_in a4;
2352 struct sockaddr_in6 a6;
2353 const struct IPv4TcpAddress *t4;
2354 const struct IPv6TcpAddress *t6;
2358 if (sizeof(struct IPv6TcpAddress) == addrlen)
2361 memset (&a6, 0, sizeof(a6));
2362 a6.sin6_family = AF_INET6;
2363 a6.sin6_port = t6->t6_port;
2364 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2365 port = ntohs (t6->t6_port);
2366 options = ntohl (t6->options);
2370 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2373 memset (&a4, 0, sizeof(a4));
2374 a4.sin_family = AF_INET;
2375 a4.sin_port = t4->t4_port;
2376 a4.sin_addr.s_addr = t4->ipv4_addr;
2377 port = ntohs (t4->t4_port);
2378 options = ntohl (t4->options);
2384 /* invalid address */
2385 LOG (GNUNET_ERROR_TYPE_WARNING,
2386 _("Unexpected address length: %u bytes\n"),
2387 (unsigned int) addrlen);
2388 asc (asc_cls, NULL, GNUNET_SYSERR);
2389 asc (asc_cls, NULL, GNUNET_OK);
2392 ppc = GNUNET_new (struct PrettyPrinterContext);
2393 ppc->plugin = plugin;
2394 if (addrlen == sizeof(struct IPv6TcpAddress))
2395 ppc->ipv6 = GNUNET_YES;
2397 ppc->ipv6 = GNUNET_NO;
2399 ppc->asc_cls = asc_cls;
2401 ppc->options = options;
2402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403 "Starting DNS reverse lookup\n");
2404 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2410 if (NULL == ppc->resolver_handle)
2416 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2417 plugin->ppc_dll_tail,
2423 * Function that will be called to check if a binary address for this
2424 * plugin is well-formed and corresponds to an address for THIS peer
2425 * (as per our configuration). Naturally, if absolutely necessary,
2426 * plugins can be a bit conservative in their answer, but in general
2427 * plugins should make sure that the address does not redirect
2428 * traffic to a 3rd party that might try to man-in-the-middle our
2431 * @param cls closure, our `struct Plugin *`
2432 * @param addr pointer to the address
2433 * @param addrlen length of @a addr
2434 * @return #GNUNET_OK if this is a plausible address for this peer
2435 * and transport, #GNUNET_SYSERR if not
2438 tcp_plugin_check_address (void *cls,
2442 struct Plugin *plugin = cls;
2443 const struct IPv4TcpAddress *v4;
2444 const struct IPv6TcpAddress *v6;
2446 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2447 (addrlen != sizeof(struct IPv6TcpAddress)) )
2449 GNUNET_break_op (0);
2450 return GNUNET_SYSERR;
2453 if (addrlen == sizeof(struct IPv4TcpAddress))
2455 struct sockaddr_in s4;
2457 v4 = (const struct IPv4TcpAddress *) addr;
2458 if (0 != memcmp (&v4->options,
2463 return GNUNET_SYSERR;
2465 memset (&s4, 0, sizeof (s4));
2466 s4.sin_family = AF_INET;
2467 #if HAVE_SOCKADDR_IN_SIN_LEN
2468 s4.sin_len = sizeof (s4);
2470 s4.sin_port = v4->t4_port;
2471 s4.sin_addr.s_addr = v4->ipv4_addr;
2474 GNUNET_NAT_test_address (plugin->nat,
2476 sizeof (struct sockaddr_in)))
2477 return GNUNET_SYSERR;
2481 struct sockaddr_in6 s6;
2483 v6 = (const struct IPv6TcpAddress *) addr;
2484 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2486 GNUNET_break_op (0);
2487 return GNUNET_SYSERR;
2489 if (0 != memcmp (&v6->options,
2494 return GNUNET_SYSERR;
2496 memset (&s6, 0, sizeof (s6));
2497 s6.sin6_family = AF_INET6;
2498 #if HAVE_SOCKADDR_IN_SIN_LEN
2499 s6.sin6_len = sizeof (s6);
2501 s6.sin6_port = v6->t6_port;
2502 s6.sin6_addr = v6->ipv6_addr;
2505 GNUNET_NAT_test_address (plugin->nat,
2507 sizeof(struct sockaddr_in6)))
2508 return GNUNET_SYSERR;
2515 * We've received a nat probe from this peer via TCP. Finish
2516 * creating the client session and resume sending of queued
2519 * @param cls closure
2520 * @param client identification of the client
2521 * @param message the actual message
2524 handle_tcp_nat_probe (void *cls,
2525 struct GNUNET_SERVER_Client *client,
2526 const struct GNUNET_MessageHeader *message)
2528 struct Plugin *plugin = cls;
2529 struct GNUNET_ATS_Session *session;
2530 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2533 struct IPv4TcpAddress *t4;
2534 struct IPv6TcpAddress *t6;
2535 const struct sockaddr_in *s4;
2536 const struct sockaddr_in6 *s6;
2538 LOG (GNUNET_ERROR_TYPE_DEBUG,
2539 "Received NAT probe\n");
2540 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2541 * a connection to this peer by running gnunet-nat-client. This peer
2542 * received the punch message and now wants us to use the new connection
2543 * as the default for that peer. Do so and then send a WELCOME message
2544 * so we can really be connected!
2546 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2549 GNUNET_SERVER_receive_done (client,
2554 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2555 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
2556 sizeof(struct GNUNET_PeerIdentity)))
2558 /* refuse connections from ourselves */
2559 GNUNET_SERVER_receive_done (client,
2564 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2565 &tcp_nat_probe->clientIdentity);
2566 if (NULL == session)
2568 LOG (GNUNET_ERROR_TYPE_DEBUG,
2569 "Did NOT find session for NAT probe!\n");
2570 GNUNET_SERVER_receive_done (client,
2574 LOG (GNUNET_ERROR_TYPE_DEBUG,
2575 "Found session for NAT probe!\n");
2577 if (NULL != session->nat_connection_timeout)
2579 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2580 session->nat_connection_timeout = NULL;
2584 GNUNET_SERVER_client_get_address (client,
2589 GNUNET_SERVER_receive_done (client,
2591 tcp_plugin_disconnect_session (plugin,
2595 GNUNET_assert (GNUNET_YES ==
2596 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
2597 &tcp_nat_probe->clientIdentity,
2599 GNUNET_SERVER_client_set_user_context (client,
2601 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2604 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2605 session->last_activity = GNUNET_TIME_absolute_get ();
2606 LOG (GNUNET_ERROR_TYPE_DEBUG,
2607 "Found address `%s' for incoming connection\n",
2608 GNUNET_a2s (vaddr, alen));
2609 switch (((const struct sockaddr *) vaddr)->sa_family)
2613 t4 = GNUNET_new (struct IPv4TcpAddress);
2614 t4->options = htonl (TCP_OPTIONS_NONE);
2615 t4->t4_port = s4->sin_port;
2616 t4->ipv4_addr = s4->sin_addr.s_addr;
2617 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2620 sizeof(struct IPv4TcpAddress),
2621 GNUNET_HELLO_ADDRESS_INFO_NONE);
2625 t6 = GNUNET_new (struct IPv6TcpAddress);
2626 t6->options = htonl (TCP_OPTIONS_NONE);
2627 t6->t6_port = s6->sin6_port;
2628 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2629 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
2632 sizeof(struct IPv6TcpAddress),
2633 GNUNET_HELLO_ADDRESS_INFO_NONE);
2637 LOG(GNUNET_ERROR_TYPE_DEBUG,
2638 "Bad address for incoming connection!\n");
2640 GNUNET_SERVER_receive_done (client,
2642 tcp_plugin_disconnect_session (plugin,
2646 GNUNET_free (vaddr);
2647 GNUNET_break (NULL == session->client);
2648 session->client = client;
2649 GNUNET_STATISTICS_update (plugin->env->stats,
2650 gettext_noop ("# TCP sessions active"),
2653 process_pending_messages (session);
2654 GNUNET_SERVER_receive_done (client,
2660 * We've received a welcome from this peer via TCP. Possibly create a
2661 * fresh client record and send back our welcome.
2663 * @param cls closure
2664 * @param client identification of the client
2665 * @param message the actual message
2668 handle_tcp_welcome (void *cls,
2669 struct GNUNET_SERVER_Client *client,
2670 const struct GNUNET_MessageHeader *message)
2672 struct Plugin *plugin = cls;
2673 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
2674 struct GNUNET_HELLO_Address *address;
2675 struct GNUNET_ATS_Session *session;
2678 struct IPv4TcpAddress t4;
2679 struct IPv6TcpAddress t6;
2680 const struct sockaddr_in *s4;
2681 const struct sockaddr_in6 *s6;
2683 if (0 == memcmp (&wm->clientIdentity,
2684 plugin->env->my_identity,
2685 sizeof(struct GNUNET_PeerIdentity)))
2687 /* refuse connections from ourselves */
2688 GNUNET_SERVER_receive_done (client,
2691 GNUNET_SERVER_client_get_address (client,
2695 LOG (GNUNET_ERROR_TYPE_INFO,
2696 "Received WELCOME message from my own identity `%s' on address `%s'\n",
2697 GNUNET_i2s (&wm->clientIdentity),
2698 GNUNET_a2s (vaddr, alen));
2699 GNUNET_free (vaddr);
2705 GNUNET_SERVER_client_get_address (client,
2709 LOG(GNUNET_ERROR_TYPE_DEBUG,
2710 "Received WELCOME message from `%s' on address `%s'\n",
2711 GNUNET_i2s (&wm->clientIdentity),
2712 GNUNET_a2s (vaddr, alen));
2713 GNUNET_free (vaddr);
2715 GNUNET_STATISTICS_update (plugin->env->stats,
2716 gettext_noop ("# TCP WELCOME messages received"),
2719 session = lookup_session_by_client (plugin,
2721 if (NULL != session)
2724 GNUNET_SERVER_client_get_address (client,
2728 LOG (GNUNET_ERROR_TYPE_DEBUG,
2729 "Found existing session %p for peer `%s'\n",
2731 GNUNET_a2s (vaddr, alen));
2732 GNUNET_free (vaddr);
2738 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2740 if (alen == sizeof(struct sockaddr_in))
2743 memset (&t4, '\0', sizeof (t4));
2744 t4.options = htonl (TCP_OPTIONS_NONE);
2745 t4.t4_port = s4->sin_port;
2746 t4.ipv4_addr = s4->sin_addr.s_addr;
2747 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2751 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2753 else if (alen == sizeof(struct sockaddr_in6))
2756 memset (&t6, '\0', sizeof (t6));
2757 t6.options = htonl (TCP_OPTIONS_NONE);
2758 t6.t6_port = s6->sin6_port;
2759 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2760 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
2764 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
2769 GNUNET_free_non_null (vaddr);
2770 GNUNET_SERVER_receive_done (client,
2774 session = create_session (plugin,
2776 plugin->env->get_address_type (plugin->env->cls,
2781 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
2782 GNUNET_HELLO_address_free (address);
2783 LOG (GNUNET_ERROR_TYPE_DEBUG,
2784 "Creating new%s session %p for peer `%s' client %p\n",
2785 GNUNET_HELLO_address_check_option (session->address,
2786 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
2789 tcp_plugin_address_to_string (plugin,
2790 session->address->address,
2791 session->address->address_length),
2793 GNUNET_free (vaddr);
2794 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2797 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2798 /* Notify transport and ATS about new session */
2799 plugin->env->session_start (plugin->env->cls,
2806 LOG(GNUNET_ERROR_TYPE_DEBUG,
2807 "Did not obtain TCP socket address for incoming connection\n");
2809 GNUNET_SERVER_receive_done (client,
2815 if (GNUNET_YES != session->expecting_welcome)
2817 GNUNET_break_op (0);
2818 GNUNET_SERVER_receive_done (client,
2822 session->last_activity = GNUNET_TIME_absolute_get ();
2823 session->expecting_welcome = GNUNET_NO;
2825 process_pending_messages (session);
2826 GNUNET_SERVER_client_set_timeout (client,
2827 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2828 GNUNET_SERVER_receive_done (client,
2834 * We've received data for this peer via TCP. Unbox,
2835 * compute latency and forward.
2837 * @param cls closure
2838 * @param client identification of the client
2839 * @param message the actual message
2842 handle_tcp_data (void *cls,
2843 struct GNUNET_SERVER_Client *client,
2844 const struct GNUNET_MessageHeader *message)
2846 struct Plugin *plugin = cls;
2847 struct GNUNET_ATS_Session *session;
2848 struct GNUNET_TIME_Relative delay;
2851 type = ntohs (message->type);
2852 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
2853 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
2855 /* We don't want to propagate WELCOME and NAT Probe messages up! */
2856 GNUNET_SERVER_receive_done (client,
2860 session = lookup_session_by_client (plugin, client);
2861 if (NULL == session)
2863 /* No inbound session found */
2867 GNUNET_SERVER_client_get_address (client,
2870 LOG (GNUNET_ERROR_TYPE_ERROR,
2871 "Received unexpected %u bytes of type %u from `%s'\n",
2872 (unsigned int) ntohs (message->size),
2873 (unsigned int) ntohs (message->type),
2877 GNUNET_SERVER_receive_done (client,
2879 GNUNET_free_non_null (vaddr);
2882 if (GNUNET_YES == session->expecting_welcome)
2884 /* Session is expecting WELCOME message */
2888 GNUNET_SERVER_client_get_address (client,
2891 LOG (GNUNET_ERROR_TYPE_ERROR,
2892 "Received unexpected %u bytes of type %u from `%s'\n",
2893 (unsigned int) ntohs (message->size),
2894 (unsigned int) ntohs (message->type),
2895 GNUNET_a2s (vaddr, alen));
2897 GNUNET_SERVER_receive_done (client,
2899 GNUNET_free_non_null (vaddr);
2903 session->last_activity = GNUNET_TIME_absolute_get ();
2908 GNUNET_SERVER_client_get_address (client,
2911 LOG (GNUNET_ERROR_TYPE_DEBUG,
2912 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
2913 (unsigned int) ntohs (message->size),
2914 (unsigned int) ntohs (message->type),
2915 GNUNET_i2s (&session->target),
2916 GNUNET_a2s (vaddr, alen));
2917 GNUNET_free_non_null (vaddr);
2920 GNUNET_STATISTICS_update (plugin->env->stats,
2921 gettext_noop ("# bytes received via TCP"),
2922 ntohs (message->size),
2925 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2928 delay = plugin->env->receive (plugin->env->cls,
2932 reschedule_session_timeout (session);
2933 if (0 == delay.rel_value_us)
2935 GNUNET_SERVER_receive_done (client,
2940 LOG (GNUNET_ERROR_TYPE_DEBUG,
2941 "Throttling receiving from `%s' for %s\n",
2942 GNUNET_i2s (&session->target),
2943 GNUNET_STRINGS_relative_time_to_string (delay,
2945 GNUNET_SERVER_disable_receive_done_warning (client);
2946 GNUNET_assert (NULL == session->receive_delay_task);
2947 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2955 * Function called whenever a peer is connected on the "SERVER" level.
2956 * Increments number of active connections and suspends server if we
2957 * have reached the limit.
2959 * @param cls closure
2960 * @param client identification of the client
2963 connect_notify (void *cls,
2964 struct GNUNET_SERVER_Client *client)
2966 struct Plugin *plugin = cls;
2970 plugin->cur_connections++;
2971 GNUNET_STATISTICS_set (plugin->env->stats,
2972 gettext_noop ("# TCP server connections active"),
2973 plugin->cur_connections,
2975 GNUNET_STATISTICS_update (plugin->env->stats,
2976 gettext_noop ("# TCP server connect events"),
2979 if (plugin->cur_connections != plugin->max_connections)
2981 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2982 _("TCP connection limit reached, suspending server\n"));
2983 GNUNET_STATISTICS_update (plugin->env->stats,
2984 gettext_noop ("# TCP service suspended"),
2987 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
2992 * Function called whenever a peer is disconnected on the "SERVER"
2993 * level. Cleans up the connection, decrements number of active
2994 * connections and if applicable resumes listening.
2996 * @param cls closure
2997 * @param client identification of the client
3000 disconnect_notify (void *cls,
3001 struct GNUNET_SERVER_Client *client)
3003 struct Plugin *plugin = cls;
3004 struct GNUNET_ATS_Session *session;
3008 GNUNET_assert (plugin->cur_connections >= 1);
3009 plugin->cur_connections--;
3010 session = lookup_session_by_client (plugin,
3012 if (NULL == session)
3013 return; /* unknown, nothing to do */
3014 LOG (GNUNET_ERROR_TYPE_DEBUG,
3015 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3016 GNUNET_i2s (&session->target),
3017 tcp_plugin_address_to_string (session->plugin,
3018 session->address->address,
3019 session->address->address_length));
3021 if (plugin->cur_connections == plugin->max_connections)
3023 GNUNET_STATISTICS_update (session->plugin->env->stats,
3024 gettext_noop ("# TCP service resumed"),
3027 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3029 GNUNET_STATISTICS_set (plugin->env->stats,
3030 gettext_noop ("# TCP server connections active"),
3031 plugin->cur_connections,
3033 GNUNET_STATISTICS_update (session->plugin->env->stats,
3034 gettext_noop ("# network-level TCP disconnect events"),
3037 tcp_plugin_disconnect_session (plugin,
3043 * We can now send a probe message, copy into buffer to really send.
3045 * @param cls closure, a `struct TCPProbeContext`
3046 * @param size max size to copy
3047 * @param buf buffer to copy message to
3048 * @return number of bytes copied into @a buf
3051 notify_send_probe (void *cls,
3055 struct TCPProbeContext *tcp_probe_ctx = cls;
3056 struct Plugin *plugin = tcp_probe_ctx->plugin;
3059 tcp_probe_ctx->transmit_handle = NULL;
3060 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3065 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3066 GNUNET_free(tcp_probe_ctx);
3069 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3071 &tcp_probe_ctx->message,
3072 sizeof(tcp_probe_ctx->message));
3073 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3074 tcp_probe_ctx->sock);
3075 ret = sizeof(tcp_probe_ctx->message);
3076 GNUNET_free (tcp_probe_ctx);
3082 * Function called by the NAT subsystem suggesting another peer wants
3083 * to connect to us via connection reversal. Try to connect back to the
3086 * @param cls closure
3087 * @param addr address to try
3088 * @param addrlen number of bytes in @a addr
3091 try_connection_reversal (void *cls,
3092 const struct sockaddr *addr,
3095 struct Plugin *plugin = cls;
3096 struct GNUNET_CONNECTION_Handle *sock;
3097 struct TCPProbeContext *tcp_probe_ctx;
3100 * We have received an ICMP response, ostensibly from a peer
3101 * that wants to connect to us! Send a message to establish a connection.
3103 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3108 /* failed for some odd reason (out of sockets?); ignore attempt */
3112 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3113 tcp_probe_ctx->message.header.size
3114 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3115 tcp_probe_ctx->message.header.type
3116 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3117 tcp_probe_ctx->message.clientIdentity
3118 = *plugin->env->my_identity;
3119 tcp_probe_ctx->plugin = plugin;
3120 tcp_probe_ctx->sock = sock;
3121 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3124 tcp_probe_ctx->transmit_handle
3125 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3126 ntohs (tcp_probe_ctx->message.header.size),
3127 GNUNET_TIME_UNIT_FOREVER_REL,
3134 * Function obtain the network type for a session
3136 * @param cls closure (`struct Plugin *`)
3137 * @param session the session
3138 * @return the network type in HBO or #GNUNET_SYSERR
3140 static enum GNUNET_ATS_Network_Type
3141 tcp_plugin_get_network (void *cls,
3142 struct GNUNET_ATS_Session *session)
3144 return session->scope;
3149 * Function obtain the network type for an address.
3151 * @param cls closure (`struct Plugin *`)
3152 * @param address the address
3153 * @return the network type
3155 static enum GNUNET_ATS_Network_Type
3156 tcp_plugin_get_network_for_address (void *cls,
3157 const struct GNUNET_HELLO_Address *address)
3159 struct Plugin *plugin = cls;
3161 struct sockaddr_in a4;
3162 struct sockaddr_in6 a6;
3163 const struct IPv4TcpAddress *t4;
3164 const struct IPv6TcpAddress *t6;
3168 addrlen = address->address_length;
3169 if (addrlen == sizeof(struct IPv6TcpAddress))
3171 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3172 t6 = address->address;
3173 memset (&a6, 0, sizeof(a6));
3174 #if HAVE_SOCKADDR_IN_SIN_LEN
3175 a6.sin6_len = sizeof (a6);
3177 a6.sin6_family = AF_INET6;
3178 a6.sin6_port = t6->t6_port;
3179 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3183 else if (addrlen == sizeof(struct IPv4TcpAddress))
3185 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3186 t4 = address->address;
3187 memset (&a4, 0, sizeof(a4));
3188 #if HAVE_SOCKADDR_IN_SIN_LEN
3189 a4.sin_len = sizeof (a4);
3191 a4.sin_family = AF_INET;
3192 a4.sin_port = t4->t4_port;
3193 a4.sin_addr.s_addr = t4->ipv4_addr;
3200 return GNUNET_ATS_NET_UNSPECIFIED;
3202 return plugin->env->get_address_type (plugin->env->cls,
3209 * Return information about the given session to the
3212 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3213 * @param peer peer we send information about
3214 * @param value our `struct GNUNET_ATS_Session` to send information about
3215 * @return #GNUNET_OK (continue to iterate)
3218 send_session_info_iter (void *cls,
3219 const struct GNUNET_PeerIdentity *peer,
3222 struct Plugin *plugin = cls;
3223 struct GNUNET_ATS_Session *session = value;
3225 notify_session_monitor (plugin,
3227 GNUNET_TRANSPORT_SS_INIT);
3228 /* FIXME: cannot tell if this is up or not from current
3230 notify_session_monitor (plugin,
3232 GNUNET_TRANSPORT_SS_UP);
3238 * Begin monitoring sessions of a plugin. There can only
3239 * be one active monitor per plugin (i.e. if there are
3240 * multiple monitors, the transport service needs to
3241 * multiplex the generated events over all of them).
3243 * @param cls closure of the plugin
3244 * @param sic callback to invoke, NULL to disable monitor;
3245 * plugin will being by iterating over all active
3246 * sessions immediately and then enter monitor mode
3247 * @param sic_cls closure for @a sic
3250 tcp_plugin_setup_monitor (void *cls,
3251 GNUNET_TRANSPORT_SessionInfoCallback sic,
3254 struct Plugin *plugin = cls;
3257 plugin->sic_cls = sic_cls;
3260 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3261 &send_session_info_iter,
3263 /* signal end of first iteration */
3264 sic (sic_cls, NULL, NULL);
3270 * Entry point for the plugin.
3272 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3273 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3276 libgnunet_plugin_transport_tcp_init (void *cls)
3278 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3279 { &handle_tcp_welcome, NULL,
3280 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3281 sizeof(struct WelcomeMessage) },
3282 { &handle_tcp_nat_probe, NULL,
3283 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3284 sizeof(struct TCP_NAT_ProbeMessage) },
3285 { &handle_tcp_data, NULL,
3286 GNUNET_MESSAGE_TYPE_ALL, 0 },
3287 { NULL, NULL, 0, 0 }
3289 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3290 struct GNUNET_TRANSPORT_PluginFunctions *api;
3291 struct Plugin *plugin;
3292 struct GNUNET_SERVICE_Context *service;
3293 unsigned long long aport;
3294 unsigned long long bport;
3295 unsigned long long max_connections;
3297 struct GNUNET_TIME_Relative idle_timeout;
3299 struct GNUNET_NETWORK_Handle *const*lsocks;
3303 struct sockaddr **addrs;
3304 socklen_t *addrlens;
3306 if (NULL == env->receive)
3308 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3309 initialze the plugin or the API */
3310 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3312 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3313 api->address_to_string = &tcp_plugin_address_to_string;
3314 api->string_to_address = &tcp_plugin_string_to_address;
3318 GNUNET_assert (NULL != env->cfg);
3320 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3324 max_connections = 128;
3328 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3332 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
3333 "ADVERTISED-PORT", &aport)) &&
3336 LOG(GNUNET_ERROR_TYPE_ERROR,
3337 _("Require valid port number for service `%s' in configuration!\n"),
3347 service = GNUNET_SERVICE_start ("transport-tcp",
3349 GNUNET_SERVICE_OPTION_NONE);
3350 if (NULL == service)
3352 LOG (GNUNET_ERROR_TYPE_WARNING,
3353 _("Failed to start service.\n"));
3361 plugin = GNUNET_new (struct Plugin);
3362 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3364 plugin->max_connections = max_connections;
3365 plugin->open_port = bport;
3366 plugin->adv_port = aport;
3368 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3369 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3370 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3372 if ( (NULL != service) &&
3374 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3379 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3380 lsocks = GNUNET_SERVICE_get_listen_sockets (service);
3383 uint32_t len = sizeof (struct WelcomeMessage);
3385 for (i=0;NULL!=lsocks[i];i++)
3388 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3392 sizeof (struct GNUNET_PeerIdentity))) ||
3394 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3396 TCP_STEALTH_INTEGRITY_LEN,
3400 /* TCP STEALTH not supported by kernel */
3401 GNUNET_assert (0 == i);
3402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3403 _("TCP_STEALTH not supported on this platform.\n"));
3409 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3410 _("TCP_STEALTH not supported on this platform.\n"));
3415 if ( (NULL != service) &&
3418 get_server_addresses ("transport-tcp",
3423 for (ret = ret_s-1; ret >= 0; ret--)
3424 LOG (GNUNET_ERROR_TYPE_INFO,
3425 "Binding to address `%s'\n",
3426 GNUNET_a2s (addrs[ret], addrlens[ret]));
3428 = GNUNET_NAT_register (env->cfg,
3431 (unsigned int) ret_s,
3432 (const struct sockaddr **) addrs,
3434 &tcp_nat_port_map_callback,
3435 &try_connection_reversal,
3437 for (ret = ret_s -1; ret >= 0; ret--)
3438 GNUNET_free (addrs[ret]);
3439 GNUNET_free_non_null (addrs);
3440 GNUNET_free_non_null (addrlens);
3444 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3451 &try_connection_reversal,
3454 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3456 api->send = &tcp_plugin_send;
3457 api->get_session = &tcp_plugin_get_session;
3458 api->disconnect_session = &tcp_plugin_disconnect_session;
3459 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3460 api->disconnect_peer = &tcp_plugin_disconnect;
3461 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3462 api->check_address = &tcp_plugin_check_address;
3463 api->address_to_string = &tcp_plugin_address_to_string;
3464 api->string_to_address = &tcp_plugin_string_to_address;
3465 api->get_network = &tcp_plugin_get_network;
3466 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3467 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3468 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3469 api->setup_monitor = &tcp_plugin_setup_monitor;
3470 plugin->service = service;
3471 if (NULL != service)
3473 plugin->server = GNUNET_SERVICE_get_server (service);
3478 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3483 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3489 = GNUNET_SERVER_create_with_sockets (NULL,
3495 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3496 GNUNET_memcpy (plugin->handlers,
3498 sizeof(my_handlers));
3499 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3500 plugin->handlers[i].callback_cls = plugin;
3502 GNUNET_SERVER_add_handlers (plugin->server,
3504 GNUNET_SERVER_connect_notify (plugin->server,
3507 GNUNET_SERVER_disconnect_notify (plugin->server,
3510 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
3513 LOG (GNUNET_ERROR_TYPE_INFO,
3514 _("TCP transport listening on port %llu\n"),
3517 LOG (GNUNET_ERROR_TYPE_INFO,
3518 _("TCP transport not listening on any port (client only)\n"));
3519 if ( (aport != bport) &&
3521 LOG (GNUNET_ERROR_TYPE_INFO,
3522 _("TCP transport advertises itself as being on port %llu\n"),
3524 /* Initially set connections to 0 */
3525 GNUNET_STATISTICS_set (plugin->env->stats,
3526 gettext_noop ("# TCP sessions active"),
3532 if (NULL != plugin->nat)
3533 GNUNET_NAT_unregister (plugin->nat);
3534 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3535 if (NULL != service)
3536 GNUNET_SERVICE_stop (service);
3537 GNUNET_free (plugin);
3538 GNUNET_free_non_null (api);
3544 * Exit point from the plugin.
3546 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3550 libgnunet_plugin_transport_tcp_done (void *cls)
3552 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3553 struct Plugin *plugin = api->cls;
3554 struct TCPProbeContext *tcp_probe;
3555 struct PrettyPrinterContext *cur;
3556 struct PrettyPrinterContext *next;
3563 LOG (GNUNET_ERROR_TYPE_DEBUG,
3564 "Shutting down TCP plugin\n");
3566 /* Removing leftover sessions */
3567 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3568 &session_disconnect_it,
3570 /* Removing leftover NAT sessions */
3571 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3572 &session_disconnect_it,
3575 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3578 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3579 plugin->ppc_dll_tail,
3581 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3582 cur->asc (cur->asc_cls,
3588 if (NULL != plugin->service)
3589 GNUNET_SERVICE_stop (plugin->service);
3591 GNUNET_SERVER_destroy (plugin->server);
3592 GNUNET_free (plugin->handlers);
3593 if (NULL != plugin->nat)
3594 GNUNET_NAT_unregister (plugin->nat);
3595 while (NULL != (tcp_probe = plugin->probe_head))
3597 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3600 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3601 GNUNET_free (tcp_probe);
3603 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3604 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3605 GNUNET_break (0 == plugin->cur_connections);
3606 GNUNET_free (plugin);
3611 /* end of plugin_transport_tcp.c */