-simplify logic
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
index 32bc65047463ac1e23deec8c08f637861a778db5..3a283e17b6f97c9f6d7ae68da9c8032eae5ab2ae 100644 (file)
@@ -1,6 +1,6 @@
 /*
   This file is part of GNUnet
-  Copyright (C) 2002--2014 Christian Grothoff (and other contributing authors)
+  Copyright (C) 2002--2015 Christian Grothoff (and other contributing authors)
 
   GNUnet is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
@@ -227,7 +227,7 @@ struct PendingMessage
   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
 
   /**
-   * Closure for transmit_cont.
+   * Closure for @e transmit_cont.
    */
   void *transmit_cont_cls;
 
@@ -239,7 +239,7 @@ struct PendingMessage
   /**
    * So that the gnunet-service-transport can group messages together,
    * these pending messages need to accept a message buffer and size
-   * instead of just a GNUNET_MessageHeader.
+   * instead of just a `struct GNUNET_MessageHeader`.
    */
   size_t message_size;
 
@@ -348,6 +348,64 @@ struct Session
 };
 
 
+/**
+ * Context for address to string conversion, closure
+ * for #append_port().
+ */
+struct PrettyPrinterContext
+{
+  /**
+   * DLL
+   */
+  struct PrettyPrinterContext *next;
+
+  /**
+   * DLL
+   */
+  struct PrettyPrinterContext *prev;
+
+  /**
+   * Our plugin.
+   */
+  struct Plugin *plugin;
+
+  /**
+   * Timeout task
+   */
+  struct GNUNET_SCHEDULER_Task *timeout_task;
+
+  /**
+   * Resolver handle
+   */
+  struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
+
+  /**
+   * Function to call with the result.
+   */
+  GNUNET_TRANSPORT_AddressStringCallback asc;
+
+  /**
+   * Clsoure for @e asc.
+   */
+  void *asc_cls;
+
+  /**
+   * IPv6 address
+   */
+  int ipv6;
+
+  /**
+   * Options
+   */
+  uint32_t options;
+
+  /**
+   * Port to add after the IP address.
+   */
+  uint16_t port;
+};
+
+
 /**
  * Encapsulation of all of the state of the plugin.
  */
@@ -419,6 +477,21 @@ struct Plugin
    */
   void *sic_cls;
 
+  /**
+   * ID of task used to update our addresses when one expires.
+   */
+  struct GNUNET_SCHEDULER_Task *address_update_task;
+
+  /**
+   * Running pretty printers: head
+   */
+  struct PrettyPrinterContext *ppc_dll_head;
+
+  /**
+   * Running pretty printers: tail
+   */
+  struct PrettyPrinterContext *ppc_dll_tail;
+
   /**
    * Welcome message used by this peer.
    */
@@ -434,11 +507,6 @@ struct Plugin
    */
   unsigned long long cur_connections;
 
-  /**
-   * ID of task used to update our addresses when one expires.
-   */
-  struct GNUNET_SCHEDULER_Task * address_update_task;
-
   /**
    * Address options
    */
@@ -492,53 +560,6 @@ notify_session_monitor (struct Plugin *plugin,
 }
 
 
-/**
- * Function called for a quick conversion of the binary address to
- * a numeric address.  Note that the caller must not free the
- * address and that the next call to this function is allowed
- * to override the address again.
- *
- * @param cls closure (`struct Plugin *`)
- * @param addr binary address
- * @param addrlen length of @a addr
- * @return string representing the same address
- */
-static const char *
-tcp_plugin_address_to_string (void *cls,
-                              const void *addr,
-                              size_t addrlen);
-
-
-/**
- * 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 @a addr
- * @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;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Accepting new incoming TCP connection from `%s'\n",
-       GNUNET_a2s (addr, addrlen));
-  if (plugin->cur_connections >= plugin->max_connections)
-    return GNUNET_NO;
-  plugin->cur_connections++;
-  return GNUNET_YES;
-}
-
-
 /**
  * Our external IP address/port mapping has changed.
  *
@@ -697,7 +718,7 @@ tcp_plugin_string_to_address (void *cls,
   address = NULL;
   plugin = NULL;
   optionstr = NULL;
-  if ((NULL == addr) || (addrlen == 0))
+  if ((NULL == addr) || (0 == addrlen))
   {
     GNUNET_break(0);
     return GNUNET_SYSERR;
@@ -733,9 +754,10 @@ tcp_plugin_string_to_address (void *cls,
   address[0] = '\0';
   address++;
 
-  if (GNUNET_OK
-      != GNUNET_STRINGS_to_address_ip (address, strlen (address),
-          &socket_address))
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_to_address_ip (address,
+                                   strlen (address),
+                                   &socket_address))
   {
     GNUNET_break(0);
     GNUNET_free(plugin);
@@ -789,7 +811,8 @@ static struct Session *
 lookup_session_by_client (struct Plugin *plugin,
                           struct GNUNET_SERVER_Client *client)
 {
-  return GNUNET_SERVER_client_get_user_context (client, struct Session);
+  return GNUNET_SERVER_client_get_user_context (client,
+                                                struct Session);
 }
 
 
@@ -829,14 +852,16 @@ tcp_plugin_disconnect_session (void *cls,
                                             session))
   {
     GNUNET_STATISTICS_update (session->plugin->env->stats,
-        gettext_noop ("# TCP sessions active"), -1, GNUNET_NO);
+                             gettext_noop ("# TCP sessions active"),
+                             -1,
+                             GNUNET_NO);
   }
   else
   {
-    GNUNET_assert(GNUNET_YES ==
-                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
-                                                        &session->target,
-                                                        session));
+    GNUNET_assert (GNUNET_YES ==
+                  GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
+                                                        &session->target,
+                                                        session));
   }
   if (NULL != session->client)
     GNUNET_SERVER_client_set_user_context (session->client,
@@ -899,18 +924,16 @@ tcp_plugin_disconnect_session (void *cls,
   if (NULL != session->receive_delay_task)
   {
     GNUNET_SCHEDULER_cancel (session->receive_delay_task);
-    if (NULL != session->client)
-      GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR);
+    session->receive_delay_task = NULL;
   }
   if (NULL != session->client)
   {
     GNUNET_SERVER_client_disconnect (session->client);
-    GNUNET_SERVER_client_drop (session->client);
     session->client = NULL;
   }
   GNUNET_HELLO_address_free (session->address);
-  GNUNET_assert(NULL == session->transmit_handle);
-  GNUNET_free(session);
+  GNUNET_assert (NULL == session->transmit_handle);
+  GNUNET_free (session);
   return GNUNET_OK;
 }
 
@@ -931,7 +954,7 @@ tcp_plugin_query_keepalive_factor (void *cls)
 
 
 /**
- * Session was idle, so disconnect it
+ * Session was idle for too long, so disconnect it
  *
  * @param cls the `struct Session` of the idle session
  * @param tc scheduler context
@@ -963,19 +986,20 @@ session_timeout (void *cls,
        GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                GNUNET_YES));
   /* call session destroy function */
-  tcp_plugin_disconnect_session (s->plugin, s);
+  tcp_plugin_disconnect_session (s->plugin,
+                                s);
 }
 
 
 /**
- * Increment session timeout due to activity
+ * Increment session timeout due to activity.
  *
  * @param s session to increment timeout for
  */
 static void
 reschedule_session_timeout (struct Session *s)
 {
-  GNUNET_assert(NULL != s->timeout_task);
+  GNUNET_assert (NULL != s->timeout_task);
   s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
 }
 
@@ -985,6 +1009,7 @@ reschedule_session_timeout (struct Session *s)
  *
  * @param plugin the plugin
  * @param address the address to create the session for
+ * @param scope network scope the address is from
  * @param client client to use, reference counter must have already been increased
  * @param is_nat this a NAT session, we should wait for a client to
  *               connect to us from an address, then assign that to
@@ -994,6 +1019,7 @@ reschedule_session_timeout (struct Session *s)
 static struct Session *
 create_session (struct Plugin *plugin,
                 const struct GNUNET_HELLO_Address *address,
+                enum GNUNET_ATS_Network_Type scope,
                 struct GNUNET_SERVER_Client *client,
                 int is_nat)
 {
@@ -1015,13 +1041,18 @@ create_session (struct Plugin *plugin,
   session->last_activity = GNUNET_TIME_absolute_get ();
   session->plugin = plugin;
   session->is_nat = is_nat;
-  session->client = client;
+  if (NULL != client)
+  {
+    session->client = client;
+    GNUNET_SERVER_client_set_user_context (client,
+                                           session);
+  }
   session->address = GNUNET_HELLO_address_copy (address);
   session->target = address->peer;
   session->expecting_welcome = GNUNET_YES;
-  session->scope = GNUNET_ATS_NET_UNSPECIFIED;
+  session->scope = scope;
   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
-      sizeof (struct WelcomeMessage));
+                     sizeof (struct WelcomeMessage));
   pm->msg = (const char *) &pm[1];
   pm->message_size = sizeof(struct WelcomeMessage);
   memcpy (&pm[1],
@@ -1029,7 +1060,8 @@ create_session (struct Plugin *plugin,
           sizeof(struct WelcomeMessage));
   pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
   GNUNET_STATISTICS_update (plugin->env->stats,
-                            gettext_noop ("# bytes currently in TCP buffers"), pm->message_size,
+                            gettext_noop ("# bytes currently in TCP buffers"),
+                           pm->message_size,
                             GNUNET_NO);
   GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
                                session->pending_messages_tail,
@@ -1085,7 +1117,9 @@ process_pending_messages (struct Session *session);
  * @return number of bytes written to @a buf
  */
 static size_t
-do_transmit (void *cls, size_t size, void *buf)
+do_transmit (void *cls,
+            size_t size,
+            void *buf)
 {
   struct Session *session = cls;
   struct GNUNET_PeerIdentity pid;
@@ -1251,11 +1285,12 @@ 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,
-                                                                  GNUNET_TIME_absolute_get_remaining (pm->timeout),
-                                                                  &do_transmit,
-                                                                  session);
+  session->transmit_handle
+    = GNUNET_SERVER_notify_transmit_ready (session->client,
+                                           pm->message_size,
+                                           GNUNET_TIME_absolute_get_remaining (pm->timeout),
+                                           &do_transmit,
+                                           session);
 }
 
 
@@ -1270,7 +1305,7 @@ process_pending_messages (struct Session *session)
  * @param cls closure
  * @param session which session must be used
  * @param msgbuf the message to transmit
- * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param msgbuf_size number of bytes in @a msgbuf
  * @param priority how important is the message (most plugins will
  *                 ignore message priority and just FIFO)
  * @param to how long to wait at most for the transmission (does not
@@ -1360,9 +1395,9 @@ tcp_plugin_send (void *cls,
                             GNUNET_TRANSPORT_SS_HANDSHAKE);
     return msgbuf_size;
   }
-  LOG(GNUNET_ERROR_TYPE_ERROR,
-      "Invalid session %p\n",
-      session);
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       "Invalid session %p\n",
+       session);
   if (NULL != cont)
     cont (cont_cls,
           &session->target,
@@ -1464,7 +1499,7 @@ tcp_plugin_update_session_timeout (void *cls,
  * Task to signal the server that we can continue
  * receiving from the TCP client now.
  *
- * @param cls the `struct Session*`
+ * @param cls the `struct Session *`
  * @param tc task context (unused)
  */
 static void
@@ -1475,8 +1510,8 @@ delayed_done (void *cls,
 
   session->receive_delay_task = NULL;
   reschedule_session_timeout (session);
-
-  GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
+  GNUNET_SERVER_receive_done (session->client,
+                             GNUNET_OK);
 }
 
 
@@ -1565,33 +1600,26 @@ tcp_plugin_get_session (void *cls,
 
     si_ctx.address = address;
     si_ctx.result = NULL;
-
     GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
                                                 &address->peer,
-                                                &session_lookup_it, &si_ctx);
+                                                &session_lookup_it,
+                                               &si_ctx);
     if (NULL != si_ctx.result)
     {
       session = si_ctx.result;
       LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Found existing session for `%s' address `%s' session %p\n",
+           "Found existing session for `%s' address `%s'\n",
            GNUNET_i2s (&address->peer),
            tcp_plugin_address_to_string (plugin,
                                          address->address,
-                                         address->address_length),
-           session);
+                                         address->address_length));
       return session;
     }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Existing sessions did not match address `%s' or peer `%s'\n",
-         tcp_plugin_address_to_string (plugin,
-                                       address->address,
-                                       address->address_length),
-        GNUNET_i2s (&address->peer));
   }
 
   if (addrlen == sizeof(struct IPv6TcpAddress))
   {
-    GNUNET_assert(NULL != address->address); /* make static analysis happy */
+    GNUNET_assert (NULL != address->address); /* make static analysis happy */
     t6 = address->address;
     options = t6->options;
     af = AF_INET6;
@@ -1627,15 +1655,20 @@ tcp_plugin_get_session (void *cls,
   }
   else
   {
-    GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop
-    ("# requests to create session with invalid address"), 1, GNUNET_NO);
+    GNUNET_STATISTICS_update (plugin->env->stats,
+                              gettext_noop ("# requests to create session with invalid address"),
+                              1,
+                              GNUNET_NO);
     return NULL;
   }
 
-  net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
+  net_type = plugin->env->get_address_type (plugin->env->cls,
+                                            sb,
+                                            sbs);
   GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
 
-  if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
+  if ( (is_natd == GNUNET_YES) &&
+       (addrlen == sizeof(struct IPv6TcpAddress)) )
   {
     /* NAT client only works with IPv4 addresses */
     return NULL;
@@ -1647,35 +1680,36 @@ tcp_plugin_get_session (void *cls,
     return NULL;
   }
 
-  if ((is_natd == GNUNET_YES)
-      && (GNUNET_YES
-          == GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
-              &address->peer)))
+  if ( (is_natd == GNUNET_YES) &&
+       (GNUNET_YES ==
+       GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
+                                               &address->peer)))
   {
     /* Only do one NAT punch attempt per peer identity */
     return NULL;
   }
 
-  if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
-      (GNUNET_NO ==
-       GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
-                                               &address->peer)))
+  if ( (is_natd == GNUNET_YES) &&
+       (NULL != plugin->nat) &&
+       (GNUNET_NO ==
+        GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
+                                                &address->peer)))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Found valid IPv4 NAT address (creating session)!\n");
     session = create_session (plugin,
                               address,
+                              net_type,
                               NULL,
                               GNUNET_YES);
-    session->scope = net_type;
     session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
                                                                     &nat_connect_timeout,
                                                                     session);
-    GNUNET_assert(GNUNET_OK ==
-                  GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
-                                                     &session->target,
-                                                     session,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
+                                                      &session->target,
+                                                      session,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
 
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Created NAT WAIT connection to `%4s' at `%s'\n",
@@ -1698,8 +1732,6 @@ tcp_plugin_get_session (void *cls,
   }
 
   /* create new outbound session */
-  GNUNET_assert(plugin->cur_connections <= plugin->max_connections);
-
   if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
   {
 #ifdef TCP_STEALTH
@@ -1751,10 +1783,6 @@ tcp_plugin_get_session (void *cls,
          GNUNET_a2s (sb, sbs));
     return NULL;
   }
-  plugin->cur_connections++;
-  if (plugin->cur_connections == plugin->max_connections)
-    GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
-
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
        GNUNET_i2s (&address->peer),
@@ -1762,15 +1790,14 @@ tcp_plugin_get_session (void *cls,
 
   session = create_session (plugin,
                             address,
-                            GNUNET_SERVER_connect_socket (plugin->server, sa),
+                            net_type,
+                            GNUNET_SERVER_connect_socket (plugin->server,
+                                                          sa),
                             GNUNET_NO);
-  session->scope = net_type;
-  GNUNET_SERVER_client_set_user_context (session->client,
-                                         session);
-  GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
-                                     &session->target,
-                                     session,
-                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
+                                            &session->target,
+                                            session,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
   /* Send TCP Welcome */
   process_pending_messages (session);
 
@@ -1778,6 +1805,16 @@ tcp_plugin_get_session (void *cls,
 }
 
 
+/**
+ * We have been asked to destroy all connections to a particular peer.
+ * This function is called on each applicable session and must tear it
+ * down.
+ *
+ * @param cls the `struct Plugin *`
+ * @param key the peer which the session belongs to (unused)
+ * @param value the `struct Session`
+ * @return #GNUNET_YES (continue to iterate)
+ */
 static int
 session_disconnect_it (void *cls,
                        const struct GNUNET_PeerIdentity *key,
@@ -1818,9 +1855,9 @@ tcp_plugin_disconnect (void *cls,
 {
   struct Plugin *plugin = cls;
 
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Disconnecting peer `%4s'\n",
-      GNUNET_i2s (target));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Disconnecting peer `%4s'\n",
+       GNUNET_i2s (target));
   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
                                               target,
                                               &session_disconnect_it,
@@ -1833,70 +1870,11 @@ tcp_plugin_disconnect (void *cls,
 
 
 /**
- * Running pretty printers: head
- */
-static struct PrettyPrinterContext *ppc_dll_head;
-
-/**
- * Running pretty printers: tail
- */
-static struct PrettyPrinterContext *ppc_dll_tail;
-
-/**
- * Context for address to string conversion, closure
- * for #append_port().
- */
-struct PrettyPrinterContext
-{
-  /**
-   * DLL
-   */
-  struct PrettyPrinterContext *next;
-
-  /**
-   * DLL
-   */
-  struct PrettyPrinterContext *prev;
-
-  /**
-   * Timeout task
-   */
-  struct GNUNET_SCHEDULER_Task * timeout_task;
-
-  /**
-   * Resolver handle
-   */
-  struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
-
-  /**
-   * Function to call with the result.
-   */
-  GNUNET_TRANSPORT_AddressStringCallback asc;
-
-  /**
-   * Clsoure for @e asc.
-   */
-  void *asc_cls;
-
-  /**
-   * Port to add after the IP address.
-   */
-  uint16_t port;
-
-  /**
-   * IPv6 address
-   */
-  int ipv6;
-
-  /**
-   * Options
-   */
-  uint32_t options;
-};
-
-
-/**
- * Append our port and forward the result.
+ * We are processing an address pretty printing request and finished
+ * the IP resolution (if applicable).  Append our port and forward the
+ * result.  If called with @a hostname NULL, we are done and should
+ * clean up the pretty printer (otherwise, there might be multiple
+ * hostnames for the IP address and we might receive more).
  *
  * @param cls the `struct PrettyPrinterContext *`
  * @param hostname hostname part of the address
@@ -1906,14 +1884,15 @@ append_port (void *cls,
              const char *hostname)
 {
   struct PrettyPrinterContext *ppc = cls;
+  struct Plugin *plugin = ppc->plugin;
   char *ret;
 
   if (NULL == hostname)
   {
     /* Final call, done */
     ppc->resolver_handle = NULL;
-    GNUNET_CONTAINER_DLL_remove (ppc_dll_head,
-                                 ppc_dll_tail,
+    GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
+                                 plugin->ppc_dll_tail,
                                  ppc);
     ppc->asc (ppc->asc_cls,
               NULL,
@@ -1943,10 +1922,9 @@ append_port (void *cls,
 
 
 /**
- * Convert the transports address to a nice, human-readable
- * format.
+ * Convert the transports address to a nice, human-readable format.
  *
- * @param cls closure
+ * @param cls closure with the `struct Plugin`
  * @param type name of the transport that generated the address
  * @param addr one of the addresses of the host, NULL for the last address
  *        the specific address format depends on the transport
@@ -1966,6 +1944,7 @@ tcp_plugin_address_pretty_printer (void *cls,
                                    GNUNET_TRANSPORT_AddressStringCallback asc,
                                    void *asc_cls)
 {
+  struct Plugin *plugin = cls;
   struct PrettyPrinterContext *ppc;
   const void *sb;
   size_t sbs;
@@ -2008,6 +1987,7 @@ tcp_plugin_address_pretty_printer (void *cls,
     return;
   }
   ppc = GNUNET_new (struct PrettyPrinterContext);
+  ppc->plugin = plugin;
   if (addrlen == sizeof(struct IPv6TcpAddress))
     ppc->ipv6 = GNUNET_YES;
   else
@@ -2027,8 +2007,8 @@ tcp_plugin_address_pretty_printer (void *cls,
     GNUNET_free (ppc);
     return;
   }
-  GNUNET_CONTAINER_DLL_insert (ppc_dll_head,
-                               ppc_dll_tail,
+  GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
+                               plugin->ppc_dll_tail,
                                ppc);
 }
 
@@ -2044,13 +2024,16 @@ 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))
+  if ( (in_port == plugin->adv_port) ||
+       (in_port == plugin->open_port) )
     return GNUNET_OK;
   return GNUNET_SYSERR;
 }
 
+
 /**
  * Function that will be called to check if a binary address for this
  * plugin is well-formed and corresponds to an address for THIS peer
@@ -2062,66 +2045,73 @@ check_port (struct Plugin *plugin, uint16_t in_port)
  *
  * @param cls closure, our `struct Plugin *`
  * @param addr pointer to the address
- * @param addrlen length of addr
+ * @param addrlen length of @a addr
  * @return #GNUNET_OK if this is a plausible address for this peer
  *         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;
-  struct IPv6TcpAddress *v6;
+  const struct IPv4TcpAddress *v4;
+  const struct IPv6TcpAddress *v6;
 
-  if ((addrlen != sizeof(struct IPv4TcpAddress))
-      && (addrlen != sizeof(struct IPv6TcpAddress)))
+  if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
+       (addrlen != sizeof(struct IPv6TcpAddress)) )
   {
-    GNUNET_break_op(0);
+    GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
 
   if (addrlen == sizeof(struct IPv4TcpAddress))
   {
-    v4 = (struct IPv4TcpAddress *) addr;
+    v4 = (const struct IPv4TcpAddress *) addr;
     if (0 != memcmp (&v4->options,
                      &plugin->myoptions,
                      sizeof(uint32_t)))
     {
-      GNUNET_break(0);
+      GNUNET_break (0);
       return GNUNET_SYSERR;
     }
-    if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port)))
+    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)))
+    if (GNUNET_OK !=
+       GNUNET_NAT_test_address (plugin->nat,
+                                &v4->ipv4_addr,
+                                sizeof (struct in_addr)))
       return GNUNET_SYSERR;
   }
   else
   {
-    v6 = (struct IPv6TcpAddress *) addr;
+    v6 = (const struct IPv6TcpAddress *) addr;
     if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
     {
-      GNUNET_break_op(0);
+      GNUNET_break_op (0);
       return GNUNET_SYSERR;
     }
     if (0 != memcmp (&v6->options,
                      &plugin->myoptions,
                      sizeof (uint32_t)))
     {
-      GNUNET_break(0);
+      GNUNET_break (0);
       return GNUNET_SYSERR;
     }
-    if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port)))
+    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)))
+    if (GNUNET_OK !=
+       GNUNET_NAT_test_address (plugin->nat,
+                                &v6->ipv6_addr,
+                                sizeof(struct in6_addr)))
       return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
 
+
 /**
  * We've received a nat probe from this peer via TCP.  Finish
  * creating the client session and resume sending of queued
@@ -2157,7 +2147,8 @@ handle_tcp_nat_probe (void *cls,
   if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
   {
     GNUNET_break_op(0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_SYSERR);
     return;
   }
 
@@ -2166,41 +2157,52 @@ handle_tcp_nat_probe (void *cls,
           sizeof(struct GNUNET_PeerIdentity)))
   {
     /* refuse connections from ourselves */
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_SYSERR);
     return;
   }
 
   session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
                                                &tcp_nat_probe->clientIdentity);
-  if (session == NULL)
+  if (NULL == session)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Did NOT find session for NAT probe!\n");
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_OK);
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Found session for NAT probe!\n");
 
-  if (session->nat_connection_timeout != NULL)
+  if (NULL != session->nat_connection_timeout)
   {
     GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
     session->nat_connection_timeout = NULL;
   }
 
-  if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
+  if (GNUNET_OK !=
+      GNUNET_SERVER_client_get_address (client,
+                                       &vaddr,
+                                       &alen))
   {
     GNUNET_break(0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVER_receive_done (client,
+                               GNUNET_SYSERR);
     tcp_plugin_disconnect_session (plugin,
                                    session);
     return;
   }
-  GNUNET_assert(
-      GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity, session) == GNUNET_YES);
-  GNUNET_SERVER_client_set_user_context(client, session);
-  GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap, &session->target,
-      session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
+                                                      &tcp_nat_probe->clientIdentity,
+                                                      session));
+  GNUNET_SERVER_client_set_user_context (client,
+                                        session);
+  (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
+                                           &session->target,
+                                           session,
+                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
   session->last_activity = GNUNET_TIME_absolute_get ();
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Found address `%s' for incoming connection\n",
@@ -2236,19 +2238,22 @@ handle_tcp_nat_probe (void *cls,
     LOG(GNUNET_ERROR_TYPE_DEBUG,
         "Bad address for incoming connection!\n");
     GNUNET_free(vaddr);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_SYSERR);
     tcp_plugin_disconnect_session (plugin,
                                    session);
     return;
   }
-  GNUNET_free(vaddr);
-  GNUNET_break(NULL == session->client);
-  GNUNET_SERVER_client_keep (client);
+  GNUNET_free (vaddr);
+  GNUNET_break (NULL == session->client);
   session->client = client;
   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);
+  GNUNET_SERVER_receive_done (client,
+                             GNUNET_OK);
 }
 
 
@@ -2320,12 +2325,6 @@ handle_tcp_welcome (void *cls,
   }
   else
   {
-    GNUNET_SERVER_client_keep (client);
-    if (NULL != plugin->service) /* Otherwise value is incremented in tcp_access_check */
-      plugin->cur_connections++;
-    if (plugin->cur_connections == plugin->max_connections)
-      GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
-
     if (GNUNET_OK ==
         GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
     {
@@ -2359,19 +2358,21 @@ handle_tcp_welcome (void *cls,
       {
         GNUNET_break (0);
         GNUNET_free_non_null (vaddr);
+        GNUNET_SERVER_receive_done (client,
+                                    GNUNET_SYSERR);
         return;
       }
       session = create_session (plugin,
                                 address,
+                                plugin->env->get_address_type (plugin->env->cls,
+                                                               vaddr,
+                                                               alen),
                                 client,
                                 GNUNET_NO);
+      GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
       GNUNET_HELLO_address_free (address);
-      session->scope
-        = plugin->env->get_address_type (plugin->env->cls,
-                                         vaddr,
-                                         alen);
       LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Creating new%s session %p for peer `%s' client %p \n",
+           "Creating new%s session %p for peer `%s' client %p\n",
            GNUNET_HELLO_address_check_option (session->address,
                                               GNUNET_HELLO_ADDRESS_INFO_INBOUND)
            ? " inbound" : "",
@@ -2381,25 +2382,23 @@ handle_tcp_welcome (void *cls,
                                          session->address->address_length),
            client);
       GNUNET_free (vaddr);
-      GNUNET_SERVER_client_set_user_context (session->client, session);
-      GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
-                                         &session->target,
-                                         session,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+      (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
+                                                &session->target,
+                                                session,
+                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
       /* Notify transport and ATS about new session */
       plugin->env->session_start (plugin->env->cls,
                                   session->address,
                                   session,
                                   session->scope);
-      notify_session_monitor (plugin,
-                              session,
-                              GNUNET_TRANSPORT_SS_INIT);
     }
     else
     {
       LOG(GNUNET_ERROR_TYPE_DEBUG,
           "Did not obtain TCP socket address for incoming connection\n");
       GNUNET_break(0);
+      GNUNET_SERVER_receive_done (client,
+                                  GNUNET_SYSERR);
       return;
     }
   }
@@ -2407,7 +2406,8 @@ handle_tcp_welcome (void *cls,
   if (session->expecting_welcome != GNUNET_YES)
   {
     GNUNET_break_op(0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_SYSERR);
     GNUNET_break(0);
     return;
   }
@@ -2416,8 +2416,9 @@ handle_tcp_welcome (void *cls,
 
   process_pending_messages (session);
   GNUNET_SERVER_client_set_timeout (client,
-      GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+                                    GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+  GNUNET_SERVER_receive_done (client,
+                              GNUNET_OK);
 }
 
 
@@ -2470,7 +2471,7 @@ handle_tcp_data (void *cls,
     GNUNET_free_non_null (vaddr);
     return;
   }
-  else if (GNUNET_YES == session->expecting_welcome)
+  if (GNUNET_YES == session->expecting_welcome)
   {
     /* Session is expecting WELCOME message */
     void *vaddr;
@@ -2511,24 +2512,64 @@ handle_tcp_data (void *cls,
   reschedule_session_timeout (session);
   if (0 == delay.rel_value_us)
   {
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_SERVER_receive_done (client,
+                                GNUNET_OK);
   }
   else
   {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Throttling receiving from `%s' for %s\n",
-        GNUNET_i2s (&session->target),
-        GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Throttling receiving from `%s' for %s\n",
+         GNUNET_i2s (&session->target),
+         GNUNET_STRINGS_relative_time_to_string (delay,
+                                                 GNUNET_YES));
     GNUNET_SERVER_disable_receive_done_warning (client);
+    GNUNET_assert (NULL == session->receive_delay_task);
     session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
-        &delayed_done, session);
+                                                                &delayed_done,
+                                                                session);
   }
 }
 
 
 /**
- * Functions with this signature are called whenever a peer
- * is disconnected on the network level.
+ * Function called whenever a peer is connected on the "SERVER" level.
+ * Increments number of active connections and suspends server if we
+ * have reached the limit.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+static void
+connect_notify (void *cls,
+               struct GNUNET_SERVER_Client *client)
+{
+  struct Plugin *plugin = cls;
+
+  plugin->cur_connections++;
+  GNUNET_STATISTICS_set (plugin->env->stats,
+                         gettext_noop ("# TCP server connections active"),
+                         plugin->cur_connections,
+                         GNUNET_NO);
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                           gettext_noop ("# TCP server connect events"),
+                           1,
+                           GNUNET_NO);
+  if (plugin->cur_connections != plugin->max_connections)
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+             _("TCP connection limit reached, suspending server\n"));
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                           gettext_noop ("# TCP service suspended"),
+                           1,
+                           GNUNET_NO);
+  GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
+}
+
+
+/**
+ * Function called whenever a peer is disconnected on the "SERVER"
+ * level.  Cleans up the connection, decrements number of active
+ * connections and if applicable resumes listening.
  *
  * @param cls closure
  * @param client identification of the client
@@ -2553,25 +2594,32 @@ disconnect_notify (void *cls,
                                      session->address->address_length));
 
   if (plugin->cur_connections == plugin->max_connections)
+  {
+    GNUNET_STATISTICS_update (session->plugin->env->stats,
+                              gettext_noop ("# TCP service resumed"),
+                              1,
+                              GNUNET_NO);
     GNUNET_SERVER_resume (plugin->server); /* Resume server  */
-
-  if (plugin->cur_connections < 1)
-    GNUNET_break(0);
-  else
-    plugin->cur_connections--;
-
-  GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop
-                            ("# network-level TCP disconnect events"),
+  }
+  GNUNET_assert (plugin->cur_connections >= 1);
+  plugin->cur_connections--;
+  GNUNET_STATISTICS_set (plugin->env->stats,
+                         gettext_noop ("# TCP server connections active"),
+                         plugin->cur_connections,
+                         GNUNET_NO);
+  GNUNET_STATISTICS_update (session->plugin->env->stats,
+                            gettext_noop ("# network-level TCP disconnect events"),
                             1,
                             GNUNET_NO);
-  tcp_plugin_disconnect_session (plugin, session);
+  tcp_plugin_disconnect_session (plugin,
+                                session);
 }
 
 
 /**
  * We can now send a probe message, copy into buffer to really send.
  *
- * @param cls closure, a struct TCPProbeContext
+ * @param cls closure, a `struct TCPProbeContext`
  * @param size max size to copy
  * @param buf buffer to copy message to
  * @return number of bytes copied into @a buf
@@ -2589,18 +2637,20 @@ notify_send_probe (void *cls,
   GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
                                plugin->probe_tail,
                                tcp_probe_ctx);
-  if (buf == NULL)
+  if (NULL == buf)
   {
     GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
     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));
+  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);
+  GNUNET_free (tcp_probe_ctx);
   return ret;
 }
 
@@ -2627,8 +2677,10 @@ try_connection_reversal (void *cls,
    * 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, addr, addrlen);
-  if (sock == NULL)
+  sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
+                                                addr,
+                                                addrlen);
+  if (NULL == sock)
   {
     /* failed for some odd reason (out of sockets?); ignore attempt */
     return;
@@ -2658,7 +2710,7 @@ try_connection_reversal (void *cls,
 /**
  * Function obtain the network type for a session
  *
- * @param cls closure ('struct Plugin*')
+ * @param cls closure (`struct Plugin *`)
  * @param session the session
  * @return the network type in HBO or #GNUNET_SYSERR
  */
@@ -2949,9 +3001,11 @@ libgnunet_plugin_transport_tcp_init (void *cls)
       goto die;
     }
     plugin->server
-      = GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check,
-                                           plugin, NULL,
-                                           idle_timeout, GNUNET_YES);
+      = GNUNET_SERVER_create_with_sockets (NULL,
+                                           plugin,
+                                          NULL,
+                                           idle_timeout,
+                                          GNUNET_YES);
   }
   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
   memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
@@ -2960,6 +3014,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
 
   GNUNET_SERVER_add_handlers (plugin->server,
                               plugin->handlers);
+  GNUNET_SERVER_connect_notify (plugin->server,
+                               &connect_notify,
+                               plugin);
   GNUNET_SERVER_disconnect_notify (plugin->server,
                                    &disconnect_notify,
                                    plugin);
@@ -2978,7 +3035,6 @@ libgnunet_plugin_transport_tcp_init (void *cls)
          _("TCP transport advertises itself as being on port %llu\n"),
          aport);
   /* Initially set connections to 0 */
-  GNUNET_assert(NULL != plugin->env->stats);
   GNUNET_STATISTICS_set (plugin->env->stats,
                          gettext_noop ("# TCP sessions active"),
                          0,
@@ -3029,14 +3085,16 @@ libgnunet_plugin_transport_tcp_done (void *cls)
                                          &session_disconnect_it,
                                          plugin);
 
-  for (cur = ppc_dll_head; NULL != cur; cur = next)
+  for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
   {
     next = cur->next;
-    GNUNET_CONTAINER_DLL_remove (ppc_dll_head,
-                                 ppc_dll_tail,
+    GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
+                                 plugin->ppc_dll_tail,
                                  cur);
     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
-    cur->asc (cur->asc_cls, NULL, GNUNET_OK);
+    cur->asc (cur->asc_cls,
+             NULL,
+             GNUNET_OK);
     GNUNET_free (cur);
   }
 
@@ -3044,7 +3102,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
     GNUNET_SERVICE_stop (plugin->service);
   else
     GNUNET_SERVER_destroy (plugin->server);
-  GNUNET_free(plugin->handlers);
+  GNUNET_free (plugin->handlers);
   if (NULL != plugin->nat)
     GNUNET_NAT_unregister (plugin->nat);
   while (NULL != (tcp_probe = plugin->probe_head))
@@ -3053,12 +3111,13 @@ libgnunet_plugin_transport_tcp_done (void *cls)
                                  plugin->probe_tail,
                                  tcp_probe);
     GNUNET_CONNECTION_destroy (tcp_probe->sock);
-    GNUNET_free(tcp_probe);
+    GNUNET_free (tcp_probe);
   }
   GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
-  GNUNET_free(plugin);
-  GNUNET_free(api);
+  GNUNET_break (0 == plugin->cur_connections);
+  GNUNET_free (plugin);
+  GNUNET_free (api);
   return NULL;
 }