2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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_connection_lib.h"
28 #include "gnunet_container_lib.h"
29 #include "gnunet_os_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_server_lib.h"
33 #include "gnunet_service_lib.h"
34 #include "gnunet_signatures.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_transport_service.h"
37 #include "gnunet_transport_plugin.h"
38 #include "transport.h"
40 #define DEBUG_TCP GNUNET_NO
42 #define DEBUG_TCP_NAT GNUNET_NO
45 * How long until we give up on transmitting the welcome message?
47 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
51 * Initial handshake message for a session.
56 * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
58 struct GNUNET_MessageHeader header;
61 * Identity of the node connecting (TCP client)
63 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;
88 * Context for sending a NAT probe via TCP.
90 struct TCPProbeContext
95 struct GNUNET_CONNECTION_Handle *sock;
100 struct TCP_NAT_ProbeMessage message;
103 * Handle to the transmission.
105 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
108 * Transport plugin handle.
110 struct Plugin *plugin;
115 * Network format for IPv4 addresses.
117 struct IPv4TcpAddress
120 * IPv4 address, in network byte order.
122 uint32_t ipv4_addr GNUNET_PACKED;
125 * Port number, in network byte order.
127 uint16_t t_port GNUNET_PACKED;
133 * Network format for IPv6 addresses.
135 struct IPv6TcpAddress
140 struct in6_addr ipv6_addr GNUNET_PACKED;
143 * Port number, in network byte order.
145 uint16_t t6_port GNUNET_PACKED;
151 * Encapsulation of all of the state of the plugin.
157 * Local network addresses (actual IP address follows this struct).
158 * PORT is NOT included!
164 * This is a doubly linked list.
166 struct LocalAddrList *next;
169 * This is a doubly linked list.
171 struct LocalAddrList *prev;
174 * Number of bytes of the address that follow
182 * Information kept for each message that is yet to
185 struct PendingMessage
189 * This is a doubly-linked list.
191 struct PendingMessage *next;
194 * This is a doubly-linked list.
196 struct PendingMessage *prev;
199 * The pending message
204 * Continuation function to call once the message
205 * has been sent. Can be NULL if there is no
206 * continuation to call.
208 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
211 * Closure for transmit_cont.
213 void *transmit_cont_cls;
216 * Timeout value for the pending message.
218 struct GNUNET_TIME_Absolute timeout;
221 * So that the gnunet-service-transport can group messages together,
222 * these pending messages need to accept a message buffer and size
223 * instead of just a GNUNET_MessageHeader.
231 * Session handle for TCP connections.
239 struct SessionHeader header;
242 * Stored in a linked list.
244 struct Session *next;
247 * Pointer to the global plugin struct.
249 struct Plugin *plugin;
252 * The client (used to identify this connection)
254 struct GNUNET_SERVER_Client *client;
257 * Messages currently pending for transmission
258 * to this peer, if any.
260 struct PendingMessage *pending_messages_head;
263 * Messages currently pending for transmission
264 * to this peer, if any.
266 struct PendingMessage *pending_messages_tail;
269 * Handle for pending transmission request.
271 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
274 * To whom are we talking to (set to our identity
275 * if we are still waiting for the welcome message)
277 struct GNUNET_PeerIdentity target;
280 * ID of task used to delay receiving more to throttle sender.
282 GNUNET_SCHEDULER_TaskIdentifier receive_delay_task;
285 * Address of the other peer (either based on our 'connect'
286 * call or on our 'accept' call).
291 * Last activity on this connection. Used to select preferred
294 struct GNUNET_TIME_Absolute last_activity;
297 * Length of connect_addr.
302 * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
304 int expecting_welcome;
307 * Was this a connection that was inbound (we accepted)? (GNUNET_YES/GNUNET_NO)
312 * Was this session created using NAT traversal?
320 * Encapsulation of all of the state of the plugin.
327 struct GNUNET_TRANSPORT_PluginEnvironment *env;
332 struct GNUNET_CONNECTION_Handle *lsock;
335 * stdout pipe handle for the gnunet-nat-server process
337 struct GNUNET_DISK_PipeHandle *server_stdout;
340 * stdout file handle (for reading) for the gnunet-nat-server process
342 const struct GNUNET_DISK_FileHandle *server_stdout_handle;
345 * ID of select gnunet-nat-server stdout read task
347 GNUNET_SCHEDULER_TaskIdentifier server_read_task;
350 * The process id of the server process (if behind NAT)
352 struct GNUNET_OS_Process *server_proc;
355 * List of open TCP sessions.
357 struct Session *sessions;
360 * Handle to the network service.
362 struct GNUNET_SERVICE_Context *service;
365 * Handle to the server for this service.
367 struct GNUNET_SERVER_Handle *server;
370 * Copy of the handler array where the closures are
371 * set to this struct's instance.
373 struct GNUNET_SERVER_MessageHandler *handlers;
376 * Handle for request of hostname resolution, non-NULL if pending.
378 struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
381 * Map of peers we have tried to contact behind a NAT
383 struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns;
386 * The external address given to us by the user. Must be actual
387 * outside visible address for NAT punching to work.
389 char *external_address;
392 * The internal address given to us by the user (or discovered).
394 char *internal_address;
397 * Address given for us to bind to (ONLY).
402 * List of our IP addresses.
404 struct LocalAddrList *lal_head;
407 * Tail of our IP address list.
409 struct LocalAddrList *lal_tail;
412 * ID of task used to update our addresses when one expires.
414 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
417 * Port that we are actually listening on.
422 * Port that the user said we would have visible to the
428 * Is this transport configured to be behind a NAT?
433 * Is this transport configured to allow connections to NAT'd peers?
438 * Should this transport advertise only NAT addresses (port set to 0)?
439 * If not, all addresses will be duplicated for NAT punching and regular
442 int only_nat_addresses;
448 * Add the given address to the list of 'local' addresses, thereby
449 * making it a 'legal' address for this peer to have.
451 * @param plugin the plugin
452 * @param arg the address, either an IPv4 or an IPv6 IP address
453 * @param arg_size number of bytes in arg
456 add_to_address_list (struct Plugin *plugin,
460 struct LocalAddrList *lal;
462 lal = plugin->lal_head;
465 if ( (lal->size == arg_size) &&
466 (0 == memcmp (&lal[1], arg, arg_size)) )
470 lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
471 lal->size = arg_size;
472 memcpy (&lal[1], arg, arg_size);
473 GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
480 * Check if the given address is in the list of 'local' addresses.
482 * @param plugin the plugin
483 * @param arg the address, either an IPv4 or an IPv6 IP address
484 * @param arg_size number of bytes in arg
485 * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
488 check_local_addr (struct Plugin *plugin,
492 struct LocalAddrList *lal;
494 lal = plugin->lal_head;
497 if ( (lal->size == arg_size) &&
498 (0 == memcmp (&lal[1], arg, arg_size)) )
502 return GNUNET_SYSERR;
507 * Function called for a quick conversion of the binary address to
508 * a numeric address. Note that the caller must not free the
509 * address and that the next call to this function is allowed
510 * to override the address again.
512 * @param cls closure ('struct Plugin*')
513 * @param addr binary address
514 * @param addrlen length of the address
515 * @return string representing the same address
518 tcp_address_to_string (void *cls,
522 static char rbuf[INET6_ADDRSTRLEN + 12];
523 char buf[INET6_ADDRSTRLEN];
527 const struct IPv4TcpAddress *t4;
528 const struct IPv6TcpAddress *t6;
532 if (addrlen == sizeof (struct IPv6TcpAddress))
536 port = ntohs (t6->t6_port);
537 memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
540 else if (addrlen == sizeof (struct IPv4TcpAddress))
544 port = ntohs (t4->t_port);
545 memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
550 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
552 _("Unexpected address length: %u\n"),
557 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
559 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
562 GNUNET_snprintf (rbuf,
564 (af == AF_INET6) ? "[%s]:%u" : "%s:%u",
572 * Find the session handle for the given client.
574 * @param plugin the plugin
575 * @param client which client to find the session handle for
576 * @return NULL if no matching session exists
578 static struct Session *
579 find_session_by_client (struct Plugin *plugin,
580 const struct GNUNET_SERVER_Client *client)
584 ret = plugin->sessions;
585 while ((ret != NULL) && (client != ret->client))
592 * Create a new session. Also queues a welcome message.
594 * @param plugin the plugin
595 * @param target peer to connect to
596 * @param client client to use
597 * @param is_nat this a NAT session, we should wait for a client to
598 * connect to us from an address, then assign that to
600 * @return new session object
602 static struct Session *
603 create_session (struct Plugin *plugin,
604 const struct GNUNET_PeerIdentity *target,
605 struct GNUNET_SERVER_Client *client,
609 struct PendingMessage *pm;
610 struct WelcomeMessage welcome;
612 if (is_nat != GNUNET_YES)
613 GNUNET_assert (client != NULL);
615 GNUNET_assert (client == NULL);
617 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
619 "Creating new session for peer `%4s'\n",
620 GNUNET_i2s (target));
622 ret = GNUNET_malloc (sizeof (struct Session));
623 ret->last_activity = GNUNET_TIME_absolute_get ();
624 ret->plugin = plugin;
625 ret->is_nat = is_nat;
626 if (is_nat != GNUNET_YES) /* If not a NAT WAIT conn, add it to global list */
628 ret->next = plugin->sessions;
629 plugin->sessions = ret;
631 ret->client = client;
632 ret->target = *target;
633 ret->expecting_welcome = GNUNET_YES;
634 pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct WelcomeMessage));
635 pm->msg = (const char*) &pm[1];
636 pm->message_size = sizeof (struct WelcomeMessage);
637 welcome.header.size = htons (sizeof (struct WelcomeMessage));
638 welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
639 welcome.clientIdentity = *plugin->env->my_identity;
640 memcpy (&pm[1], &welcome, sizeof (welcome));
641 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
642 GNUNET_STATISTICS_update (plugin->env->stats,
643 gettext_noop ("# bytes currently in TCP buffers"),
646 GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head,
647 ret->pending_messages_tail,
649 if (is_nat != GNUNET_YES)
650 GNUNET_STATISTICS_update (plugin->env->stats,
651 gettext_noop ("# TCP sessions active"),
659 * If we have pending messages, ask the server to
660 * transmit them (schedule the respective tasks, etc.)
662 * @param session for which session should we do this
664 static void process_pending_messages (struct Session *session);
668 * Function called to notify a client about the socket
669 * being ready to queue more data. "buf" will be
670 * NULL and "size" zero if the socket was closed for
671 * writing in the meantime.
674 * @param size number of bytes available in buf
675 * @param buf where the callee should write the message
676 * @return number of bytes written to buf
679 do_transmit (void *cls, size_t size, void *buf)
681 struct Session *session = cls;
682 struct GNUNET_PeerIdentity pid;
683 struct Plugin *plugin;
684 struct PendingMessage *pos;
685 struct PendingMessage *hd;
686 struct PendingMessage *tl;
687 struct GNUNET_TIME_Absolute now;
691 session->transmit_handle = NULL;
692 plugin = session->plugin;
696 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
698 "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
699 GNUNET_i2s (&session->target));
701 /* timeout; cancel all messages that have already expired */
705 now = GNUNET_TIME_absolute_get ();
706 while ( (NULL != (pos = session->pending_messages_head)) &&
707 (pos->timeout.abs_value <= now.abs_value) )
709 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
710 session->pending_messages_tail,
713 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
715 "Failed to transmit %u byte message to `%4s'.\n",
717 GNUNET_i2s (&session->target));
719 ret += pos->message_size;
720 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
722 /* do this call before callbacks (so that if callbacks destroy
723 session, they have a chance to cancel actions done by this
725 process_pending_messages (session);
726 pid = session->target;
727 /* no do callbacks and do not use session again since
728 the callbacks may abort the session */
729 while (NULL != (pos = hd))
731 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
732 if (pos->transmit_cont != NULL)
733 pos->transmit_cont (pos->transmit_cont_cls,
734 &pid, GNUNET_SYSERR);
737 GNUNET_STATISTICS_update (plugin->env->stats,
738 gettext_noop ("# bytes currently in TCP buffers"),
741 GNUNET_STATISTICS_update (plugin->env->stats,
742 gettext_noop ("# bytes discarded by TCP (timeout)"),
747 /* copy all pending messages that would fit */
752 while (NULL != (pos = session->pending_messages_head))
754 if (ret + pos->message_size > size)
756 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
757 session->pending_messages_tail,
759 GNUNET_assert (size >= pos->message_size);
760 /* FIXME: this memcpy can be up to 7% of our total runtime */
761 memcpy (cbuf, pos->msg, pos->message_size);
762 cbuf += pos->message_size;
763 ret += pos->message_size;
764 size -= pos->message_size;
765 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
767 /* schedule 'continuation' before callbacks so that callbacks that
768 cancel everything don't cause us to use a session that no longer
770 process_pending_messages (session);
771 session->last_activity = GNUNET_TIME_absolute_get ();
772 pid = session->target;
773 /* we'll now call callbacks that may cancel the session; hence
774 we should not use 'session' after this point */
775 while (NULL != (pos = hd))
777 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
778 if (pos->transmit_cont != NULL)
779 pos->transmit_cont (pos->transmit_cont_cls,
783 GNUNET_assert (hd == NULL);
784 GNUNET_assert (tl == NULL);
786 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
788 "Transmitting %u bytes\n",
791 GNUNET_STATISTICS_update (plugin->env->stats,
792 gettext_noop ("# bytes currently in TCP buffers"),
795 GNUNET_STATISTICS_update (plugin->env->stats,
796 gettext_noop ("# bytes transmitted via TCP"),
804 * If we have pending messages, ask the server to
805 * transmit them (schedule the respective tasks, etc.)
807 * @param session for which session should we do this
810 process_pending_messages (struct Session *session)
812 struct PendingMessage *pm;
814 GNUNET_assert (session->client != NULL);
815 if (session->transmit_handle != NULL)
817 if (NULL == (pm = session->pending_messages_head))
820 session->transmit_handle
821 = GNUNET_SERVER_notify_transmit_ready (session->client,
823 GNUNET_TIME_absolute_get_remaining
825 &do_transmit, session);
830 * Functions with this signature are called whenever we need
831 * to close a session due to a disconnect or failure to
832 * establish a connection.
834 * @param session session to close down
837 disconnect_session (struct Session *session)
839 struct Session *prev;
841 struct PendingMessage *pm;
844 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
846 "Disconnecting from `%4s' at %s (session %p).\n",
847 GNUNET_i2s (&session->target),
848 (session->connect_addr != NULL) ?
849 tcp_address_to_string (session->plugin,
850 session->connect_addr,
851 session->connect_alen) : "*",
854 /* remove from session list */
856 pos = session->plugin->sessions;
857 while (pos != session)
863 session->plugin->sessions = session->next;
865 prev->next = session->next;
866 session->plugin->env->session_end (session->plugin->env->cls,
870 if (session->transmit_handle != NULL)
872 GNUNET_CONNECTION_notify_transmit_ready_cancel
873 (session->transmit_handle);
874 session->transmit_handle = NULL;
876 while (NULL != (pm = session->pending_messages_head))
879 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
881 pm->transmit_cont != NULL
882 ? "Could not deliver message to `%4s'.\n"
884 "Could not deliver message to `%4s', notifying.\n",
885 GNUNET_i2s (&session->target));
887 GNUNET_STATISTICS_update (session->plugin->env->stats,
888 gettext_noop ("# bytes currently in TCP buffers"),
889 - (int64_t) pm->message_size,
891 GNUNET_STATISTICS_update (session->plugin->env->stats,
892 gettext_noop ("# bytes discarded by TCP (disconnect)"),
895 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
896 session->pending_messages_tail,
898 if (NULL != pm->transmit_cont)
899 pm->transmit_cont (pm->transmit_cont_cls,
900 &session->target, GNUNET_SYSERR);
903 GNUNET_break (session->client != NULL);
904 if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK)
906 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
907 if (session->client != NULL)
908 GNUNET_SERVER_receive_done (session->client,
911 if (session->client != NULL)
912 GNUNET_SERVER_client_drop (session->client);
913 GNUNET_STATISTICS_update (session->plugin->env->stats,
914 gettext_noop ("# TCP sessions active"),
917 GNUNET_free_non_null (session->connect_addr);
918 GNUNET_free (session);
923 * Given two otherwise equivalent sessions, pick the better one.
925 * @param s1 one session (also default)
926 * @param s2 other session
927 * @return "better" session (more active)
929 static struct Session *
930 select_better_session (struct Session *s1,
937 if ( (s1->expecting_welcome == GNUNET_NO) &&
938 (s2->expecting_welcome == GNUNET_YES) )
940 if ( (s1->expecting_welcome == GNUNET_YES) &&
941 (s2->expecting_welcome == GNUNET_NO) )
943 if (s1->last_activity.abs_value < s2->last_activity.abs_value)
945 if (s1->last_activity.abs_value > s2->last_activity.abs_value)
947 if ( (GNUNET_YES == s1->inbound) &&
948 (GNUNET_NO == s2->inbound) )
950 if ( (GNUNET_NO == s1->inbound) &&
951 (GNUNET_YES == s2->inbound) )
958 * We learned about a peer (possibly behind NAT) so run the
959 * gnunet-nat-client to send dummy ICMP responses.
961 * @param plugin the plugin for this transport
962 * @param addr the address of the peer (IPv4-only)
965 run_gnunet_nat_client (struct Plugin *plugin,
966 const struct sockaddr_in *sa)
968 char inet4[INET_ADDRSTRLEN];
969 char port_as_string[6];
970 struct GNUNET_OS_Process *proc;
972 GNUNET_assert (sa->sin_family == AF_INET);
973 if (NULL == inet_ntop (AF_INET,
975 inet4, INET_ADDRSTRLEN))
977 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
980 GNUNET_snprintf(port_as_string,
981 sizeof (port_as_string),
985 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
987 _("Running gnunet-nat-client %s %s %u\n"),
988 plugin->external_address,
990 (unsigned int) plugin->adv_port);
992 proc = GNUNET_OS_start_process (NULL,
996 plugin->external_address,
1000 /* we know that the gnunet-nat-client will terminate virtually
1002 GNUNET_OS_process_wait (proc);
1003 GNUNET_OS_process_close (proc);
1008 * Function that can be used by the transport service to transmit
1009 * a message using the plugin. Note that in the case of a
1010 * peer disconnecting, the continuation MUST be called
1011 * prior to the disconnect notification itself. This function
1012 * will be called with this peer's HELLO message to initiate
1013 * a fresh connection to another peer.
1015 * @param cls closure
1016 * @param target who should receive this message
1017 * @param msg the message to transmit
1018 * @param msgbuf_size number of bytes in 'msg'
1019 * @param priority how important is the message (most plugins will
1020 * ignore message priority and just FIFO)
1021 * @param timeout how long to wait at most for the transmission (does not
1022 * require plugins to discard the message after the timeout,
1023 * just advisory for the desired delay; most plugins will ignore
1025 * @param session which session must be used (or NULL for "any")
1026 * @param addr the address to use (can be NULL if the plugin
1027 * is "on its own" (i.e. re-use existing TCP connection))
1028 * @param addrlen length of the address in bytes
1029 * @param force_address GNUNET_YES if the plugin MUST use the given address,
1030 * GNUNET_NO means the plugin may use any other address and
1031 * GNUNET_SYSERR means that only reliable existing
1032 * bi-directional connections should be used (regardless
1034 * @param cont continuation to call once the message has
1035 * been transmitted (or if the transport is ready
1036 * for the next transmission call; or if the
1037 * peer disconnected...); can be NULL
1038 * @param cont_cls closure for cont
1039 * @return number of bytes used (on the physical network, with overheads);
1040 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1041 * and does NOT mean that the message was not transmitted (DV and NAT)
1044 tcp_plugin_send (void *cls,
1045 const struct GNUNET_PeerIdentity *target,
1049 struct GNUNET_TIME_Relative timeout,
1050 struct Session *session,
1054 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1056 struct Plugin *plugin = cls;
1057 struct Session *cand_session;
1058 struct Session *next;
1059 struct PendingMessage *pm;
1060 struct GNUNET_CONNECTION_Handle *sa;
1064 struct sockaddr_in a4;
1065 struct sockaddr_in6 a6;
1066 const struct IPv4TcpAddress *t4;
1067 const struct IPv6TcpAddress *t6;
1068 unsigned int is_natd;
1070 GNUNET_STATISTICS_update (plugin->env->stats,
1071 gettext_noop ("# bytes TCP was asked to transmit"),
1074 /* FIXME: we could do this cheaper with a hash table
1075 where we could restrict the iteration to entries that match
1076 the target peer... */
1077 is_natd = GNUNET_NO;
1078 if (session == NULL)
1080 cand_session = NULL;
1081 next = plugin->sessions;
1082 while (NULL != (session = next))
1084 next = session->next;
1085 GNUNET_assert (session->client != NULL);
1086 if (0 != memcmp (target,
1088 sizeof (struct GNUNET_PeerIdentity)))
1090 if ( ( (GNUNET_SYSERR == force_address) &&
1091 (session->expecting_welcome == GNUNET_NO) ) ||
1092 (GNUNET_NO == force_address) )
1094 cand_session = select_better_session (cand_session,
1098 if (GNUNET_SYSERR == force_address)
1100 GNUNET_break (GNUNET_YES == force_address);
1106 if ( (addrlen != session->connect_alen) &&
1107 (session->is_nat == GNUNET_NO) )
1109 if ((0 != memcmp (session->connect_addr,
1111 addrlen)) && (session->is_nat == GNUNET_NO))
1113 cand_session = select_better_session (cand_session,
1116 session = cand_session;
1118 if ( (session == NULL) &&
1122 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1124 "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n",
1125 GNUNET_i2s (target));
1127 GNUNET_STATISTICS_update (plugin->env->stats,
1128 gettext_noop ("# bytes discarded by TCP (no address and no connection)"),
1133 if (session == NULL)
1135 if (addrlen == sizeof (struct IPv6TcpAddress))
1139 memset (&a6, 0, sizeof (a6));
1140 #if HAVE_SOCKADDR_IN_SIN_LEN
1141 a6.sin6_len = sizeof (a6);
1143 a6.sin6_family = AF_INET6;
1144 a6.sin6_port = t6->t6_port;
1145 if (t6->t6_port == 0)
1146 is_natd = GNUNET_YES;
1147 memcpy (&a6.sin6_addr,
1149 sizeof (struct in6_addr));
1153 else if (addrlen == sizeof (struct IPv4TcpAddress))
1157 memset (&a4, 0, sizeof (a4));
1158 #if HAVE_SOCKADDR_IN_SIN_LEN
1159 a4.sin_len = sizeof (a4);
1161 a4.sin_family = AF_INET;
1162 a4.sin_port = t4->t_port;
1163 if (t4->t_port == 0)
1164 is_natd = GNUNET_YES;
1165 a4.sin_addr.s_addr = t4->ipv4_addr;
1171 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1173 _("Address of unexpected length: %u\n"),
1179 if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
1180 return -1; /* NAT client only works with IPv4 addresses */
1183 if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) &&
1184 (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)))
1187 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1189 _("Found valid IPv4 NAT address (creating session)!\n"));
1191 session = create_session (plugin,
1195 /* create new message entry */
1196 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1197 /* FIXME: the memset of this malloc can be up to 2% of our total runtime */
1198 pm->msg = (const char*) &pm[1];
1199 memcpy (&pm[1], msg, msgbuf_size);
1200 /* FIXME: this memcpy can be up to 7% of our total run-time
1201 (for transport service) */
1202 pm->message_size = msgbuf_size;
1203 pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1204 pm->transmit_cont = cont;
1205 pm->transmit_cont_cls = cont_cls;
1207 /* append pm to pending_messages list */
1208 GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head,
1209 session->pending_messages_tail,
1210 session->pending_messages_tail,
1213 GNUNET_assert(GNUNET_CONTAINER_multihashmap_put(plugin->nat_wait_conns, &target->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK);
1215 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1217 "Created NAT WAIT connection to `%4s' at `%s'\n",
1218 GNUNET_i2s (target),
1219 GNUNET_a2s (sb, sbs));
1221 run_gnunet_nat_client (plugin, &a4);
1224 else if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)))
1226 /* Only do one NAT punch attempt per peer identity */
1229 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1233 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1235 "Failed to create connection to `%4s' at `%s'\n",
1236 GNUNET_i2s (target),
1237 GNUNET_a2s (sb, sbs));
1239 GNUNET_STATISTICS_update (plugin->env->stats,
1240 gettext_noop ("# bytes discarded by TCP (failed to connect)"),
1246 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1248 "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
1249 GNUNET_i2s (target),
1250 GNUNET_a2s (sb, sbs));
1252 session = create_session (plugin,
1254 GNUNET_SERVER_connect_socket (plugin->server,
1256 session->connect_addr = GNUNET_malloc (addrlen);
1257 memcpy (session->connect_addr,
1260 session->connect_alen = addrlen;
1262 GNUNET_assert (session != NULL);
1263 GNUNET_assert (session->client != NULL);
1264 GNUNET_STATISTICS_update (plugin->env->stats,
1265 gettext_noop ("# bytes currently in TCP buffers"),
1268 /* create new message entry */
1269 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
1270 pm->msg = (const char*) &pm[1];
1271 memcpy (&pm[1], msg, msgbuf_size);
1272 pm->message_size = msgbuf_size;
1273 pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1274 pm->transmit_cont = cont;
1275 pm->transmit_cont_cls = cont_cls;
1277 /* append pm to pending_messages list */
1278 GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head,
1279 session->pending_messages_tail,
1280 session->pending_messages_tail,
1283 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1285 "Asked to transmit %u bytes to `%s', added message to list.\n",
1287 GNUNET_i2s (target));
1289 process_pending_messages (session);
1295 * Function that can be called to force a disconnect from the
1296 * specified neighbour. This should also cancel all previously
1297 * scheduled transmissions. Obviously the transmission may have been
1298 * partially completed already, which is OK. The plugin is supposed
1299 * to close the connection (if applicable) and no longer call the
1300 * transmit continuation(s).
1302 * Finally, plugin MUST NOT call the services's receive function to
1303 * notify the service that the connection to the specified target was
1304 * closed after a getting this call.
1306 * @param cls closure
1307 * @param target peer for which the last transmission is
1311 tcp_plugin_disconnect (void *cls,
1312 const struct GNUNET_PeerIdentity *target)
1314 struct Plugin *plugin = cls;
1315 struct Session *session;
1316 struct Session *next;
1317 struct PendingMessage *pm;
1320 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1322 "Asked to cancel session with `%4s'\n",
1323 GNUNET_i2s (target));
1325 next = plugin->sessions;
1326 while (NULL != (session = next))
1328 next = session->next;
1329 if (0 != memcmp (target,
1331 sizeof (struct GNUNET_PeerIdentity)))
1333 pm = session->pending_messages_head;
1336 pm->transmit_cont = NULL;
1337 pm->transmit_cont_cls = NULL;
1340 disconnect_session (session);
1346 * Context for address to string conversion.
1348 struct PrettyPrinterContext
1351 * Function to call with the result.
1353 GNUNET_TRANSPORT_AddressStringCallback asc;
1356 * Clsoure for 'asc'.
1361 * Port to add after the IP address.
1368 * Append our port and forward the result.
1370 * @param cls the 'struct PrettyPrinterContext*'
1371 * @param hostname hostname part of the address
1374 append_port (void *cls, const char *hostname)
1376 struct PrettyPrinterContext *ppc = cls;
1379 if (hostname == NULL)
1381 ppc->asc (ppc->asc_cls, NULL);
1385 GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
1386 ppc->asc (ppc->asc_cls, ret);
1392 * Convert the transports address to a nice, human-readable
1395 * @param cls closure
1396 * @param type name of the transport that generated the address
1397 * @param addr one of the addresses of the host, NULL for the last address
1398 * the specific address format depends on the transport
1399 * @param addrlen length of the address
1400 * @param numeric should (IP) addresses be displayed in numeric form?
1401 * @param timeout after how long should we give up?
1402 * @param asc function to call on each string
1403 * @param asc_cls closure for asc
1406 tcp_plugin_address_pretty_printer (void *cls,
1411 struct GNUNET_TIME_Relative timeout,
1412 GNUNET_TRANSPORT_AddressStringCallback asc,
1415 struct Plugin *plugin = cls;
1416 struct PrettyPrinterContext *ppc;
1419 struct sockaddr_in a4;
1420 struct sockaddr_in6 a6;
1421 const struct IPv4TcpAddress *t4;
1422 const struct IPv6TcpAddress *t6;
1425 if (addrlen == sizeof (struct IPv6TcpAddress))
1428 memset (&a6, 0, sizeof (a6));
1429 a6.sin6_family = AF_INET6;
1430 a6.sin6_port = t6->t6_port;
1431 memcpy (&a6.sin6_addr,
1433 sizeof (struct in6_addr));
1434 port = ntohs (t6->t6_port);
1438 else if (addrlen == sizeof (struct IPv4TcpAddress))
1441 memset (&a4, 0, sizeof (a4));
1442 a4.sin_family = AF_INET;
1443 a4.sin_port = t4->t_port;
1444 a4.sin_addr.s_addr = t4->ipv4_addr;
1445 port = ntohs (t4->t_port);
1451 /* invalid address */
1452 GNUNET_break_op (0);
1453 asc (asc_cls, NULL);
1456 ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
1458 ppc->asc_cls = asc_cls;
1460 GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
1463 !numeric, timeout, &append_port, ppc);
1468 * Check if the given port is plausible (must be either
1469 * our listen port or our advertised port). If it is
1470 * neither, we return GNUNET_SYSERR.
1472 * @param plugin global variables
1473 * @param in_port port number to check
1474 * @return GNUNET_OK if port is either open_port or adv_port
1477 check_port (struct Plugin *plugin, uint16_t in_port)
1479 if ( (plugin->behind_nat == GNUNET_YES) && (in_port == 0) )
1481 if ( (plugin->only_nat_addresses == GNUNET_YES) &&
1482 (plugin->behind_nat == GNUNET_YES) )
1484 return GNUNET_SYSERR; /* odd case... */
1486 if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
1488 return GNUNET_SYSERR;
1493 * Function that will be called to check if a binary address for this
1494 * plugin is well-formed and corresponds to an address for THIS peer
1495 * (as per our configuration). Naturally, if absolutely necessary,
1496 * plugins can be a bit conservative in their answer, but in general
1497 * plugins should make sure that the address does not redirect
1498 * traffic to a 3rd party that might try to man-in-the-middle our
1501 * @param cls closure, our 'struct Plugin*'
1502 * @param addr pointer to the address
1503 * @param addrlen length of addr
1504 * @return GNUNET_OK if this is a plausible address for this peer
1505 * and transport, GNUNET_SYSERR if not
1508 tcp_plugin_check_address (void *cls,
1512 struct Plugin *plugin = cls;
1513 struct IPv4TcpAddress *v4;
1514 struct IPv6TcpAddress *v6;
1516 if ((addrlen != sizeof (struct IPv4TcpAddress)) &&
1517 (addrlen != sizeof (struct IPv6TcpAddress)))
1519 GNUNET_break_op (0);
1520 return GNUNET_SYSERR;
1522 if (addrlen == sizeof (struct IPv4TcpAddress))
1524 v4 = (struct IPv4TcpAddress *) addr;
1526 check_port (plugin, ntohs (v4->t_port)))
1527 return GNUNET_SYSERR;
1529 check_local_addr (plugin, &v4->ipv4_addr, sizeof (uint32_t)))
1531 return GNUNET_SYSERR;
1536 v6 = (struct IPv6TcpAddress *) addr;
1537 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1539 GNUNET_break_op (0);
1540 return GNUNET_SYSERR;
1543 check_port (plugin, ntohs (v6->t6_port)))
1544 return GNUNET_SYSERR;
1546 check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr)))
1548 return GNUNET_SYSERR;
1555 * We've received a nat probe from this peer via TCP. Finish
1556 * creating the client session and resume sending of queued
1559 * @param cls closure
1560 * @param client identification of the client
1561 * @param message the actual message
1564 handle_tcp_nat_probe (void *cls,
1565 struct GNUNET_SERVER_Client *client,
1566 const struct GNUNET_MessageHeader *message)
1568 struct Plugin *plugin = cls;
1569 struct Session *session;
1570 struct TCP_NAT_ProbeMessage *tcp_nat_probe;
1573 struct IPv4TcpAddress *t4;
1574 struct IPv6TcpAddress *t6;
1575 const struct sockaddr_in *s4;
1576 const struct sockaddr_in6 *s6;
1579 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1581 "received tcp NAT probe\n");
1583 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
1584 * a connection to this peer by running gnunet-nat-client. This peer
1585 * received the punch message and now wants us to use the new connection
1586 * as the default for that peer. Do so and then send a WELCOME message
1587 * so we can really be connected!
1589 if (ntohs(message->size) != sizeof(struct TCP_NAT_ProbeMessage))
1594 tcp_nat_probe = (struct TCP_NAT_ProbeMessage *)message;
1596 if (GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey) == GNUNET_YES)
1599 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1601 "Found session for NAT probe!\n");
1603 session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey);
1604 GNUNET_assert(session != NULL);
1605 GNUNET_assert(GNUNET_CONTAINER_multihashmap_remove(plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey, session) == GNUNET_YES);
1606 GNUNET_SERVER_client_keep (client);
1607 session->client = client;
1608 session->last_activity = GNUNET_TIME_absolute_get ();
1609 session->inbound = GNUNET_NO;
1612 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1615 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1617 "handle_tcp_nat_probe Found address `%s' for incoming connection %p\n",
1618 GNUNET_a2s (vaddr, alen),
1621 if (((const struct sockaddr *)vaddr)->sa_family == AF_INET)
1624 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1625 t4->t_port = s4->sin_port;
1626 t4->ipv4_addr = s4->sin_addr.s_addr;
1627 session->connect_addr = t4;
1628 session->connect_alen = sizeof (struct IPv4TcpAddress);
1630 else if (((const struct sockaddr *)vaddr)->sa_family == AF_INET6)
1633 t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
1634 t6->t6_port = s6->sin6_port;
1635 memcpy (&t6->ipv6_addr,
1637 sizeof (struct in6_addr));
1638 session->connect_addr = t6;
1639 session->connect_alen = sizeof (struct IPv6TcpAddress);
1644 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1646 "Bad address for incoming connection!\n");
1649 GNUNET_free (vaddr);
1652 session->next = plugin->sessions;
1653 plugin->sessions = session;
1654 GNUNET_STATISTICS_update (plugin->env->stats,
1655 gettext_noop ("# TCP sessions active"),
1658 process_pending_messages (session);
1663 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1665 "Did NOT find session for NAT probe!\n");
1669 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1673 * We've received a welcome from this peer via TCP. Possibly create a
1674 * fresh client record and send back our welcome.
1676 * @param cls closure
1677 * @param client identification of the client
1678 * @param message the actual message
1681 handle_tcp_welcome (void *cls,
1682 struct GNUNET_SERVER_Client *client,
1683 const struct GNUNET_MessageHeader *message)
1685 struct Plugin *plugin = cls;
1686 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
1687 struct Session *session;
1690 struct IPv4TcpAddress *t4;
1691 struct IPv6TcpAddress *t6;
1692 const struct sockaddr_in *s4;
1693 const struct sockaddr_in6 *s6;
1696 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1698 "Received %s message from a `%4s/%p'.\n",
1700 GNUNET_i2s (&wm->clientIdentity), client);
1702 GNUNET_STATISTICS_update (plugin->env->stats,
1703 gettext_noop ("# TCP WELCOME messages received"),
1706 session = find_session_by_client (plugin, client);
1708 if (session == NULL)
1710 GNUNET_SERVER_client_keep (client);
1712 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1714 "Received %s message from a `%4s/%p', creating session\n",
1716 GNUNET_i2s (&wm->clientIdentity), client);
1718 session = create_session (plugin,
1719 &wm->clientIdentity, client, GNUNET_NO);
1720 session->inbound = GNUNET_YES;
1722 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1725 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1727 "Found address `%s' for incoming connection %p\n",
1728 GNUNET_a2s (vaddr, alen),
1731 if (alen == sizeof (struct sockaddr_in))
1734 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1735 t4->t_port = s4->sin_port;
1736 t4->ipv4_addr = s4->sin_addr.s_addr;
1737 session->connect_addr = t4;
1738 session->connect_alen = sizeof (struct IPv4TcpAddress);
1740 else if (alen == sizeof (struct sockaddr_in6))
1743 t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
1744 t6->t6_port = s6->sin6_port;
1745 memcpy (&t6->ipv6_addr,
1747 sizeof (struct in6_addr));
1748 session->connect_addr = t6;
1749 session->connect_alen = sizeof (struct IPv6TcpAddress);
1752 GNUNET_free (vaddr);
1757 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1759 "Did not obtain TCP socket address for incoming connection\n");
1763 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1765 "Creating new session %p for connection %p\n",
1768 process_pending_messages (session);
1774 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1776 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1778 "Found address `%s' (already have session) for incoming connection %p\n",
1779 GNUNET_a2s (vaddr, alen),
1785 if (session->expecting_welcome != GNUNET_YES)
1787 GNUNET_break_op (0);
1788 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1791 session->last_activity = GNUNET_TIME_absolute_get ();
1792 session->expecting_welcome = GNUNET_NO;
1793 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1798 * Task to signal the server that we can continue
1799 * receiving from the TCP client now.
1801 * @param cls the 'struct Session*'
1802 * @param tc task context (unused)
1805 delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1807 struct Session *session = cls;
1808 struct GNUNET_TIME_Relative delay;
1810 session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK;
1811 delay = session->plugin->env->receive (session->plugin->env->cls,
1816 if (delay.rel_value == 0)
1817 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
1819 session->receive_delay_task =
1820 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
1825 * We've received data for this peer via TCP. Unbox,
1826 * compute latency and forward.
1828 * @param cls closure
1829 * @param client identification of the client
1830 * @param message the actual message
1833 handle_tcp_data (void *cls,
1834 struct GNUNET_SERVER_Client *client,
1835 const struct GNUNET_MessageHeader *message)
1837 struct Plugin *plugin = cls;
1838 struct Session *session;
1839 struct GNUNET_TIME_Relative delay;
1841 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type)) || (ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE))
1843 /* We don't want to propagate WELCOME and NAT Probe messages up! */
1844 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1847 session = find_session_by_client (plugin, client);
1848 if ( (NULL == session) || (GNUNET_YES == session->expecting_welcome))
1850 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1853 session->last_activity = GNUNET_TIME_absolute_get ();
1855 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1857 "Passing %u bytes of type %u from `%4s' to transport service.\n",
1858 (unsigned int) ntohs (message->size),
1859 (unsigned int) ntohs (message->type),
1860 GNUNET_i2s (&session->target));
1862 GNUNET_STATISTICS_update (plugin->env->stats,
1863 gettext_noop ("# bytes received via TCP"),
1864 ntohs (message->size),
1866 delay = plugin->env->receive (plugin->env->cls, &session->target, message, 1,
1868 (GNUNET_YES == session->inbound) ? NULL : session->connect_addr,
1869 (GNUNET_YES == session->inbound) ? 0 : session->connect_alen);
1870 if (delay.rel_value == 0)
1871 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1873 session->receive_delay_task =
1874 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
1879 * Functions with this signature are called whenever a peer
1880 * is disconnected on the network level.
1882 * @param cls closure
1883 * @param client identification of the client
1886 disconnect_notify (void *cls,
1887 struct GNUNET_SERVER_Client *client)
1889 struct Plugin *plugin = cls;
1890 struct Session *session;
1894 session = find_session_by_client (plugin, client);
1895 if (session == NULL)
1896 return; /* unknown, nothing to do */
1898 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1900 "Destroying session of `%4s' with %s (%p) due to network-level disconnect.\n",
1901 GNUNET_i2s (&session->target),
1902 (session->connect_addr != NULL) ?
1903 tcp_address_to_string (session->plugin,
1904 session->connect_addr,
1905 session->connect_alen) : "*",
1908 disconnect_session (session);
1913 * Add the IP of our network interface to the list of
1914 * our external IP addresses.
1916 * @param cls the 'struct Plugin*'
1917 * @param name name of the interface
1918 * @param isDefault do we think this may be our default interface
1919 * @param addr address of the interface
1920 * @param addrlen number of bytes in addr
1921 * @return GNUNET_OK to continue iterating
1924 process_interfaces (void *cls,
1927 const struct sockaddr *addr, socklen_t addrlen)
1929 struct Plugin *plugin = cls;
1931 struct IPv4TcpAddress t4;
1932 struct IPv6TcpAddress t6;
1933 struct IPv4TcpAddress t4_nat;
1934 struct IPv6TcpAddress t6_nat;
1938 char buf[INET_ADDRSTRLEN];
1940 af = addr->sa_family;
1944 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1945 GNUNET_assert(NULL != inet_ntop(AF_INET, &t4.ipv4_addr, &buf[0], INET_ADDRSTRLEN));
1946 if ((plugin->bind_address != NULL) && (0 != strcmp(buf, plugin->bind_address)))
1948 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1950 "Not notifying transport of address %s\n",
1951 GNUNET_a2s (addr, addrlen));
1954 add_to_address_list (plugin, &t4.ipv4_addr, sizeof (uint32_t));
1955 if ((plugin->behind_nat == GNUNET_YES) && (plugin->only_nat_addresses == GNUNET_YES))
1956 t4.t_port = htons(0);
1957 else if (plugin->behind_nat == GNUNET_YES) /* We are behind NAT, but will advertise NAT and normal addresses */
1959 t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1960 t4_nat.t_port = htons(plugin->adv_port);
1964 t4.t_port = htons (plugin->adv_port);
1968 else if (af == AF_INET6)
1970 if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) ||
1971 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg, "transport-tcp", "DISABLEV6")) )
1973 /* skip link local addresses */
1976 memcpy (&t6.ipv6_addr,
1977 &((struct sockaddr_in6 *) addr)->sin6_addr,
1978 sizeof (struct in6_addr));
1979 add_to_address_list (plugin, &t6.ipv6_addr, sizeof (struct in6_addr));
1980 if ((plugin->behind_nat == GNUNET_YES) && (plugin->only_nat_addresses == GNUNET_YES))
1981 t6.t6_port = htons(0);
1982 else if (plugin->behind_nat == GNUNET_YES) /* We are behind NAT, but will advertise NAT and normal addresses */
1984 memcpy (&t6_nat.ipv6_addr,
1985 &((struct sockaddr_in6 *) addr)->sin6_addr,
1986 sizeof (struct in6_addr));
1987 t6_nat.t6_port = htons(plugin->adv_port);
1991 t6.t6_port = htons (plugin->adv_port);
2000 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2002 _("Found address `%s' (%s) len %d\n"),
2003 GNUNET_a2s (addr, addrlen), name, args);
2004 plugin->env->notify_address (plugin->env->cls,
2006 arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
2008 if (arg_nat != NULL)
2010 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2012 _("Found address `%s' (%s) len %d\n"),
2013 GNUNET_a2s (addr, addrlen), name, args);
2014 plugin->env->notify_address (plugin->env->cls,
2016 arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL);
2024 * Function called by the resolver for each address obtained from DNS
2025 * for our own hostname. Add the addresses to the list of our
2026 * external IP addresses.
2028 * @param cls closure
2029 * @param addr one of the addresses of the host, NULL for the last address
2030 * @param addrlen length of the address
2033 process_hostname_ips (void *cls,
2034 const struct sockaddr *addr, socklen_t addrlen)
2036 struct Plugin *plugin = cls;
2040 plugin->hostname_dns = NULL;
2043 /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */
2044 process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
2048 * We can now send a probe message, copy into buffer to really send.
2050 * @param cls closure, a struct TCPProbeContext
2051 * @param size max size to copy
2052 * @param buf buffer to copy message to
2054 static size_t notify_send_probe (void *cls,
2055 size_t size, void *buf)
2057 struct TCPProbeContext *tcp_probe_ctx = cls;
2064 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
2065 memcpy(buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
2066 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
2067 tcp_probe_ctx->sock);
2069 GNUNET_free(tcp_probe_ctx);
2070 return sizeof(tcp_probe_ctx->message);
2075 * We have been notified that gnunet-nat-server has written something to stdout.
2076 * Handle the output, then reschedule this function to be called again once
2077 * more is available.
2079 * @param cls the plugin handle
2080 * @param tc the scheduling context
2083 tcp_plugin_server_read (void *cls,
2084 const struct GNUNET_SCHEDULER_TaskContext *tc)
2086 struct Plugin *plugin = cls;
2091 const char *port_start;
2092 struct sockaddr_in sin_addr;
2093 struct TCPProbeContext *tcp_probe_ctx;
2094 struct GNUNET_CONNECTION_Handle *sock;
2096 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2098 memset (mybuf, 0, sizeof(mybuf));
2099 bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle,
2105 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2107 "Finished reading from server stdout with code: %d\n",
2114 for (i = 0; i < sizeof(mybuf); i++)
2116 if (mybuf[i] == '\n')
2119 if ((mybuf[i] == ':') && (i + 1 < sizeof(mybuf)))
2122 port_start = &mybuf[i + 1];
2126 /* construct socket address of sender */
2127 memset (&sin_addr, 0, sizeof (sin_addr));
2128 sin_addr.sin_family = AF_INET;
2129 sin_addr.sin_port = htons((uint16_t) port);
2130 #if HAVE_SOCKADDR_IN_SIN_LEN
2131 sin_addr.sin_len = sizeof (sin_addr);
2133 if ( (NULL == port_start) ||
2134 (1 != sscanf (port_start, "%d", &port)) ||
2135 (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) )
2137 /* should we restart gnunet-nat-server? */
2138 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2140 _("gnunet-nat-server generated malformed address `%s'\n"),
2142 plugin->server_read_task
2143 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2144 plugin->server_stdout_handle,
2145 &tcp_plugin_server_read,
2151 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2153 "gnunet-nat-server read: %s:%d\n",
2158 * We have received an ICMP response, ostensibly from a peer
2159 * that wants to connect to us! Send a message to establish a connection.
2161 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
2162 (const struct sockaddr *)&sin_addr,
2166 /* failed for some odd reason (out of sockets?); ignore attempt */
2167 plugin->server_read_task =
2168 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2169 plugin->server_stdout_handle,
2170 &tcp_plugin_server_read,
2175 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2176 "Sending TCP probe message to `%s:%u'!\n",
2178 (unsigned int) port);
2179 /* FIXME: do we need to track these probe context objects so that
2180 we can clean them up on plugin unload? */
2182 = GNUNET_malloc(sizeof(struct TCPProbeContext));
2183 tcp_probe_ctx->message.header.size
2184 = htons(sizeof(struct TCP_NAT_ProbeMessage));
2185 tcp_probe_ctx->message.header.type
2186 = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
2187 memcpy (&tcp_probe_ctx->message.clientIdentity,
2188 plugin->env->my_identity,
2189 sizeof(struct GNUNET_PeerIdentity));
2190 tcp_probe_ctx->plugin = plugin;
2191 tcp_probe_ctx->sock = sock;
2192 tcp_probe_ctx->transmit_handle
2193 = GNUNET_CONNECTION_notify_transmit_ready (sock,
2194 ntohs (tcp_probe_ctx->message.header.size),
2195 GNUNET_TIME_UNIT_FOREVER_REL,
2196 ¬ify_send_probe, tcp_probe_ctx);
2198 plugin->server_read_task =
2199 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2200 plugin->server_stdout_handle,
2201 &tcp_plugin_server_read,
2207 * Start the gnunet-nat-server process for users behind NAT.
2209 * @param plugin the transport plugin
2211 * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
2214 tcp_transport_start_nat_server(struct Plugin *plugin)
2216 plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES,
2219 if (plugin->server_stdout == NULL)
2220 return GNUNET_SYSERR;
2223 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2225 "Starting gnunet-nat-server process cmd: %s %s\n", "gnunet-nat-server", plugin->internal_address);
2227 /* Start the server process */
2228 plugin->server_proc = GNUNET_OS_start_process(NULL, plugin->server_stdout, "gnunet-nat-server", "gnunet-nat-server", plugin->internal_address, NULL);
2229 if (plugin->server_proc == NULL)
2232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2233 "Failed to start gnunet-nat-server process\n");
2235 return GNUNET_SYSERR;
2237 /* Close the write end of the read pipe */
2238 GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
2240 plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
2241 plugin->server_read_task =
2242 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2243 plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
2249 * Return the actual path to a file found in the current
2250 * PATH environment variable.
2252 * @param binary the name of the file to find
2255 get_path_from_PATH (char *binary)
2263 p = getenv ("PATH");
2266 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2267 _("PATH environment variable is unset.\n"));
2270 path = GNUNET_strdup (p); /* because we write on it */
2271 buf = GNUNET_malloc (strlen (path) + 20);
2274 while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
2277 sprintf (buf, "%s/%s", pos, binary);
2278 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2285 sprintf (buf, "%s/%s", pos, binary);
2286 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2297 * Check whether the suid bit is set on a file.
2298 * Attempts to find the file using the current
2299 * PATH environment variable as a search path.
2301 * @param binary the name of the file to check
2304 check_gnunet_nat_binary(char *binary)
2306 struct stat statbuf;
2314 GNUNET_asprintf (&binaryexe, "%s.exe", binary);
2315 p = get_path_from_PATH (binaryexe);
2318 p = get_path_from_PATH (binary);
2322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2323 _("Could not find binary `%s' in PATH!\n"),
2327 if (0 != STAT (p, &statbuf))
2329 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2330 _("stat (%s) failed: %s\n"),
2334 return GNUNET_SYSERR;
2338 if ( (0 != (statbuf.st_mode & S_ISUID)) &&
2339 (statbuf.st_uid == 0) )
2343 rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
2344 if (INVALID_SOCKET == rawsock)
2346 DWORD err = GetLastError ();
2347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2348 "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) have failed! GLE = %d\n", err);
2349 return GNUNET_NO; /* not running as administrator */
2351 closesocket (rawsock);
2357 * Entry point for the plugin.
2359 * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
2360 * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
2363 libgnunet_plugin_transport_tcp_init (void *cls)
2365 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
2366 {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
2367 sizeof (struct WelcomeMessage)},
2368 {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, sizeof (struct TCP_NAT_ProbeMessage)},
2369 {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
2372 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2373 struct GNUNET_TRANSPORT_PluginFunctions *api;
2374 struct Plugin *plugin;
2375 struct GNUNET_SERVICE_Context *service;
2376 unsigned long long aport;
2377 unsigned long long bport;
2381 int only_nat_addresses;
2382 char *internal_address;
2383 char *external_address;
2384 struct sockaddr_in in_addr;
2385 struct IPv4TcpAddress t4;
2387 service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
2388 if (service == NULL)
2390 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2391 _("Failed to start service for `%s' transport plugin.\n"),
2396 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2400 /* We are behind nat (according to the user) */
2401 if (check_gnunet_nat_binary("gnunet-nat-server") == GNUNET_YES)
2403 behind_nat = GNUNET_YES;
2407 behind_nat = GNUNET_NO;
2408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Configuration specified you are behind a NAT, but gnunet-nat-server is not installed properly (suid bit not set)!\n");
2412 behind_nat = GNUNET_NO; /* We are not behind nat! */
2414 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2418 if (check_gnunet_nat_binary("gnunet-nat-client") == GNUNET_YES)
2419 allow_nat = GNUNET_YES; /* We will try to connect to NAT'd peers */
2422 allow_nat = GNUNET_NO;
2423 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Configuration specified you want to connect to NAT'd peers, but gnunet-nat-client is not installed properly (suid bit not set)!\n");
2427 allow_nat = GNUNET_NO; /* We don't want to try to help NAT'd peers */
2430 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2432 "ONLY_NAT_ADDRESSES"))
2433 only_nat_addresses = GNUNET_YES; /* We will only report our addresses as NAT'd */
2435 only_nat_addresses = GNUNET_NO; /* We will report our addresses as NAT'd and non-NAT'd */
2437 external_address = NULL;
2438 if (((GNUNET_YES == behind_nat) || (GNUNET_YES == allow_nat)) && (GNUNET_OK !=
2439 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2442 &external_address)))
2444 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2446 ("Require EXTERNAL_ADDRESS for service `%s' in configuration (either BEHIND_NAT or ALLOW_NAT set to YES)!\n"),
2448 GNUNET_SERVICE_stop (service);
2452 if ((external_address != NULL) && (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1))
2454 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Malformed EXTERNAL_ADDRESS %s given in configuration!\n", external_address);
2457 internal_address = NULL;
2458 if ((GNUNET_YES == behind_nat) && (GNUNET_OK !=
2459 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2462 &internal_address)))
2464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2465 _("Require INTERNAL_ADDRESS for service `%s' in configuration!\n"),
2467 GNUNET_SERVICE_stop (service);
2468 GNUNET_free_non_null(external_address);
2472 if ((internal_address != NULL) && (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1))
2474 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Malformed INTERNAL_ADDRESS %s given in configuration!\n", internal_address);
2479 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2485 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2488 &aport)) && (aport > 65535)))
2490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2492 ("Require valid port number for service `%s' in configuration!\n"),
2494 GNUNET_free_non_null(external_address);
2495 GNUNET_free_non_null(internal_address);
2496 GNUNET_SERVICE_stop (service);
2502 plugin = GNUNET_malloc (sizeof (struct Plugin));
2503 plugin->open_port = bport;
2504 plugin->adv_port = aport;
2505 plugin->external_address = external_address;
2506 plugin->internal_address = internal_address;
2507 plugin->behind_nat = behind_nat;
2508 plugin->allow_nat = allow_nat;
2509 plugin->only_nat_addresses = only_nat_addresses;
2511 plugin->lsock = NULL;
2512 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2514 api->send = &tcp_plugin_send;
2515 api->disconnect = &tcp_plugin_disconnect;
2516 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
2517 api->check_address = &tcp_plugin_check_address;
2518 api->address_to_string = &tcp_address_to_string;
2519 plugin->service = service;
2520 plugin->server = GNUNET_SERVICE_get_server (service);
2521 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
2522 memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
2525 sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
2527 plugin->handlers[i].callback_cls = plugin;
2528 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
2530 if (plugin->behind_nat == GNUNET_YES)
2532 if (GNUNET_YES != tcp_transport_start_nat_server(plugin))
2534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2537 ("Failed to start %s required for NAT in %s!\n"),
2540 GNUNET_free_non_null(external_address);
2541 GNUNET_free_non_null(internal_address);
2542 GNUNET_SERVICE_stop (service);
2548 if (allow_nat == GNUNET_YES)
2550 plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(100);
2551 GNUNET_assert(plugin->nat_wait_conns != NULL);
2554 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("TCP transport listening on port %llu\n"), bport);
2556 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2557 _("TCP transport advertises itself as being on port %llu\n"),
2559 GNUNET_SERVER_disconnect_notify (plugin->server,
2563 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-tcp", "BINDTO", &plugin->bind_address))
2564 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Binding tcp plugin to specific address: `%s'\n", plugin->bind_address);
2566 if (plugin->behind_nat == GNUNET_NO)
2568 GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
2571 plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->cfg,
2573 HOSTNAME_RESOLVE_TIMEOUT,
2574 &process_hostname_ips,
2577 if ((plugin->behind_nat == GNUNET_YES) && (inet_pton(AF_INET, plugin->external_address, &t4.ipv4_addr) == 1))
2579 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s:0\n", plugin->external_address);
2580 t4.t_port = htons(0);
2581 add_to_address_list (plugin, &t4.ipv4_addr, sizeof (uint32_t));
2582 plugin->env->notify_address (plugin->env->cls,
2584 &t4, sizeof(t4), GNUNET_TIME_UNIT_FOREVER_REL);
2586 else if ((plugin->external_address != NULL) && (inet_pton(AF_INET, plugin->external_address, &t4.ipv4_addr) == 1))
2588 t4.t_port = htons(plugin->adv_port);
2589 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s:%d\n", plugin->external_address, plugin->adv_port);
2590 add_to_address_list (plugin, &t4.ipv4_addr, sizeof (uint32_t));
2591 plugin->env->notify_address (plugin->env->cls,
2593 &t4, sizeof(t4), GNUNET_TIME_UNIT_FOREVER_REL);
2601 * Exit point from the plugin.
2604 libgnunet_plugin_transport_tcp_done (void *cls)
2606 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2607 struct Plugin *plugin = api->cls;
2608 struct Session *session;
2609 struct LocalAddrList *lal;
2611 while (NULL != (session = plugin->sessions))
2612 disconnect_session (session);
2613 if (NULL != plugin->hostname_dns)
2615 GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
2616 plugin->hostname_dns = NULL;
2618 GNUNET_SERVICE_stop (plugin->service);
2619 GNUNET_free (plugin->handlers);
2620 while (NULL != (lal = plugin->lal_head))
2622 GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
2628 if (plugin->behind_nat == GNUNET_YES)
2630 if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
2631 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
2632 GNUNET_OS_process_wait (plugin->server_proc);
2633 GNUNET_OS_process_close (plugin->server_proc);
2634 plugin->server_proc = NULL;
2636 GNUNET_free_non_null(plugin->bind_address);
2637 GNUNET_free (plugin);
2642 /* end of plugin_transport_tcp.c */