call GNUNET_SERVER_receive_done() also on internal error paths
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
index 315d32131dd5de0d4def0f4d90f37f721bb433de..17e30c0b790c087e1fa50710426f32b7d4b7175d 100644 (file)
@@ -826,6 +826,9 @@ set_alternative_address (struct NeighbourMapEntry *n,
   n->alternative_address.session = session;
   n->alternative_address.ats_active = GNUNET_NO;
   n->alternative_address.keep_alive_nonce = 0;
+  GNUNET_assert (GNUNET_YES ==
+                 GST_ats_is_known (n->alternative_address.address,
+                                   n->alternative_address.session));
 }
 
 
@@ -839,37 +842,29 @@ set_alternative_address (struct NeighbourMapEntry *n,
  *        address must be setup)
  * @param bandwidth_in inbound quota to be used when connection is up
  * @param bandwidth_out outbound quota to be used when connection is up
- * @param is_active #GNUNET_YES to mark this as the active address with ATS
  */
 static void
 set_primary_address (struct NeighbourMapEntry *n,
                      const struct GNUNET_HELLO_Address *address,
                      struct Session *session,
                      struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
-                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
-                     int is_active)
+                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
 {
   if (session == n->primary_address.session)
   {
-    if (is_active != n->primary_address.ats_active)
+    GST_validation_set_address_use (n->primary_address.address,
+                                    GNUNET_YES);
+    if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
     {
-      n->primary_address.ats_active = is_active;
-      GST_validation_set_address_use (n->primary_address.address,
-                                      is_active);
+      n->primary_address.bandwidth_in = bandwidth_in;
+      GST_neighbours_set_incoming_quota (&address->peer,
+                                         bandwidth_in);
     }
-    if (GNUNET_YES == is_active)
+    if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
     {
-      if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
-      {
-        n->primary_address.bandwidth_in = bandwidth_in;
-        GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in);
-      }
-      if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
-      {
-        n->primary_address.bandwidth_out = bandwidth_out;
-        send_outbound_quota (&address->peer,
-                             bandwidth_out);
-      }
+      n->primary_address.bandwidth_out = bandwidth_out;
+      send_outbound_quota (&address->peer,
+                           bandwidth_out);
     }
     return;
   }
@@ -897,18 +892,17 @@ set_primary_address (struct NeighbourMapEntry *n,
   n->primary_address.bandwidth_in = bandwidth_in;
   n->primary_address.bandwidth_out = bandwidth_out;
   n->primary_address.session = session;
-  n->primary_address.ats_active = is_active;
   n->primary_address.keep_alive_nonce = 0;
-  if (GNUNET_YES == is_active)
-  {
-    /* subsystems about address use */
-    GST_validation_set_address_use (n->primary_address.address,
-                                    GNUNET_YES);
-    GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in);
-    send_outbound_quota (&address->peer,
-                         bandwidth_out);
-  }
-
+  GNUNET_assert (GNUNET_YES ==
+                 GST_ats_is_known (n->primary_address.address,
+                                   n->primary_address.session));
+  /* subsystems about address use */
+  GST_validation_set_address_use (n->primary_address.address,
+                                  GNUNET_YES);
+  GST_neighbours_set_incoming_quota (&address->peer,
+                                     bandwidth_in);
+  send_outbound_quota (&address->peer,
+                       bandwidth_out);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Neighbour `%s' switched to address `%s'\n",
               GNUNET_i2s (&n->id),
@@ -1046,7 +1040,7 @@ send_with_session (struct NeighbourMapEntry *n,
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
   struct GNUNET_TIME_Relative result = GNUNET_TIME_UNIT_FOREVER_REL;
 
-  GNUNET_assert (n->primary_address.session != NULL);
+  GNUNET_assert (NULL != n->primary_address.session);
   if ( ((NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name)) ||
         (-1 == papi->send (papi->cls,
                            n->primary_address.session,
@@ -1236,13 +1230,20 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
 static void
 transmit_send_continuation (void *cls,
                             const struct GNUNET_PeerIdentity *receiver,
-                            int success, size_t size_payload, size_t physical)
+                            int success,
+                            size_t size_payload,
+                            size_t physical)
 {
   struct MessageQueue *mq = cls;
   struct NeighbourMapEntry *n;
 
   if (NULL == (n = lookup_neighbour (receiver)))
   {
+    if (NULL != mq->cont)
+      mq->cont (mq->cont_cls,
+                GNUNET_SYSERR /* not connected */,
+                size_payload,
+                0);
     GNUNET_free (mq);
     return; /* disconnect or other error while transmitting, can happen */
   }
@@ -1267,7 +1268,6 @@ transmit_send_continuation (void *cls,
     GNUNET_break (0);
   }
 
-
   GNUNET_break (size_payload == mq->message_buf_size);
   bytes_in_send_queue -= mq->message_buf_size;
   GNUNET_STATISTICS_set (GST_stats,
@@ -1339,9 +1339,9 @@ try_transmission_to_peer (struct NeighbourMapEntry *n)
     if (timeout.rel_value_us > 0)
       break;
     GNUNET_STATISTICS_update (GST_stats,
-                             gettext_noop
-                             ("# messages timed out while in transport queue"),
-                             1, GNUNET_NO);
+                             gettext_noop ("# messages timed out while in transport queue"),
+                             1,
+                              GNUNET_NO);
     GNUNET_CONTAINER_DLL_remove (n->messages_head,
                                  n->messages_tail,
                                  mq);
@@ -1396,10 +1396,11 @@ send_keepalive (struct NeighbourMapEntry *n)
 
   nonce = 0; /* 0 indicates 'not set' */
   while (0 == nonce)
-    nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+    nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                      UINT32_MAX);
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending keep alive to peer `%s' with nonce %u\n",
+              "Sending KEEPALIVE to peer `%s' with nonce %u\n",
               GNUNET_i2s (&n->id),
               nonce);
   m.header.size = htons (sizeof (struct SessionKeepAliveMessage));
@@ -1414,7 +1415,7 @@ send_keepalive (struct NeighbourMapEntry *n)
                                GNUNET_YES,
                               NULL, NULL);
   GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop ("# keepalives sent"),
+                            gettext_noop ("# KEEPALIVES sent"),
                             1,
                            GNUNET_NO);
   n->primary_address.keep_alive_nonce = nonce;
@@ -1440,9 +1441,12 @@ GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
   struct SessionKeepAliveMessage msg;
 
   if (sizeof (struct SessionKeepAliveMessage) != ntohs (m->size))
+  {
+    GNUNET_break_op (0);
     return;
+  }
 
-  msg_in = (struct SessionKeepAliveMessage *) m;
+  msg_in = (const struct SessionKeepAliveMessage *) m;
   if (NULL == (n = lookup_neighbour (neighbour)))
   {
     GNUNET_STATISTICS_update (GST_stats,
@@ -1461,8 +1465,13 @@ GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
   }
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Received keep alive request from peer `%s' with nonce %u\n",
-      GNUNET_i2s (&n->id), ntohl (msg_in->nonce));
+              "Received KEEPALIVE request from peer `%s' with nonce %u\n",
+              GNUNET_i2s (&n->id),
+              ntohl (msg_in->nonce));
+  GNUNET_STATISTICS_update (GST_stats,
+                            gettext_noop ("# KEEPALIVES received in good order"),
+                            1,
+                           GNUNET_NO);
 
   /* send reply to allow neighbour to measure latency */
   msg.header.size = htons (sizeof (struct SessionKeepAliveMessage));
@@ -1493,61 +1502,70 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
   struct NeighbourMapEntry *n;
   const struct SessionKeepAliveMessage *msg;
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
-  struct GNUNET_ATS_Information ats;
   struct GNUNET_TIME_Relative latency;
 
   if (sizeof (struct SessionKeepAliveMessage) != ntohs (m->size))
+  {
+    GNUNET_break_op (0);
     return;
+  }
 
   msg = (const struct SessionKeepAliveMessage *) m;
   if (NULL == (n = lookup_neighbour (neighbour)))
   {
     GNUNET_STATISTICS_update (GST_stats,
-                              gettext_noop
-                              ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
-                              1, GNUNET_NO);
+                              gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not connected)"),
+                              1,
+                              GNUNET_NO);
     return;
   }
   if ( (GNUNET_TRANSPORT_PS_CONNECTED != n->state) ||
        (GNUNET_YES != n->expect_latency_response) )
   {
     GNUNET_STATISTICS_update (GST_stats,
-                              gettext_noop
-                              ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
-                              1, GNUNET_NO);
+                              gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not expected)"),
+                              1,
+                              GNUNET_NO);
     return;
   }
   if (NULL == n->primary_address.address)
   {
     GNUNET_STATISTICS_update (GST_stats,
-                              gettext_noop
-                              ("# KEEPALIVE_RESPONSE messages discarded (address changed)"),
-                              1, GNUNET_NO);
+                              gettext_noop ("# KEEPALIVE_RESPONSEs discarded (address changed)"),
+                              1,
+                              GNUNET_NO);
     return;
   }
   if (n->primary_address.keep_alive_nonce != ntohl (msg->nonce))
   {
-    GNUNET_STATISTICS_update (GST_stats,
-                              gettext_noop
-                              ("# KEEPALIVE_RESPONSE messages discarded (wrong nonce)"),
-                              1, GNUNET_NO);
+    if (0 == n->primary_address.keep_alive_nonce)
+      GNUNET_STATISTICS_update (GST_stats,
+                                gettext_noop ("# KEEPALIVE_RESPONSEs discarded (no nonce)"),
+                                1,
+                                GNUNET_NO);
+    else
+      GNUNET_STATISTICS_update (GST_stats,
+                                gettext_noop ("# KEEPALIVE_RESPONSEs discarded (bad nonce)"),
+                                1,
+                                GNUNET_NO);
     return;
   }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-        "Received keep alive response from peer `%s' for session %p\n",
-        GNUNET_i2s (&n->id), n->primary_address.session);
+  GNUNET_STATISTICS_update (GST_stats,
+                            gettext_noop ("# KEEPALIVE_RESPONSEs received (OK)"),
+                            1,
+                            GNUNET_NO);
 
-  }
 
   /* Update session timeout here */
   if (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name)))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-        "Updating session for peer `%s' for session %p\n",
-        GNUNET_i2s (&n->id), n->primary_address.session);
-    papi->update_session_timeout (papi->cls, &n->id, n->primary_address.session);
+                "Updating session for peer `%s' for session %p\n",
+                GNUNET_i2s (&n->id),
+                n->primary_address.session);
+    papi->update_session_timeout (papi->cls,
+                                  &n->id,
+                                  n->primary_address.session);
   }
   else
   {
@@ -1562,18 +1580,13 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
 
   latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Latency for peer `%s' is %s\n",
+              "Received KEEPALIVE_RESPONSE from peer `%s', latency is %s\n",
               GNUNET_i2s (&n->id),
              GNUNET_STRINGS_relative_time_to_string (latency,
                                                      GNUNET_YES));
-  /* append latency */
-  ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
-  ats.value = htonl ( (latency.rel_value_us > UINT32_MAX)
-                      ? UINT32_MAX
-                      : (uint32_t) latency.rel_value_us );
-  GST_ats_update_metrics (n->primary_address.address,
-                          n->primary_address.session,
-                          &ats, 1);
+  GST_ats_update_delay (n->primary_address.address,
+                        GNUNET_TIME_relative_divide (latency,
+                                                     2));
 }
 
 
@@ -1590,8 +1603,9 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
  * @return how long to wait before reading more from this sender
  */
 struct GNUNET_TIME_Relative
-GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
-                                        *sender, ssize_t size, int *do_forward)
+GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity *sender,
+                                        ssize_t size,
+                                        int *do_forward)
 {
   struct NeighbourMapEntry *n;
   struct GNUNET_TIME_Relative ret;
@@ -1692,14 +1706,20 @@ GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
   {
     GNUNET_break (0);
     if (NULL != cont)
-      cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
+      cont (cont_cls,
+            GNUNET_SYSERR,
+            msg_size,
+            0);
     return;
   }
   if (GNUNET_YES != test_connected (n))
   {
     GNUNET_break (0);
     if (NULL != cont)
-      cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
+      cont (cont_cls,
+            GNUNET_SYSERR,
+            msg_size,
+            0);
     return;
   }
   bytes_in_send_queue += msg_size;
@@ -1715,10 +1735,13 @@ GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
   mq->message_buf_size = msg_size;
   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enqueueing %u bytes to send to peer %s\n",
-      msg_size, GNUNET_i2s (target));
-
-  GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Enqueueing %u bytes to send to peer %s\n",
+              msg_size,
+              GNUNET_i2s (target));
+  GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
+                                    n->messages_tail,
+                                    mq);
   if (NULL != n->task)
     GNUNET_SCHEDULER_cancel (n->task);
   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
@@ -1890,6 +1913,7 @@ send_syn (struct NeighbourAddress *na)
         disconnect_neighbour (n);
         break;
     }
+    return;
   }
   GST_neighbours_notify_data_sent (na->address,
                                    na->session,
@@ -2123,16 +2147,6 @@ struct BlacklistCheckSwitchContext
    */
   struct GST_BlacklistCheck *blc;
 
-  /**
-   * Address we are asking the blacklist subsystem about.
-   */
-  struct GNUNET_HELLO_Address *address;
-
-  /**
-   * Session we should use in conjunction with @e address, can be NULL.
-   */
-  struct Session *session;
-
   /**
    * Inbound bandwidth that was assigned to @e address.
    */
@@ -2151,11 +2165,17 @@ struct BlacklistCheckSwitchContext
  *
  * @param cls blc_ctx bl context
  * @param peer the peer
- * @param result the result
+ * @param address address associated with the request
+ * @param session session associated with the request
+ * @param result #GNUNET_OK if the connection is allowed,
+ *               #GNUNET_NO if not,
+ *               #GNUNET_SYSERR if operation was aborted
  */
 static void
 try_connect_bl_check_cont (void *cls,
                            const struct GNUNET_PeerIdentity *peer,
+                          const struct GNUNET_HELLO_Address *address,
+                          struct Session *session,
                            int result)
 {
   struct BlacklistCheckSwitchContext *blc_ctx = cls;
@@ -2263,7 +2283,9 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
       (blc = GST_blacklist_test_allowed (target,
                                          NULL,
                                          &try_connect_bl_check_cont,
-                                         blc_ctx)))
+                                         blc_ctx,
+                                        NULL,
+                                        NULL)))
   {
     blc_ctx->blc = blc;
   }
@@ -2439,6 +2461,9 @@ try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
     /* switch to a different session, but keeping same address; could
        happen if there is a 2nd inbound connection */
     n->primary_address.session = session;
+    GNUNET_assert (GNUNET_YES ==
+                   GST_ats_is_known (n->primary_address.address,
+                                     n->primary_address.session));
   }
   n->primary_address.bandwidth_in = bandwidth_in;
   n->primary_address.bandwidth_out = bandwidth_out;
@@ -2457,54 +2482,66 @@ try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
  * @param cls the `struct BlacklistCheckSwitchContext` with
  *        the information about the future address
  * @param peer the peer we may switch addresses on
- * @param result #GNUNET_NO if we are not allowed to use the new
- *        address
+ * @param address address associated with the request
+ * @param session session associated with the request
+ * @param result #GNUNET_OK if the connection is allowed,
+ *               #GNUNET_NO if not,
+ *               #GNUNET_SYSERR if operation was aborted
  */
 static void
 switch_address_bl_check_cont (void *cls,
                               const struct GNUNET_PeerIdentity *peer,
+                             const struct GNUNET_HELLO_Address *address,
+                             struct Session *session,
                               int result)
 {
   struct BlacklistCheckSwitchContext *blc_ctx = cls;
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
   struct NeighbourMapEntry *n;
 
-  if (result == GNUNET_NO)
+  if (GNUNET_SYSERR == result)
+    goto cleanup;
+
+  papi = GST_plugins_find (address->transport_name);
+  GNUNET_assert (NULL != papi);
+
+  if (GNUNET_NO == result)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n",
-                GST_plugins_a2s (blc_ctx->address),
-                blc_ctx->session,
-                GNUNET_i2s (&blc_ctx->address->peer));
+                GST_plugins_a2s (address),
+               session,
+                GNUNET_i2s (peer));
     GNUNET_STATISTICS_update (GST_stats,
                               "# ATS suggestions ignored (blacklist denied)",
                               1,
                               GNUNET_NO);
-    /* FIXME: tell plugin to force killing session here and now
-       (note: _proper_ plugin API for this does not yet exist) */
-    GST_ats_block_address (blc_ctx->address,
-                           blc_ctx->session);
+    papi->disconnect_session (papi->cls,
+                             session);
+    if (GNUNET_YES !=
+       GNUNET_HELLO_address_check_option (address,
+                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
+      GST_ats_block_address (address,
+                            NULL);
     goto cleanup;
   }
 
-  papi = GST_plugins_find (blc_ctx->address->transport_name);
-  GNUNET_assert (NULL != papi);
 
-  if (NULL == blc_ctx->session)
+  if (NULL == session)
   {
     /* need to create a session, ATS only gave us an address */
-    blc_ctx->session = papi->get_session (papi->cls,
-                                          blc_ctx->address);
+    session = papi->get_session (papi->cls,
+                                address);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Obtained new session for peer `%s' and  address '%s': %p\n",
-                GNUNET_i2s (&blc_ctx->address->peer),
-                GST_plugins_a2s (blc_ctx->address),
-                blc_ctx->session);
-    if (NULL != blc_ctx->session)
-      GST_ats_new_session (blc_ctx->address,
-                           blc_ctx->session);
+                GNUNET_i2s (&address->peer),
+                GST_plugins_a2s (address),
+                session);
+    if (NULL != session)
+      GST_ats_new_session (address,
+                           session);
   }
-  if (NULL == blc_ctx->session)
+  if (NULL == session)
   {
     /* session creation failed, bad!, fail! */
     GNUNET_STATISTICS_update (GST_stats,
@@ -2514,10 +2551,10 @@ switch_address_bl_check_cont (void *cls,
     /* No session could be obtained, remove blacklist check and clean up */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Failed to obtain new session for peer `%s' and address '%s'\n",
-                GNUNET_i2s (&blc_ctx->address->peer),
-                GST_plugins_a2s (blc_ctx->address));
-    GST_ats_block_address (blc_ctx->address,
-                           blc_ctx->session);
+                GNUNET_i2s (&address->peer),
+                GST_plugins_a2s (address));
+    GST_ats_block_address (address,
+                           session);
     goto cleanup;
   }
 
@@ -2525,8 +2562,8 @@ switch_address_bl_check_cont (void *cls,
      it is theoretically possible that the situation changed in
      the meantime, hence we check again here */
   if (GNUNET_OK ==
-      try_run_fast_ats_update (blc_ctx->address,
-                               blc_ctx->session,
+      try_run_fast_ats_update (address,
+                               session,
                                blc_ctx->bandwidth_in,
                                blc_ctx->bandwidth_out))
     goto cleanup; /* was just a minor update, we're done */
@@ -2540,26 +2577,25 @@ switch_address_bl_check_cont (void *cls,
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Peer `%s' switches to address `%s'\n",
-              GNUNET_i2s (&blc_ctx->address->peer),
-              GST_plugins_a2s (blc_ctx->address));
+              GNUNET_i2s (&address->peer),
+              GST_plugins_a2s (address));
 
   switch (n->state)
   {
   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
     GNUNET_break (0);
-    GST_ats_block_address (blc_ctx->address,
-                           blc_ctx->session);
+    GST_ats_block_address (address,
+                           session);
     free_neighbour (n);
     return;
   case GNUNET_TRANSPORT_PS_INIT_ATS:
     /* We requested an address and ATS suggests one:
      * set primary address and send SYN message*/
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                         address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     if (ACK_SEND_SYN_ACK == n->ack_state)
     {
       /* Send pending SYN_ACK message */
@@ -2577,11 +2613,10 @@ switch_address_bl_check_cont (void *cls,
      * Switch and send new SYN */
     /* ATS suggests a different address, switch again */
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                         address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     if (ACK_SEND_SYN_ACK == n->ack_state)
     {
       /* Send pending SYN_ACK message */
@@ -2598,11 +2633,10 @@ switch_address_bl_check_cont (void *cls,
     /* We requested an address and ATS suggests one:
      * set primary address and send SYN_ACK message*/
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                         address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     /* Send an ACK message as a response to the SYN msg */
     set_state_and_timeout (n,
                            GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
@@ -2623,11 +2657,10 @@ switch_address_bl_check_cont (void *cls,
                             n->connect_ack_timestamp);
     }
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                        address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     set_state_and_timeout (n,
                            GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
@@ -2635,12 +2668,12 @@ switch_address_bl_check_cont (void *cls,
   case GNUNET_TRANSPORT_PS_CONNECTED:
     GNUNET_assert (NULL != n->primary_address.address);
     GNUNET_assert (NULL != n->primary_address.session);
-    GNUNET_break (n->primary_address.session != blc_ctx->session);
+    GNUNET_break (n->primary_address.session != session);
     /* ATS asks us to switch a life connection; see if we can get
        a SYN_ACK on it before we actually do this! */
     set_alternative_address (n,
-                             blc_ctx->address,
-                             blc_ctx->session,
+                             address,
+                             session,
                              blc_ctx->bandwidth_in,
                              blc_ctx->bandwidth_out);
     set_state_and_timeout (n,
@@ -2654,11 +2687,10 @@ switch_address_bl_check_cont (void *cls,
     break;
   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                         address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     if (ACK_SEND_SYN_ACK == n->ack_state)
     {
       /* Send pending SYN_ACK message */
@@ -2675,11 +2707,10 @@ switch_address_bl_check_cont (void *cls,
     /* ATS asks us to switch while we were trying to reconnect; switch to new
        address and send SYN again */
     set_primary_address (n,
-                         blc_ctx->address,
-                         blc_ctx->session,
+                         address,
+                         session,
                          blc_ctx->bandwidth_in,
-                         blc_ctx->bandwidth_out,
-                         GNUNET_NO);
+                         blc_ctx->bandwidth_out);
     set_state_and_timeout (n,
                            GNUNET_TRANSPORT_PS_RECONNECT_SENT,
                            GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
@@ -2687,8 +2718,8 @@ switch_address_bl_check_cont (void *cls,
     break;
   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
     if ( (0 == GNUNET_HELLO_address_cmp (n->primary_address.address,
-                                         blc_ctx->address)) &&
-         (n->primary_address.session == blc_ctx->session) )
+                                         address)) &&
+         (n->primary_address.session == session) )
     {
       /* ATS switches back to still-active session */
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2701,8 +2732,8 @@ switch_address_bl_check_cont (void *cls,
     }
     /* ATS asks us to switch a life connection, send */
     set_alternative_address (n,
-                             blc_ctx->address,
-                             blc_ctx->session,
+                            address,
+                             session,
                              blc_ctx->bandwidth_in,
                              blc_ctx->bandwidth_out);
     set_state_and_timeout (n,
@@ -2731,7 +2762,6 @@ switch_address_bl_check_cont (void *cls,
   GNUNET_CONTAINER_DLL_remove (pending_bc_head,
                                pending_bc_tail,
                                blc_ctx);
-  GNUNET_HELLO_address_free (blc_ctx->address);
   GNUNET_free (blc_ctx);
 }
 
@@ -2791,14 +2821,14 @@ GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
   }
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "ATS suggests address '%s' for peer `%s'\n",
+             "ATS suggests address '%s' for peer `%s' at %u/%u speed\n",
              GST_plugins_a2s (address),
-             GNUNET_i2s (&address->peer));
+             GNUNET_i2s (&address->peer),
+              (unsigned int) ntohl (bandwidth_in.value__),
+              (unsigned int) ntohl (bandwidth_out.value__));
 
   /* Perform blacklist check */
   blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
-  blc_ctx->address = GNUNET_HELLO_address_copy (address);
-  blc_ctx->session = session;
   blc_ctx->bandwidth_in = bandwidth_in;
   blc_ctx->bandwidth_out = bandwidth_out;
   GNUNET_CONTAINER_DLL_insert (pending_bc_head,
@@ -2807,7 +2837,9 @@ GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
   if (NULL != (blc = GST_blacklist_test_allowed (&address->peer,
                                                  address->transport_name,
                                                  &switch_address_bl_check_cont,
-                                                 blc_ctx)))
+                                                 blc_ctx,
+                                                address,
+                                                session)))
   {
     blc_ctx->blc = blc;
   }
@@ -2829,12 +2861,12 @@ send_utilization_data (void *cls,
                        void *value)
 {
   struct NeighbourMapEntry *n = value;
-  struct GNUNET_ATS_Information atsi[4];
   uint32_t bps_in;
   uint32_t bps_out;
   struct GNUNET_TIME_Relative delta;
 
-  if (GNUNET_YES != test_connected (n))
+  if ( (GNUNET_YES != test_connected (n)) ||
+       (NULL == n->primary_address.address) )
     return GNUNET_OK;
   delta = GNUNET_TIME_absolute_get_difference (n->last_util_transmission,
                                                GNUNET_TIME_absolute_get ());
@@ -2845,19 +2877,14 @@ send_utilization_data (void *cls,
   if ((0 != n->util_total_bytes_sent) && (0 != delta.rel_value_us))
     bps_out = (1000LL * 1000LL * n->util_total_bytes_sent) / delta.rel_value_us;
 
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "`%s' total: received %u Bytes/s, sent %u Bytes/s\n",
               GNUNET_i2s (key),
               bps_in,
               bps_out);
-  atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_OUT);
-  atsi[0].value = htonl (bps_out);
-  atsi[1].type = htonl (GNUNET_ATS_UTILIZATION_IN);
-  atsi[1].value = htonl (bps_in);
-  GST_ats_update_metrics (n->primary_address.address,
-                          n->primary_address.session,
-                          atsi, 2);
+  GST_ats_update_utilization (n->primary_address.address,
+                              bps_in,
+                              bps_out);
   n->util_total_bytes_recv = 0;
   n->util_total_bytes_sent = 0;
   n->last_util_transmission = GNUNET_TIME_absolute_get ();
@@ -3183,8 +3210,7 @@ GST_neighbours_handle_session_syn_ack (const struct GNUNET_MessageHeader *messag
                          n->primary_address.address,
                          n->primary_address.session,
                          n->primary_address.bandwidth_in,
-                         n->primary_address.bandwidth_out,
-                         GNUNET_YES);
+                         n->primary_address.bandwidth_out);
     send_session_ack_message (n);
     break;
   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
@@ -3225,8 +3251,7 @@ GST_neighbours_handle_session_syn_ack (const struct GNUNET_MessageHeader *messag
                          n->alternative_address.address,
                          n->alternative_address.session,
                          n->alternative_address.bandwidth_in,
-                         n->alternative_address.bandwidth_out,
-                         GNUNET_YES);
+                         n->alternative_address.bandwidth_out);
     GNUNET_STATISTICS_update (GST_stats,
                               gettext_noop ("# Successful attempts to switch addresses"),
                               1,
@@ -3382,6 +3407,9 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
     /* Destroy the inbound address since it cannot be used */
     free_address (&n->primary_address);
     n->primary_address = n->alternative_address;
+    GNUNET_assert (GNUNET_YES ==
+                   GST_ats_is_known (n->primary_address.address,
+                                     n->primary_address.session));
     memset (&n->alternative_address,
             0,
             sizeof (struct NeighbourAddress));
@@ -3432,9 +3460,9 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
     return GNUNET_SYSERR;
   }
   GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop
-                            ("# ACK messages received"),
-                            1, GNUNET_NO);
+                            gettext_noop ("# ACK messages received"),
+                            1,
+                            GNUNET_NO);
   if (NULL == (n = lookup_neighbour (&address->peer)))
   {
     GNUNET_break_op (0);
@@ -3467,7 +3495,8 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
                 print_ack_state (n->ack_state));
 
     GNUNET_STATISTICS_update (GST_stats,
-                              gettext_noop ("# unexpected ACK messages"), 1,
+                              gettext_noop ("# unexpected ACK messages"),
+                              1,
                               GNUNET_NO);
     return GNUNET_OK;
   }
@@ -3482,13 +3511,9 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
                          GNUNET_TRANSPORT_PS_CONNECTED,
                          GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
 
-  /* Set primary address to used */
-  set_primary_address (n,
-                       n->primary_address.address,
-                       n->primary_address.session,
-                       n->primary_address.bandwidth_in,
-                       n->primary_address.bandwidth_out,
-                       GNUNET_YES);
+  /* Reset backoff for primary address */
+  GST_ats_block_reset (n->primary_address.address,
+                       n->primary_address.session);
   return GNUNET_OK;
 }
 
@@ -3832,8 +3857,6 @@ GST_neighbours_stop ()
       GST_blacklist_test_cancel (cur->blc);
       cur->blc = NULL;
     }
-    if (NULL != cur->address)
-      GNUNET_HELLO_address_free (cur->address);
     GNUNET_free (cur);
   }
 }