fixing coverity 10465: Resource leak
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
index 47e2713870609e97b384ba20ac990aae32df1f7f..32a0706dc6d618f17e729758dbc39d90ad28e716 100644 (file)
@@ -40,6 +40,7 @@
 #include "transport.h"
 
 
+
 /**
  * Size of the neighbour hash map.
  */
  */
 #define BLACKLIST_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
 
+#define DEBUG_MALLOC GNUNET_NO
+
+#if DEBUG_MALLOC
+
+struct Allocator
+{
+  struct Allocator *prev;
+  struct Allocator *next;
+
+  unsigned int bytes_alloced;
+  unsigned int max_alloced;
+  unsigned int diff;
+  unsigned int line;
+
+  struct GNUNET_TIME_Absolute max_alloced_when;
+  struct GNUNET_TIME_Absolute last_alloced_when;
+
+};
+
+struct Allocator *aehead;
+struct Allocator *aetail;
+
+struct Allocation
+{
+  struct Allocation *prev;
+  struct Allocation *next;
+
+  struct Allocator *alloc;
+  unsigned int bytes_alloced;
+  void *p;
+  unsigned int line;
+};
+
+struct Allocation *ahead;
+struct Allocation *atail;
+
+static int bytes_alloced;
+
+static struct Allocator *
+find_allocator (int line)
+{
+  struct Allocator *cur = aehead;
+  while (NULL != cur)
+  {
+      if (line == cur->line)
+        return cur;
+      cur = cur->next;
+  }
+  return cur;
+}
+
+static void
+print_allocators ()
+{
+  static int start = GNUNET_YES;
+  static struct GNUNET_TIME_Absolute next;
+  static struct GNUNET_TIME_Relative rem;
+  struct Allocator *cur = aehead;
+  if (start)
+  {
+      next = GNUNET_TIME_UNIT_ZERO_ABS;
+      start = GNUNET_NO;
+  }
+  if (0 == (rem = GNUNET_TIME_absolute_get_remaining(next)).rel_value)
+  {
+      fprintf (stderr, "Allocated in `%s' total: %5u bytes\n", __FILE__, bytes_alloced);
+      while (NULL != cur)
+      {
+          char *last_alloc = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string(cur->max_alloced_when));
+          fprintf (stderr, "Allocated from line %4u :%5u bytes (diff %5i bytes, max alloc: %5u @ %s, last alloc %s)\n",
+              cur->line, cur->bytes_alloced, cur->diff, cur->max_alloced,
+              last_alloc,
+              GNUNET_STRINGS_absolute_time_to_string(cur->last_alloced_when));
+          GNUNET_free (last_alloc);
+          cur->diff = 0;
+          cur = cur->next;
+      }
+      fprintf (stderr, "\n");
+    next = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), GNUNET_TIME_UNIT_SECONDS);
+  }
+}
+
+#endif
+
+static void
+MEMDEBUG_add_alloc (void *p, size_t size, int line)
+{
+#if DEBUG_MALLOC
+  struct Allocation *alloc = GNUNET_malloc (sizeof (struct Allocation));
+  struct Allocator *allocator = find_allocator(line);
+  if (NULL == allocator)
+  {
+      allocator = GNUNET_malloc (sizeof (struct Allocator));
+      allocator->line = line;
+      GNUNET_CONTAINER_DLL_insert (aehead, aetail, allocator);
+  }
+  alloc->alloc = allocator;
+  alloc->p = p;
+  alloc->line = line;
+  alloc->bytes_alloced = size;
+  allocator->bytes_alloced += size;
+  allocator->last_alloced_when = GNUNET_TIME_absolute_get();
+  if (allocator->bytes_alloced >= allocator->max_alloced)
+  {
+      allocator->max_alloced = allocator->bytes_alloced;
+      allocator->max_alloced_when = allocator->last_alloced_when;
+  }
+  allocator->diff += size;
+  GNUNET_CONTAINER_DLL_insert (ahead, atail, alloc);
+  print_allocators ();
+  bytes_alloced += size;
+#endif
+}
+
+
+static void *
+MEMDEBUG_malloc (size_t size, int line)
+{
+  void * ret;
+
+  ret = GNUNET_malloc (size);
+#if DEBUG_MALLOC
+  if (NULL != ret)
+      MEMDEBUG_add_alloc (ret, size, line);
+#endif
+  return ret;
+
+}
+
+static void
+MEMDEBUG_free (void * alloc, int line)
+{
+#if DEBUG_MALLOC
+  struct Allocation *cur;
+  struct Allocator *allocator;
+  cur = ahead;
+  while (NULL != cur)
+  {
+      if (alloc == cur->p)
+        break;
+      cur = cur->next;
+  }
+  if (NULL == cur)
+  {
+    fprintf (stderr, "Unmonitored free from line %4u\n", line);
+    GNUNET_break (0);
+    return;
+  }
+  allocator = cur->alloc;
+  if (NULL == allocator)
+  {
+      GNUNET_break (0);
+  }
+  GNUNET_CONTAINER_DLL_remove (ahead, atail, cur);
+  allocator->bytes_alloced -= cur->bytes_alloced;
+  allocator->diff -= cur->bytes_alloced;
+  GNUNET_assert (allocator->bytes_alloced >= 0);
+  bytes_alloced -= cur->bytes_alloced;
+  GNUNET_assert (bytes_alloced >= 0);
+  GNUNET_free (cur);
+#endif
+  GNUNET_free (alloc);
+}
+
+static void
+MEMDEBUG_free_non_null (void * alloc, int line)
+{
+  if (alloc != NULL)
+    MEMDEBUG_free (alloc, line);
+}
+
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
@@ -146,7 +318,7 @@ struct SessionDisconnectMessage
    * Purpose of the signature.  Extends over the timestamp.
    * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
    */
-  struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
 
   /**
    * Absolute time at the sender.  Only the most recent connect
@@ -157,14 +329,14 @@ struct SessionDisconnectMessage
   /**
    * Public key of the sender.
    */
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+  struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
 
   /**
    * Signature of the peer that sends us the disconnect.  Only
    * valid if the timestamp is AFTER the timestamp from the
    * corresponding 'CONNECT' message.
    */
-  struct GNUNET_CRYPTO_RsaSignature signature;
+  struct GNUNET_CRYPTO_EccSignature signature;
 
 };
 
@@ -221,10 +393,10 @@ struct MessageQueue
  * Possible state of a neighbour.  Initially, we are S_NOT_CONNECTED.
  *
  * Then, there are two main paths. If we receive a CONNECT message, we
- * first run a check against the blacklist and ask ATS for a
- * suggestion.  (S_CONNECT_RECV_ATS).  If the blacklist comes back
- * positive, we give the address to ATS.  If ATS makes a suggestion,
- * we ALSO give that suggestion to the blacklist
+ * first run a check against the blacklist (S_CONNECT_RECV_BLACKLIST_INBOUND).
+ * If this check is successful, we give the inbound address to ATS.
+ * After the check we ask ATS for a suggestion (S_CONNECT_RECV_ATS).
+ * If ATS makes a suggestion, we ALSO give that suggestion to the blacklist
  * (S_CONNECT_RECV_BLACKLIST).  Once the blacklist approves the
  * address we got from ATS, we send our CONNECT_ACK and go to
  * S_CONNECT_RECV_ACK.  If we receive a SESSION_ACK, we go to
@@ -301,6 +473,11 @@ enum State
    */
   S_CONNECT_SENT,
 
+  /**
+   * Received a CONNECT, do a blacklist check for inbound address
+   */
+  S_CONNECT_RECV_BLACKLIST_INBOUND,
+
   /**
    * Received a CONNECT, asking ATS about address suggestions.
    */
@@ -363,7 +540,13 @@ enum State
   S_DISCONNECT,
 
   /**
-   * We're finished with the disconnect; clean up state now!
+   * We're finished with the disconnect; and are cleaning up the state
+   * now!  We put the struct into this state when we are really in the
+   * task that calls 'free' on it and are about to remove the record
+   * from the map.  We should never find a 'struct NeighbourMapEntry'
+   * in this state in the map.  Accessing a 'struct NeighbourMapEntry'
+   * in this state virtually always means using memory that has been
+   * freed (the exception being the cleanup code in 'free_neighbour').
    */
   S_DISCONNECT_FINISHED
 };
@@ -473,6 +656,11 @@ struct NeighbourMapEntry
    */
   struct GNUNET_TIME_Absolute connect_ack_timestamp;
 
+  /**
+   * ATS address suggest handle
+   */
+  struct GNUNET_ATS_SuggestHandle *suggest_handle;
+
   /**
    * Time where we should cut the connection (timeout) if we don't
    * make progress in the state machine (or get a KEEPALIVE_RESPONSE
@@ -540,22 +728,11 @@ struct BlackListCheckContext
    * Address that is being checked.
    */
   struct NeighbourAddress na;
-  
-  /**
-   * ATS information about the address.
-   */
-  struct GNUNET_ATS_Information *ats;
 
   /**
    * Handle to the ongoing blacklist check.
    */
   struct GST_BlacklistCheck *bc;
-
-  /**
-   * Size of the 'ats' array.
-   */
-  uint32_t ats_count;
-
 };
 
 
@@ -584,7 +761,7 @@ static void *callback_cls;
 /**
  * Function to call when we connected to a neighbour.
  */
-static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
+static NotifyConnect connect_notify_cb;
 
 /**
  * Function to call when we disconnected from a neighbour.
@@ -629,56 +806,40 @@ print_state (int state)
   {
   case S_NOT_CONNECTED:
     return "S_NOT_CONNECTED";
-    break;
   case S_INIT_ATS:
     return "S_INIT_ATS";
-    break;
   case S_INIT_BLACKLIST:
     return "S_INIT_BLACKLIST";
-    break;
   case S_CONNECT_SENT:
     return "S_CONNECT_SENT";
-    break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
+    return "S_CONNECT_RECV_BLACKLIST_INBOUND";
   case S_CONNECT_RECV_ATS:
     return "S_CONNECT_RECV_ATS";
-    break;
   case S_CONNECT_RECV_BLACKLIST:
     return "S_CONNECT_RECV_BLACKLIST";
-    break;
   case S_CONNECT_RECV_ACK:
     return "S_CONNECT_RECV_ACK";
-    break;
   case S_CONNECTED:
     return "S_CONNECTED";
-    break;
   case S_RECONNECT_ATS:
     return "S_RECONNECT_ATS";
-    break;
   case S_RECONNECT_BLACKLIST:
     return "S_RECONNECT_BLACKLIST";
-    break;
   case S_RECONNECT_SENT:
     return "S_RECONNECT_SENT";
-    break;
   case S_CONNECTED_SWITCHING_BLACKLIST:
     return "S_CONNECTED_SWITCHING_BLACKLIST";
-    break;
   case S_CONNECTED_SWITCHING_CONNECT_SENT:
     return "S_CONNECTED_SWITCHING_CONNECT_SENT";
-    break;
   case S_DISCONNECT:
     return "S_DISCONNECT";
-    break;
   case S_DISCONNECT_FINISHED:
     return "S_DISCONNECT_FINISHED";
-    break;
   default:
-    return "UNDEFINED";
     GNUNET_break (0);
-    break;
+    return "UNDEFINED";
   }
-  GNUNET_break (0);
-  return "UNDEFINED";
 }
 
 /**
@@ -698,6 +859,7 @@ test_connected (struct NeighbourMapEntry *n)
   case S_INIT_ATS:
   case S_INIT_BLACKLIST:
   case S_CONNECT_SENT:
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
   case S_CONNECT_RECV_ATS:
   case S_CONNECT_RECV_BLACKLIST:
   case S_CONNECT_RECV_ACK:
@@ -757,11 +919,14 @@ free_address (struct NeighbourAddress *na)
   {
     GST_validation_set_address_use (na->address, na->session, GNUNET_NO, __LINE__);
     GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_NO);
+    address_change_cb (NULL, &na->address->peer, NULL);
   }
+
   na->ats_active = GNUNET_NO;
   if (NULL != na->address)
   {
-    GNUNET_HELLO_address_free (na->address);
+    MEMDEBUG_free (na->address, __LINE__);
+    //GNUNET_HELLO_address_free (na->address);
     na->address = NULL;
   }
   na->session = NULL;
@@ -789,7 +954,6 @@ set_address (struct NeighbourAddress *na,
             int is_active)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
-
   if (NULL == (papi = GST_plugins_find (address->transport_name)))  
   {
     GNUNET_break (0);
@@ -804,6 +968,8 @@ set_address (struct NeighbourAddress *na,
       na->ats_active = is_active;
       GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, is_active);
       GST_validation_set_address_use (na->address, na->session, is_active,  __LINE__);
+      if (is_active)
+        address_change_cb (NULL, &address->peer, address);
     }
     if (GNUNET_YES == is_active)
     {
@@ -825,6 +991,7 @@ set_address (struct NeighbourAddress *na,
     return;
   }
   na->address = GNUNET_HELLO_address_copy (address);
+  MEMDEBUG_add_alloc (na->address, GNUNET_HELLO_address_get_size (na->address), __LINE__);
   na->bandwidth_in = bandwidth_in;
   na->bandwidth_out = bandwidth_out;
   na->session = session;
@@ -832,10 +999,9 @@ set_address (struct NeighbourAddress *na,
   if (GNUNET_YES == is_active)
   {
     /* Telling ATS about new session */
-    GNUNET_ATS_address_update (GST_ats, na->address, na->session, NULL, 0);
     GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_YES);
     GST_validation_set_address_use (na->address, na->session, GNUNET_YES,  __LINE__);
-
+    address_change_cb (NULL, &address->peer, address);
     /* FIXME: is this the right place to set quotas? */
     GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in);
     send_outbound_quota (&address->peer, bandwidth_out);
@@ -855,6 +1021,7 @@ free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
 {
   struct MessageQueue *mq;
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
+  struct GNUNET_HELLO_Address *backup_primary;
 
   n->is_active = NULL; /* always free'd by its own continuation! */
 
@@ -863,8 +1030,8 @@ free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
   {
     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
     if (NULL != mq->cont)
-      mq->cont (mq->cont_cls, GNUNET_SYSERR);
-    GNUNET_free (mq);
+      mq->cont (mq->cont_cls, GNUNET_SYSERR, mq->message_buf_size, 0);
+    MEMDEBUG_free (mq, __LINE__);
   }
   /* It is too late to send other peer disconnect notifications, but at
      least internally we need to get clean... */
@@ -877,6 +1044,20 @@ free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
     disconnect_notify_cb (callback_cls, &n->id);
   }
 
+  n->state = S_DISCONNECT_FINISHED;
+
+  if (NULL != n->primary_address.address)
+  {
+    backup_primary = GNUNET_HELLO_address_copy(n->primary_address.address);
+    MEMDEBUG_add_alloc (backup_primary, GNUNET_HELLO_address_get_size(backup_primary), __LINE__);
+  }
+  else
+    backup_primary = NULL;
+
+  /* free addresses and mark as unused */
+  free_address (&n->primary_address);
+  free_address (&n->alternative_address);
+
   /* FIXME-PLUGIN-API: This does not seem to guarantee that all
      transport sessions eventually get killed due to inactivity; they
      MUST have their own timeout logic (but at least TCP doesn't have
@@ -886,26 +1067,28 @@ free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
      API gives us not even the means to selectively kill only one of
      them! Killing all sessions like this seems to be very, very
      wrong. */
+
+  /* cut transport-level connection */
   if ((GNUNET_NO == keep_sessions) &&
-      (NULL != n->primary_address.address) &&
-      (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name))))
+      (NULL != backup_primary) &&
+      (NULL != (papi = GST_plugins_find (backup_primary->transport_name))))
     papi->disconnect (papi->cls, &n->id);
 
-  n->state = S_DISCONNECT_FINISHED;
+  MEMDEBUG_free_non_null (backup_primary, __LINE__);
 
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
                                                        &n->id.hashPubKey, n));
 
-  /* cut transport-level connection */
-  free_address (&n->primary_address);
-  free_address (&n->alternative_address);
-
   // FIXME-ATS-API: we might want to be more specific about
   // which states we do this from in the future (ATS should
   // have given us a 'suggest_address' handle, and if we have
   // such a handle, we should cancel the operation here!
-  GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
+  if (NULL != n->suggest_handle)
+  {
+       GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
+       n->suggest_handle = NULL;
+  }
 
   if (GNUNET_SCHEDULER_NO_TASK != n->task)
   {
@@ -913,10 +1096,9 @@ free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
     n->task = GNUNET_SCHEDULER_NO_TASK;
   }
   /* free rest of memory */
-  GNUNET_free (n);
+  MEMDEBUG_free (n, __LINE__);
 }
 
-
 /**
  * Transmit a message using the current session of the given
  * neighbour.
@@ -940,15 +1122,15 @@ send_with_session (struct NeighbourMapEntry *n,
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
 
   GNUNET_assert (n->primary_address.session != NULL);
-  if ( ( (NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name))) ||
+  if ( ((NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name)) ||
         (-1 == papi->send (papi->cls,
                            n->primary_address.session,
                            msgbuf, msgbuf_size,
                            priority,
                            timeout,
-                           cont, cont_cls))) &&
-       (NULL != cont) )
-    cont (cont_cls, &n->id, GNUNET_SYSERR);
+                           cont, cont_cls)))) &&
+       (NULL != cont))
+    cont (cont_cls, &n->id, GNUNET_SYSERR, msgbuf_size, 0);
   GNUNET_break (NULL != papi);
 }
 
@@ -973,10 +1155,12 @@ master_task (void *cls,
  * @param cls NULL
  * @param target identity of the neighbour that was disconnected
  * @param result GNUNET_OK if the disconnect got out successfully
+ * @param payload bytes payload
+ * @param physical bytes physical
  */
 static void
 send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
-                      int result)
+                      int result, size_t payload, size_t physical)
 {
   struct NeighbourMapEntry *n;
 
@@ -1010,8 +1194,8 @@ send_disconnect (struct NeighbourMapEntry *n)
       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
   disconnect_msg.reserved = htonl (0);
   disconnect_msg.purpose.size =
-      htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
-             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+      htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+             sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
              sizeof (struct GNUNET_TIME_AbsoluteNBO));
   disconnect_msg.purpose.purpose =
       htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
@@ -1019,7 +1203,7 @@ send_disconnect (struct NeighbourMapEntry *n)
       GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
   disconnect_msg.public_key = GST_my_public_key;
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
+                 GNUNET_CRYPTO_ecc_sign (GST_my_private_key,
                                          &disconnect_msg.purpose,
                                          &disconnect_msg.signature));
 
@@ -1056,7 +1240,8 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
   case S_CONNECT_SENT:
     send_disconnect (n); 
     n->state = S_DISCONNECT;
-    break;   
+    break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
   case S_CONNECT_RECV_ATS:
   case S_CONNECT_RECV_BLACKLIST:
     /* we never ACK'ed the other peer's request, no need to send DISCONNECT */
@@ -1118,17 +1303,22 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
  * @param cls the 'struct MessageQueue' of the message
  * @param receiver intended receiver
  * @param success whether it worked or not
+ * @param size_payload bytes payload sent
+ * @param physical bytes sent on wire
  */
 static void
 transmit_send_continuation (void *cls,
                             const struct GNUNET_PeerIdentity *receiver,
-                            int success)
+                            int success, size_t size_payload, size_t physical)
 {
   struct MessageQueue *mq = cls;
   struct NeighbourMapEntry *n;
 
   if (NULL == (n = lookup_neighbour (receiver)))
+  {
+    MEMDEBUG_free (mq, __LINE__);
     return; /* disconnect or other error while transmitting, can happen */
+  }
   if (n->is_active == mq)
   {
     /* this is still "our" neighbour, remove us from its queue
@@ -1138,7 +1328,18 @@ transmit_send_continuation (void *cls,
       GNUNET_SCHEDULER_cancel (n->task);
     n->task = GNUNET_SCHEDULER_add_now (&master_task, n);    
   }
-  GNUNET_assert (bytes_in_send_queue >= mq->message_buf_size);
+  if (bytes_in_send_queue < mq->message_buf_size)
+  {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Bytes_in_send_queue `%u', Message_size %u, result: %s, payload %u, on wire %u\n",
+                  bytes_in_send_queue, mq->message_buf_size,
+                  (GNUNET_OK == success) ? "OK" : "FAIL",
+                         size_payload, physical);
+      GNUNET_break (0);
+  }
+
+
+  GNUNET_break (size_payload == mq->message_buf_size);
   bytes_in_send_queue -= mq->message_buf_size;
   GNUNET_STATISTICS_set (GST_stats,
                         gettext_noop
@@ -1160,8 +1361,8 @@ transmit_send_continuation (void *cls,
               ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
               (success == GNUNET_OK) ? "success" : "FAILURE");
   if (NULL != mq->cont)
-    mq->cont (mq->cont_cls, success);
-  GNUNET_free (mq);
+    mq->cont (mq->cont_cls, success, size_payload, physical);
+  MEMDEBUG_free (mq, __LINE__);
 }
 
 
@@ -1213,7 +1414,7 @@ try_transmission_to_peer (struct NeighbourMapEntry *n)
                              1, GNUNET_NO);
     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
     n->is_active = mq;
-    transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);     /* timeout */
+    transmit_send_continuation (mq, &n->id, GNUNET_SYSERR, mq->message_buf_size, 0);     /* timeout */
   }
   if (NULL == mq)
     return;                     /* no more messages */
@@ -1228,8 +1429,9 @@ try_transmission_to_peer (struct NeighbourMapEntry *n)
 
 /**
  * Send keepalive message to the neighbour.  Must only be called
- * if we are on 'connected' state.  Will internally determine
- * if a keepalive is truly needed (so can always be called).
+ * if we are on 'connected' state or while trying to switch addresses.
+ * Will internally determine if a keepalive is truly needed (so can
+ * always be called).
  *
  * @param n neighbour that went idle and needs a keepalive
  */
@@ -1238,7 +1440,9 @@ send_keepalive (struct NeighbourMapEntry *n)
 {
   struct GNUNET_MessageHeader m;
 
-  GNUNET_assert (S_CONNECTED == n->state);
+  GNUNET_assert ((S_CONNECTED == n->state) ||
+                 (S_CONNECTED_SWITCHING_BLACKLIST == n->state) ||
+                 (S_CONNECTED_SWITCHING_CONNECT_SENT));
   if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value > 0)
     return; /* no keepalive needed at this time */
   m.size = htons (sizeof (struct GNUNET_MessageHeader));
@@ -1301,17 +1505,13 @@ GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
  * plus calculated latency) to ATS.
  *
  * @param neighbour neighbour to keep alive
- * @param ats performance data
- * @param ats_count number of entries in ats
  */
 void
-GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
-                                   const struct GNUNET_ATS_Information *ats,
-                                   uint32_t ats_count)
+GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour)
 {
   struct NeighbourMapEntry *n;
   uint32_t latency;
-  struct GNUNET_ATS_Information ats_new[ats_count + 1];
+  struct GNUNET_ATS_Information ats;
 
   if (NULL == (n = lookup_neighbour (neighbour)))
   {
@@ -1333,21 +1533,20 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
   n->expect_latency_response = GNUNET_NO;
   n->latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time);
   n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Latency for peer `%s' is %llu ms\n",
               GNUNET_i2s (&n->id), n->latency.rel_value);
-  memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
   /* append latency */
-  ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
+  ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
   if (n->latency.rel_value > UINT32_MAX)
     latency = UINT32_MAX;
   else
     latency = n->latency.rel_value;
-  ats_new[ats_count].value = htonl (latency);
-  GNUNET_ATS_address_update (GST_ats, 
-                            n->primary_address.address, 
-                            n->primary_address.session, ats_new,
-                            ats_count + 1);
+  ats.value = htonl (latency);
+  GST_update_ats_metrics (&n->id,
+                                                                                         n->primary_address.address,
+                                                                                       n->primary_address.session,
+                                                                                       &ats, 1);
 }
 
 
@@ -1463,14 +1662,14 @@ GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
   {
     GNUNET_break (0);
     if (NULL != cont)
-      cont (cont_cls, GNUNET_SYSERR);
+      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);
+      cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
     return;
   }
   bytes_in_send_queue += msg_size;
@@ -1478,7 +1677,7 @@ GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
                         gettext_noop
                         ("# bytes in message queue for other peers"),
                         bytes_in_send_queue, GNUNET_NO);
-  mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
+  mq = MEMDEBUG_malloc (sizeof (struct MessageQueue) + msg_size, __LINE__);
   mq->cont = cont;
   mq->cont_cls = cont_cls;
   memcpy (&mq[1], msg, msg_size);
@@ -1505,7 +1704,7 @@ send_session_connect (struct NeighbourAddress *na)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
   struct SessionConnectMessage connect_msg;
-  
+
   if (NULL == (papi = GST_plugins_find (na->address->transport_name)))  
   {
     GNUNET_break (0);
@@ -1529,6 +1728,7 @@ send_session_connect (struct NeighbourAddress *na)
                     UINT_MAX,
                     GNUNET_TIME_UNIT_FOREVER_REL,
                     NULL, NULL);
+
 }
 
 
@@ -1546,7 +1746,7 @@ send_session_connect_ack_message (const struct GNUNET_HELLO_Address *address,
 {
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
   struct SessionConnectMessage connect_msg;
-  
+
   if (NULL == (papi = GST_plugins_find (address->transport_name)))  
   {
     GNUNET_break (0);
@@ -1569,6 +1769,7 @@ send_session_connect_ack_message (const struct GNUNET_HELLO_Address *address,
                     UINT_MAX,
                     GNUNET_TIME_UNIT_FOREVER_REL,
                     NULL, NULL);
+
 }
 
 
@@ -1586,7 +1787,7 @@ setup_neighbour (const struct GNUNET_PeerIdentity *peer)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Creating new neighbour entry for `%s'\n", 
              GNUNET_i2s (peer));
-  n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
+  n = MEMDEBUG_malloc (sizeof (struct NeighbourMapEntry), __LINE__);
   n->id = *peer;
   n->state = S_NOT_CONNECTED;
   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
@@ -1639,12 +1840,16 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
   struct NeighbourMapEntry *n;
 
   if (NULL == neighbours)  
-    return; /* during shutdown, do nothing */
+  {
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Asked to connect to peer `%s' during shutdown\n",
+                     GNUNET_i2s (target));
+               return; /* during shutdown, do nothing */
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
              "Asked to connect to peer `%s'\n",
               GNUNET_i2s (target));
-  if (0 ==
-      memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
+  if (0 == memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
   {
     /* refuse to connect to myself */
     /* FIXME: can this happen? Is this not an API violation? */
@@ -1665,6 +1870,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
     case S_INIT_ATS:
     case S_INIT_BLACKLIST:
     case S_CONNECT_SENT:
+    case S_CONNECT_RECV_BLACKLIST_INBOUND:
     case S_CONNECT_RECV_ATS:
     case S_CONNECT_RECV_BLACKLIST:
     case S_CONNECT_RECV_ACK:
@@ -1701,7 +1907,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
   n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
 
   GNUNET_ATS_reset_backoff (GST_ats, target);
-  GNUNET_ATS_suggest_address (GST_ats, target);
+  n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, target);
 }
 
 
@@ -1725,14 +1931,6 @@ handle_test_blacklist_cont (void *cls,
               "Connection to new address of peer `%s' based on blacklist is `%s'\n",
               GNUNET_i2s (peer),
               (GNUNET_OK == result) ? "allowed" : "FORBIDDEN");
-  if (GNUNET_OK == result)
-  {
-    /* valid new address, let ATS know! */
-    GNUNET_ATS_address_update (GST_ats, 
-                              bcc->na.address, 
-                              bcc->na.session, 
-                              bcc->ats, bcc->ats_count);
-  }
   if (NULL == (n = lookup_neighbour (peer)))
     goto cleanup; /* nobody left to care about new address */
   switch (n->state)
@@ -1766,13 +1964,15 @@ handle_test_blacklist_cont (void *cls,
     }
     else
     {
+      // FIXME: should also possibly destroy session with plugin!?
       GNUNET_ATS_address_destroyed (GST_ats,
                                    bcc->na.address,
                                    NULL);
+      free_address (&n->primary_address);
       n->state = S_INIT_ATS;
       n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
       // FIXME: do we need to ask ATS again for suggestions?
-      GNUNET_ATS_suggest_address (GST_ats, &n->id);
+      n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     }
     break;
   case S_CONNECT_SENT:
@@ -1786,9 +1986,23 @@ handle_test_blacklist_cont (void *cls,
                                        n->connect_ack_timestamp);
     }
     break; 
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
+    if (GNUNET_OK == result)
+    {
+      /* valid new address, let ATS know! */
+      GNUNET_ATS_address_add (GST_ats,
+                              bcc->na.address,
+                              bcc->na.session,
+                              NULL, 0);
+    }
+    n->state = S_CONNECT_RECV_ATS;
+    n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
+    GNUNET_ATS_reset_backoff (GST_ats, peer);
+    n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, peer);
+    break;
   case S_CONNECT_RECV_ATS:
     /* still waiting on ATS suggestion, don't care about blacklist */
-    break; 
+    break;
   case S_CONNECT_RECV_BLACKLIST:
     if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address))
       break; /* result for an address we currently don't care about */
@@ -1804,14 +2018,16 @@ handle_test_blacklist_cont (void *cls,
     }
     else
     {
+      // FIXME: should also possibly destroy session with plugin!?
       GNUNET_ATS_address_destroyed (GST_ats,
                                    bcc->na.address,
                                    NULL);
+      free_address (&n->primary_address);
       n->state = S_INIT_ATS;
       n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
       // FIXME: do we need to ask ATS again for suggestions?
       GNUNET_ATS_reset_backoff (GST_ats, peer);
-      GNUNET_ATS_suggest_address (GST_ats, &n->id);
+      n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     }
     break;
   case S_CONNECT_RECV_ACK:
@@ -1856,7 +2072,7 @@ handle_test_blacklist_cont (void *cls,
       n->state = S_RECONNECT_ATS;
       n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
       // FIXME: do we need to ask ATS again for suggestions?
-      GNUNET_ATS_suggest_address (GST_ats, &n->id);
+      n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     }
     break;
   case S_RECONNECT_SENT:
@@ -1912,11 +2128,12 @@ handle_test_blacklist_cont (void *cls,
     break;
   }
  cleanup:
-  GNUNET_HELLO_address_free (bcc->na.address);
+  MEMDEBUG_free (bcc->na.address, __LINE__);
+  //GNUNET_HELLO_address_free (bcc->na.address);
   GNUNET_CONTAINER_DLL_remove (bc_head,
                               bc_tail,
                               bcc);
-  GNUNET_free (bcc);
+  MEMDEBUG_free (bcc, __LINE__);
 }
 
 
@@ -1929,29 +2146,22 @@ handle_test_blacklist_cont (void *cls,
  * @param address address of the other peer, NULL if other peer
  *                       connected to us
  * @param session session to use (or NULL)
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
  */
 static void
 check_blacklist (const struct GNUNET_PeerIdentity *peer,
                 struct GNUNET_TIME_Absolute ts,
                 const struct GNUNET_HELLO_Address *address,
-                struct Session *session,
-                const struct GNUNET_ATS_Information *ats,
-                uint32_t ats_count)
+                struct Session *session)
 {
   struct BlackListCheckContext *bcc;
   struct GST_BlacklistCheck *bc;
 
   bcc =
-      GNUNET_malloc (sizeof (struct BlackListCheckContext) +
-                     sizeof (struct GNUNET_ATS_Information) * ats_count);
-  bcc->ats_count = ats_count;
+      MEMDEBUG_malloc (sizeof (struct BlackListCheckContext), __LINE__);
   bcc->na.address = GNUNET_HELLO_address_copy (address);
+  MEMDEBUG_add_alloc (bcc->na.address, GNUNET_HELLO_address_get_size (address), __LINE__);
   bcc->na.session = session;
   bcc->na.connect_timestamp = ts;
-  bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
-  memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
   GNUNET_CONTAINER_DLL_insert (bc_head,
                               bc_tail,
                               bcc);
@@ -1973,16 +2183,12 @@ check_blacklist (const struct GNUNET_PeerIdentity *peer,
  * @param address address of the other peer, NULL if other peer
  *                       connected to us
  * @param session session to use (or NULL)
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
  */
 void
 GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
                                const struct GNUNET_PeerIdentity *peer,
                                const struct GNUNET_HELLO_Address *address,
-                               struct Session *session,
-                               const struct GNUNET_ATS_Information *ats,
-                               uint32_t ats_count)
+                               struct Session *session)
 {
   const struct SessionConnectMessage *scm;
   struct NeighbourMapEntry *n;
@@ -1991,6 +2197,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received CONNECT message from peer `%s'\n", 
              GNUNET_i2s (peer));
+
   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
   {
     GNUNET_break_op (0);
@@ -2006,24 +2213,27 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
     n = setup_neighbour (peer);
   n->send_connect_ack = 1;
   n->connect_ack_timestamp = ts;
+
   switch (n->state)
   {  
   case S_NOT_CONNECTED:
-    n->state = S_CONNECT_RECV_ATS;
-    n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
-    GNUNET_ATS_reset_backoff (GST_ats, peer);
-    GNUNET_ATS_suggest_address (GST_ats, peer);
-    check_blacklist (peer, ts, address, session, ats, ats_count);
+    n->state = S_CONNECT_RECV_BLACKLIST_INBOUND;
+    /* Do a blacklist check for the new address */
+    check_blacklist (peer, ts, address, session);
     break;
   case S_INIT_ATS:
+    /* CONNECT message takes priority over us asking ATS for address */
+    n->state = S_CONNECT_RECV_BLACKLIST_INBOUND;
+    /* fallthrough */
   case S_INIT_BLACKLIST:
   case S_CONNECT_SENT:
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
   case S_CONNECT_RECV_ATS:
   case S_CONNECT_RECV_BLACKLIST:
   case S_CONNECT_RECV_ACK:
     /* It can never hurt to have an alternative address in the above cases, 
        see if it is allowed */
-    check_blacklist (peer, ts, address, session, ats, ats_count);
+    check_blacklist (peer, ts, address, session);
     break;
   case S_CONNECTED:
     /* we are already connected and can thus send the ACK immediately;
@@ -2034,14 +2244,14 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
     n->send_connect_ack = 0;
     send_session_connect_ack_message (n->primary_address.address,
                                      n->primary_address.session, ts);
-    check_blacklist (peer, ts, address, session, ats, ats_count);
+    check_blacklist (peer, ts, address, session);
     break;
   case S_RECONNECT_ATS:
   case S_RECONNECT_BLACKLIST:
   case S_RECONNECT_SENT:
     /* It can never hurt to have an alternative address in the above cases, 
        see if it is allowed */
-    check_blacklist (peer, ts, address, session, ats, ats_count);
+    check_blacklist (peer, ts, address, session);
     break;
   case S_CONNECTED_SWITCHING_BLACKLIST:
   case S_CONNECTED_SWITCHING_CONNECT_SENT:
@@ -2053,7 +2263,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
     n->send_connect_ack = 0;
     send_session_connect_ack_message (n->primary_address.address,
                                      n->primary_address.session, ts);
-    check_blacklist (peer, ts, address, session, ats, ats_count);
+    check_blacklist (peer, ts, address, session);
     break;
   case S_DISCONNECT:
     /* get rid of remains without terminating sessions, ready to re-try */
@@ -2061,7 +2271,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
     n = setup_neighbour (peer);
     n->state = S_CONNECT_RECV_ATS;
     GNUNET_ATS_reset_backoff (GST_ats, peer);
-    GNUNET_ATS_suggest_address (GST_ats, peer);
+    n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, peer);
     break;
   case S_DISCONNECT_FINISHED:
     /* should not be possible */
@@ -2111,6 +2321,8 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
   if (NULL == (papi = GST_plugins_find (address->transport_name)))
   {
     /* we don't have the plugin for this address */
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "2348 : `%s' \n", address->transport_name);
     GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
     return;
   }
@@ -2118,11 +2330,27 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
   {
     GNUNET_break (0);
     if (strlen (address->transport_name) > 0)
-      GNUNET_ATS_address_destroyed (GST_ats, address, session);
+      GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
     return;
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "ATS tells us to switch to address '%s' session %p for "
+              "peer `%s' in state %s (quota in/out %u %u )\n",
+              (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
+              session,
+              GNUNET_i2s (peer),
+              print_state (n->state),
+              ntohl (bandwidth_in.value__),
+              ntohl (bandwidth_out.value__));
+
   if (NULL == session)
+  {
     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 (&address->peer), GST_plugins_a2s (address), session);
+  }
   if (NULL == session)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2131,10 +2359,6 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "ATS tells us to switch to address '%s' for peer `%s'\n",
-              (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
-              GNUNET_i2s (peer));
   switch (n->state)
   {
   case S_NOT_CONNECTED:
@@ -2148,7 +2372,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_INIT_BLACKLIST:
     /* ATS suggests a different address, switch again */
@@ -2157,7 +2381,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_CONNECT_SENT:
     /* ATS suggests a different address, switch again */
@@ -2167,7 +2391,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_CONNECT_RECV_ATS:
     set_address (&n->primary_address,
@@ -2176,7 +2400,13 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
+    break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
+    n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
+    check_blacklist (&n->id,
+                     n->connect_ack_timestamp,
+                     address, session);
     break;
   case S_CONNECT_RECV_BLACKLIST:
   case S_CONNECT_RECV_ACK:
@@ -2187,7 +2417,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_CONNECTED:
     GNUNET_assert (NULL != n->primary_address.address);
@@ -2206,7 +2436,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->state = S_CONNECTED_SWITCHING_BLACKLIST;
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
-                    address, session, ats, ats_count);
+                    address, session);
     break;
   case S_RECONNECT_ATS:
     set_address (&n->primary_address,
@@ -2215,7 +2445,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_RECONNECT_BLACKLIST:
     /* ATS asks us to switch while we were trying to reconnect; switch to new
@@ -2225,7 +2455,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count);    
+                    address, session);
     break;
   case S_RECONNECT_SENT:
     /* ATS asks us to switch while we were trying to reconnect; switch to new
@@ -2236,7 +2466,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT);
     check_blacklist (&n->id,
                     n->connect_ack_timestamp,
-                    address, session, ats, ats_count); 
+                    address, session);
     break;
   case S_CONNECTED_SWITCHING_BLACKLIST:
     if (n->primary_address.session == session)
@@ -2251,7 +2481,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
                 address, session, bandwidth_in, bandwidth_out, GNUNET_NO);
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
-                    address, session, ats, ats_count);
+                    address, session);
     break;
   case S_CONNECTED_SWITCHING_CONNECT_SENT:
     if (n->primary_address.session == session)
@@ -2267,7 +2497,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     n->state = S_CONNECTED_SWITCHING_BLACKLIST;
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
-                    address, session, ats, ats_count);
+                    address, session);
     break;
   case S_DISCONNECT:
     /* not going to switch addresses while disconnecting */
@@ -2300,6 +2530,11 @@ master_task (void *cls,
 
   n->task = GNUNET_SCHEDULER_NO_TASK;
   delay = GNUNET_TIME_absolute_get_remaining (n->timeout);  
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Master task runs for neighbour `%s' in state %s with timeout in %llu ms\n",
+             GNUNET_i2s (&n->id),
+             print_state(n->state),
+             (unsigned long long) delay.rel_value);
   switch (n->state)
   {
   case S_NOT_CONNECTED:
@@ -2340,6 +2575,17 @@ master_task (void *cls,
       return;
     }
     break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
+    if (0 == delay.rel_value)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Connection to `%s' timed out waiting BLACKLIST to approve address to use for received CONNECT\n",
+                  GNUNET_i2s (&n->id));
+      n->state = S_DISCONNECT_FINISHED;
+      free_neighbour (n, GNUNET_NO);
+      return;
+    }
+    break;
   case S_CONNECT_RECV_ATS:
     if (0 == delay.rel_value)
     {
@@ -2442,7 +2688,6 @@ master_task (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Cleaning up connection to `%s' after sending DISCONNECT\n",
                GNUNET_i2s (&n->id));
-    n->state = S_DISCONNECT_FINISHED;
     free_neighbour (n, GNUNET_NO);
     return;
   case S_DISCONNECT_FINISHED:
@@ -2454,8 +2699,16 @@ master_task (void *cls,
     GNUNET_break (0);
     break;  
   }
-  delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time),
-                                   delay);
+  if ( (S_CONNECTED_SWITCHING_CONNECT_SENT == n->state) ||
+       (S_CONNECTED_SWITCHING_BLACKLIST == n->state) ||
+       (S_CONNECTED == n->state) )    
+  {
+    /* if we are *now* in one of these three states, we're sending
+       keep alive messages, so we need to consider the keepalive
+       delay, not just the connection timeout */
+    delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time),
+                                     delay);
+  }
   if (GNUNET_SCHEDULER_NO_TASK == n->task)
     n->task = GNUNET_SCHEDULER_add_delayed (delay,
                                            &master_task,
@@ -2492,16 +2745,12 @@ send_session_ack_message (struct NeighbourMapEntry *n)
  * @param address address of the other peer, NULL if other peer
  *                       connected to us
  * @param session session to use (or NULL)
- * @param ats performance data
- * @param ats_count number of entries in ats
  */
 void
 GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
                                    const struct GNUNET_PeerIdentity *peer,
                                    const struct GNUNET_HELLO_Address *address,
-                                   struct Session *session,
-                                   const struct GNUNET_ATS_Information *ats,
-                                   uint32_t ats_count)
+                                   struct Session *session)
 {
   const struct SessionConnectMessage *scm;
   struct GNUNET_TIME_Absolute ts;
@@ -2510,6 +2759,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received CONNECT_ACK message from peer `%s'\n",
               GNUNET_i2s (peer));
+
   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
   {
     GNUNET_break_op (0);
@@ -2548,7 +2798,14 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
                           gettext_noop ("# peers connected"), 
                           ++neighbours_connected,
                           GNUNET_NO);
-    connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+    connect_notify_cb (callback_cls, &n->id,
+                       n->primary_address.bandwidth_in,
+                       n->primary_address.bandwidth_out);
+    /* Tell ATS that the outbound session we created to send CONNECT was successfull */
+    GNUNET_ATS_address_add (GST_ats,
+                            n->primary_address.address,
+                            n->primary_address.session,
+                            NULL, 0);
     set_address (&n->primary_address,
                 n->primary_address.address,
                 n->primary_address.session,
@@ -2557,6 +2814,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
                 GNUNET_YES);
     send_session_ack_message (n);
     break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
   case S_CONNECT_RECV_ATS:
   case S_CONNECT_RECV_BLACKLIST:
   case S_CONNECT_RECV_ACK:
@@ -2592,6 +2850,10 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
     n->state = S_CONNECTED;
     n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
     GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
+    GNUNET_ATS_address_add(GST_ats,
+                           n->alternative_address.address,
+                           n->alternative_address.session,
+                           NULL, 0);
     set_address (&n->primary_address,
                 n->alternative_address.address,
                 n->alternative_address.session,
@@ -2624,8 +2886,10 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
  *
  * @param peer identity of the peer where the session died
  * @param session session that is gone
+ * @return GNUNET_YES if this was a session used, GNUNET_NO if
+ *        this session was not in use
  */
-void
+int
 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
                                    struct Session *session)
 {
@@ -2641,15 +2905,16 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
     if (bcc->na.session == session)
     {
       GST_blacklist_test_cancel (bcc->bc);
-      GNUNET_HELLO_address_free (bcc->na.address);
+      MEMDEBUG_free (bcc->na.address, __LINE__);
+      //GNUNET_HELLO_address_free (bcc->na.address);
       GNUNET_CONTAINER_DLL_remove (bc_head,
                                   bc_tail,
                                   bcc);
-      GNUNET_free (bcc);
+      MEMDEBUG_free (bcc, __LINE__);
     }
   }
   if (NULL == (n = lookup_neighbour (peer)))
-    return; /* can't affect us */
+    return GNUNET_NO; /* can't affect us */
   if (session != n->primary_address.session)
   {
     if (session == n->alternative_address.session)
@@ -2661,42 +2926,42 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
       else
        GNUNET_break (0);
     }
-    return; /* doesn't affect us further */
+    return GNUNET_NO; /* doesn't affect us further */
   }
 
   n->expect_latency_response = GNUNET_NO;
-
   switch (n->state)
   {
   case S_NOT_CONNECTED:
     GNUNET_break (0);
     free_neighbour (n, GNUNET_NO);
-    return;
+    return GNUNET_YES;
   case S_INIT_ATS:
     GNUNET_break (0);
     free_neighbour (n, GNUNET_NO);
-    return;
+    return GNUNET_YES;
   case S_INIT_BLACKLIST:
   case S_CONNECT_SENT:
     free_address (&n->primary_address);
     n->state = S_INIT_ATS;
     n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
     // FIXME: need to ask ATS for suggestions again?
-    GNUNET_ATS_suggest_address (GST_ats, &n->id);
+    n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     break;
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
   case S_CONNECT_RECV_ATS:    
   case S_CONNECT_RECV_BLACKLIST:
   case S_CONNECT_RECV_ACK:
     /* error on inbound session; free neighbour entirely */
     free_address (&n->primary_address);
     free_neighbour (n, GNUNET_NO);
-    return;
+    return GNUNET_YES;
   case S_CONNECTED:
     free_address (&n->primary_address);
     n->state = S_RECONNECT_ATS;
     n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
     /* FIXME: is this ATS call needed? */
-    GNUNET_ATS_suggest_address (GST_ats, &n->id);
+    n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     break;
   case S_RECONNECT_ATS:
     /* we don't have an address, how can it go down? */
@@ -2707,7 +2972,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
     n->state = S_RECONNECT_ATS;
     n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT);
     // FIXME: need to ask ATS for suggestions again?
-    GNUNET_ATS_suggest_address (GST_ats, &n->id);
+    n->suggest_handle = GNUNET_ATS_suggest_address (GST_ats, &n->id);
     break;
   case S_CONNECTED_SWITCHING_BLACKLIST:
     /* primary went down while we were checking secondary against
@@ -2732,6 +2997,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
     break;
   case S_DISCONNECT_FINISHED:
     /* neighbour was freed and plugins told to terminate session */
+    return GNUNET_NO;
     break;
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state));
@@ -2741,6 +3007,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
   if (GNUNET_SCHEDULER_NO_TASK != n->task)
     GNUNET_SCHEDULER_cancel (n->task);
   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
+  return GNUNET_YES;
 }
 
 
@@ -2754,16 +3021,12 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
  * @param address address of the other peer, NULL if other peer
  *                       connected to us
  * @param session session to use (or NULL)
- * @param ats performance data
- * @param ats_count number of entries in ats
  */
 void
 GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
                                   const struct GNUNET_PeerIdentity *peer,
                                   const struct GNUNET_HELLO_Address *address,
-                                  struct Session *session,
-                                  const struct GNUNET_ATS_Information *ats,
-                                  uint32_t ats_count)
+                                  struct Session *session)
 {
   struct NeighbourMapEntry *n;
 
@@ -2794,7 +3057,13 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
                         gettext_noop ("# peers connected"), 
                         ++neighbours_connected,
                         GNUNET_NO);
-  connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+  connect_notify_cb (callback_cls, &n->id,
+                     n->primary_address.bandwidth_in,
+                     n->primary_address.bandwidth_out);
+  GNUNET_ATS_address_add(GST_ats,
+                         n->primary_address.address,
+                         n->primary_address.session,
+                         NULL, 0);
   set_address (&n->primary_address,
               n->primary_address.address,
               n->primary_address.session,
@@ -2868,7 +3137,7 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
 {
   struct NeighbourMapEntry *n;
   const struct SessionDisconnectMessage *sdm;
-  GNUNET_HashCode hc;
+  struct GNUNET_HashCode hc;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received DISCONNECT message from peer `%s'\n",
@@ -2894,7 +3163,7 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
     return;
   }
   GNUNET_CRYPTO_hash (&sdm->public_key,
-                      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                      sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
                       &hc);
   if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity)))
   {
@@ -2902,15 +3171,15 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
     return;
   }
   if (ntohl (sdm->purpose.size) !=
-      sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
-      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+      sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+      sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
       sizeof (struct GNUNET_TIME_AbsoluteNBO))
   {
     GNUNET_break_op (0);
     return;
   }
   if (GNUNET_OK !=
-      GNUNET_CRYPTO_rsa_verify
+      GNUNET_CRYPTO_ecc_verify
       (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose,
        &sdm->signature, &sdm->public_key))
   {
@@ -2952,13 +3221,31 @@ struct IteratorContext
  * @return GNUNET_OK (continue to iterate)
  */
 static int
-neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
+neighbours_iterate (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct IteratorContext *ic = cls;
   struct NeighbourMapEntry *n = value;
 
   if (GNUNET_YES == test_connected (n))
-    ic->cb (ic->cb_cls, &n->id, NULL, 0, n->primary_address.address);
+  {
+    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
+    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
+
+    if (NULL != n->primary_address.address)
+    {
+      bandwidth_in = n->primary_address.bandwidth_in;
+      bandwidth_out = n->primary_address.bandwidth_out;
+    }
+    else
+    {
+      bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
+      bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
+    }
+
+    ic->cb (ic->cb_cls, &n->id,
+            n->primary_address.address,
+            bandwidth_in, bandwidth_out);
+  }
   return GNUNET_OK;
 }
 
@@ -3021,14 +3308,20 @@ GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer)
   switch (n->state)
   {
   case S_CONNECTED:
+  case S_CONNECTED_SWITCHING_CONNECT_SENT:
+  case S_CONNECTED_SWITCHING_BLACKLIST:
   case S_RECONNECT_SENT:
   case S_RECONNECT_ATS:
+  case S_RECONNECT_BLACKLIST:
     return n->latency;
   case S_NOT_CONNECTED:
   case S_INIT_BLACKLIST:
   case S_INIT_ATS:
-  case S_CONNECT_SENT:
+  case S_CONNECT_RECV_BLACKLIST_INBOUND:
+  case S_CONNECT_RECV_ATS:
   case S_CONNECT_RECV_BLACKLIST:
+  case S_CONNECT_RECV_ACK:
+  case S_CONNECT_SENT:
   case S_DISCONNECT:
   case S_DISCONNECT_FINISHED:
     return GNUNET_TIME_UNIT_FOREVER_REL;
@@ -3067,18 +3360,20 @@ GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
  * @param disconnect_cb function to call if we disconnect from a peer
  * @param peer_address_cb function to call if we change an active address
  *                   of a neighbour
+ * @param max_fds maximum number of fds to use
  */
 void
 GST_neighbours_start (void *cls,
-                      GNUNET_TRANSPORT_NotifyConnect connect_cb,
+                                                                       NotifyConnect connect_cb,
                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb,
-                      GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb)
+                      GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb,
+                      unsigned int max_fds)
 {
   callback_cls = cls;
   connect_notify_cb = connect_cb;
   disconnect_notify_cb = disconnect_cb;
   address_change_cb = peer_address_cb;
-  neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
+  neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE, GNUNET_NO);
 }
 
 
@@ -3091,7 +3386,7 @@ GST_neighbours_start (void *cls,
  * @return GNUNET_OK (continue to iterate)
  */
 static int
-disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
+disconnect_all_neighbours (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct NeighbourMapEntry *n = value;