X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fplugin_transport_tcp.c;h=e79440e5e59a368fe41657d4650c6df59a68e08a;hb=f181f6eaf8cdb1fdb47dc98cf171ad1be842b441;hp=689cb37842c714fcc8dc3be868df6f713fa0fe0f;hpb=30ebb14c293181d8aa3c3502526388ec92d3895b;p=oweals%2Fgnunet.git diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 689cb3784..e79440e5e 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -24,6 +24,7 @@ */ #include "platform.h" #include "gnunet_hello_lib.h" +#include "gnunet_constants.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_nat_lib.h" @@ -38,15 +39,11 @@ #include "gnunet_transport_plugin.h" #include "transport.h" -#define DEBUG_TCP GNUNET_NO +#define DEBUG_TCP GNUNET_EXTRA_LOGGING -#define DEBUG_TCP_NAT GNUNET_YES - -/** - * How long until we give up on transmitting the welcome message? - */ -#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) +#define DEBUG_TCP_NAT GNUNET_EXTRA_LOGGING +GNUNET_NETWORK_STRUCT_BEGIN /** * Initial handshake message for a session. @@ -83,7 +80,7 @@ struct TCP_NAT_ProbeMessage struct GNUNET_PeerIdentity clientIdentity; }; - +GNUNET_NETWORK_STRUCT_END /** * Context for sending a NAT probe via TCP. @@ -123,6 +120,8 @@ struct TCPProbeContext }; +GNUNET_NETWORK_STRUCT_BEGIN + /** * Network format for IPv4 addresses. */ @@ -136,7 +135,7 @@ struct IPv4TcpAddress /** * Port number, in network byte order. */ - uint16_t t_port GNUNET_PACKED; + uint16_t t4_port GNUNET_PACKED; }; @@ -157,7 +156,7 @@ struct IPv6TcpAddress uint16_t t6_port GNUNET_PACKED; }; - +GNUNET_NETWORK_STRUCT_END /** * Encapsulation of all of the state of the plugin. @@ -165,52 +164,6 @@ struct IPv6TcpAddress struct Plugin; -/** - * Local network addresses (actual IP address follows this struct). - * PORT is NOT included! - */ -struct LocalAddrList -{ - - /** - * This is a doubly linked list. - */ - struct LocalAddrList *next; - - /** - * This is a doubly linked list. - */ - struct LocalAddrList *prev; - - /** - * Link to plugin. - */ - struct Plugin *plugin; - - /** - * Handle to NAT holes we've tried to punch for this address. - */ - struct GNUNET_NAT_Handle *nat; - - /** - * Pointer to a 'struct IPv4/V6TcpAddress' describing our external IP and port - * as obtained from the NAT by automatic port mapping. - */ - void *external_nat_address; - - /** - * Number of bytes in 'external_nat_address' - */ - size_t ena_size; - - /** - * Number of bytes of the address that follow - */ - size_t size; - -}; - - /** * Information kept for each message that is yet to * be transmitted. @@ -346,6 +299,10 @@ struct Session */ int is_nat; + /** + * ATS network type in NBO + */ + uint32_t ats_address_network_type; }; @@ -365,30 +322,17 @@ struct Plugin struct GNUNET_CONNECTION_Handle *lsock; /** - * stdout pipe handle for the gnunet-nat-server process - */ - struct GNUNET_DISK_PipeHandle *server_stdout; - - /** - * stdout file handle (for reading) for the gnunet-nat-server process - */ - const struct GNUNET_DISK_FileHandle *server_stdout_handle; - - /** - * ID of select gnunet-nat-server stdout read task + * Our handle to the NAT module. */ - GNUNET_SCHEDULER_TaskIdentifier server_read_task; - - /** - * The process id of the server process (if behind NAT) - */ - struct GNUNET_OS_Process *server_proc; + struct GNUNET_NAT_Handle *nat; /** * List of open TCP sessions. */ struct Session *sessions; + struct GNUNET_CONTAINER_MultiHashMap * sessionmap; + /** * Handle to the network service. */ @@ -405,49 +349,11 @@ struct Plugin */ struct GNUNET_SERVER_MessageHandler *handlers; - /** - * Handle for request of hostname resolution, non-NULL if pending. - */ - struct GNUNET_RESOLVER_RequestHandle *hostname_dns; - /** * Map of peers we have tried to contact behind a NAT */ struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; - /** - * The external address given to us by the user. Used for HELLOs - * and address validation. - */ - char *external_address; - - /** - * The internal address given to us by the user (or discovered). - * Used for NAT traversal (ICMP method), but not as a 'validateable' - * address in HELLOs. - */ - char *internal_address; - - /** - * Address given for us to bind to (ONLY). - */ - char *bind_address; - - /** - * use local addresses? - */ - int use_localaddresses; - - /** - * List of our IP addresses. - */ - struct LocalAddrList *lal_head; - - /** - * Tail of our IP address list. - */ - struct LocalAddrList *lal_tail; - /** * List of active TCP probes. */ @@ -463,6 +369,11 @@ struct Plugin */ struct GNUNET_RESOLVER_RequestHandle *ext_dns; + /** + * How many more TCP sessions are we allowed to open right now? + */ + unsigned long long max_connections; + /** * ID of task used to update our addresses when one expires. */ @@ -479,32 +390,33 @@ struct Plugin */ uint16_t adv_port; - /** - * Is this transport configured to be behind a NAT? - */ - int behind_nat; - - /** - * Has the NAT been punched? - */ - int nat_punched; - - /** - * Is this transport configured to allow connections to NAT'd peers? - */ - int enable_nat_client; +}; - /** - * Should we run the gnunet-nat-server? - */ - int enable_nat_server; - /** - * Are we allowed to try UPnP/PMP for NAT traversal? - */ - int enable_upnp; +/** + * Function to check if an inbound connection is acceptable. + * Mostly used to limit the total number of open connections + * we can have. + * + * @param cls the 'struct Plugin' + * @param ucred credentials, if available, otherwise NULL + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). + */ +static int +plugin_tcp_access_check (void *cls, + const struct GNUNET_CONNECTION_Credentials *ucred, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct Plugin *plugin = cls; -}; + if (0 == plugin->max_connections) + return GNUNET_NO; + plugin->max_connections--; + return GNUNET_YES; +} /** @@ -517,188 +429,42 @@ struct Plugin * @param addrlen actual lenght of the address */ static void -nat_port_map_callback (void *cls, - int add_remove, - const struct sockaddr *addr, - socklen_t addrlen) +tcp_nat_port_map_callback (void *cls, int add_remove, + const struct sockaddr *addr, socklen_t addrlen) { - struct LocalAddrList *lal = cls; - struct Plugin *plugin = lal->plugin; - int af; + struct Plugin *plugin = cls; struct IPv4TcpAddress t4; struct IPv6TcpAddress t6; void *arg; - uint16_t args; + size_t args; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "NPMC called with %d for address `%s'\n", add_remove, + GNUNET_a2s (addr, addrlen)); /* convert 'addr' to our internal format */ - af = addr->sa_family; - switch (af) - { - case AF_INET: - t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - t4.t_port = ((struct sockaddr_in *) addr)->sin_port; - arg = &t4; - args = sizeof (t4); - break; - case AF_INET6: - memcpy (&t6.ipv6_addr, - &((struct sockaddr_in6 *) addr)->sin6_addr, - sizeof (struct in6_addr)); - t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port; - arg = &t6; - args = sizeof (t6); - break; - default: - GNUNET_break (0); - return; - } - + switch (addr->sa_family) + { + case AF_INET: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); + t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + t4.t4_port = ((struct sockaddr_in *) addr)->sin_port; + arg = &t4; + args = sizeof (t4); + break; + case AF_INET6: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); + memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port; + arg = &t6; + args = sizeof (t6); + break; + default: + GNUNET_break (0); + return; + } /* modify our published address list */ - if (GNUNET_YES == add_remove) - { - plugin->env->notify_address (plugin->env->cls, - "tcp", - arg, args, GNUNET_TIME_UNIT_FOREVER_REL); - GNUNET_free_non_null (lal->external_nat_address); - lal->external_nat_address = GNUNET_memdup (arg, args); - lal->ena_size = args; - } - else - { - plugin->env->notify_address (plugin->env->cls, - "tcp", - arg, args, GNUNET_TIME_UNIT_ZERO); - GNUNET_free_non_null (lal->external_nat_address); - lal->ena_size = 0; - } -} - - -/** - * Add the given address to the list of 'local' addresses, thereby - * making it a 'legal' address for this peer to have. - * - * @param plugin the plugin - * @param arg the address, either an IPv4 or an IPv6 IP address - * @param arg_size number of bytes in arg - */ -static void -add_to_address_list (struct Plugin *plugin, - const void *arg, - size_t arg_size) -{ - struct LocalAddrList *lal; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - const struct sockaddr *sa; - socklen_t salen; - - lal = plugin->lal_head; - while (NULL != lal) - { - if ( (lal->size == arg_size) && - (0 == memcmp (&lal[1], arg, arg_size)) ) - return; - lal = lal->next; - } - lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size); - lal->plugin = plugin; - lal->size = arg_size; - memcpy (&lal[1], arg, arg_size); - GNUNET_CONTAINER_DLL_insert (plugin->lal_head, - plugin->lal_tail, - lal); - if (plugin->open_port == 0) - return; /* we're not listening at all... */ - if (arg_size == sizeof (struct in_addr)) - { - memset (&v4, 0, sizeof (v4)); - v4.sin_family = AF_INET; - v4.sin_port = htons (plugin->open_port); - memcpy (&v4.sin_addr, arg, arg_size); -#if HAVE_SOCKADDR_IN_SIN_LEN - v4.sin_len = sizeof (struct sockaddr_in); -#endif - sa = (const struct sockaddr*) &v4; - salen = sizeof (v4); - } - else if (arg_size == sizeof (struct in6_addr)) - { - memset (&v6, 0, sizeof (v6)); - v6.sin6_family = AF_INET6; - v6.sin6_port = htons (plugin->open_port); - memcpy (&v6.sin6_addr, arg, arg_size); -#if HAVE_SOCKADDR_IN_SIN_LEN - v6.sin6_len = sizeof (struct sockaddr_in6); -#endif - sa = (const struct sockaddr*) &v6; - salen = sizeof (v6); - } - else - { - GNUNET_break (0); - return; - } - if ( (plugin->behind_nat == GNUNET_YES) && - (plugin->enable_upnp == GNUNET_YES) ) - lal->nat = GNUNET_NAT_register (plugin->env->cfg, - sa, salen, - &nat_port_map_callback, - lal); -} - - -/** - * Check if the given address is in the list of 'local' addresses. - * - * @param plugin the plugin - * @param arg the address, either an IPv4 or an IPv6 IP address - * @param arg_size number of bytes in arg - * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not - */ -static int -check_local_addr (struct Plugin *plugin, - const void *arg, - size_t arg_size) -{ - struct LocalAddrList *lal; - - lal = plugin->lal_head; - while (NULL != lal) - { - if ( (lal->size == arg_size) && - (0 == memcmp (&lal[1], arg, arg_size)) ) - return GNUNET_OK; - lal = lal->next; - } - return GNUNET_SYSERR; -} - - -/** - * Check if the given address is in the list of 'mapped' addresses. - * - * @param plugin the plugin - * @param arg the address, either a 'struct IPv4TcpAddress' or a 'struct IPv6TcpAddress' - * @param arg_size number of bytes in arg - * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not - */ -static int -check_mapped_addr (struct Plugin *plugin, - const void *arg, - size_t arg_size) -{ - struct LocalAddrList *lal; - - lal = plugin->lal_head; - while (NULL != lal) - { - if ( (lal->ena_size == arg_size) && - (0 == memcmp (lal->external_nat_address, arg, arg_size)) ) - return GNUNET_OK; - lal = lal->next; - } - return GNUNET_SYSERR; + plugin->env->notify_address (plugin->env->cls, add_remove, arg, args); } @@ -713,10 +479,8 @@ check_mapped_addr (struct Plugin *plugin, * @param addrlen length of the address * @return string representing the same address */ -static const char* -tcp_address_to_string (void *cls, - const void *addr, - size_t addrlen) +static const char * +tcp_address_to_string (void *cls, const void *addr, size_t addrlen) { static char rbuf[INET6_ADDRSTRLEN + 12]; char buf[INET6_ADDRSTRLEN]; @@ -729,40 +493,36 @@ tcp_address_to_string (void *cls, uint16_t port; if (addrlen == sizeof (struct IPv6TcpAddress)) - { - t6 = addr; - af = AF_INET6; - port = ntohs (t6->t6_port); - memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); - sb = &a6; - } + { + t6 = addr; + af = AF_INET6; + port = ntohs (t6->t6_port); + memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); + sb = &a6; + } else if (addrlen == sizeof (struct IPv4TcpAddress)) - { - t4 = addr; - af = AF_INET; - port = ntohs (t4->t_port); - memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); - sb = &a4; - } + { + t4 = addr; + af = AF_INET; + port = ntohs (t4->t4_port); + memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); + sb = &a4; + } else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Unexpected address length: %u bytes\n"), - (unsigned int) addrlen); - GNUNET_break (0); - return NULL; - } + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Unexpected address length: %u bytes\n"), + (unsigned int) addrlen); + GNUNET_break (0); + return NULL; + } if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); - return NULL; - } - GNUNET_snprintf (rbuf, - sizeof (rbuf), - (af == AF_INET6) ? "[%s]:%u" : "%s:%u", - buf, - port); + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); + return NULL; + } + GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u", + buf, port); return rbuf; } @@ -799,10 +559,8 @@ find_session_by_client (struct Plugin *plugin, * @return new session object */ static struct Session * -create_session (struct Plugin *plugin, - const struct GNUNET_PeerIdentity *target, - struct GNUNET_SERVER_Client *client, - int is_nat) +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + struct GNUNET_SERVER_Client *client, int is_nat) { struct Session *ret; struct PendingMessage *pm; @@ -813,25 +571,26 @@ create_session (struct Plugin *plugin, else GNUNET_assert (client == NULL); #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Creating new session for peer `%4s'\n", - GNUNET_i2s (target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Creating new session for peer `%4s'\n", + GNUNET_i2s (target)); #endif ret = GNUNET_malloc (sizeof (struct Session)); ret->last_activity = GNUNET_TIME_absolute_get (); ret->plugin = plugin; ret->is_nat = is_nat; - if (is_nat != GNUNET_YES) /* If not a NAT WAIT conn, add it to global list */ - { - ret->next = plugin->sessions; - plugin->sessions = ret; - } + if (is_nat != GNUNET_YES) /* If not a NAT WAIT conn, add it to global list */ + { + ret->next = plugin->sessions; + plugin->sessions = ret; + } ret->client = client; ret->target = *target; ret->expecting_welcome = GNUNET_YES; - pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct WelcomeMessage)); - pm->msg = (const char*) &pm[1]; + ret->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + pm = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct WelcomeMessage)); + pm->msg = (const char *) &pm[1]; pm->message_size = sizeof (struct WelcomeMessage); welcome.header.size = htons (sizeof (struct WelcomeMessage)); welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME); @@ -839,16 +598,13 @@ create_session (struct Plugin *plugin, memcpy (&pm[1], &welcome, sizeof (welcome)); pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - pm->message_size, - GNUNET_NO); + gettext_noop ("# bytes currently in TCP buffers"), + pm->message_size, GNUNET_NO); GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, - ret->pending_messages_tail, - pm); + ret->pending_messages_tail, pm); if (is_nat != GNUNET_YES) GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP sessions active"), - 1, + gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); return ret; } @@ -860,7 +616,8 @@ create_session (struct Plugin *plugin, * * @param session for which session should we do this */ -static void process_pending_messages (struct Session *session); +static void +process_pending_messages (struct Session *session); /** @@ -887,114 +644,106 @@ do_transmit (void *cls, size_t size, void *buf) char *cbuf; size_t ret; + GNUNET_assert (session != NULL); session->transmit_handle = NULL; plugin = session->plugin; if (buf == NULL) - { + { #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Timeout trying to transmit to peer `%4s', discarding message queue.\n", - GNUNET_i2s (&session->target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Timeout trying to transmit to peer `%4s', discarding message queue.\n", + GNUNET_i2s (&session->target)); #endif - /* timeout; cancel all messages that have already expired */ - hd = NULL; - tl = NULL; - ret = 0; - now = GNUNET_TIME_absolute_get (); - while ( (NULL != (pos = session->pending_messages_head)) && - (pos->timeout.abs_value <= now.abs_value) ) - { - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pos); + /* timeout; cancel all messages that have already expired */ + hd = NULL; + tl = NULL; + ret = 0; + now = GNUNET_TIME_absolute_get (); + while ((NULL != (pos = session->pending_messages_head)) && + (pos->timeout.abs_value <= now.abs_value)) + { + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pos); #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Failed to transmit %u byte message to `%4s'.\n", - pos->message_size, - GNUNET_i2s (&session->target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Failed to transmit %u byte message to `%4s'.\n", + pos->message_size, GNUNET_i2s (&session->target)); #endif - ret += pos->message_size; - GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); - } - /* do this call before callbacks (so that if callbacks destroy - session, they have a chance to cancel actions done by this - call) */ - process_pending_messages (session); - pid = session->target; - /* no do callbacks and do not use session again since - the callbacks may abort the session */ - while (NULL != (pos = hd)) - { - GNUNET_CONTAINER_DLL_remove (hd, tl, pos); - if (pos->transmit_cont != NULL) - pos->transmit_cont (pos->transmit_cont_cls, - &pid, GNUNET_SYSERR); - GNUNET_free (pos); - } - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - - (int64_t) ret, - GNUNET_NO); - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (timeout)"), - ret, - GNUNET_NO); - return 0; + ret += pos->message_size; + GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); + } + /* do this call before callbacks (so that if callbacks destroy + * session, they have a chance to cancel actions done by this + * call) */ + process_pending_messages (session); + pid = session->target; + /* no do callbacks and do not use session again since + * the callbacks may abort the session */ + while (NULL != (pos = hd)) + { + GNUNET_CONTAINER_DLL_remove (hd, tl, pos); + if (pos->transmit_cont != NULL) + pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_SYSERR); + GNUNET_free (pos); } + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) ret, GNUNET_NO); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (timeout)"), ret, + GNUNET_NO); + return 0; + } /* copy all pending messages that would fit */ ret = 0; cbuf = buf; hd = NULL; tl = NULL; while (NULL != (pos = session->pending_messages_head)) - { - if (ret + pos->message_size > size) - break; - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pos); - GNUNET_assert (size >= pos->message_size); - /* FIXME: this memcpy can be up to 7% of our total runtime */ - memcpy (cbuf, pos->msg, pos->message_size); - cbuf += pos->message_size; - ret += pos->message_size; - size -= pos->message_size; - GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); - } + { + if (ret + pos->message_size > size) + break; + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pos); + GNUNET_assert (size >= pos->message_size); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Transmitting message of type %u\n", + ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type)); + /* FIXME: this memcpy can be up to 7% of our total runtime */ + memcpy (cbuf, pos->msg, pos->message_size); + cbuf += pos->message_size; + ret += pos->message_size; + size -= pos->message_size; + GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos); + } /* schedule 'continuation' before callbacks so that callbacks that - cancel everything don't cause us to use a session that no longer - exists... */ + * cancel everything don't cause us to use a session that no longer + * exists... */ process_pending_messages (session); session->last_activity = GNUNET_TIME_absolute_get (); pid = session->target; /* we'll now call callbacks that may cancel the session; hence - we should not use 'session' after this point */ + * we should not use 'session' after this point */ while (NULL != (pos = hd)) - { - GNUNET_CONTAINER_DLL_remove (hd, tl, pos); - if (pos->transmit_cont != NULL) - pos->transmit_cont (pos->transmit_cont_cls, - &pid, GNUNET_OK); - GNUNET_free (pos); - } + { + GNUNET_CONTAINER_DLL_remove (hd, tl, pos); + if (pos->transmit_cont != NULL) + pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_OK); + GNUNET_free (pos); + } GNUNET_assert (hd == NULL); GNUNET_assert (tl == NULL); #if DEBUG_TCP > 1 - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Transmitting %u bytes\n", - ret); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Transmitting %u bytes\n", + ret); #endif GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - - (int64_t) ret, - GNUNET_NO); + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) ret, GNUNET_NO); GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes transmitted via TCP"), - ret, - GNUNET_NO); + gettext_noop ("# bytes transmitted via TCP"), ret, + GNUNET_NO); return ret; } @@ -1016,12 +765,11 @@ process_pending_messages (struct Session *session) if (NULL == (pm = session->pending_messages_head)) return; - session->transmit_handle - = GNUNET_SERVER_notify_transmit_ready (session->client, - pm->message_size, + session->transmit_handle = + GNUNET_SERVER_notify_transmit_ready (session->client, pm->message_size, GNUNET_TIME_absolute_get_remaining - (pm->timeout), - &do_transmit, session); + (pm->timeout), &do_transmit, + session); } @@ -1040,23 +788,23 @@ disconnect_session (struct Session *session) struct PendingMessage *pm; #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Disconnecting from `%4s' at %s.\n", GNUNET_i2s (&session->target), - (session->connect_addr != NULL) ? - tcp_address_to_string (session->plugin, - session->connect_addr, - session->connect_alen) : "*"); + (session->connect_addr != + NULL) ? tcp_address_to_string (session->plugin, + session->connect_addr, + session->connect_alen) : + "*"); #endif /* remove from session list */ prev = NULL; pos = session->plugin->sessions; while (pos != session) - { - prev = pos; - pos = pos->next; - } + { + prev = pos; + pos = pos->next; + } if (prev == NULL) session->plugin->sessions = session->next; else @@ -1064,57 +812,52 @@ disconnect_session (struct Session *session) /* clean up state */ if (session->transmit_handle != NULL) - { - GNUNET_CONNECTION_notify_transmit_ready_cancel - (session->transmit_handle); - session->transmit_handle = NULL; - } + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (session->transmit_handle); + session->transmit_handle = NULL; + } + session->plugin->env->session_end (session->plugin->env->cls, + &session->target, session); while (NULL != (pm = session->pending_messages_head)) - { + { #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - pm->transmit_cont != NULL - ? "Could not deliver message to `%4s'.\n" - : "Could not deliver message to `%4s', notifying.\n", - GNUNET_i2s (&session->target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + pm->transmit_cont != + NULL ? "Could not deliver message to `%4s'.\n" : + "Could not deliver message to `%4s', notifying.\n", + GNUNET_i2s (&session->target)); #endif - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - - (int64_t) pm->message_size, - GNUNET_NO); - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (disconnect)"), - pm->message_size, - GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, - session->pending_messages_tail, - pm); - if (NULL != pm->transmit_cont) - pm->transmit_cont (pm->transmit_cont_cls, - &session->target, GNUNET_SYSERR); - GNUNET_free (pm); - } + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) pm->message_size, GNUNET_NO); + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (disconnect)"), + pm->message_size, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pm); + if (NULL != pm->transmit_cont) + pm->transmit_cont (pm->transmit_cont_cls, &session->target, + GNUNET_SYSERR); + GNUNET_free (pm); + } GNUNET_break (session->client != NULL); if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (session->receive_delay_task); - if (session->client != NULL) - GNUNET_SERVER_receive_done (session->client, - GNUNET_SYSERR); - } - else if (session->client != NULL) + { + GNUNET_SCHEDULER_cancel (session->receive_delay_task); + if (session->client != NULL) + GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); + } + if (session->client != NULL) + { GNUNET_SERVER_client_drop (session->client); + session->client = NULL; + } GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# TCP sessions active"), - -1, - GNUNET_NO); + gettext_noop ("# TCP sessions active"), -1, + GNUNET_NO); GNUNET_free_non_null (session->connect_addr); - - session->plugin->env->session_end (session->plugin->env->cls, - &session->target, - session); - + GNUNET_assert (NULL == session->transmit_handle); GNUNET_free (session); } @@ -1127,99 +870,38 @@ disconnect_session (struct Session *session) * @return "better" session (more active) */ static struct Session * -select_better_session (struct Session *s1, - struct Session *s2) +select_better_session (struct Session *s1, struct Session *s2) { if (s1 == NULL) return s2; if (s2 == NULL) return s1; - if ( (s1->expecting_welcome == GNUNET_NO) && - (s2->expecting_welcome == GNUNET_YES) ) + if ((s1->expecting_welcome == GNUNET_NO) && + (s2->expecting_welcome == GNUNET_YES)) return s1; - if ( (s1->expecting_welcome == GNUNET_YES) && - (s2->expecting_welcome == GNUNET_NO) ) + if ((s1->expecting_welcome == GNUNET_YES) && + (s2->expecting_welcome == GNUNET_NO)) return s2; if (s1->last_activity.abs_value < s2->last_activity.abs_value) return s2; if (s1->last_activity.abs_value > s2->last_activity.abs_value) return s1; - if ( (GNUNET_YES == s1->inbound) && - (GNUNET_NO == s2->inbound) ) + if ((GNUNET_YES == s1->inbound) && (GNUNET_NO == s2->inbound)) return s1; - if ( (GNUNET_NO == s1->inbound) && - (GNUNET_YES == s2->inbound) ) + if ((GNUNET_NO == s1->inbound) && (GNUNET_YES == s2->inbound)) return s2; return s1; } + /** - * We learned about a peer (possibly behind NAT) so run the - * gnunet-nat-client to send dummy ICMP responses. - * - * @param plugin the plugin for this transport - * @param sa the address of the peer (IPv4-only) - */ -static void -run_gnunet_nat_client (struct Plugin *plugin, - const struct sockaddr_in *sa) -{ - char inet4[INET_ADDRSTRLEN]; - char port_as_string[6]; - struct GNUNET_OS_Process *proc; - - if (plugin->internal_address == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("Internal IP address not known, cannot use ICMP NAT traversal method\n")); - return; - } - GNUNET_assert (sa->sin_family == AF_INET); - if (NULL == inet_ntop (AF_INET, - &sa->sin_addr, - inet4, INET_ADDRSTRLEN)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); - return; - } - GNUNET_snprintf(port_as_string, - sizeof (port_as_string), - "%d", - plugin->adv_port); -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - _("Running gnunet-nat-client %s %s %u\n"), - plugin->internal_address, - inet4, - (unsigned int) plugin->adv_port); -#endif - proc = GNUNET_OS_start_process (NULL, - NULL, - "gnunet-nat-client", - "gnunet-nat-client", - plugin->internal_address, - inet4, - port_as_string, - NULL); - if (NULL == proc) - return; - /* we know that the gnunet-nat-client will terminate virtually - instantly */ - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_close (proc); -} - - -/** - * Function that can be used by the transport service to transmit - * a message using the plugin. Note that in the case of a - * peer disconnecting, the continuation MUST be called - * prior to the disconnect notification itself. This function - * will be called with this peer's HELLO message to initiate - * a fresh connection to another peer. + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. * * @param cls closure * @param target who should receive this message @@ -1250,16 +932,10 @@ run_gnunet_nat_client (struct Plugin *plugin, * and does NOT mean that the message was not transmitted (DV and NAT) */ static ssize_t -tcp_plugin_send (void *cls, - const struct GNUNET_PeerIdentity *target, - const char *msg, - size_t msgbuf_size, - uint32_t priority, - struct GNUNET_TIME_Relative timeout, - struct Session *session, - const void *addr, - size_t addrlen, - int force_address, +tcp_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, + const char *msg, size_t msgbuf_size, uint32_t priority, + struct GNUNET_TIME_Relative timeout, struct Session *session, + const void *addr, size_t addrlen, int force_address, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; @@ -1277,216 +953,309 @@ tcp_plugin_send (void *cls, unsigned int is_natd; GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes TCP was asked to transmit"), - msgbuf_size, - GNUNET_NO); + gettext_noop ("# bytes TCP was asked to transmit"), + msgbuf_size, GNUNET_NO); /* FIXME: we could do this cheaper with a hash table - where we could restrict the iteration to entries that match - the target peer... */ + * where we could restrict the iteration to entries that match + * the target peer... */ is_natd = GNUNET_NO; if (session == NULL) + { + cand_session = NULL; + next = plugin->sessions; + while (NULL != (session = next)) { - cand_session = NULL; - next = plugin->sessions; - while (NULL != (session = next)) - { - next = session->next; - GNUNET_assert (session->client != NULL); - if (0 != memcmp (target, - &session->target, - sizeof (struct GNUNET_PeerIdentity))) - continue; - if ( ( (GNUNET_SYSERR == force_address) && - (session->expecting_welcome == GNUNET_NO) ) || - (GNUNET_NO == force_address) ) - { - cand_session = select_better_session (cand_session, - session); - continue; - } - if (GNUNET_SYSERR == force_address) - continue; - GNUNET_break (GNUNET_YES == force_address); - if (addr == NULL) - { - GNUNET_break (0); - break; - } - if ( (addrlen != session->connect_alen) && - (session->is_nat == GNUNET_NO) ) - continue; - if ((0 != memcmp (session->connect_addr, - addr, - addrlen)) && (session->is_nat == GNUNET_NO)) - continue; - cand_session = select_better_session (cand_session, - session); - } - session = cand_session; - } - if ( (session == NULL) && - (addr == NULL) ) - { + next = session->next; + GNUNET_assert (session->client != NULL); + if (0 != + memcmp (target, &session->target, + sizeof (struct GNUNET_PeerIdentity))) + continue; + if (((GNUNET_SYSERR == force_address) && + (session->expecting_welcome == GNUNET_NO)) || + (GNUNET_NO == force_address)) + { + cand_session = select_better_session (cand_session, session); + continue; + } + if (GNUNET_SYSERR == force_address) + continue; + GNUNET_break (GNUNET_YES == force_address); + if (addr == NULL) + { + GNUNET_break (0); + break; + } + if ((addrlen != session->connect_alen) && (session->is_nat == GNUNET_NO)) + continue; + if ((0 != memcmp (session->connect_addr, addr, addrlen)) && + (session->is_nat == GNUNET_NO)) + continue; + cand_session = select_better_session (cand_session, session); + } + session = cand_session; + } + if ((session == NULL) && (addrlen == 0)) + { #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n", - GNUNET_i2s (target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n", + GNUNET_i2s (target)); #endif - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (no address and no connection)"), - msgbuf_size, - GNUNET_NO); - return -1; - } + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (no address and no connection)"), + msgbuf_size, GNUNET_NO); + return -1; + } if (session == NULL) + { + if (addrlen == sizeof (struct IPv6TcpAddress)) { - if (addrlen == sizeof (struct IPv6TcpAddress)) - { - t6 = addr; - af = AF_INET6; - memset (&a6, 0, sizeof (a6)); + GNUNET_assert (NULL != addr); /* make static analysis happy */ + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); #if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = sizeof (a6); + a6.sin6_len = sizeof (a6); #endif - a6.sin6_family = AF_INET6; - a6.sin6_port = t6->t6_port; - if (t6->t6_port == 0) - is_natd = GNUNET_YES; - memcpy (&a6.sin6_addr, - &t6->ipv6_addr, - sizeof (struct in6_addr)); - sb = &a6; - sbs = sizeof (a6); - } - else if (addrlen == sizeof (struct IPv4TcpAddress)) - { - t4 = addr; - af = AF_INET; - memset (&a4, 0, sizeof (a4)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + if (t6->t6_port == 0) + is_natd = GNUNET_YES; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + GNUNET_assert (NULL != addr); /* make static analysis happy */ + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); #if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = sizeof (a4); + a4.sin_len = sizeof (a4); #endif - a4.sin_family = AF_INET; - a4.sin_port = t4->t_port; - if (t4->t_port == 0) - is_natd = GNUNET_YES; - a4.sin_addr.s_addr = t4->ipv4_addr; - sb = &a4; - sbs = sizeof (a4); - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Address of unexpected length: %u\n"), - addrlen); - GNUNET_break (0); - return -1; - } - - if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) - return -1; /* NAT client only works with IPv4 addresses */ - - - if ( (plugin->enable_nat_client == GNUNET_YES) && - (is_natd == GNUNET_YES) && - (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, - &target->hashPubKey)) ) - { + a4.sin_family = AF_INET; + a4.sin_port = t4->t4_port; + if (t4->t4_port == 0) + is_natd = GNUNET_YES; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + sbs = sizeof (a4); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Address of unexpected length: %u\n"), addrlen); + GNUNET_break (0); + return -1; + } + + if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) + return -1; /* NAT client only works with IPv4 addresses */ + if (0 == plugin->max_connections) + return -1; /* saturated */ + + if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && + (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &target->hashPubKey))) + { #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - _("Found valid IPv4 NAT address (creating session)!\n")); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + _("Found valid IPv4 NAT address (creating session)!\n")); #endif - session = create_session (plugin, - target, - NULL, - GNUNET_YES); - - /* create new message entry */ - pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); - /* FIXME: the memset of this malloc can be up to 2% of our total runtime */ - pm->msg = (const char*) &pm[1]; - memcpy (&pm[1], msg, msgbuf_size); - /* FIXME: this memcpy can be up to 7% of our total run-time - (for transport service) */ - pm->message_size = msgbuf_size; - pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); - pm->transmit_cont = cont; - pm->transmit_cont_cls = cont_cls; - - /* append pm to pending_messages list */ - GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head, - session->pending_messages_tail, - session->pending_messages_tail, - pm); - - GNUNET_assert(GNUNET_CONTAINER_multihashmap_put(plugin->nat_wait_conns, - &target->hashPubKey, - session, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); + session = create_session (plugin, target, NULL, GNUNET_YES); + GNUNET_assert (session != NULL); + + /* create new message entry */ + pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); + /* FIXME: the memset of this malloc can be up to 2% of our total runtime */ + pm->msg = (const char *) &pm[1]; + memcpy (&pm[1], msg, msgbuf_size); + /* FIXME: this memcpy can be up to 7% of our total run-time + * (for transport service) */ + pm->message_size = msgbuf_size; + pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); + pm->transmit_cont = cont; + pm->transmit_cont_cls = cont_cls; + + /* append pm to pending_messages list */ + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); + + GNUNET_assert (GNUNET_CONTAINER_multihashmap_put + (plugin->nat_wait_conns, &target->hashPubKey, session, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == + GNUNET_OK); #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Created NAT WAIT connection to `%4s' at `%s'\n", - GNUNET_i2s (target), - GNUNET_a2s (sb, sbs)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Created NAT WAIT connection to `%4s' at `%s'\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); #endif - run_gnunet_nat_client (plugin, &a4); - return 0; - } - if ( (plugin->enable_nat_client == GNUNET_YES) && - (is_natd == GNUNET_YES) && - (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, - &target->hashPubKey)) ) - { - /* Only do one NAT punch attempt per peer identity */ - return -1; - } - sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); - if (sa == NULL) - { + GNUNET_NAT_run_client (plugin->nat, &a4); + return 0; + } + if ((is_natd == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &target->hashPubKey))) + { + /* Only do one NAT punch attempt per peer identity */ + return -1; + } + sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); + if (sa == NULL) + { #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Failed to create connection to `%4s' at `%s'\n", - GNUNET_i2s (target), - GNUNET_a2s (sb, sbs)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Failed to create connection to `%4s' at `%s'\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); #endif - GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes discarded by TCP (failed to connect)"), - msgbuf_size, - GNUNET_NO); - return -1; - } + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (failed to connect)"), + msgbuf_size, GNUNET_NO); + return -1; + } + GNUNET_assert (0 != plugin->max_connections); + plugin->max_connections--; #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", - GNUNET_i2s (target), - GNUNET_a2s (sb, sbs)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); #endif - session = create_session (plugin, - target, - GNUNET_SERVER_connect_socket (plugin->server, - sa), - GNUNET_NO); - session->connect_addr = GNUNET_malloc (addrlen); - memcpy (session->connect_addr, - addr, - addrlen); - session->connect_alen = addrlen; + session = + create_session (plugin, target, + GNUNET_SERVER_connect_socket (plugin->server, sa), + GNUNET_NO); + session->connect_addr = GNUNET_malloc (addrlen); + memcpy (session->connect_addr, addr, addrlen); + session->connect_alen = addrlen; + if (addrlen != 0) + { + struct GNUNET_ATS_Information ats; + ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs); + session->ats_address_network_type = ats.value; + } + else + GNUNET_break (0); + } + else /* session != NULL */ + { + /* check if session is valid */ + struct Session *ses = plugin->sessions; + + if (0 != + memcmp (target, &session->target, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Got session %p for `%s', but should be for peer `%s'!\n", + session, GNUNET_i2s (&session->target), + GNUNET_h2s (&target->hashPubKey)); + return -1; + } + + while ((ses != NULL) && (ses != session)) + ses = ses->next; + if (ses == NULL) + { + return -1; } + } + GNUNET_assert (session != NULL); + GNUNET_assert (session->client != NULL); + GNUNET_SERVER_client_set_timeout (session->client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + msgbuf_size, GNUNET_NO); + /* create new message entry */ + pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); + pm->msg = (const char *) &pm[1]; + memcpy (&pm[1], msg, msgbuf_size); + pm->message_size = msgbuf_size; + pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); + pm->transmit_cont = cont; + pm->transmit_cont_cls = cont_cls; + + /* append pm to pending_messages list */ + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit %u bytes to `%s', added message to list.\n", + msgbuf_size, GNUNET_i2s (target)); +#endif + process_pending_messages (session); + return msgbuf_size; +} + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param target who should receive this message + * @param msg the message to transmit + * @param msgbuf_size number of bytes in 'msg' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param timeout how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param session which session must be used (or NULL for "any") + * @param addr the address to use (can be NULL if the plugin + * is "on its own" (i.e. re-use existing TCP connection)) + * @param addrlen length of the address in bytes + * @param force_address GNUNET_YES if the plugin MUST use the given address, + * GNUNET_NO means the plugin may use any other address and + * GNUNET_SYSERR means that only reliable existing + * bi-directional connections should be used (regardless + * of address) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV and NAT) + */ +static ssize_t +tcp_plugin_send_new (void *cls, + const struct + GNUNET_PeerIdentity * + target, + const char *msg, + size_t msgbuf_size, + uint32_t priority, + struct GNUNET_TIME_Relative timeout, + struct Session * session, + GNUNET_TRANSPORT_TransmitContinuation + cont, void *cont_cls) +{ + struct Plugin * plugin = cls; + struct PendingMessage *pm; + GNUNET_assert (session != NULL); GNUNET_assert (session->client != NULL); + + GNUNET_SERVER_client_set_timeout (session->client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes currently in TCP buffers"), - msgbuf_size, - GNUNET_NO); + gettext_noop ("# bytes currently in TCP buffers"), + msgbuf_size, GNUNET_NO); /* create new message entry */ pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); - pm->msg = (const char*) &pm[1]; + pm->msg = (const char *) &pm[1]; memcpy (&pm[1], msg, msgbuf_size); pm->message_size = msgbuf_size; pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); @@ -1494,21 +1263,203 @@ tcp_plugin_send (void *cls, pm->transmit_cont_cls = cont_cls; /* append pm to pending_messages list */ - GNUNET_CONTAINER_DLL_insert_after (session->pending_messages_head, - session->pending_messages_tail, - session->pending_messages_tail, - pm); + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Asked to transmit %u bytes to `%s', added message to list.\n", - msgbuf_size, - GNUNET_i2s (target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit %u bytes to `%s', added message to list.\n", + msgbuf_size, GNUNET_i2s (target)); #endif process_pending_messages (session); return msgbuf_size; } +struct SessionItCtx +{ + void * addr; + size_t addrlen; + struct Session * result; +}; + +int session_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct SessionItCtx * si_ctx = cls; + struct Session * session = value; + + if (session->connect_alen != si_ctx->addrlen) + return GNUNET_YES; + if (0 != memcmp (&session->connect_addr, si_ctx->addr, si_ctx->addrlen)) + return GNUNET_YES; + + /* Found existing session */ + si_ctx->result = session; + return GNUNET_NO; +} + + +/** + * Create a new session to transmit data to the target + * This session will used to send data to this peer and the plugin will + * notify us by calling the env->session_end function + * + * @param cls closure + * @param target the neighbour id + * @param addr pointer to the address + * @param addrlen length of addr + * @return the session if the address is valid, NULL otherwise + */ +const void * tcp_plugin_create_session (void *cls, + const struct GNUNET_PeerIdentity *target, + const void *addr, + size_t addrlen) +{ + struct Plugin * plugin = cls; + struct Session * session = NULL; + + int af; + const void *sb; + size_t sbs; + struct GNUNET_CONNECTION_Handle *sa; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + unsigned int is_natd; + + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + GNUNET_assert (NULL != addr); /* make static analysis happy */ + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); +#if HAVE_SOCKADDR_IN_SIN_LEN + a6.sin6_len = sizeof (a6); +#endif + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + if (t6->t6_port == 0) + is_natd = GNUNET_YES; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + GNUNET_assert (NULL != addr); /* make static analysis happy */ + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = sizeof (a4); +#endif + a4.sin_family = AF_INET; + a4.sin_port = t4->t4_port; + if (t4->t4_port == 0) + is_natd = GNUNET_YES; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + sbs = sizeof (a4); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Address of unexpected length: %u\n"), addrlen); + GNUNET_break (0); + return NULL; + } + + /* look for existing session */ + if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &target->hashPubKey)) + { + struct SessionItCtx si_ctx; + si_ctx.addr = &sbs; + si_ctx.addrlen = sbs; + GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &target->hashPubKey, &session_it, &si_ctx); + if (si_ctx.result != NULL) + session = si_ctx.result; + return session; + } + + if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) + return NULL; /* NAT client only works with IPv4 addresses */ + + if (0 == plugin->max_connections) + return NULL; /* saturated */ + + if ((is_natd == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &target->hashPubKey))) + return NULL; /* Only do one NAT punch attempt per peer identity */ + + if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && + (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &target->hashPubKey))) + { +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + _("Found valid IPv4 NAT address (creating session)!\n")); +#endif + session = create_session (plugin, target, NULL, GNUNET_YES); + GNUNET_assert (session != NULL); + + GNUNET_assert (GNUNET_CONTAINER_multihashmap_put + (plugin->nat_wait_conns, &target->hashPubKey, session, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Created NAT WAIT connection to `%4s' at `%s'\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); +#endif + GNUNET_NAT_run_client (plugin->nat, &a4); + return session; + } + + /* create new outbound session */ + GNUNET_assert (0 != plugin->max_connections); + sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); + if (sa == NULL) + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Failed to create connection to `%4s' at `%s'\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); +#endif + return NULL; + } + plugin->max_connections--; +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", + GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); +#endif + session = create_session (plugin, + target, + GNUNET_SERVER_connect_socket (plugin->server, sa), + GNUNET_NO); + session->connect_addr = GNUNET_malloc (addrlen); + memcpy (session->connect_addr, addr, addrlen); + session->connect_alen = addrlen; + if (addrlen != 0) + { + struct GNUNET_ATS_Information ats; + ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs); + session->ats_address_network_type = ats.value; + } + else + GNUNET_break (0); + + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &target->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + /* Send TCP Welcome */ + process_pending_messages (session); + + return session; +} + /** * Function that can be called to force a disconnect from the @@ -1527,8 +1478,7 @@ tcp_plugin_send (void *cls, * to be cancelled */ static void -tcp_plugin_disconnect (void *cls, - const struct GNUNET_PeerIdentity *target) +tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; struct Session *session; @@ -1536,32 +1486,29 @@ tcp_plugin_disconnect (void *cls, struct PendingMessage *pm; #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Asked to cancel session with `%4s'\n", - GNUNET_i2s (target)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to cancel session with `%4s'\n", GNUNET_i2s (target)); #endif next = plugin->sessions; while (NULL != (session = next)) - { - next = session->next; - if (0 != memcmp (target, - &session->target, - sizeof (struct GNUNET_PeerIdentity))) - continue; - pm = session->pending_messages_head; - while (pm != NULL) - { - pm->transmit_cont = NULL; - pm->transmit_cont_cls = NULL; - pm = pm->next; - } - GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# transport-service disconnect requests for TCP"), - 1, - GNUNET_NO); - disconnect_session (session); - } + { + next = session->next; + if (0 != + memcmp (target, &session->target, sizeof (struct GNUNET_PeerIdentity))) + continue; + pm = session->pending_messages_head; + while (pm != NULL) + { + pm->transmit_cont = NULL; + pm->transmit_cont_cls = NULL; + pm = pm->next; + } + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# transport-service disconnect requests for TCP"), + 1, GNUNET_NO); + disconnect_session (session); + } } @@ -1600,11 +1547,11 @@ append_port (void *cls, const char *hostname) char *ret; if (hostname == NULL) - { - ppc->asc (ppc->asc_cls, NULL); - GNUNET_free (ppc); - return; - } + { + ppc->asc (ppc->asc_cls, NULL); + GNUNET_free (ppc); + return; + } GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); ppc->asc (ppc->asc_cls, ret); GNUNET_free (ret); @@ -1626,16 +1573,13 @@ append_port (void *cls, const char *hostname) * @param asc_cls closure for asc */ static void -tcp_plugin_address_pretty_printer (void *cls, - const char *type, - const void *addr, - size_t addrlen, +tcp_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { - struct Plugin *plugin = cls; struct PrettyPrinterContext *ppc; const void *sb; size_t sbs; @@ -1646,44 +1590,39 @@ tcp_plugin_address_pretty_printer (void *cls, uint16_t port; if (addrlen == sizeof (struct IPv6TcpAddress)) - { - t6 = addr; - memset (&a6, 0, sizeof (a6)); - a6.sin6_family = AF_INET6; - a6.sin6_port = t6->t6_port; - memcpy (&a6.sin6_addr, - &t6->ipv6_addr, - sizeof (struct in6_addr)); - port = ntohs (t6->t6_port); - sb = &a6; - sbs = sizeof (a6); - } + { + t6 = addr; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + port = ntohs (t6->t6_port); + sb = &a6; + sbs = sizeof (a6); + } else if (addrlen == sizeof (struct IPv4TcpAddress)) - { - t4 = addr; - memset (&a4, 0, sizeof (a4)); - a4.sin_family = AF_INET; - a4.sin_port = t4->t_port; - a4.sin_addr.s_addr = t4->ipv4_addr; - port = ntohs (t4->t_port); - sb = &a4; - sbs = sizeof (a4); - } + { + t4 = addr; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->t4_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + port = ntohs (t4->t4_port); + sb = &a4; + sbs = sizeof (a4); + } else - { - /* invalid address */ - GNUNET_break_op (0); - asc (asc_cls, NULL); - return; - } + { + /* invalid address */ + GNUNET_break_op (0); + asc (asc_cls, NULL); + return; + } ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); ppc->asc = asc; ppc->asc_cls = asc_cls; ppc->port = port; - GNUNET_RESOLVER_hostname_get (plugin->env->cfg, - sb, - sbs, - !numeric, timeout, &append_port, ppc); + GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); } @@ -1698,8 +1637,7 @@ tcp_plugin_address_pretty_printer (void *cls, * @return GNUNET_OK if port is either open_port or adv_port */ static int -check_port (struct Plugin *plugin, - uint16_t in_port) +check_port (struct Plugin *plugin, uint16_t in_port) { if ((in_port == plugin->adv_port) || (in_port == plugin->open_port)) return GNUNET_OK; @@ -1723,9 +1661,7 @@ check_port (struct Plugin *plugin, * and transport, GNUNET_SYSERR if not */ static int -tcp_plugin_check_address (void *cls, - const void *addr, - size_t addrlen) +tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; struct IPv4TcpAddress *v4; @@ -1733,41 +1669,35 @@ tcp_plugin_check_address (void *cls, if ((addrlen != sizeof (struct IPv4TcpAddress)) && (addrlen != sizeof (struct IPv6TcpAddress))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } if (addrlen == sizeof (struct IPv4TcpAddress)) - { - v4 = (struct IPv4TcpAddress *) addr; - if (GNUNET_OK == - check_mapped_addr (plugin, v4, sizeof (struct IPv4TcpAddress))) - return GNUNET_OK; - if (GNUNET_OK != - check_port (plugin, ntohs (v4->t_port))) - return GNUNET_SYSERR; - if (GNUNET_OK != - check_local_addr (plugin, &v4->ipv4_addr, sizeof (struct in_addr))) - return GNUNET_SYSERR; - } + { + v4 = (struct IPv4TcpAddress *) addr; + if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr, + sizeof (struct in_addr))) + return GNUNET_SYSERR; + } else + { + v6 = (struct IPv6TcpAddress *) addr; + if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) { - v6 = (struct IPv6TcpAddress *) addr; - if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK == - check_mapped_addr (plugin, v6, sizeof (struct IPv6TcpAddress))) - return GNUNET_OK; - if (GNUNET_OK != - check_port (plugin, ntohs (v6->t6_port))) - return GNUNET_SYSERR; - if (GNUNET_OK != - check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr))) - return GNUNET_SYSERR; + GNUNET_break_op (0); + return GNUNET_SYSERR; } + if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr, + sizeof (struct in6_addr))) + return GNUNET_SYSERR; + } return GNUNET_OK; } @@ -1782,9 +1712,8 @@ tcp_plugin_check_address (void *cls, * @param message the actual message */ static void -handle_tcp_nat_probe (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; struct Session *session; @@ -1797,9 +1726,7 @@ handle_tcp_nat_probe (void *cls, const struct sockaddr_in6 *s6; #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "received tcp NAT probe\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "received NAT probe\n"); #endif /* We have received a TCP NAT probe, meaning we (hopefully) initiated * a connection to this peer by running gnunet-nat-client. This peer @@ -1807,49 +1734,51 @@ handle_tcp_nat_probe (void *cls, * as the default for that peer. Do so and then send a WELCOME message * so we can really be connected! */ - if (ntohs(message->size) != sizeof(struct TCP_NAT_ProbeMessage)) - { - GNUNET_break_op(0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - if (0 == memcmp (&tcp_nat_probe->clientIdentity, - plugin->env->my_identity, - sizeof (struct GNUNET_PeerIdentity))) - { - /* refuse connections from ourselves */ - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *)message; - session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, - &tcp_nat_probe->clientIdentity.hashPubKey); + if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message; + if (0 == + memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + /* refuse connections from ourselves */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + session = + GNUNET_CONTAINER_multihashmap_get (plugin->nat_wait_conns, + &tcp_nat_probe-> + clientIdentity.hashPubKey); if (session == NULL) - { + { #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Did NOT find session for NAT probe!\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Did NOT find session for NAT probe!\n"); #endif - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found session for NAT probe!\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found session for NAT probe!\n"); #endif - GNUNET_assert(GNUNET_CONTAINER_multihashmap_remove(plugin->nat_wait_conns, - &tcp_nat_probe->clientIdentity.hashPubKey, - session) == GNUNET_YES); - if (GNUNET_OK != - GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) - { - GNUNET_break (0); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } + GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove + (plugin->nat_wait_conns, + &tcp_nat_probe->clientIdentity.hashPubKey, + session) == GNUNET_YES); + if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { + GNUNET_break (0); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } GNUNET_SERVER_client_keep (client); session->client = client; @@ -1857,52 +1786,47 @@ handle_tcp_nat_probe (void *cls, session->inbound = GNUNET_NO; #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found address `%s' for incoming connection\n", - GNUNET_a2s (vaddr, alen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found address `%s' for incoming connection\n", + GNUNET_a2s (vaddr, alen)); #endif - switch (((const struct sockaddr *)vaddr)->sa_family) - { - case AF_INET: - s4 = vaddr; - t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); - t4->t_port = s4->sin_port; - t4->ipv4_addr = s4->sin_addr.s_addr; - session->connect_addr = t4; - session->connect_alen = sizeof (struct IPv4TcpAddress); - break; - case AF_INET6: - s6 = vaddr; - t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); - t6->t6_port = s6->sin6_port; - memcpy (&t6->ipv6_addr, - &s6->sin6_addr, - sizeof (struct in6_addr)); - session->connect_addr = t6; - session->connect_alen = sizeof (struct IPv6TcpAddress); - break; - default: - GNUNET_break_op (0); + switch (((const struct sockaddr *) vaddr)->sa_family) + { + case AF_INET: + s4 = vaddr; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->t4_port = s4->sin_port; + t4->ipv4_addr = s4->sin_addr.s_addr; + session->connect_addr = t4; + session->connect_alen = sizeof (struct IPv4TcpAddress); + break; + case AF_INET6: + s6 = vaddr; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->t6_port = s6->sin6_port; + memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); + session->connect_addr = t6; + session->connect_alen = sizeof (struct IPv6TcpAddress); + break; + default: + GNUNET_break_op (0); #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Bad address for incoming connection!\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Bad address for incoming connection!\n"); #endif - GNUNET_free (vaddr); - GNUNET_SERVER_client_drop (client); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + GNUNET_free (vaddr); + GNUNET_SERVER_client_drop (client); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } GNUNET_free (vaddr); - + session->next = plugin->sessions; plugin->sessions = session; GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP sessions active"), - 1, - GNUNET_NO); + gettext_noop ("# TCP sessions active"), 1, + GNUNET_NO); process_pending_messages (session); GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -1917,8 +1841,7 @@ handle_tcp_nat_probe (void *cls, * @param message the actual message */ static void -handle_tcp_welcome (void *cls, - struct GNUNET_SERVER_Client *client, +handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; @@ -1930,108 +1853,100 @@ handle_tcp_welcome (void *cls, struct IPv6TcpAddress *t6; const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; - - if (0 == memcmp (&wm->clientIdentity, - plugin->env->my_identity, - sizeof (struct GNUNET_PeerIdentity))) - { - /* refuse connections from ourselves */ - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + + if (0 == + memcmp (&wm->clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + /* refuse connections from ourselves */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Received %s message from `%4s'.\n", - "WELCOME", + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Received %s message from `%4s'.\n", "WELCOME", GNUNET_i2s (&wm->clientIdentity)); #endif GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# TCP WELCOME messages received"), - 1, - GNUNET_NO); + gettext_noop ("# TCP WELCOME messages received"), 1, + GNUNET_NO); session = find_session_by_client (plugin, client); if (session == NULL) - { + { #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Received %s message from a `%4s', creating new session\n", - "WELCOME", - GNUNET_i2s (&wm->clientIdentity)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Received %s message from a `%4s', creating new session\n", + "WELCOME", GNUNET_i2s (&wm->clientIdentity)); #endif - GNUNET_SERVER_client_keep (client); - session = create_session (plugin, - &wm->clientIdentity, - client, - GNUNET_NO); - session->inbound = GNUNET_YES; - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) - { + GNUNET_SERVER_client_keep (client); + session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO); + session->inbound = GNUNET_YES; + if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { #if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found address `%s' for incoming connection\n", - GNUNET_a2s (vaddr, alen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found address `%s' for incoming connection\n", + GNUNET_a2s (vaddr, alen)); #endif - if (alen == sizeof (struct sockaddr_in)) - { - s4 = vaddr; - t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); - t4->t_port = s4->sin_port; - t4->ipv4_addr = s4->sin_addr.s_addr; - session->connect_addr = t4; - session->connect_alen = sizeof (struct IPv4TcpAddress); - } - else if (alen == sizeof (struct sockaddr_in6)) - { - s6 = vaddr; - t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); - t6->t6_port = s6->sin6_port; - memcpy (&t6->ipv6_addr, - &s6->sin6_addr, - sizeof (struct in6_addr)); - session->connect_addr = t6; - session->connect_alen = sizeof (struct IPv6TcpAddress); - } - - GNUNET_free (vaddr); - } - else - { + + if (alen == sizeof (struct sockaddr_in)) + { + s4 = vaddr; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->t4_port = s4->sin_port; + t4->ipv4_addr = s4->sin_addr.s_addr; + session->connect_addr = t4; + session->connect_alen = sizeof (struct IPv4TcpAddress); + } + else if (alen == sizeof (struct sockaddr_in6)) + { + s6 = vaddr; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->t6_port = s6->sin6_port; + memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); + session->connect_addr = t6; + session->connect_alen = sizeof (struct IPv6TcpAddress); + } + + struct GNUNET_ATS_Information ats; + ats = plugin->env->get_address_type (plugin->env->cls, vaddr ,alen); + session->ats_address_network_type = ats.value; + + GNUNET_free (vaddr); + } + else + { #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Did not obtain TCP socket address for incoming connection\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Did not obtain TCP socket address for incoming connection\n"); #endif - } - process_pending_messages (session); } + process_pending_messages (session); + } else - { + { #if DEBUG_TCP_NAT - if (GNUNET_OK == - GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found address `%s' (already have session)\n", - GNUNET_a2s (vaddr, alen)); - GNUNET_free (vaddr); - } -#endif + if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found address `%s' (already have session)\n", + GNUNET_a2s (vaddr, alen)); + GNUNET_free (vaddr); } +#endif + } if (session->expecting_welcome != GNUNET_YES) - { - GNUNET_break_op (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } session->last_activity = GNUNET_TIME_absolute_get (); session->expecting_welcome = GNUNET_NO; + GNUNET_SERVER_client_set_timeout (client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -2044,24 +1959,22 @@ handle_tcp_welcome (void *cls, * @param tc task context (unused) */ static void -delayed_done (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *session = cls; struct GNUNET_TIME_Relative delay; + struct GNUNET_ATS_Information ats; session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK; - delay = session->plugin->env->receive (session->plugin->env->cls, - &session->target, - NULL, - NULL, 0, - session, - NULL, 0); + delay = + session->plugin->env->receive (session->plugin->env->cls, + &session->target, NULL, &ats, 0, session, + NULL, 0); if (delay.rel_value == 0) GNUNET_SERVER_receive_done (session->client, GNUNET_OK); else session->receive_delay_task = - GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); + GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); } @@ -2074,8 +1987,7 @@ delayed_done (void *cls, * @param message the actual message */ static void -handle_tcp_data (void *cls, - struct GNUNET_SERVER_Client *client, +handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; @@ -2084,60 +1996,62 @@ handle_tcp_data (void *cls, uint16_t type; type = ntohs (message->type); - if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || - (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) ) - { - /* We don't want to propagate WELCOME and NAT Probe messages up! */ - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } + if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || + (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type)) + { + /* We don't want to propagate WELCOME and NAT Probe messages up! */ + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } session = find_session_by_client (plugin, client); - if ( (NULL == session) || (GNUNET_YES == session->expecting_welcome) ) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + if ((NULL == session) || (GNUNET_YES == session->expecting_welcome)) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } session->last_activity = GNUNET_TIME_absolute_get (); -#if DEBUG_TCP > 1 - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Passing %u bytes of type %u from `%4s' to transport service.\n", +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Passing %u bytes of type %u from `%4s' to transport service.\n", (unsigned int) ntohs (message->size), - (unsigned int) ntohs (message->type), - GNUNET_i2s (&session->target)); + (unsigned int) ntohs (message->type), + GNUNET_i2s (&session->target)); #endif GNUNET_STATISTICS_update (plugin->env->stats, - gettext_noop ("# bytes received via TCP"), - ntohs (message->size), - GNUNET_NO); - struct GNUNET_TRANSPORT_ATS_Information distance[2]; - distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE); + gettext_noop ("# bytes received via TCP"), + ntohs (message->size), GNUNET_NO); + struct GNUNET_ATS_Information distance[2]; + + distance[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); distance[0].value = htonl (1); - distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); - distance[1].value = htonl (0); - delay = plugin->env->receive (plugin->env->cls, &session->target, message, - (const struct GNUNET_TRANSPORT_ATS_Information *) &distance, - 2, - session, - (GNUNET_YES == session->inbound) ? NULL : session->connect_addr, - (GNUNET_YES == session->inbound) ? 0 : session->connect_alen); + distance[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + distance[1].value = session->ats_address_network_type; + GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + + delay = + plugin->env->receive (plugin->env->cls, &session->target, message, + (const struct GNUNET_ATS_Information *) &distance, + 1, session, + (GNUNET_YES == + session->inbound) ? NULL : session->connect_addr, + (GNUNET_YES == + session->inbound) ? 0 : session->connect_alen); if (delay.rel_value == 0) - { - GNUNET_SERVER_receive_done (client, GNUNET_OK); - } + { + GNUNET_SERVER_receive_done (client, GNUNET_OK); + } else - { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Throttling receiving from `%s' for %llu ms\n", - GNUNET_i2s (&session->target), - (unsigned long long) delay.rel_value); + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Throttling receiving from `%s' for %llu ms\n", + GNUNET_i2s (&session->target), + (unsigned long long) delay.rel_value); #endif - GNUNET_SERVER_disable_receive_done_warning (client); - session->receive_delay_task = - GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); - } + GNUNET_SERVER_disable_receive_done_warning (client); + session->receive_delay_task = + GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); + } } @@ -2149,257 +2063,35 @@ handle_tcp_data (void *cls, * @param client identification of the client */ static void -disconnect_notify (void *cls, - struct GNUNET_SERVER_Client *client) +disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) { struct Plugin *plugin = cls; struct Session *session; if (client == NULL) return; + plugin->max_connections++; session = find_session_by_client (plugin, client); if (session == NULL) return; /* unknown, nothing to do */ #if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Destroying session of `%4s' with %s due to network-level disconnect.\n", GNUNET_i2s (&session->target), - (session->connect_addr != NULL) ? - tcp_address_to_string (session->plugin, - session->connect_addr, - session->connect_alen) : "*"); + (session->connect_addr != + NULL) ? tcp_address_to_string (session->plugin, + session->connect_addr, + session->connect_alen) : + "*"); #endif GNUNET_STATISTICS_update (session->plugin->env->stats, - gettext_noop ("# network-level TCP disconnect events"), - 1, - GNUNET_NO); + gettext_noop + ("# network-level TCP disconnect events"), 1, + GNUNET_NO); disconnect_session (session); } -static int check_localaddress (const struct sockaddr *addr, socklen_t addrlen) -{ - uint32_t res = 0; - int local = GNUNET_NO; - int af = addr->sa_family; - switch (af) - { - case AF_INET: - { - uint32_t netmask = 0x7F000000; - uint32_t address = ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr); - res = (address >> 24) ^ (netmask >> 24); - if (res != 0) - local = GNUNET_NO; - else - local = GNUNET_YES; -#if DEBUG_TCP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Checking IPv4 address `%s': %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); -#endif - break; - } - case AF_INET6: - { - if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr) || - IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) - local = GNUNET_YES; - else - local = GNUNET_NO; -#if DEBUG_TCP - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Checking IPv6 address `%s' : %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); -#endif - break; - } - } - return local; -} - -/** - * Add the IP of our network interface to the list of - * our internal IP addresses. - * - * @param cls the 'struct Plugin*' - * @param name name of the interface - * @param isDefault do we think this may be our default interface - * @param addr address of the interface - * @param addrlen number of bytes in addr - * @return GNUNET_OK to continue iterating - */ -static int -process_interfaces (void *cls, - const char *name, - int isDefault, - const struct sockaddr *addr, socklen_t addrlen) -{ - struct Plugin *plugin = cls; - int af; - struct IPv4TcpAddress t4; - struct IPv6TcpAddress t6; - struct IPv4TcpAddress t4_nat; - struct IPv6TcpAddress t6_nat; - void *arg; - uint16_t args; - void *arg_nat; - char buf[INET6_ADDRSTRLEN]; - - af = addr->sa_family; - arg_nat = NULL; - - if (plugin->use_localaddresses == GNUNET_NO) - { - if (GNUNET_YES == check_localaddress (addr, addrlen)) - { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - "Not notifying transport of address `%s' (local address)\n", - GNUNET_a2s (addr, addrlen)); -#endif - return GNUNET_OK; - } - } - - switch (af) - { - case AF_INET: - t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - GNUNET_assert (NULL != inet_ntop(AF_INET, - &t4.ipv4_addr, - buf, - sizeof (buf))); - if ( (plugin->bind_address != NULL) && - (0 != strcmp(buf, plugin->bind_address)) ) - { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Not notifying transport of address `%s' (does not match bind address)\n", - GNUNET_a2s (addr, addrlen)); -#endif - return GNUNET_OK; - } - if ( (plugin->internal_address == NULL) && - (isDefault) ) - plugin->internal_address = GNUNET_strdup (buf); - add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr)); - if (plugin->behind_nat == GNUNET_YES) - { - /* Also advertise as NAT (with port 0) */ - t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - t4_nat.t_port = htons(0); - arg_nat = &t4_nat; - } - t4.t_port = htons (plugin->adv_port); - arg = &t4; - args = sizeof (t4); - break; - case AF_INET6: - if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) || - (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg, - "nat", - "DISABLEV6")) ) - { - /* skip link local addresses */ - return GNUNET_OK; - } - memcpy (&t6.ipv6_addr, - &((struct sockaddr_in6 *) addr)->sin6_addr, - sizeof (struct in6_addr)); - - /* check bind address */ - GNUNET_assert (NULL != inet_ntop(AF_INET6, - &t6.ipv6_addr, - buf, - sizeof (buf))); - - if ( (plugin->bind_address != NULL) && - (0 != strcmp(buf, plugin->bind_address)) ) - { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Not notifying transport of address `%s' (does not match bind address)\n", - GNUNET_a2s (addr, addrlen)); -#endif - return GNUNET_OK; - } - - add_to_address_list (plugin, - &t6.ipv6_addr, - sizeof (struct in6_addr)); - if (plugin->behind_nat == GNUNET_YES) - { - /* Also advertise as NAT (with port 0) */ - memcpy (&t6_nat.ipv6_addr, - &((struct sockaddr_in6 *) addr)->sin6_addr, - sizeof (struct in6_addr)); - t6_nat.t6_port = htons(0); - arg_nat = &t6; - } - t6.t6_port = htons (plugin->adv_port); - arg = &t6; - args = sizeof (t6); - break; - default: - GNUNET_break (0); - return GNUNET_OK; - } - if (plugin->adv_port != 0) - { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found address `%s' (%s) len %d\n", - GNUNET_a2s (addr, addrlen), name, args); -#endif - plugin->env->notify_address (plugin->env->cls, - "tcp", - arg, args, GNUNET_TIME_UNIT_FOREVER_REL); - } - - if (arg_nat != NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - _("Found address `%s' (%s) len %d\n"), - GNUNET_a2s (addr, addrlen), name, args); - plugin->env->notify_address (plugin->env->cls, - "tcp", - arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL); - } - - return GNUNET_OK; -} - - -/** - * Function called by the resolver for each address obtained from DNS - * for our own hostname. Add the addresses to the list of our - * external IP addresses. - * - * @param cls closure - * @param addr one of the addresses of the host, NULL for the last address - * @param addrlen length of the address - */ -static void -process_hostname_ips (void *cls, - const struct sockaddr *addr, socklen_t addrlen) -{ - struct Plugin *plugin = cls; - - if (addr == NULL) - { - plugin->hostname_dns = NULL; - return; - } - /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */ - process_interfaces (plugin, "", GNUNET_YES, addr, addrlen); -} - - /** * We can now send a probe message, copy into buffer to really send. * @@ -2409,408 +2101,80 @@ process_hostname_ips (void *cls, * @return number of bytes copied into buf */ static size_t -notify_send_probe (void *cls, - size_t size, - void *buf) +notify_send_probe (void *cls, size_t size, void *buf) { struct TCPProbeContext *tcp_probe_ctx = cls; struct Plugin *plugin = tcp_probe_ctx->plugin; size_t ret; tcp_probe_ctx->transmit_handle = NULL; - GNUNET_CONTAINER_DLL_remove (plugin->probe_head, - plugin->probe_tail, - tcp_probe_ctx); + GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, + tcp_probe_ctx); if (buf == NULL) - { - GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO); - GNUNET_free(tcp_probe_ctx); - return 0; - } - GNUNET_assert(size >= sizeof(tcp_probe_ctx->message)); - memcpy(buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message)); + { + GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO); + GNUNET_free (tcp_probe_ctx); + return 0; + } + GNUNET_assert (size >= sizeof (tcp_probe_ctx->message)); + memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message)); GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server, tcp_probe_ctx->sock); - ret = sizeof(tcp_probe_ctx->message); - GNUNET_free(tcp_probe_ctx); + ret = sizeof (tcp_probe_ctx->message); + GNUNET_free (tcp_probe_ctx); return ret; } /** - * We have been notified that gnunet-nat-server has written something to stdout. - * Handle the output, then reschedule this function to be called again once - * more is available. + * Function called by the NAT subsystem suggesting another peer wants + * to connect to us via connection reversal. Try to connect back to the + * given IP. * - * @param cls the plugin handle - * @param tc the scheduling context + * @param cls closure + * @param addr address to try + * @param addrlen number of bytes in addr */ static void -tcp_plugin_server_read (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +try_connection_reversal (void *cls, const struct sockaddr *addr, + socklen_t addrlen) { struct Plugin *plugin = cls; - char mybuf[40]; - ssize_t bytes; - size_t i; - int port; - const char *port_start; - struct sockaddr_in sin_addr; - struct TCPProbeContext *tcp_probe_ctx; struct GNUNET_CONNECTION_Handle *sock; - - if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - memset (mybuf, 0, sizeof(mybuf)); - bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, - mybuf, - sizeof(mybuf)); - if (bytes < 1) - { -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Finished reading from server stdout with code: %d\n", - bytes); -#endif - /* FIXME: consider process_wait here? */ - return; - } - - port_start = NULL; - for (i = 0; i < sizeof(mybuf); i++) - { - if (mybuf[i] == '\n') - { - mybuf[i] = '\0'; - break; - } - if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) ) - { - mybuf[i] = '\0'; - port_start = &mybuf[i + 1]; - } - } - - /* construct socket address of sender */ - memset (&sin_addr, 0, sizeof (sin_addr)); - sin_addr.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - sin_addr.sin_len = sizeof (sin_addr); -#endif - if ( (NULL == port_start) || - (1 != sscanf (port_start, "%d", &port)) || - (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) ) - { - /* should we restart gnunet-nat-server? */ - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("gnunet-nat-server generated malformed address `%s'\n"), - mybuf); - plugin->server_read_task - = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &tcp_plugin_server_read, - plugin); - return; - } - sin_addr.sin_port = htons((uint16_t) port); -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "gnunet-nat-server read: %s:%d\n", - mybuf, port); -#endif + struct TCPProbeContext *tcp_probe_ctx; /** * We have received an ICMP response, ostensibly from a peer * that wants to connect to us! Send a message to establish a connection. */ - sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, - (const struct sockaddr *)&sin_addr, - sizeof (sin_addr)); + sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen); if (sock == NULL) - { - /* failed for some odd reason (out of sockets?); ignore attempt */ - plugin->server_read_task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &tcp_plugin_server_read, - plugin); - return; - } + { + /* failed for some odd reason (out of sockets?); ignore attempt */ + return; + } - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "Sending TCP probe message to `%s:%u'!\n", - mybuf, - (unsigned int) port); /* FIXME: do we need to track these probe context objects so that - we can clean them up on plugin unload? */ - tcp_probe_ctx - = GNUNET_malloc(sizeof(struct TCPProbeContext)); - tcp_probe_ctx->message.header.size - = htons(sizeof(struct TCP_NAT_ProbeMessage)); - tcp_probe_ctx->message.header.type - = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); - memcpy (&tcp_probe_ctx->message.clientIdentity, - plugin->env->my_identity, - sizeof(struct GNUNET_PeerIdentity)); + * we can clean them up on plugin unload? */ + tcp_probe_ctx = GNUNET_malloc (sizeof (struct TCPProbeContext)); + tcp_probe_ctx->message.header.size = + htons (sizeof (struct TCP_NAT_ProbeMessage)); + tcp_probe_ctx->message.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); + memcpy (&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)); tcp_probe_ctx->plugin = plugin; tcp_probe_ctx->sock = sock; - GNUNET_CONTAINER_DLL_insert (plugin->probe_head, - plugin->probe_tail, - tcp_probe_ctx); - tcp_probe_ctx->transmit_handle - = GNUNET_CONNECTION_notify_transmit_ready (sock, - ntohs (tcp_probe_ctx->message.header.size), - GNUNET_TIME_UNIT_FOREVER_REL, - ¬ify_send_probe, tcp_probe_ctx); - - plugin->server_read_task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &tcp_plugin_server_read, - plugin); -} - - -/** - * Start the gnunet-nat-server process for users behind NAT. - * - * @param plugin the transport plugin - * @return GNUNET_YES if process was started, GNUNET_SYSERR on error - */ -static int -tcp_transport_start_nat_server (struct Plugin *plugin) -{ - if (plugin->internal_address == NULL) - return GNUNET_SYSERR; - plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, - GNUNET_NO, - GNUNET_YES); - if (plugin->server_stdout == NULL) - return GNUNET_SYSERR; -#if DEBUG_TCP_NAT - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp" - "Starting %s %s\n", "gnunet-nat-server", plugin->internal_address); -#endif - /* Start the server process */ - plugin->server_proc = GNUNET_OS_start_process (NULL, - plugin->server_stdout, - "gnunet-nat-server", - "gnunet-nat-server", - plugin->internal_address, - NULL); - if (plugin->server_proc == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("Failed to start %s\n"), - "gnunet-nat-server"); - GNUNET_DISK_pipe_close (plugin->server_stdout); - plugin->server_stdout = NULL; - return GNUNET_SYSERR; - } - /* Close the write end of the read pipe */ - GNUNET_DISK_pipe_close_end(plugin->server_stdout, - GNUNET_DISK_PIPE_END_WRITE); - plugin->server_stdout_handle - = GNUNET_DISK_pipe_handle (plugin->server_stdout, - GNUNET_DISK_PIPE_END_READ); - plugin->server_read_task - = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, - &tcp_plugin_server_read, - plugin); - return GNUNET_YES; -} - - -/** - * Return the actual path to a file found in the current - * PATH environment variable. - * - * @param binary the name of the file to find - * @return path to binary, NULL if not found - */ -static char * -get_path_from_PATH (const char *binary) -{ - char *path; - char *pos; - char *end; - char *buf; - const char *p; - - p = getenv ("PATH"); - if (p == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("PATH environment variable is unset.\n")); - return NULL; - } - path = GNUNET_strdup (p); /* because we write on it */ - buf = GNUNET_malloc (strlen (path) + 20); - pos = path; - - while (NULL != (end = strchr (pos, PATH_SEPARATOR))) - { - *end = '\0'; - sprintf (buf, "%s/%s", pos, binary); - if (GNUNET_DISK_file_test (buf) == GNUNET_YES) - { - GNUNET_free (path); - return buf; - } - pos = end + 1; - } - sprintf (buf, "%s/%s", pos, binary); - if (GNUNET_DISK_file_test (buf) == GNUNET_YES) - { - GNUNET_free (path); - return buf; - } - GNUNET_free (buf); - GNUNET_free (path); - return NULL; -} - - -/** - * Check whether the suid bit is set on a file. - * Attempts to find the file using the current - * PATH environment variable as a search path. - * - * @param binary the name of the file to check - * @return GNUNET_YES if the file is SUID, - * GNUNET_NO if not, - * GNUNET_SYSERR on error - */ -static int -check_gnunet_nat_binary (const char *binary) -{ - struct stat statbuf; - char *p; -#ifdef MINGW - SOCKET rawsock; - char *binaryexe; - - GNUNET_asprintf (&binaryexe, "%s.exe", binary); - p = get_path_from_PATH (binaryexe); - free (binaryexe); -#else - p = get_path_from_PATH (binary); -#endif - if (p == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Could not find binary `%s' in PATH!\n"), - binary); - return GNUNET_NO; - } - if (0 != STAT (p, &statbuf)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("stat (%s) failed: %s\n"), - p, - STRERROR (errno)); - GNUNET_free (p); - return GNUNET_SYSERR; - } - GNUNET_free (p); -#ifndef MINGW - if ( (0 != (statbuf.st_mode & S_ISUID)) && - (statbuf.st_uid == 0) ) - return GNUNET_YES; - return GNUNET_NO; -#else - rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (INVALID_SOCKET == rawsock) - { - DWORD err = GetLastError (); - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err); - return GNUNET_NO; /* not running as administrator */ - } - closesocket (rawsock); - return GNUNET_YES; -#endif -} - - -/** - * Our (external) hostname was resolved. - * - * @param cls the 'struct Plugin' - * @param addr NULL on error, otherwise result of DNS lookup - * @param addrlen number of bytes in addr - */ -static void -process_external_ip (void *cls, - const struct sockaddr *addr, - socklen_t addrlen) -{ - struct Plugin *plugin = cls; - const struct sockaddr_in *s; - struct IPv4TcpAddress t4; - char buf[INET_ADDRSTRLEN]; - - plugin->ext_dns = NULL; - if (addr == NULL) - return; - GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); - s = (const struct sockaddr_in *) addr; - t4.ipv4_addr = s->sin_addr.s_addr; - if ( (plugin->behind_nat == GNUNET_YES) && - (plugin->enable_nat_server == GNUNET_YES) ) - { - t4.t_port = htons(0); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Notifying transport of address %s:%d\n", - plugin->external_address, - 0); - } - else - { - t4.t_port = htons(plugin->adv_port); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Notifying transport of address %s:%d\n", - plugin->external_address, - (int) plugin->adv_port); - } - - if ((plugin->bind_address != NULL) && (plugin->behind_nat == GNUNET_NO)) - { - GNUNET_assert (NULL != inet_ntop(AF_INET, - &t4.ipv4_addr, - buf, - sizeof (buf))); - if (0 != strcmp (plugin->bind_address, buf)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - "NAT is not enabled and specific bind address `%s' differs from external address `%s'! Not notifying about external address `%s'\n", - plugin->bind_address, - plugin->external_address, - plugin->external_address); - return; - } - } - - add_to_address_list (plugin, - &t4.ipv4_addr, - sizeof (struct in_addr)); + GNUNET_CONTAINER_DLL_insert (plugin->probe_head, plugin->probe_tail, + tcp_probe_ctx); + tcp_probe_ctx->transmit_handle = + GNUNET_CONNECTION_notify_transmit_ready (sock, + ntohs (tcp_probe_ctx-> + message.header.size), + GNUNET_TIME_UNIT_FOREVER_REL, + ¬ify_send_probe, + tcp_probe_ctx); - plugin->env->notify_address (plugin->env->cls, - "tcp", - &t4, sizeof(t4), - GNUNET_TIME_UNIT_FOREVER_REL); } @@ -2826,7 +2190,8 @@ libgnunet_plugin_transport_tcp_init (void *cls) static const struct GNUNET_SERVER_MessageHandler my_handlers[] = { {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, sizeof (struct WelcomeMessage)}, - {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, sizeof (struct TCP_NAT_ProbeMessage)}, + {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, + sizeof (struct TCP_NAT_ProbeMessage)}, {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0}, {NULL, NULL, 0, 0} }; @@ -2836,238 +2201,121 @@ libgnunet_plugin_transport_tcp_init (void *cls) struct GNUNET_SERVICE_Context *service; unsigned long long aport; unsigned long long bport; + unsigned long long max_connections; unsigned int i; - int behind_nat; - int nat_punched; - int enable_nat_client; - int enable_nat_server; - int enable_upnp; - int use_localaddresses; - char *internal_address; - char *external_address; - char *bind_address; - struct sockaddr_in in_addr; struct GNUNET_TIME_Relative idle_timeout; + int ret; + struct sockaddr **addrs; + socklen_t *addrlens; - behind_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "BEHIND_NAT"); - nat_punched = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "NAT_PUNCHED"); - enable_nat_client = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "ENABLE_NAT_CLIENT"); - enable_nat_server = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "ENABLE_NAT_SERVER"); - enable_upnp = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "nat", - "ENABLE_UPNP"); - - if ( (GNUNET_YES == enable_nat_server) && - (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) ) - { - enable_nat_server = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), - "gnunet-nat-server"); - } - - if ( (GNUNET_YES == enable_nat_client) && - (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) ) - { - enable_nat_client = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), - "gnunet-nat-client"); - } - - external_address = NULL; - if (GNUNET_OK == - GNUNET_CONFIGURATION_have_value (env->cfg, - "nat", - "EXTERNAL_ADDRESS")) - { - (void) GNUNET_CONFIGURATION_get_value_string (env->cfg, - "nat", - "EXTERNAL_ADDRESS", - &external_address); - } - - if ( (external_address != NULL) && - (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1) ) - { - - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("Malformed %s `%s' given in configuration!\n"), - "EXTERNAL_ADDRESS", - external_address); - return NULL; - } - if ( (external_address == NULL) && - (nat_punched == GNUNET_YES) ) - { - nat_punched = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Configuration says NAT was punched, but `%s' is not given. Option ignored.\n"), - "EXTERNAL_ADDRESS"); - } - - if (GNUNET_YES == nat_punched) - { - enable_nat_server = GNUNET_NO; - enable_upnp = GNUNET_NO; - } - - bind_address = NULL; - if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg, - "nat", - "BINDTO", - &bind_address)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, - "tcp", - _("Binding TCP plugin to specific address: `%s'\n"), - bind_address); - } - - internal_address = NULL; - if (GNUNET_OK == - GNUNET_CONFIGURATION_have_value (env->cfg, - "nat", - "INTERNAL_ADDRESS")) - { - (void) GNUNET_CONFIGURATION_get_value_string (env->cfg, - "nat", - "INTERNAL_ADDRESS", - &internal_address); - } - - if ( (internal_address != NULL) && - (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1) ) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("Malformed %s `%s' given in configuration!\n"), - "INTERNAL_ADDRESS", - internal_address); - GNUNET_free_non_null(internal_address); - GNUNET_free_non_null(external_address); - return NULL; - } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", + "MAX_CONNECTIONS", + &max_connections)) + max_connections = 128; - if ((bind_address != NULL) && (internal_address != NULL)) - { - if (0 != strcmp(internal_address, bind_address )) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - "Specific bind address `%s' and internal address `%s' must not differ, forcing internal address to bind address!\n", - bind_address, internal_address); - GNUNET_free (internal_address); - internal_address = bind_address; - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp","New internal address `%s'\n", internal_address); - } - } - aport = 0; - if ( (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-tcp", - "PORT", - &bport)) || - (bport > 65535) || - ((GNUNET_OK == - GNUNET_CONFIGURATION_get_value_number (env->cfg, - "transport-tcp", - "ADVERTISED-PORT", - &aport)) && - (aport > 65535)) ) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Require valid port number for service `%s' in configuration!\n"), - "transport-tcp"); - GNUNET_free_non_null(external_address); - GNUNET_free_non_null(internal_address); - return NULL; - } - - use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, - "transport-tcp", - "USE_LOCALADDR"); - if (use_localaddresses == GNUNET_SYSERR) - use_localaddresses = GNUNET_NO; - + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "PORT", + &bport)) || (bport > 65535) || + ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", + "ADVERTISED-PORT", &aport)) && + (aport > 65535))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _ + ("Require valid port number for service `%s' in configuration!\n"), + "transport-tcp"); + return NULL; + } if (aport == 0) aport = bport; if (bport == 0) aport = 0; - if (bport != 0) + { + service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); + if (service == NULL) { - service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); - if (service == NULL) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "tcp", - _("Failed to start service.\n")); - return NULL; - } + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp", + _("Failed to start service.\n")); + return NULL; } + } else service = NULL; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections); + plugin->max_connections = max_connections; plugin->open_port = bport; plugin->adv_port = aport; - plugin->bind_address = bind_address; - plugin->external_address = external_address; - plugin->internal_address = internal_address; - plugin->behind_nat = behind_nat; - plugin->nat_punched = nat_punched; - plugin->enable_nat_client = enable_nat_client; - plugin->enable_nat_server = enable_nat_server; - plugin->enable_upnp = enable_upnp; - plugin->use_localaddresses = use_localaddresses; plugin->env = env; plugin->lsock = NULL; + if ((service != NULL) && + (GNUNET_SYSERR != + (ret = + GNUNET_SERVICE_get_server_addresses ("transport-tcp", env->cfg, &addrs, + &addrlens)))) + { + plugin->nat = + GNUNET_NAT_register (env->cfg, GNUNET_YES, aport, (unsigned int) ret, + (const struct sockaddr **) addrs, addrlens, + &tcp_nat_port_map_callback, + &try_connection_reversal, plugin); + while (ret > 0) + { + ret--; + GNUNET_assert (addrs[ret] != NULL); + GNUNET_free (addrs[ret]); + } + GNUNET_free_non_null (addrs); + GNUNET_free_non_null (addrlens); + } + else + { + plugin->nat = + GNUNET_NAT_register (env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, + &try_connection_reversal, plugin); + } api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &tcp_plugin_send; + + api->send_with_session = &tcp_plugin_send_new; + api->create_session = &tcp_plugin_create_session; + api->disconnect = &tcp_plugin_disconnect; api->address_pretty_printer = &tcp_plugin_address_pretty_printer; api->check_address = &tcp_plugin_check_address; api->address_to_string = &tcp_address_to_string; plugin->service = service; - if (service != NULL) - { - plugin->server = GNUNET_SERVICE_get_server (service); - } + if (service != NULL) + { + plugin->server = GNUNET_SERVICE_get_server (service); + } else - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (env->cfg, - "transport-tcp", - "TIMEOUT", - &idle_timeout)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Failed to find option %s in section %s!\n"), - "TIMEOUT", - "transport-tcp"); - GNUNET_free_non_null(external_address); - GNUNET_free_non_null(internal_address); - GNUNET_free (api); - return NULL; - } - plugin->server = GNUNET_SERVER_create_with_sockets (NULL, NULL, NULL, - idle_timeout, GNUNET_YES); + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp", + "TIMEOUT", &idle_timeout)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Failed to find option %s in section %s!\n"), + "TIMEOUT", "transport-tcp"); + if (plugin->nat != NULL) + GNUNET_NAT_unregister (plugin->nat); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; } + plugin->server = + GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin, + NULL, idle_timeout, GNUNET_YES); + } plugin->handlers = GNUNET_malloc (sizeof (my_handlers)); memcpy (plugin->handlers, my_handlers, sizeof (my_handlers)); for (i = 0; @@ -3075,66 +2323,20 @@ libgnunet_plugin_transport_tcp_init (void *cls) i++) plugin->handlers[i].callback_cls = plugin; GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers); - GNUNET_SERVER_disconnect_notify (plugin->server, - &disconnect_notify, - plugin); - GNUNET_OS_network_interfaces_list (&process_interfaces, plugin); - - if ( (plugin->behind_nat == GNUNET_YES) && - (plugin->enable_nat_server == GNUNET_YES) && - (GNUNET_YES != tcp_transport_start_nat_server(plugin)) ) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _("Failed to start %s required for NAT in %s!\n"), - "gnunet-nat-server" - "transport-tcp"); - GNUNET_free_non_null(external_address); - GNUNET_free_non_null(internal_address); - if (service != NULL) - GNUNET_SERVICE_stop (service); - else - GNUNET_SERVER_destroy (plugin->server); - GNUNET_free (api); - return NULL; - } - - if (enable_nat_client == GNUNET_YES) - { - plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16); - GNUNET_assert (plugin->nat_wait_conns != NULL); - } - + GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin); + plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16); if (bport != 0) - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, - "tcp", - _("TCP transport listening on port %llu\n"), - bport); + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _("TCP transport listening on port %llu\n"), bport); else - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, - "tcp", - _("TCP transport not listening on any port (client only)\n")); + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _ + ("TCP transport not listening on any port (client only)\n")); if (aport != bport) - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, - "tcp", - _("TCP transport advertises itself as being on port %llu\n"), + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _ + ("TCP transport advertises itself as being on port %llu\n"), aport); - - plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->cfg, - AF_UNSPEC, - HOSTNAME_RESOLVE_TIMEOUT, - &process_hostname_ips, - plugin); - - if (plugin->external_address != NULL) - { - plugin->ext_dns = GNUNET_RESOLVER_ip_get (env->cfg, - plugin->external_address, - AF_INET, - GNUNET_TIME_UNIT_MINUTES, - &process_external_ip, - plugin); - } return api; } @@ -3148,55 +2350,26 @@ libgnunet_plugin_transport_tcp_done (void *cls) struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; struct Session *session; - struct LocalAddrList *lal; struct TCPProbeContext *tcp_probe; - if (plugin->ext_dns != NULL) - { - GNUNET_RESOLVER_request_cancel (plugin->ext_dns); - plugin->ext_dns = NULL; - } while (NULL != (session = plugin->sessions)) disconnect_session (session); - if (NULL != plugin->hostname_dns) - { - GNUNET_RESOLVER_request_cancel (plugin->hostname_dns); - plugin->hostname_dns = NULL; - } if (plugin->service != NULL) GNUNET_SERVICE_stop (plugin->service); else GNUNET_SERVER_destroy (plugin->server); GNUNET_free (plugin->handlers); - while (NULL != (lal = plugin->lal_head)) - { - GNUNET_CONTAINER_DLL_remove (plugin->lal_head, - plugin->lal_tail, - lal); - if (lal->nat != NULL) - GNUNET_NAT_unregister (lal->nat); - GNUNET_free_non_null (lal->external_nat_address); - GNUNET_free (lal); - } + if (plugin->nat != NULL) + GNUNET_NAT_unregister (plugin->nat); while (NULL != (tcp_probe = plugin->probe_head)) - { - GNUNET_CONTAINER_DLL_remove (plugin->probe_head, - plugin->probe_tail, - tcp_probe); - GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); - GNUNET_free (tcp_probe); - } - - if ((plugin->behind_nat == GNUNET_YES) && - (plugin->enable_nat_server == GNUNET_YES)) - { - if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM)) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); - GNUNET_OS_process_wait (plugin->server_proc); - GNUNET_OS_process_close (plugin->server_proc); - plugin->server_proc = NULL; - } - GNUNET_free_non_null(plugin->bind_address); + { + GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, + tcp_probe); + GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); + GNUNET_free (tcp_probe); + } + GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); + GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap); GNUNET_free (plugin); GNUNET_free (api); return NULL;