From: Matthias Wachs Date: Thu, 16 Feb 2012 11:54:12 +0000 (+0000) Subject: - fixing assertion in gnunet_service_ats_addresses X-Git-Tag: initial-import-from-subversion-38251~14842 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=e686141383bfc85a709d125f6d37d23918937028;hp=6788139a93a9f114971c3702bb449158f1f87746;p=oweals%2Fgnunet.git - fixing assertion in gnunet_service_ats_addresses --- diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 325ebaf8b..83db537fc 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -270,19 +270,22 @@ struct Session /** * Address of the other peer (either based on our 'connect' * call or on our 'accept' call). + * + * struct IPv4TcpAddress or struct IPv6TcpAddress + * */ - void *connect_addr; + void *addr; /** - * Last activity on this connection. Used to select preferred - * connection. + * Length of connect_addr. */ - struct GNUNET_TIME_Absolute last_activity; + size_t addrlen; /** - * Length of connect_addr. + * Last activity on this connection. Used to select preferred + * connection. */ - size_t connect_alen; + struct GNUNET_TIME_Absolute last_activity; /** * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO) @@ -326,11 +329,6 @@ struct Plugin */ struct GNUNET_NAT_Handle *nat; - /** - * List of open TCP sessions. - */ - struct Session *sessions; - struct GNUNET_CONTAINER_MultiHashMap * sessionmap; /** @@ -527,6 +525,27 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen) } +struct SessionClientCtx +{ + const struct GNUNET_SERVER_Client *client; + struct Session *ret; +}; + +int session_lookup_by_client_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct SessionClientCtx *sc_ctx = cls; + struct Session *s = value; + + if (s->client == sc_ctx->client) + { + sc_ctx->ret = s; + return GNUNET_NO; + } + return GNUNET_YES; +} + /** * Find the session handle for the given client. * @@ -535,15 +554,16 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen) * @return NULL if no matching session exists */ static struct Session * -find_session_by_client (struct Plugin *plugin, +lookup_session_by_client (struct Plugin *plugin, const struct GNUNET_SERVER_Client *client) { - struct Session *ret; + struct SessionClientCtx sc_ctx; + sc_ctx.client = client; + sc_ctx.ret = NULL; - ret = plugin->sessions; - while ((ret != NULL) && (client != ret->client)) - ret = ret->next; - return ret; + GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_lookup_by_client_it, &sc_ctx); + + return sc_ctx.ret; } @@ -570,20 +590,15 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, GNUNET_assert (client != NULL); 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)); -#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; - } ret->client = client; ret->target = *target; ret->expecting_welcome = GNUNET_YES; @@ -783,32 +798,16 @@ process_pending_messages (struct Session *session) static void disconnect_session (struct Session *session) { - struct Session *prev; - struct Session *pos; struct PendingMessage *pm; + struct Plugin * plugin = session->plugin; -#if DEBUG_TCP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Disconnecting from `%4s' at %s.\n", + "Disconnecting session %p for peer `%s' address `%s'\n", + session, GNUNET_i2s (&session->target), - (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; - } - if (prev == NULL) - session->plugin->sessions = session->next; - else - prev->next = session->next; + tcp_address_to_string(NULL, session->addr, session->addrlen)); + + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(plugin->sessionmap, &session->target.hashPubKey, session)); /* clean up state */ if (session->transmit_handle != NULL) @@ -856,7 +855,7 @@ disconnect_session (struct Session *session) GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# TCP sessions active"), -1, GNUNET_NO); - GNUNET_free_non_null (session->connect_addr); + GNUNET_free_non_null (session->addr); GNUNET_assert (NULL == session->transmit_handle); GNUNET_free (session); } @@ -921,11 +920,11 @@ tcp_plugin_send (void *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 (&session->target)); -#endif + process_pending_messages (session); return msgbuf_size; } @@ -937,18 +936,44 @@ struct SessionItCtx struct Session * result; }; -int session_it (void *cls, +int session_lookup_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) +#if 0 + char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); + char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + "Comparing: %s %u <-> %s %u\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); + GNUNET_free (a1); + GNUNET_free (a2); +#endif + if (session->addrlen != si_ctx->addrlen) + { return GNUNET_YES; - if (0 != memcmp (&session->connect_addr, si_ctx->addr, si_ctx->addrlen)) + } + if (0 != memcmp (session->addr, si_ctx->addr, si_ctx->addrlen)) + { return GNUNET_YES; - + } +#if 0 + a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); + a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + "Comparing: %s %u <-> %s %u , OK!\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); + GNUNET_free (a1); + GNUNET_free (a2); +#endif /* Found existing session */ si_ctx->result = session; return GNUNET_NO; @@ -987,12 +1012,33 @@ tcp_plugin_get_session (void *cls, addrlen = address->address_length; -#if DEBUG_TCP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Trying to get session for `%s' address length %i\n", tcp_address_to_string(NULL, address->address, address->address_length), addrlen); -#endif + + /* look for existing session */ + if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) + { + struct SessionItCtx si_ctx; + + si_ctx.addr = (void *) address->address; + si_ctx.addrlen = address->address_length; + + si_ctx.result = NULL; + + GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &address->peer.hashPubKey, &session_lookup_it, &si_ctx); + if (si_ctx.result != NULL) + { + session = si_ctx.result; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found exisiting session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); + return session; + } + } if (addrlen == sizeof (struct IPv6TcpAddress)) { @@ -1036,21 +1082,6 @@ tcp_plugin_get_session (void *cls, return NULL; } - /* look for existing session */ - if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) - { - struct SessionItCtx si_ctx; - si_ctx.addr = &sbs; - si_ctx.addrlen = sbs; - si_ctx.result = NULL; - GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &address->peer.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 */ @@ -1073,6 +1104,8 @@ tcp_plugin_get_session (void *cls, _("Found valid IPv4 NAT address (creating session)!\n")); #endif session = create_session (plugin, &address->peer, NULL, GNUNET_YES); + session->addrlen = 0; + session->addr = NULL; GNUNET_assert (session != NULL); GNUNET_assert (GNUNET_CONTAINER_multihashmap_put @@ -1100,18 +1133,18 @@ tcp_plugin_get_session (void *cls, 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 (&session->target), GNUNET_a2s (sb, sbs)); -#endif + GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); + session = create_session (plugin, &address->peer, GNUNET_SERVER_connect_socket (plugin->server, sa), GNUNET_NO); - session->connect_addr = GNUNET_malloc (addrlen); - memcpy (session->connect_addr, address->address, addrlen); - session->connect_alen = addrlen; + session->addr = GNUNET_malloc (addrlen); + memcpy (session->addr, address->address, addrlen); + session->addrlen = addrlen; if (addrlen != 0) { struct GNUNET_ATS_Information ats; @@ -1123,6 +1156,12 @@ tcp_plugin_get_session (void *cls, GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Creating new session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); + /* Send TCP Welcome */ process_pending_messages (session); @@ -1130,6 +1169,20 @@ tcp_plugin_get_session (void *cls, } +int session_disconnect_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct Session *session = value; + + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# transport-service disconnect requests for TCP"), + 1, GNUNET_NO); + disconnect_session (session); + return GNUNET_YES; +} + /** * Function that can be called to force a disconnect from the * specified neighbour. This should also cancel all previously @@ -1150,34 +1203,11 @@ static void tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; - struct Session *session; - struct Session *next; - struct PendingMessage *pm; -#if DEBUG_TCP 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); - } + "Disconnecting peer `%4s'\n", GNUNET_i2s (target)); + + GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &target->hashPubKey, session_disconnect_it, plugin); } @@ -1466,16 +1496,16 @@ handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, 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); + session->addr = t4; + session->addrlen = 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); + session->addr = t6; + session->addrlen = sizeof (struct IPv6TcpAddress); break; default: GNUNET_break_op (0); @@ -1491,8 +1521,8 @@ handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, } GNUNET_free (vaddr); - session->next = plugin->sessions; - plugin->sessions = session; + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &session->target.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); @@ -1531,42 +1561,42 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, 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", + "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); - session = find_session_by_client (plugin, client); - if (session == NULL) + session = lookup_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)); -#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)) { -#if DEBUG_TCP_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", - "Found address `%s' for incoming connection\n", + "Found existing session %p for peer `%s'\n", + session, GNUNET_a2s (vaddr, alen)); -#endif + GNUNET_free (vaddr); + } + } + else + { + 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 (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); + session->addr = t4; + session->addrlen = sizeof (struct IPv4TcpAddress); } else if (alen == sizeof (struct sockaddr_in6)) { @@ -1574,8 +1604,8 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, 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); + session->addr = t6; + session->addrlen = sizeof (struct IPv6TcpAddress); } struct GNUNET_ATS_Information ats; @@ -1591,19 +1621,7 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, "Did not obtain TCP socket address for incoming connection\n"); #endif } - 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 + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &wm->clientIdentity.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } if (session->expecting_welcome != GNUNET_YES) @@ -1614,6 +1632,10 @@ handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, } session->last_activity = GNUNET_TIME_absolute_get (); session->expecting_welcome = GNUNET_NO; + + + process_pending_messages (session); + GNUNET_SERVER_client_set_timeout (client, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_SERVER_receive_done (client, GNUNET_OK); @@ -1672,20 +1694,30 @@ handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } - session = find_session_by_client (plugin, client); - if ((NULL == session) || (GNUNET_YES == session->expecting_welcome)) + session = lookup_session_by_client (plugin, client); + if (NULL == session) { + /* No inbound session found */ + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + else if (GNUNET_YES == session->expecting_welcome) + { + /* Session is expecting WELCOME message */ + GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } + session->last_activity = GNUNET_TIME_absolute_get (); -#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)); -#endif + GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes received via TCP"), ntohs (message->size), GNUNET_NO); @@ -1697,14 +1729,13 @@ handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, 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); + delay = plugin->env->receive (plugin->env->cls, + &session->target, + message, + (const struct GNUNET_ATS_Information *) &distance, + 1, session, + (GNUNET_YES == session->inbound) ? NULL : session->addr, + (GNUNET_YES == session->inbound) ? 0 : session->addrlen); if (delay.rel_value == 0) { GNUNET_SERVER_receive_done (client, GNUNET_OK); @@ -1740,17 +1771,17 @@ disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) if (client == NULL) return; plugin->max_connections++; - session = find_session_by_client (plugin, client); + session = lookup_session_by_client (plugin, client); if (session == NULL) return; /* unknown, nothing to do */ #if 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 != + (session->addr != NULL) ? tcp_address_to_string (session->plugin, - session->connect_addr, - session->connect_alen) : + session->addr, + session->addrlen) : "*"); #endif GNUNET_STATISTICS_update (session->plugin->env->stats, @@ -2016,11 +2047,14 @@ libgnunet_plugin_transport_tcp_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - struct Session *session; struct TCPProbeContext *tcp_probe; - while (NULL != (session = plugin->sessions)) - disconnect_session (session); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Shutting down TCP plugin\n"); + + + /* Removing leftover sessions */ + GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL); + if (plugin->service != NULL) GNUNET_SERVICE_stop (plugin->service); else