- fixing assertion in gnunet_service_ats_addresses
authorMatthias Wachs <wachs@net.in.tum.de>
Thu, 16 Feb 2012 11:54:12 +0000 (11:54 +0000)
committerMatthias Wachs <wachs@net.in.tum.de>
Thu, 16 Feb 2012 11:54:12 +0000 (11:54 +0000)
src/transport/plugin_transport_tcp.c

index 325ebaf8b94ee0d1c2d90a664d3fd1630191efe0..83db537fc70779d018feba2dffd39d71dec64285 100644 (file)
@@ -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