- fix coverity
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_peer.c
index b9d29c00c6ac11c2c83cdb491cbf7cad13fcfd8f..fa16db4bbb6b6e99c97b1be34607f385538d84a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2013, 2015 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
-
-
+/**
+ * @file cadet/gnunet-service-cadet_peer.c
+ * @brief GNUnet CADET service connection handling
+ * @author Bartlomiej Polot
+ */
 #include "platform.h"
 #include "gnunet_util_lib.h"
-
 #include "gnunet_signatures.h"
-
 #include "gnunet_transport_service.h"
+#include "gnunet_ats_service.h"
 #include "gnunet_core_service.h"
 #include "gnunet_statistics_service.h"
-
 #include "cadet_protocol.h"
-
 #include "gnunet-service-cadet_peer.h"
 #include "gnunet-service-cadet_dht.h"
 #include "gnunet-service-cadet_connection.h"
  */
 struct CadetPeerQueue
 {
-    /**
-      * DLL next
-      */
+  /**
+   * DLL next
+   */
   struct CadetPeerQueue *next;
 
-    /**
-      * DLL previous
-      */
+  /**
+   * DLL previous
+   */
   struct CadetPeerQueue *prev;
 
-    /**
-     * Peer this transmission is directed to.
-     */
+  /**
+   * Peer this transmission is directed to.
+   */
   struct CadetPeer *peer;
 
-    /**
-     * Connection this message belongs to.
-     */
+  /**
+   * Connection this message belongs to.
+   */
   struct CadetConnection *c;
 
-    /**
-     * Is FWD in c?
-     */
+  /**
+   * Is FWD in c?
+   */
   int fwd;
 
-    /**
-     * Pointer to info stucture used as cls.
-     */
+  /**
+   * Pointer to info stucture used as cls.
+   */
   void *cls;
 
   /**
@@ -95,59 +95,55 @@ struct CadetPeerQueue
   uint32_t payload_id;
 
   /**
-     * Size of the message
-     */
+   * Size of the message
+   */
   size_t size;
 
-    /**
-     * Set when this message starts waiting for CORE.
-     */
+  /**
+   * Set when this message starts waiting for CORE.
+   */
   struct GNUNET_TIME_Absolute start_waiting;
 
-    /**
-     * Function to call on sending.
-     */
-  GCP_sent callback;
+  /**
+   * Function to call on sending.
+   */
+  GCP_sent cont;
 
-    /**
-     * Closure for callback.
-     */
-  void *callback_cls;
+  /**
+   * Closure for callback.
+   */
+  void *cont_cls;
 };
 
+
 /**
  * Struct containing all information regarding a given peer
  */
 struct CadetPeer
 {
-    /**
-     * ID of the peer
-     */
+  /**
+   * ID of the peer
+   */
   GNUNET_PEER_Id id;
 
-    /**
-     * Axolotl permanent public key.
-     */
-  struct GNUNET_CRYPTO_EcdhePublicKey ax_key;
-
-    /**
-     * Last time we heard from this peer
-     */
+  /**
+   * Last time we heard from this peer
+   */
   struct GNUNET_TIME_Absolute last_contact;
 
-    /**
-     * Paths to reach the peer, ordered by ascending hop count
-     */
+  /**
+   * Paths to reach the peer, ordered by ascending hop count
+   */
   struct CadetPeerPath *path_head;
 
-    /**
-     * Paths to reach the peer, ordered by ascending hop count
-     */
+  /**
+   * Paths to reach the peer, ordered by ascending hop count
+   */
   struct CadetPeerPath *path_tail;
 
-    /**
-     * Handle to stop the DHT search for paths to this peer
-     */
+  /**
+   * Handle to stop the DHT search for paths to this peer
+   */
   struct GCD_search_handle *search_h;
 
   /**
@@ -155,19 +151,19 @@ struct CadetPeer
    */
   struct GNUNET_SCHEDULER_Task *search_delayed;
 
-    /**
-     * Tunnel to this peer, if any.
-     */
+  /**
+   * Tunnel to this peer, if any.
+   */
   struct CadetTunnel *tunnel;
 
-    /**
-     * Connections that go through this peer, indexed by tid;
-     */
+  /**
+   * Connections that go through this peer; indexed by tid.
+   */
   struct GNUNET_CONTAINER_MultiHashMap *connections;
 
-    /**
-     * Handle for queued transmissions
-     */
+  /**
+   * Handle for queued transmissions
+   */
   struct GNUNET_CORE_TransmitHandle *core_transmit;
 
   /**
@@ -194,6 +190,18 @@ struct CadetPeer
    * Hello message.
    */
   struct GNUNET_HELLO_Message* hello;
+
+  /**
+   * Handle to us offering the HELLO to the transport.
+   */
+  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+  /**
+   * Handle to our ATS request asking ATS to suggest an address
+   * to TRANSPORT for this peer (to establish a direct link).
+   */
+  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
 };
 
 
@@ -217,7 +225,7 @@ extern struct GNUNET_PeerIdentity my_full_id;
 extern GNUNET_PEER_Id myid;
 
 /**
- * Peers known, indexed by PeerIdentity (CadetPeer).
+ * Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`.
  */
 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
 
@@ -232,15 +240,25 @@ static unsigned long long max_peers;
 static unsigned long long drop_percent;
 
 /**
- * Handle to communicate with core.
+ * Handle to communicate with CORE.
  */
 static struct GNUNET_CORE_Handle *core_handle;
 
+/**
+ * Handle to communicate with ATS.
+ */
+static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
 /**
  * Handle to try to start new connections.
  */
 static struct GNUNET_TRANSPORT_Handle *transport_handle;
 
+/**
+ * Shutdown falg.
+ */
+static int in_shutdown;
+
 
 /******************************************************************************/
 /*****************************     DEBUG      *********************************/
@@ -255,6 +273,7 @@ static struct GNUNET_TRANSPORT_Handle *transport_handle;
 static void
 queue_debug (const struct CadetPeer *p, enum GNUNET_ErrorType level)
 {
+  struct GNUNET_TIME_Relative core_wait_time;
   struct CadetPeerQueue *q;
   int do_log;
 
@@ -267,7 +286,12 @@ queue_debug (const struct CadetPeer *p, enum GNUNET_ErrorType level)
   LOG2 (level, "QQQ Message queue towards %s\n", GCP_2s (p));
   LOG2 (level, "QQQ  queue length: %u\n", p->queue_n);
   LOG2 (level, "QQQ  core tmt rdy: %p\n", p->core_transmit);
-
+  if (NULL != p->core_transmit)
+  {
+    core_wait_time = GNUNET_TIME_absolute_get_duration (p->tmt_time);
+    LOG2 (level, "QQQ  core called %s ago\n",
+          GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
+  }
   for (q = p->queue_head; NULL != q; q = q->next)
   {
     LOG2 (level, "QQQ  - %s %s on %s\n",
@@ -319,10 +343,9 @@ GCP_debug (const struct CadetPeer *p, enum GNUNET_ErrorType level)
 
   LOG2 (level, "PPP core transmit handle %p\n", p->core_transmit);
   LOG2 (level, "PPP DHT GET handle %p\n", p->search_h);
+  conns = 0;
   if (NULL != p->connections)
-    conns = GNUNET_CONTAINER_multihashmap_size (p->connections);
-  else
-    conns = 0;
+    conns += GNUNET_CONTAINER_multihashmap_size (p->connections);
   LOG2 (level, "PPP # connections over link to peer: %u\n", conns);
   queue_debug (p, level);
   LOG2 (level, "PPP DEBUG END\n");
@@ -338,7 +361,7 @@ GCP_debug (const struct CadetPeer *p, enum GNUNET_ErrorType level)
  * Iterator to notify all connections of a broken link. Mark connections
  * to destroy after all traffic has been sent.
  *
- * @param cls Closure (peer disconnected).
+ * @param cls Closure (disconnected peer).
  * @param key Current key code (peer id).
  * @param value Value in the hash map (connection).
  *
@@ -352,10 +375,10 @@ notify_broken (void *cls,
   struct CadetPeer *peer = cls;
   struct CadetConnection *c = value;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  notifying %s due to %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Notifying %s due to %s disconnect\n",
        GCC_2s (c), GCP_2s (peer));
-  GCC_notify_broken (c, peer);
-
+  GCC_neighbor_disconnected (c, peer);
   return GNUNET_YES;
 }
 
@@ -364,7 +387,6 @@ notify_broken (void *cls,
  * Remove the direct path to the peer.
  *
  * @param peer Peer to remove the direct path from.
- *
  */
 static struct CadetPeerPath *
 pop_direct_path (struct CadetPeer *peer)
@@ -375,7 +397,9 @@ pop_direct_path (struct CadetPeer *peer)
   {
     if (2 >= iter->length)
     {
-      GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+      GNUNET_CONTAINER_DLL_remove (peer->path_head,
+                                  peer->path_tail,
+                                  iter);
       return iter;
     }
   }
@@ -387,6 +411,7 @@ pop_direct_path (struct CadetPeer *peer)
 /***************************** CORE CALLBACKS *********************************/
 /******************************************************************************/
 
+
 /**
  * Method called whenever a given peer connects.
  *
@@ -394,41 +419,51 @@ pop_direct_path (struct CadetPeer *peer)
  * @param peer peer identity this notification is about
  */
 static void
-core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
+core_connect (void *cls,
+              const struct GNUNET_PeerIdentity *peer)
 {
-  struct CadetPeer *mp;
+  struct CadetPeer *neighbor;
   struct CadetPeerPath *path;
   char own_id[16];
 
-  strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
-  mp = GCP_get (peer);
-  if (myid == mp->id)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id);
+  GCC_check_connections ();
+  GNUNET_snprintf (own_id,
+                   sizeof (own_id),
+                   "%s",
+                   GNUNET_i2s (&my_full_id));
+  neighbor = GCP_get (peer, GNUNET_YES);
+  if (myid == neighbor->id)
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "CONNECTED %s (self)\n",
+         own_id);
     path = path_new (1);
   }
   else
   {
-    LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n",
-         own_id, GNUNET_i2s (peer));
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "CONNECTED %s <= %s\n",
+         own_id,
+         GNUNET_i2s (peer));
     path = path_new (2);
-    path->peers[1] = mp->id;
-    GNUNET_PEER_change_rc (mp->id, 1);
-    GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
+    path->peers[1] = neighbor->id;
+    GNUNET_PEER_change_rc (neighbor->id, 1);
   }
   path->peers[0] = myid;
   GNUNET_PEER_change_rc (myid, 1);
-  GCP_add_path (mp, path, GNUNET_YES);
-
-  mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
-
-  if (NULL != GCP_get_tunnel (mp) &&
-      0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer))
-  {
-    GCP_connect (mp);
-  }
-
-  return;
+  GCP_add_path (neighbor, path, GNUNET_YES);
+
+  GNUNET_assert (NULL == neighbor->connections);
+  neighbor->connections = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
+  GNUNET_STATISTICS_update (stats,
+                            "# peers",
+                            1,
+                            GNUNET_NO);
+
+  if ( (NULL != GCP_get_tunnel (neighbor)) &&
+       (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
+    GCP_connect (neighbor);
+  GCC_check_connections ();
 }
 
 
@@ -439,38 +474,51 @@ core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
  * @param peer peer identity this notification is about
  */
 static void
-core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+core_disconnect (void *cls,
+                 const struct GNUNET_PeerIdentity *peer)
 {
   struct CadetPeer *p;
   struct CadetPeerPath *direct_path;
   char own_id[16];
 
-  strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
+  GCC_check_connections ();
+  strncpy (own_id, GNUNET_i2s (&my_full_id), 16);
+  own_id[15] = '\0';
   p = GNUNET_CONTAINER_multipeermap_get (peers, peer);
   if (NULL == p)
   {
-    GNUNET_break (0);
+    GNUNET_break (GNUNET_YES == in_shutdown);
     return;
   }
   if (myid == p->id)
-    LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id);
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "DISCONNECTED %s (self)\n",
+         own_id);
   else
-    LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s <= %s\n",
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "DISCONNECTED %s <= %s\n",
          own_id, GNUNET_i2s (peer));
   direct_path = pop_direct_path (p);
-  GNUNET_CONTAINER_multihashmap_iterate (p->connections, &notify_broken, p);
-  GNUNET_CONTAINER_multihashmap_destroy (p->connections);
-  p->connections = NULL;
+  if (NULL != p->connections)
+  {
+    GNUNET_CONTAINER_multihashmap_iterate (p->connections,
+                                           &notify_broken,
+                                           p);
+    GNUNET_CONTAINER_multihashmap_destroy (p->connections);
+    p->connections = NULL;
+  }
   if (NULL != p->core_transmit)
-    {
-      GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
-      p->core_transmit = NULL;
-      p->tmt_time.abs_value_us = 0;
-    }
-  GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
-
+  {
+    GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
+    p->core_transmit = NULL;
+    p->tmt_time.abs_value_us = 0;
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# peers",
+                            -1,
+                            GNUNET_NO);
   path_destroy (direct_path);
-  return;
+  GCC_check_connections ();
 }
 
 
@@ -491,7 +539,8 @@ static struct GNUNET_CORE_MessageHandler core_handlers[] = {
     sizeof (struct GNUNET_CADET_Poll)},
   {&GCC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0},
   {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0},
-  {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_AX, 0}
+  {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_AX, 0},
+  {NULL, 0, 0}
 };
 
 
@@ -529,7 +578,6 @@ core_init (void *cls,
       GNUNET_assert (0);
   }
   GML_start ();
-  return;
 }
 
 
@@ -676,7 +724,8 @@ get_priority (struct CadetPeerQueue *q)
   }
 
   /* Bulky payload has lower priority, control traffic has higher. */
-  if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type)
+  if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type
+      || GNUNET_MESSAGE_TYPE_CADET_AX == q->type)
     return low;
   else
     return high;
@@ -684,7 +733,79 @@ get_priority (struct CadetPeerQueue *q)
 
 
 /**
- * Iterator over tunnel hash map entries to destroy the tunnel during shutdown.
+ * Destroy the peer_info and free any allocated resources linked to it
+ *
+ * @param peer The peer_info to destroy.
+ * @return #GNUNET_OK on success
+ */
+static int
+peer_destroy (struct CadetPeer *peer)
+{
+  struct GNUNET_PeerIdentity id;
+  struct CadetPeerPath *p;
+  struct CadetPeerPath *nextp;
+
+  GNUNET_PEER_resolve (peer->id, &id);
+  GNUNET_PEER_change_rc (peer->id, -1);
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "destroying peer %s\n",
+       GNUNET_i2s (&id));
+
+  if (GNUNET_YES !=
+      GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
+  {
+    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n");
+  }
+  GCP_stop_search (peer);
+  p = peer->path_head;
+  while (NULL != p)
+  {
+    nextp = p->next;
+    GNUNET_CONTAINER_DLL_remove (peer->path_head,
+                                 peer->path_tail,
+                                 p);
+    path_destroy (p);
+    p = nextp;
+  }
+  if (NULL != peer->tunnel)
+    GCT_destroy_empty (peer->tunnel);
+  if (NULL != peer->connections)
+  {
+    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (peer->connections));
+    GNUNET_CONTAINER_multihashmap_destroy (peer->connections);
+    peer->connections = NULL;
+  }
+  if (NULL != peer->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+    peer->hello_offer = NULL;
+  }
+  if (NULL != peer->connectivity_suggestion)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
+    peer->connectivity_suggestion = NULL;
+  }
+  while (NULL != peer->queue_head)
+  {
+    GCP_queue_destroy (peer->queue_head, GNUNET_YES, GNUNET_NO, 0);
+  }
+  if (NULL != peer->core_transmit)
+  {
+    GNUNET_break (0); /* GCP_queue_destroy should've cancelled it! */
+    GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+    peer->core_transmit = NULL;
+  }
+
+  GNUNET_free_non_null (peer->hello);
+  GNUNET_free (peer);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Iterator over peer hash map entries to destroy the peer during in_shutdown.
  *
  * @param cls closure
  * @param key current key code
@@ -693,15 +814,18 @@ get_priority (struct CadetPeerQueue *q)
  *         #GNUNET_NO if not.
  */
 static int
-shutdown_tunnel (void *cls,
-                 const struct GNUNET_PeerIdentity *key,
-                 void *value)
+shutdown_peer (void *cls,
+               const struct GNUNET_PeerIdentity *key,
+               void *value)
 {
   struct CadetPeer *p = value;
   struct CadetTunnel *t = p->tunnel;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  shutting down %s\n", GCP_2s (p));
   if (NULL != t)
     GCT_destroy (t);
+  p->tunnel = NULL;
+  peer_destroy (p);
   return GNUNET_YES;
 }
 
@@ -711,15 +835,15 @@ shutdown_tunnel (void *cls,
  * Check if peer is searching for a path (either active or delayed search).
  *
  * @param peer Peer to check
- *
- * @return GNUNET_YES if there is a search active.
- *         GNUNET_NO otherwise.
+ * @return #GNUNET_YES if there is a search active.
+ *         #GNUNET_NO otherwise.
  */
 static int
 is_searching (const struct CadetPeer *peer)
 {
-  return (NULL == peer->search_h && NULL == peer->search_delayed) ?
-         GNUNET_NO : GNUNET_YES;
+  return ( (NULL == peer->search_h) &&
+           (NULL == peer->search_delayed) ) ?
+    GNUNET_NO : GNUNET_YES;
 }
 
 
@@ -727,59 +851,16 @@ is_searching (const struct CadetPeer *peer)
  * @brief Start a search for a peer.
  *
  * @param cls Closure (Peer to search for).
- * @param tc Task context.
  */
 static void
-delayed_search (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+delayed_search (void *cls)
 {
   struct CadetPeer *peer = cls;
 
   peer->search_delayed = NULL;
-
-  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
-    return;
-
+  GCC_check_connections ();
   GCP_start_search (peer);
-}
-
-
-/**
- * Destroy the peer_info and free any allocated resources linked to it
- *
- * @param peer The peer_info to destroy.
- *
- * @return GNUNET_OK on success
- */
-static int
-peer_destroy (struct CadetPeer *peer)
-{
-  struct GNUNET_PeerIdentity id;
-  struct CadetPeerPath *p;
-  struct CadetPeerPath *nextp;
-
-  GNUNET_PEER_resolve (peer->id, &id);
-  GNUNET_PEER_change_rc (peer->id, -1);
-
-  LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id));
-
-  if (GNUNET_YES !=
-    GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
-  {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n");
-  }
-  GCP_stop_search (peer);
-  p = peer->path_head;
-  while (NULL != p)
-  {
-    nextp = p->next;
-    GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
-    path_destroy (p);
-    p = nextp;
-  }
-  GCT_destroy_empty (peer->tunnel);
-  GNUNET_free (peer);
-  return GNUNET_OK;
+  GCC_check_connections ();
 }
 
 
@@ -787,7 +868,6 @@ peer_destroy (struct CadetPeer *peer)
  * Returns if peer is used (has a tunnel or is neighbor).
  *
  * @param peer Peer to check.
- *
  * @return #GNUNET_YES if peer is in use.
  */
 static int
@@ -885,7 +965,6 @@ peer_delete_oldest (void)
  * considering the tunnel properties.
  *
  * @param peer The destination peer.
- *
  * @return Best current known path towards the peer, if any.
  */
 static struct CadetPeerPath *
@@ -922,7 +1001,6 @@ peer_get_best_path (const struct CadetPeer *peer)
  * - For payload traffic, check the connection flow control.
  *
  * @param q Queue element to inspect.
- *
  * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise.
  */
 static int
@@ -980,8 +1058,8 @@ peer_get_first_message (const struct CadetPeer *peer)
  * paths form the initial tunnel, which can be optimized later.
  * Called on each result obtained for the DHT search.
  *
- * @param cls closure
- * @param path
+ * @param cls Closure (peer towards a path has been found).
+ * @param path Path created from the DHT query. Will be freed afterwards.
  */
 static void
 search_handler (void *cls, const struct CadetPeerPath *path)
@@ -989,6 +1067,7 @@ search_handler (void *cls, const struct CadetPeerPath *path)
   struct CadetPeer *peer = cls;
   unsigned int connection_count;
 
+  GCC_check_connections ();
   GCP_add_path_to_all (path, GNUNET_NO);
 
   /* Count connections */
@@ -996,14 +1075,17 @@ search_handler (void *cls, const struct CadetPeerPath *path)
 
   /* If we already have our minimum (or more) connections, it's enough */
   if (CONNECTIONS_PER_TUNNEL <= connection_count)
+  {
+    GCC_check_connections ();
     return;
+  }
 
   if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
     GCP_connect (peer);
   }
-  return;
+  GCC_check_connections ();
 }
 
 
@@ -1020,6 +1102,21 @@ get_core_size (size_t message_size)
   return message_size + sizeof (struct GNUNET_CADET_ACK);
 }
 
+/**
+ * Test if a message type is connection management traffic
+ * or regular payload traffic.
+ *
+ * @param type Message type.
+ *
+ * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise.
+ */
+static int
+is_connection_management (uint16_t type)
+{
+  return type == GNUNET_MESSAGE_TYPE_CADET_ACK ||
+         type == GNUNET_MESSAGE_TYPE_CADET_POLL;
+}
+
 
 /**
  * Fill a core buffer with the appropriate data for the queued message.
@@ -1097,6 +1194,27 @@ fill_buf (struct CadetPeerQueue *queue, void *buf, size_t size, uint32_t *pid)
 }
 
 
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @param q Queue handle with info about the message.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (struct CadetPeerQueue *q)
+{
+  if (0 == drop_percent)
+    return GNUNET_NO;
+
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+    return GNUNET_YES;
+
+  return GNUNET_NO;
+}
+
+
 /**
  * Core callback to write a queued packet to core buffer
  *
@@ -1113,6 +1231,7 @@ queue_send (void *cls, size_t size, void *buf)
   struct CadetConnection *c;
   struct CadetPeerQueue *queue;
   struct GNUNET_TIME_Relative core_wait_time;
+  const char *wait_s;
   const struct GNUNET_PeerIdentity *dst_id;
   size_t msg_size;
   size_t total_size;
@@ -1120,6 +1239,7 @@ queue_send (void *cls, size_t size, void *buf)
   char *dst;
   uint32_t pid;
 
+  GCC_check_connections ();
   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n",
@@ -1128,9 +1248,34 @@ queue_send (void *cls, size_t size, void *buf)
   /* Sanity checking */
   if (NULL == buf || 0 == size)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n");
-    peer->tmt_time.abs_value_us = 0;
-    peer->core_transmit = NULL;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  not allowed/\n");
+    if (GNUNET_NO == in_shutdown)
+    {
+      queue = peer_get_first_message (peer);
+      if (NULL == queue)
+      {
+        peer->core_transmit = NULL;
+        peer->tmt_time.abs_value_us = 0;
+        GCC_check_connections ();
+        return 0;
+      }
+      dst_id = GNUNET_PEER_resolve2 (peer->id);
+      peer->core_transmit =
+          GNUNET_CORE_notify_transmit_ready (core_handle,
+                                             GNUNET_NO, get_priority (queue),
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             dst_id,
+                                             get_core_size (queue->size),
+                                             &queue_send,
+                                             peer);
+      peer->tmt_time = GNUNET_TIME_absolute_get ();
+    }
+    else
+    {
+      peer->core_transmit = NULL;
+      peer->tmt_time.abs_value_us = 0;
+    }
+    GCC_check_connections ();
     return 0;
   }
 
@@ -1148,8 +1293,13 @@ queue_send (void *cls, size_t size, void *buf)
     return 0;
   }
   core_wait_time = GNUNET_TIME_absolute_get_duration (peer->tmt_time);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " core wait time %s\n",
-       GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
+  wait_s = GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_YES);
+  if (core_wait_time.rel_value_us >= 1000000)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         " %s: core wait time %s (> 1 second) for %u bytes\n",
+         GCP_2s (peer), wait_s, queue->size);
+  }
   peer->tmt_time.abs_value_us = 0;
 
   /* Copy all possible messages to the core buffer */
@@ -1157,17 +1307,16 @@ queue_send (void *cls, size_t size, void *buf)
   {
     c = queue->c;
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  on connection %s %s\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  on conn %s %s\n",
          GCC_2s (c), GC_f2s(queue->fwd));
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  size %u ok (%u/%u)\n",
          queue->size, total_size, size);
 
     msg_size = fill_buf (queue, (void *) dst, size, &pid);
 
-    if (0 < drop_percent &&
-        GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+    if (should_I_drop (queue))
     {
-      LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on connection %s %s\n",
+      LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on conn %s %s\n",
            GC_m2s (queue->type), GC_m2s (queue->payload_type),
            queue->payload_id, GCC_2s (c), GC_f2s (queue->fwd));
       msg_size = 0;
@@ -1175,9 +1324,10 @@ queue_send (void *cls, size_t size, void *buf)
     else
     {
       LOG (GNUNET_ERROR_TYPE_INFO,
-           "snd %s (%s %4u) on connection %s (%p) %s (size %u)\n",
+           ">>> %s (%s %4u) on conn %s (%p) %s [%5u], after %s\n",
            GC_m2s (queue->type), GC_m2s (queue->payload_type),
-           queue->payload_id, GCC_2s (c), c, GC_f2s (queue->fwd), msg_size);
+           queue->payload_id, GCC_2s (c), c,
+           GC_f2s (queue->fwd), msg_size, wait_s);
     }
     total_size += msg_size;
     rest -= msg_size;
@@ -1222,7 +1372,7 @@ queue_send (void *cls, size_t size, void *buf)
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  return %d\n", total_size);
   queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
-
+  GCC_check_connections ();
   return total_size;
 }
 
@@ -1248,12 +1398,15 @@ queue_send (void *cls, size_t size, void *buf)
  *         #GNUNET_NO otherwise.
  */
 int
-GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
-                   int sent, uint32_t pid)
+GCP_queue_destroy (struct CadetPeerQueue *queue,
+                   int clear_cls,
+                   int sent,
+                   uint32_t pid)
 {
   struct CadetPeer *peer;
   int connection_destroyed;
 
+  GCC_check_connections ();
   peer = queue->peer;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy %s\n", GC_m2s (queue->type));
   if (GNUNET_YES == clear_cls)
@@ -1269,6 +1422,7 @@ GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
       case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
       case GNUNET_MESSAGE_TYPE_CADET_KX:
       case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+      case GNUNET_MESSAGE_TYPE_CADET_AX:
       case GNUNET_MESSAGE_TYPE_CADET_ACK:
       case GNUNET_MESSAGE_TYPE_CADET_POLL:
         GNUNET_free_non_null (queue->cls);
@@ -1282,23 +1436,21 @@ GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
   }
   GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
 
-  if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK &&
-      queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL)
+  if (!is_connection_management (queue->type))
   {
     peer->queue_n--;
   }
 
-  if (NULL != queue->callback)
+  if (NULL != queue->cont)
   {
     struct GNUNET_TIME_Relative wait_time;
 
     wait_time = GNUNET_TIME_absolute_get_duration (queue->start_waiting);
     LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback, time elapsed %s\n",
          GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
-    connection_destroyed = queue->callback (queue->callback_cls,
-                                            queue->c, sent, queue->type, pid,
-                                            queue->fwd, queue->size,
-                                            wait_time);
+    connection_destroyed = queue->cont (queue->cont_cls,
+                                        queue->c, sent, queue->type, pid,
+                                        queue->fwd, queue->size, wait_time);
   }
   else
   {
@@ -1313,6 +1465,7 @@ GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
   }
 
   GNUNET_free (queue);
+  GCC_check_connections ();
   return connection_destroyed;
 }
 
@@ -1323,7 +1476,11 @@ GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
  * @param peer Peer towards which to queue the message.
  * @param cls Closure (@c type dependant). It will be used by queue_send to
  *            build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
+ * @param type Type of the message.
+ * @param payload_type Type of the message's payload
+ *                     0 if the message is a retransmission (unknown payload).
+ *                     UINT16_MAX if the message does not have payload.
+ * @param payload_id ID of the payload (MID, ACK #, etc)
  * @param size Size of the message.
  * @param c Connection this message belongs to (can be NULL).
  * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
@@ -1334,47 +1491,44 @@ GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
  *         message has been sent and therefore the handle is no longer valid.
  */
 struct CadetPeerQueue *
-GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
-               uint16_t payload_type, uint32_t payload_id, size_t size,
-               struct CadetConnection *c, int fwd,
-               GCP_sent cont, void *cont_cls)
+GCP_queue_add (struct CadetPeer *peer,
+               void *cls,
+               uint16_t type,
+               uint16_t payload_type,
+               uint32_t payload_id,
+               size_t size,
+               struct CadetConnection *c,
+               int fwd,
+               GCP_sent cont,
+               void *cont_cls)
 {
   struct CadetPeerQueue *q;
-  int error_level;
   int priority;
   int call_core;
 
-  if (NULL == c && GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN != type)
-    error_level = GNUNET_ERROR_TYPE_ERROR;
-  else
-    error_level = GNUNET_ERROR_TYPE_INFO;
-  LOG (error_level,
-       "que %s (%s %4u) on connection %s (%p) %s towards %s (size %u)\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n",
        GC_m2s (type), GC_m2s (payload_type), payload_id,
        GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
 
-  if (error_level == GNUNET_ERROR_TYPE_ERROR)
-    GNUNET_assert (0);
   if (NULL == peer->connections)
   {
     /* We are not connected to this peer, ignore request. */
-    LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GCP_2s (peer));
+    LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
     GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
                               GNUNET_NO);
     return NULL;
   }
 
   priority = 0;
-
-  if (GNUNET_MESSAGE_TYPE_CADET_POLL == type ||
-      GNUNET_MESSAGE_TYPE_CADET_ACK == type)
+  if (is_connection_management (type))
   {
     priority = 100;
   }
-
   LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
 
-  call_core = (NULL == c || type == GNUNET_MESSAGE_TYPE_CADET_KX) ?
+  call_core = (NULL == c || GNUNET_MESSAGE_TYPE_CADET_KX == type) ?
                GNUNET_YES : GCC_is_sendable (c, fwd);
   q = GNUNET_new (struct CadetPeerQueue);
   q->cls = cls;
@@ -1385,8 +1539,8 @@ GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
   q->peer = peer;
   q->c = c;
   q->fwd = fwd;
-  q->callback = cont;
-  q->callback_cls = cont_cls;
+  q->cont = cont;
+  q->cont_cls = cont_cls;
   if (100 > priority)
   {
     GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, q);
@@ -1429,6 +1583,7 @@ GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
 
   }
   queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
+  GCC_check_connections ();
   return q;
 }
 
@@ -1441,21 +1596,25 @@ GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
  *          the sent continuation call.
  */
 void
-GCP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
+GCP_queue_cancel (struct CadetPeer *peer,
+                  struct CadetConnection *c)
 {
   struct CadetPeerQueue *q;
   struct CadetPeerQueue *next;
   struct CadetPeerQueue *prev;
   int connection_destroyed;
 
+  GCC_check_connections ();
   connection_destroyed = GNUNET_NO;
   for (q = peer->queue_head; NULL != q; q = next)
   {
     prev = q->prev;
     if (q->c == c)
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GC_m2s (q->type));
-      GNUNET_break (GNUNET_NO == connection_destroyed);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "GMP queue cancel %s\n",
+           GC_m2s (q->type));
+      GNUNET_assert (GNUNET_NO == connection_destroyed);
       if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY == q->type)
       {
         q->c = NULL;
@@ -1479,12 +1638,14 @@ GCP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
     }
   }
 
-  if (NULL == peer->queue_head && NULL != peer->core_transmit)
+  if ( (NULL == peer->queue_head) &&
+       (NULL != peer->core_transmit) )
   {
     GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
     peer->core_transmit = NULL;
     peer->tmt_time.abs_value_us = 0;
   }
+  GCC_check_connections ();
 }
 
 
@@ -1540,16 +1701,17 @@ GCP_connection_pop (struct CadetPeer *peer,
   struct GNUNET_MessageHeader *msg;
   int dest;
 
+  GCC_check_connections ();
   GNUNET_assert (NULL != destroyed);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_pop on connection %p\n", c);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_pop on conn %p\n", c);
   for (q = peer->queue_head; NULL != q; q = next)
   {
     next = q->next;
     if (q->c != c)
       continue;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " - queued: %s (%s %u), callback: %p\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " - queued: %s (%s %u), cont: %p\n",
          GC_m2s (q->type), GC_m2s (q->payload_type), q->payload_id,
-         q->callback);
+         q->cont);
     switch (q->type)
     {
       case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
@@ -1568,6 +1730,8 @@ GCP_connection_pop (struct CadetPeer *peer,
 
       case GNUNET_MESSAGE_TYPE_CADET_KX:
       case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+      case GNUNET_MESSAGE_TYPE_CADET_AX:
+      case GNUNET_MESSAGE_TYPE_CADET_AX_KX:
         msg = (struct GNUNET_MessageHeader *) q->cls;
         dest = GCP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0);
         if (GNUNET_YES == dest)
@@ -1582,10 +1746,11 @@ GCP_connection_pop (struct CadetPeer *peer,
         LOG (GNUNET_ERROR_TYPE_DEBUG, "Unknown message %s\n", GC_m2s (q->type));
     }
   }
-
+  GCC_check_connections ();
   return NULL;
 }
 
+
 /**
  * Unlock a possibly locked queue for a connection.
  *
@@ -1602,6 +1767,7 @@ GCP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
   struct CadetPeerQueue *q;
   size_t size;
 
+  GCC_check_connections ();
   if (NULL != peer->core_transmit)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  already unlocked!\n");
@@ -1625,6 +1791,7 @@ GCP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
                                          &queue_send,
                                          peer);
   peer->tmt_time = GNUNET_TIME_absolute_get ();
+  GCC_check_connections ();
 }
 
 
@@ -1636,7 +1803,9 @@ GCP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
 void
 GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "GCP_init\n");
+  in_shutdown = GNUNET_NO;
   peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
@@ -1661,7 +1830,7 @@ GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
     LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
     LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
   }
-
+  ats_ch = GNUNET_ATS_connectivity_init (c);
   core_handle = GNUNET_CORE_connect (c, /* Main configuration */
                                      NULL,      /* Closure passed to CADET functions */
                                      &core_init,        /* Call core_init once connected */
@@ -1706,32 +1875,46 @@ GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
 void
 GCP_shutdown (void)
 {
-  GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL);
-
-  if (core_handle != NULL)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Shutting down peer subsystem\n");
+  in_shutdown = GNUNET_YES;
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &shutdown_peer,
+                                         NULL);
+  if (NULL != core_handle)
   {
     GNUNET_CORE_disconnect (core_handle);
     core_handle = NULL;
   }
-  if (transport_handle != NULL)
+  if (NULL != transport_handle)
   {
     GNUNET_TRANSPORT_disconnect (transport_handle);
     transport_handle = NULL;
   }
+  if (NULL != ats_ch)
+  {
+    GNUNET_ATS_connectivity_done (ats_ch);
+    ats_ch = NULL;
+  }
   GNUNET_PEER_change_rc (myid, -1);
+  GNUNET_CONTAINER_multipeermap_destroy (peers);
+  peers = NULL;
 }
 
 
 /**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
+ * Retrieve the CadetPeer stucture associated with the peer. Optionally create
+ * one and insert it in the appropriate structures if the peer is not known yet.
  *
  * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ *               #GNUNET_NO otherwise.
  *
  * @return Existing or newly created peer structure.
+ *         NULL if unknown and not requested @a create
  */
 struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id)
+GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create)
 {
   struct CadetPeer *peer;
 
@@ -1743,9 +1926,12 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id)
     {
       peer_delete_oldest ();
     }
-        GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer,
-                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
-        peer->id = GNUNET_PEER_intern (peer_id);
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CONTAINER_multipeermap_put (peers,
+                                                      peer_id,
+                                                      peer,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+    peer->id = GNUNET_PEER_intern (peer_id);
   }
   peer->last_contact = GNUNET_TIME_absolute_get ();
 
@@ -1754,36 +1940,36 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id)
 
 
 /**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
  *
  * @param peer Short identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ *               #GNUNET_NO otherwise.
  *
  * @return Existing or newly created peer structure.
+ *         NULL if unknown and not requested @a create
  */
 struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer)
+GCP_get_short (const GNUNET_PEER_Id peer, int create)
 {
-  return GCP_get (GNUNET_PEER_resolve2 (peer));
+  return GCP_get (GNUNET_PEER_resolve2 (peer), create);
 }
 
 
 /**
- * Try to connect to a peer on transport level.
+ * Function called once #GNUNET_TRANSPORT_offer_hello() is done.
+ * Marks the operation as finished.
  *
- * @param cls Closure (peer).
- * @param tc TaskContext.
+ * @param cls Closure (our `struct CadetPeer`).
  */
 static void
-try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+hello_offer_done (void *cls)
 {
   struct CadetPeer *peer = cls;
 
-  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
-    return;
-
-  GNUNET_TRANSPORT_try_connect (transport_handle,
-                                GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
+  peer->hello_offer = NULL;
 }
 
 
@@ -1798,12 +1984,14 @@ void
 GCP_connect (struct CadetPeer *peer)
 {
   struct CadetTunnel *t;
-  struct CadetPeerPath *p;
+  struct CadetPeerPath *path;
   struct CadetConnection *c;
   int rerun_search;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GCP_2s (peer));
-
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "peer_connect towards %s\n",
+       GCP_2s (peer));
   /* If we have a current hello, try to connect using it. */
   GCP_try_connect (peer);
 
@@ -1814,27 +2002,27 @@ GCP_connect (struct CadetPeer *peer)
   if (NULL != peer->path_head)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  some path exists\n");
-    p = peer_get_best_path (peer);
-    if (NULL != p)
+    path = peer_get_best_path (peer);
+    if (NULL != path)
     {
       char *s;
 
-      s = path_2s (p);
+      s = path_2s (path);
       LOG (GNUNET_ERROR_TYPE_DEBUG, "  path to use: %s\n", s);
       GNUNET_free (s);
 
-      c = GCT_use_path (t, p);
+      c = GCT_use_path (t, path);
       if (NULL == c)
       {
         /* This case can happen when the path includes a first hop that is
          * not yet known to be connected.
          *
          * This happens quite often during testing when running cadet
-         * under valgrind: core connect notifications come very late and the
-         * DHT result has already come and created a valid path.
-         * In this case, the peer->connections hashmap will be NULL and
-         * tunnel_use_path will not be able to create a connection from that
-         * path.
+         * under valgrind: core connect notifications come very late
+         * and the DHT result has already come and created a valid
+         * path.  In this case, the peer->connections
+         * hashmaps will be NULL and tunnel_use_path will not be able
+         * to create a connection from that path.
          *
          * Re-running the DHT GET should give core time to callback.
          *
@@ -1861,13 +2049,16 @@ GCP_connect (struct CadetPeer *peer)
 
     GCP_stop_search (peer);
     delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
-    peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay, &delayed_search,
+    peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay,
+                                                         &delayed_search,
                                                          peer);
+    GCC_check_connections ();
     return;
   }
 
   if (GNUNET_NO == is_searching (peer))
     GCP_start_search (peer);
+  GCC_check_connections ();
 }
 
 
@@ -1893,6 +2084,7 @@ GCP_is_neighbor (const struct CadetPeer *peer)
   }
 
   /* Is not a neighbor but connections is not NULL, probably disconnecting */
+  GNUNET_break (0);
   return GNUNET_NO;
 }
 
@@ -1908,9 +2100,11 @@ GCP_is_neighbor (const struct CadetPeer *peer)
 void
 GCP_add_tunnel (struct CadetPeer *peer)
 {
+  GCC_check_connections ();
   if (NULL != peer->tunnel)
     return;
   peer->tunnel = GCT_new (peer);
+  GCC_check_connections ();
 }
 
 
@@ -1923,38 +2117,29 @@ GCP_add_tunnel (struct CadetPeer *peer)
  *
  * @param peer Peer to add connection to.
  * @param c Connection to add.
- *
- * @return GNUNET_OK on success.
+ * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
  */
-int
+void
 GCP_add_connection (struct CadetPeer *peer,
-                    struct CadetConnection *c)
+                    struct CadetConnection *c,
+                    int pred)
 {
-  int result;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GCC_2s (c));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GCP_2s (peer));
-
-  if (NULL == peer->connections)
-  {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Peer %s is not a neighbor!\n",
-         GCP_2s (peer));
-    return GNUNET_SYSERR;
-  }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "peer %s ok, has %u connections.\n",
-       GCP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
-  result = GNUNET_CONTAINER_multihashmap_put (peer->connections,
-                                              GCC_get_h (c),
-                                              c,
-                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+       "adding connection %s\n",
+       GCC_2s (c));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "to peer %s\n",
+       GCP_2s (peer));
+  GNUNET_assert (NULL != peer->connections);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap_put (peer->connections,
+                                                    GCC_get_h (c),
+                                                    c,
+                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " now has %u connections.\n",
+       "Peer %s has now %u connections.\n",
+       GCP_2s (peer),
        GNUNET_CONTAINER_multihashmap_size (peer->connections));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result);
-
-  return result;
 }
 
 
@@ -1963,7 +2148,7 @@ GCP_add_connection (struct CadetPeer *peer,
  * is the shortest.
  *
  * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
+ * @param path New path to add. Last peer must be @c peer.
  *             Path will be either used of freed if already known.
  * @param trusted Do we trust that this path is real?
  *
@@ -1971,14 +2156,17 @@ GCP_add_connection (struct CadetPeer *peer,
  *         NULL on error.
  */
 struct CadetPeerPath *
-GCP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path,
+GCP_add_path (struct CadetPeer *peer,
+              struct CadetPeerPath *path,
               int trusted)
 {
   struct CadetPeerPath *aux;
   unsigned int l;
   unsigned int l2;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "adding path [%u] to peer %s\n",
        path->length, GCP_2s (peer));
 
   if (NULL == peer || NULL == path
@@ -2042,16 +2230,19 @@ GCP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path,
       }
     }
   }
-  GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail,
+  GNUNET_CONTAINER_DLL_insert_tail (peer->path_head,
+                                   peer->path_tail,
                                     path);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  added last\n");
 
 finish:
   if (NULL != peer->tunnel
-      && CONNECTIONS_PER_TUNNEL < GCT_count_connections (peer->tunnel))
+      && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
+      && 2 < path->length) /* Direct paths are handled by core_connect */
   {
     GCP_connect (peer);
   }
+  GCC_check_connections ();
   return path;
 }
 
@@ -2094,36 +2285,41 @@ GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
   unsigned int i;
 
   /* TODO: invert and add */
+  GCC_check_connections ();
   for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
   for (i++; i < p->length; i++)
   {
-    struct CadetPeer *aux;
+    struct CadetPeer *peer;
     struct CadetPeerPath *copy;
 
-    aux = GCP_get_short (p->peers[i]);
+    peer = GCP_get_short (p->peers[i], GNUNET_YES);
     copy = path_duplicate (p);
     copy->length = i + 1;
-    GCP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
+    GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed);
   }
+  GCC_check_connections ();
 }
 
 
 /**
- * Remove any path to the peer that has the extact same peers as the one given.
+ * Remove any path to the peer that has the exact same peers as the one given.
  *
  * @param peer Peer to remove the path from.
  * @param path Path to remove. Is always destroyed .
  */
 void
-GCP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
+GCP_remove_path (struct CadetPeer *peer,
+                struct CadetPeerPath *path)
 {
   struct CadetPeerPath *iter;
   struct CadetPeerPath *next;
 
+  GCC_check_connections ();
   GNUNET_assert (myid == path->peers[0]);
   GNUNET_assert (peer->id == path->peers[path->length - 1]);
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "Removing path %p (%u) from %s\n",
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Removing path %p (%u) from %s\n",
        path, path->length, GCP_2s (peer));
 
   for (iter = peer->path_head; NULL != iter; iter = next)
@@ -2131,12 +2327,35 @@ GCP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
     next = iter->next;
     if (0 == path_cmp (path, iter))
     {
-      GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+      GNUNET_CONTAINER_DLL_remove (peer->path_head,
+                                  peer->path_tail,
+                                  iter);
       if (iter != path)
         path_destroy (iter);
     }
   }
   path_destroy (path);
+  GCC_check_connections ();
+}
+
+
+/**
+ * Check that we are aware of a connection from a neighboring peer.
+ *
+ * @param peer Peer to the connection is with
+ * @param c Connection that should be in the map with this peer.
+ */
+void
+GCP_check_connection (const struct CadetPeer *peer,
+                      const struct CadetConnection *c)
+{
+  GNUNET_assert (NULL != peer);
+  GNUNET_assert (NULL != peer->connections);
+    return;
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_contains_value (peer->connections,
+                                                               GCC_get_h (c),
+                                                               c));
 }
 
 
@@ -2145,32 +2364,31 @@ GCP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
  *
  * @param peer Peer to remove connection from.
  * @param c Connection to remove.
- *
- * @return GNUNET_OK on success.
  */
-int
+void
 GCP_remove_connection (struct CadetPeer *peer,
                        const struct CadetConnection *c)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GCC_2s (c));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GCP_2s (peer));
-
-  if (NULL == peer || NULL == peer->connections)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Peer %s is not a neighbor!\n",
-         GCP_2s (peer));
-    return GNUNET_SYSERR;
-  }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "peer %s ok, has %u connections.\n",
-       GCP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
-
-  return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
-                                               GCC_get_h (c),
-                                               c);
+       "Removing connection %s\n",
+       GCC_2s (c));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "from peer %s\n",
+       GCP_2s (peer));
+  if ( (NULL == peer) ||
+       (NULL == peer->connections) )
+    return;
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (peer->connections,
+                                                       GCC_get_h (c),
+                                                       c));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Peer %s remains with %u connections.\n",
+       GCP_2s (peer),
+       GNUNET_CONTAINER_multihashmap_size (peer->connections));
 }
 
+
 /**
  * Start the DHT search for new paths towards the peer: we don't have
  * enough good connections.
@@ -2183,7 +2401,8 @@ GCP_start_search (struct CadetPeer *peer)
   const struct GNUNET_PeerIdentity *id;
   struct CadetTunnel *t = peer->tunnel;
 
-  if (NULL != peer->search_h)
+  GCC_check_connections ();
+ if (NULL != peer->search_h)
   {
     GNUNET_break (0);
     return;
@@ -2207,6 +2426,7 @@ GCP_start_search (struct CadetPeer *peer)
   {
     GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
   }
+  GCC_check_connections ();
 }
 
 
@@ -2219,6 +2439,7 @@ GCP_start_search (struct CadetPeer *peer)
 void
 GCP_stop_search (struct CadetPeer *peer)
 {
+  GCC_check_connections ();
   if (NULL != peer->search_h)
   {
     GCD_search_stop (peer->search_h);
@@ -2229,6 +2450,7 @@ GCP_stop_search (struct CadetPeer *peer)
     GNUNET_SCHEDULER_cancel (peer->search_delayed);
     peer->search_delayed = NULL;
   }
+  GCC_check_connections ();
 }
 
 
@@ -2289,6 +2511,8 @@ GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t)
 struct CadetTunnel *
 GCP_get_tunnel (const struct CadetPeer *peer)
 {
+  if (NULL == peer)
+    return NULL;
   return peer->tunnel;
 }
 
@@ -2300,12 +2524,14 @@ GCP_get_tunnel (const struct CadetPeer *peer)
  * @param hello Hello message.
  */
 void
-GCP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello)
+GCP_set_hello (struct CadetPeer *peer,
+              const struct GNUNET_HELLO_Message *hello)
 {
   struct GNUNET_HELLO_Message *old;
   size_t size;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
+  GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
   if (NULL == hello)
     return;
 
@@ -2313,17 +2539,15 @@ GCP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello)
   if (NULL == old)
   {
     size = GNUNET_HELLO_size (hello);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size);
     peer->hello = GNUNET_malloc (size);
     memcpy (peer->hello, hello, size);
   }
   else
   {
     peer->hello = GNUNET_HELLO_merge (old, hello);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n",
-         peer->hello, GNUNET_HELLO_size (hello));
     GNUNET_free (old);
   }
+  GCC_check_connections ();
 }
 
 
@@ -2369,68 +2593,29 @@ GCP_try_connect (struct CadetPeer *peer)
 
   if (NULL == transport_handle)
     return;
-
+  GCC_check_connections ();
+  if (GNUNET_YES == GCP_is_neighbor (peer))
+    return;
   hello = GCP_get_hello (peer);
   if (NULL == hello)
     return;
 
   mh = GNUNET_HELLO_get_header (hello);
-  GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer);
-}
-
-
-/**
- * Check if the given ECDH key is correct for the peer.
- *
- * This function caches the results if the key has been previoulsy checked,
- * otherwise checks that the key is signed with the peer's ID (EdDSA key).
- *
- * TODO: save the cached public key to permanent storage / peerinfo.
- *
- * @param peer Peer whose key to check.
- * @param key ECDH key to check.
- * @param purpose Purpose of the signature (followed by the key).
- * @param sig Signature with the peer's EdDSA key (PeerID).
- */
-int
-GCP_check_key (struct CadetPeer *peer,
-               const struct GNUNET_CRYPTO_EcdhePublicKey *key,
-               const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
-               const struct GNUNET_CRYPTO_EddsaSignature *sig)
-{
-  struct GNUNET_CRYPTO_EddsaPublicKey *pub;
-  int verified;
-
-  /* Is it the same as the cached key? */
-  if (0 == memcmp (&peer->ax_key, key, sizeof (*key)))
-    return GNUNET_OK;
-
-  /* New key, verify. */
-  pub = (struct GNUNET_CRYPTO_EddsaPublicKey *) GCP_get_id (peer);
-  verified = GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_AXKX,
-                                         purpose, sig, pub);
-
-  if (GNUNET_OK != verified)
-    return GNUNET_SYSERR;
-
-  /* Cache key for later. */
-  peer->ax_key = *key;
-  return GNUNET_OK;
-}
-
-
-/**
- * Get the Identity ECDH key of the peer.
- *
- * @param peer Peer whose key to get.
- *
- * @return Peer's permanent ECDH key (might be all 0: unknown).
- *
- */
-struct GNUNET_CRYPTO_EcdhePublicKey *
-GCP_get_ecdh_key (struct CadetPeer *peer)
-{
-  return &peer->ax_key;
+  if (NULL != peer->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+    peer->hello_offer = NULL;
+  }
+  peer->hello_offer = GNUNET_TRANSPORT_offer_hello (transport_handle,
+                                                    mh,
+                                                    &hello_offer_done,
+                                                    peer);
+  if (NULL == peer->connectivity_suggestion)
+    peer->connectivity_suggestion
+      = GNUNET_ATS_connectivity_suggest (ats_ch,
+                                         GNUNET_PEER_resolve2 (peer->id),
+                                         1 /* strength */);
+  GCC_check_connections ();
 }
 
 
@@ -2444,8 +2629,8 @@ GCP_get_ecdh_key (struct CadetPeer *peer)
  */
 void
 GCP_notify_broken_link (struct CadetPeer *peer,
-                        struct GNUNET_PeerIdentity *peer1,
-                        struct GNUNET_PeerIdentity *peer2)
+                        const struct GNUNET_PeerIdentity *peer1,
+                        const struct GNUNET_PeerIdentity *peer2)
 {
   struct CadetPeerPath *iter;
   struct CadetPeerPath *next;
@@ -2453,6 +2638,7 @@ GCP_notify_broken_link (struct CadetPeer *peer,
   GNUNET_PEER_Id p1;
   GNUNET_PEER_Id p2;
 
+  GCC_check_connections ();
   p1 = GNUNET_PEER_search (peer1);
   p2 = GNUNET_PEER_search (peer2);
 
@@ -2481,6 +2667,7 @@ GCP_notify_broken_link (struct CadetPeer *peer,
       }
     }
   }
+  GCC_check_connections ();
 }
 
 
@@ -2504,6 +2691,34 @@ GCP_count_paths (const struct CadetPeer *peer)
 }
 
 
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param cls Closure for @a callback.
+ *
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *peer,
+                   GCP_path_iterator callback,
+                   void *cls)
+{
+  struct CadetPeerPath *iter;
+  unsigned int i;
+
+  for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
+  {
+    i++;
+    if (GNUNET_YES != callback (cls, peer, iter))
+      break;
+  }
+
+  return i;
+}
+
+
 /**
  * Iterate all known peers.
  *
@@ -2511,9 +2726,14 @@ GCP_count_paths (const struct CadetPeer *peer)
  * @param cls Closure for @c iter.
  */
 void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls)
 {
-  GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls);
+  GCC_check_connections ();
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         iter,
+                                         cls);
+  GCC_check_connections ();
 }
 
 
@@ -2531,3 +2751,6 @@ GCP_2s (const struct CadetPeer *peer)
     return "(NULL)";
   return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
 }
+
+
+/* end of gnunet-service-cadet_peer.c */