-fix (C) notices
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_connection.c
index 3626e47e5e6a685e821fb07eedcc879de7f57646..2fe0c277b40058cf9c981511b81d3467491a988a 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001-2015 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2001-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
@@ -14,8 +14,8 @@
 
      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_connection.c
 #include "gnunet-service-cadet_tunnel.h"
 
 
+/**
+ * Should we run somewhat expensive checks on our invariants?
+ */
+#define CHECK_INVARIANTS 0
+
+
 #define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
 #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
 
@@ -65,6 +71,7 @@ struct CadetFlowControl
 
   /**
    * How many messages do we accept in the queue.
+   * If 0, the connection is broken in this direction (next hop disconnected).
    */
   unsigned int queue_max;
 
@@ -198,12 +205,12 @@ struct CadetConnection
   struct CadetPeerQueue *maintenance_q;
 
   /**
-   * Should equal #get_next_hop(this).
+   * Should equal #get_next_hop(), or NULL if that peer disconnected.
    */
   struct CadetPeer *next_peer;
 
   /**
-   * Should equal #get_prev_hop(this).
+   * Should equal #get_prev_hop(), or NULL if that peer disconnected.
    */
   struct CadetPeer *prev_peer;
 
@@ -223,14 +230,33 @@ struct CadetConnection
   unsigned int pending_messages;
 
   /**
-   * Destroy flag: if true, destroy on last message.
+   * Destroy flag:
+   * - if 0, connection in use.
+   * - if 1, destroy on last message.
+   * - if 2, connection is being destroyed don't re-enter.
    */
   int destroy;
 
+  /**
+   * In-connection-map flag. Sometimes, when @e destroy is set but
+   * actual destruction is delayed to enable us to finish processing
+   * queues (i.e. in the direction that is still working), we remove
+   * the connection from the map to prevent it from still being
+   * found (and used) by accident. This flag is set to #GNUNET_YES
+   * for a connection that is not in the #connections map.  Should
+   * only be #GNUNET_YES if #destroy is also non-zero.
+   */
+  int was_removed;
+
   /**
    * Counter to do exponential backoff when creating a connection (max 64).
    */
   unsigned short create_retry;
+
+  /**
+   * Task to check if connection has duplicates.
+   */
+  struct GNUNET_SCHEDULER_Task *check_duplicates_task;
 };
 
 
@@ -311,6 +337,8 @@ static struct GNUNET_TIME_Relative create_connection_time;
 /********************************   STATIC  ***********************************/
 /******************************************************************************/
 
+
+
 #if 0 // avoid compiler warning for unused static function
 static void
 fc_debug (struct CadetFlowControl *fc)
@@ -433,6 +461,12 @@ connection_get (const struct GNUNET_CADET_Hash *cid)
 }
 
 
+/**
+ * Change the connection state. Cannot change a connection marked as destroyed.
+ *
+ * @param c Connection to change.
+ * @param state New state to set.
+ */
 static void
 connection_change_state (struct CadetConnection* c,
                          enum CadetConnectionState state)
@@ -496,6 +530,7 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
   int delta;
 
   /* If origin, there is no connection to send ACKs. Wrong function! */
+  GCC_check_connections ();
   if (GCC_is_origin (c, fwd))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n",
@@ -518,6 +553,7 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "  last pid recv: %u, last ack sent: %u\n",
          prev_fc->last_pid_recv, prev_fc->last_ack_sent);
+    GCC_check_connections ();
     return;
   }
 
@@ -531,6 +567,7 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
   if (ack == prev_fc->last_ack_sent && GNUNET_NO == force)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
+    GCC_check_connections ();
     return;
   }
 
@@ -546,22 +583,24 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
     else
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
+      GCC_check_connections ();
       return;
     }
   }
 
   prev_fc->last_ack_sent = ack;
 
-  /* Build ACK message and send on connection */
+  /* Build ACK message and send on conn */
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ACK);
   msg.ack = htonl (ack);
   msg.cid = c->id;
 
-  prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header, 0, ack, c,
-                                                !fwd, GNUNET_YES,
+  prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header, UINT16_MAX, ack,
+                                                c, !fwd, GNUNET_YES,
                                                 &ack_sent, prev_fc);
   GNUNET_assert (NULL != prev_fc->ack_msg);
+  GCC_check_connections ();
 }
 
 
@@ -578,7 +617,6 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
  * @param fwd Was this a FWD going message?
  * @param size Size of the message.
  * @param wait Time spent waiting for core (only the time for THIS message)
- *
  * @return #GNUNET_YES if connection was destroyed, #GNUNET_NO otherwise.
  */
 static int
@@ -593,6 +631,7 @@ conn_message_sent (void *cls,
   double usecsperbyte;
   int forced;
 
+  GCC_check_connections ();
   LOG (GNUNET_ERROR_TYPE_DEBUG, "connection message_sent\n");
 
   GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
@@ -628,6 +667,7 @@ conn_message_sent (void *cls,
       LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n",
            GC_m2s (type));
     }
+    GCC_check_connections ();
     return GNUNET_NO;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages);
@@ -638,6 +678,7 @@ conn_message_sent (void *cls,
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "!  destroying connection!\n");
     GCC_destroy (c);
+    GCC_check_connections ();
     return GNUNET_YES;
   }
   /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
@@ -656,7 +697,9 @@ conn_message_sent (void *cls,
       if (GNUNET_YES == sent)
       {
         GNUNET_assert (NULL != q);
-        fc->last_pid_sent = pid; // FIXME
+        fc->last_pid_sent = pid;
+        if (GC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
+          GCC_start_poll (c, fwd);
         GCC_send_ack (c, fwd, GNUNET_NO);
         connection_reset_timeout (c, fwd);
       }
@@ -691,6 +734,7 @@ conn_message_sent (void *cls,
       break;
 
     case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
       break;
 
     default:
@@ -722,6 +766,7 @@ conn_message_sent (void *cls,
     p->avg /= p->size;
   }
   p->idx = (p->idx + 1) % AVG_MSGS;
+  GCC_check_connections ();
   return GNUNET_NO;
 }
 
@@ -751,7 +796,7 @@ get_prev_hop (const struct CadetConnection *c)
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  ID: %s (%u)\n",
        GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
 
-  return GCP_get_short (id);
+  return GCP_get_short (id, GNUNET_YES);
 }
 
 
@@ -780,7 +825,59 @@ get_next_hop (const struct CadetConnection *c)
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  ID: %s (%u)\n",
        GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
 
-  return GCP_get_short (id);
+  return GCP_get_short (id, GNUNET_YES);
+}
+
+
+/**
+ * Check that the direct neighbours (previous and next hop)
+ * are properly associated with this connection.
+ *
+ * @param c connection to check
+ */
+static void
+check_neighbours (const struct CadetConnection *c)
+{
+  if (NULL == c->path)
+    return; /* nothing to check */
+  GCP_check_connection (get_next_hop (c), c);
+  GCP_check_connection (get_prev_hop (c), c);
+}
+
+
+/**
+ * Helper for #GCC_check_connections().  Calls #check_neighbours().
+ *
+ * @param cls NULL
+ * @param key ignored
+ * @param value the `struct CadetConnection` to check
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+check_connection (void *cls,
+                  const struct GNUNET_HashCode *key,
+                  void *value)
+{
+  struct CadetConnection *c = value;
+
+  check_neighbours (c);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Check invariants for all connections using #check_neighbours().
+ */
+void
+GCC_check_connections ()
+{
+  if (0 == CHECK_INVARIANTS)
+    return;
+  if (NULL == connections)
+    return;
+  GNUNET_CONTAINER_multihashmap_iterate (connections,
+                                         &check_connection,
+                                         NULL);
 }
 
 
@@ -795,9 +892,7 @@ get_next_hop (const struct CadetConnection *c)
 static struct CadetPeer *
 get_hop (struct CadetConnection *c, int fwd)
 {
-  if (fwd)
-    return get_next_hop (c);
-  return get_prev_hop (c);
+  return (fwd) ? get_next_hop (c) : get_prev_hop (c);
 }
 
 
@@ -878,19 +973,22 @@ static void
 send_connection_ack (struct CadetConnection *connection, int fwd)
 {
   struct CadetTunnel *t;
+  size_t size = sizeof (struct GNUNET_CADET_ConnectionACK);
 
+  GCC_check_connections ();
   t = connection->t;
-  LOG (GNUNET_ERROR_TYPE_INFO, "---> {%14s ACK} on connection %s\n",
-       GC_f2s (!fwd), GCC_2s (connection));
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "==> { C %s ACK} %19s on conn %s (%p) %s [%5u]\n",
+       GC_f2s (!fwd), "", GCC_2s (connection), connection, GC_f2s (fwd), size);
   GCP_queue_add (get_hop (connection, fwd), NULL,
-                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0, 0,
-                 sizeof (struct GNUNET_CADET_ConnectionACK),
-                 connection, fwd, &conn_message_sent, NULL);
+                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, UINT16_MAX, 0,
+                 size, connection, fwd, &conn_message_sent, NULL);
   connection->pending_messages++;
   if (CADET_TUNNEL_NEW == GCT_get_cstate (t))
     GCT_change_cstate (t, CADET_TUNNEL_WAITING);
   if (CADET_CONNECTION_READY != connection->state)
     connection_change_state (connection, CADET_CONNECTION_SENT);
+  GCC_check_connections ();
 }
 
 
@@ -910,13 +1008,16 @@ send_broken (struct CadetConnection *c,
 {
   struct GNUNET_CADET_ConnectionBroken msg;
 
+  GCC_check_connections ();
   msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
   msg.cid = c->id;
   msg.peer1 = *id1;
   msg.peer2 = *id2;
-  GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, 0, 0, c, fwd,
-                                                    GNUNET_YES, NULL, NULL));
+  GNUNET_assert (NULL ==
+                 GCC_send_prebuilt_message (&msg.header, UINT16_MAX, 0, c, fwd,
+                                            GNUNET_YES, NULL, NULL));
+  GCC_check_connections ();
 }
 
 
@@ -938,7 +1039,8 @@ send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
   struct GNUNET_CADET_ConnectionBroken *msg;
   struct CadetPeer *neighbor;
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "---> BROKEN on unknown connection %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_INFO, "--> BROKEN on unknown connection %s\n",
        GNUNET_h2s (GC_h2hc (connection_id)));
 
   msg = GNUNET_new (struct GNUNET_CADET_ConnectionBroken);
@@ -950,11 +1052,13 @@ send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
     msg->peer2 = *id2;
   else
     memset (&msg->peer2, 0, sizeof (msg->peer2));
-  neighbor = GCP_get (peer_id);
+  neighbor = GCP_get (peer_id, GNUNET_NO); /* We MUST know neighbor. */
+  GNUNET_assert (NULL != neighbor);
   GCP_queue_add (neighbor, msg, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
-                 0, 2, sizeof (struct GNUNET_CADET_ConnectionBroken),
+                 UINT16_MAX, 2, sizeof (struct GNUNET_CADET_ConnectionBroken),
                  NULL, GNUNET_SYSERR, /* connection, fwd */
                  NULL, NULL); /* continuation */
+  GCC_check_connections ();
 }
 
 
@@ -970,11 +1074,14 @@ send_connection_keepalive (struct CadetConnection *c, int fwd)
   struct GNUNET_MessageHeader msg;
   struct CadetFlowControl *fc;
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "keepalive %s for connection %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "keepalive %s for connection %s\n",
        GC_f2s (fwd), GCC_2s (c));
 
+  GNUNET_assert (NULL != c->t);
   fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  if (0 < fc->queue_n)
+  if (0 < fc->queue_n || GNUNET_YES == GCT_has_queued_traffic (c->t))
   {
     LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n");
     return;
@@ -989,6 +1096,7 @@ send_connection_keepalive (struct CadetConnection *c, int fwd)
   GNUNET_assert (NULL ==
                  GCT_send_prebuilt_message (&msg, c->t, c,
                                             GNUNET_NO, NULL, NULL));
+  GCC_check_connections ();
 }
 
 
@@ -1001,7 +1109,8 @@ send_connection_keepalive (struct CadetConnection *c, int fwd)
 static void
 connection_recreate (struct CadetConnection *c, int fwd)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "sending connection recreate\n");
   if (fwd)
     GCC_send_create (c);
   else
@@ -1059,7 +1168,6 @@ connection_maintain (struct CadetConnection *c, int fwd)
 }
 
 
-
 /**
  * Keep the connection alive.
  *
@@ -1071,7 +1179,9 @@ connection_maintain (struct CadetConnection *c, int fwd)
 static void
 connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s keepalive for %s\n",
        GC_f2s (fwd), GCC_2s (c));
 
   if (fwd)
@@ -1083,7 +1193,7 @@ connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
     return;
 
   connection_maintain (c, fwd);
-
+  GCC_check_connections ();
   /* Next execution will be scheduled by message_sent or _maintain*/
 }
 
@@ -1098,9 +1208,11 @@ static void
 connection_fwd_keepalive (void *cls,
                           const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  GCC_check_connections ();
   connection_keepalive ((struct CadetConnection *) cls,
                         GNUNET_YES,
                         tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+  GCC_check_connections ();
 }
 
 
@@ -1114,9 +1226,11 @@ static void
 connection_bck_keepalive (void *cls,
                           const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  GCC_check_connections ();
   connection_keepalive ((struct CadetConnection *) cls,
                         GNUNET_NO,
                         tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+  GCC_check_connections ();
 }
 
 
@@ -1136,6 +1250,7 @@ schedule_next_keepalive (struct CadetConnection *c, int fwd)
   struct GNUNET_SCHEDULER_Task * *task_id;
   GNUNET_SCHEDULER_TaskCallback keepalive_task;
 
+  GCC_check_connections ();
   if (GNUNET_NO == GCC_is_origin (c, fwd))
     return;
 
@@ -1175,9 +1290,13 @@ schedule_next_keepalive (struct CadetConnection *c, int fwd)
   }
 
   /* Schedule the task */
-  *task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n",
+  *task_id = GNUNET_SCHEDULER_add_delayed (delay,
+                                           keepalive_task,
+                                           c);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "next keepalive in %s\n",
        GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
+  GCC_check_connections ();
 }
 
 
@@ -1196,7 +1315,9 @@ connection_unlock_queue (struct CadetConnection *c, int fwd)
 {
   struct CadetPeer *peer;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_unlock_queue %s on %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "connection_unlock_queue %s on %s\n",
        GC_f2s (fwd), GCC_2s (c));
 
   if (GCC_is_terminal (c, fwd))
@@ -1207,6 +1328,7 @@ connection_unlock_queue (struct CadetConnection *c, int fwd)
 
   peer = get_hop (c, fwd);
   GCP_queue_unlock (peer, c);
+  GCC_check_connections ();
 }
 
 
@@ -1220,12 +1342,15 @@ connection_unlock_queue (struct CadetConnection *c, int fwd)
  * @param fwd Cancel fwd traffic?
  */
 static void
-connection_cancel_queues (struct CadetConnection *c, int fwd)
+connection_cancel_queues (struct CadetConnection *c,
+                          int fwd)
 {
   struct CadetFlowControl *fc;
   struct CadetPeer *peer;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Cancel %s queues for connection %s\n",
+  GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Cancel %s queues for connection %s\n",
        GC_f2s (fwd), GCC_2s (c));
   if (NULL == c)
   {
@@ -1238,10 +1363,16 @@ connection_cancel_queues (struct CadetConnection *c, int fwd)
   {
     GNUNET_SCHEDULER_cancel (fc->poll_task);
     fc->poll_task = NULL;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Cancel POLL in ccq for fc %p\n", fc);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cancelled POLL task for fc %p\n", fc);
+  }
+  if (NULL != fc->poll_msg)
+  {
+    GCC_cancel (fc->poll_msg);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cancelled POLL msg for fc %p\n", fc);
   }
   peer = get_hop (c, fwd);
   GCP_queue_cancel (peer, c);
+  GCC_check_connections ();
 }
 
 
@@ -1253,13 +1384,14 @@ connection_cancel_queues (struct CadetConnection *c, int fwd)
  * @param tc TaskContext.
  */
 static void
-connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+connection_poll (void *cls,
+                 const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
 /**
  * Callback called when a queued POLL message is sent.
  *
- * @param cls Closure (FC).
+ * @param cls Closure (flow control context).
  * @param c Connection this message was on.
  * @param q Queue handler this call invalidates.
  * @param type Type of message sent.
@@ -1274,21 +1406,29 @@ poll_sent (void *cls,
 {
   struct CadetFlowControl *fc = cls;
 
+  GNUNET_assert (fc->poll_msg == q);
+  fc->poll_msg = NULL;
   if (2 == c->destroy)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL canceled on shutdown\n");
     return;
   }
+  if (0 == fc->queue_max)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL cancelled: neighbor disconnected\n");
+    return;
+  }
   LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL sent for %s, scheduling new one!\n",
        GCC_2s (c));
-  fc->poll_msg = NULL;
+  GNUNET_assert (NULL == fc->poll_task);
   fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
   fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
-                                                &connection_poll, fc);
+                                                &connection_poll,
+                                                fc);
   LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
-
 }
 
+
 /**
  * Function called if a connection has been stalled for a while,
  * possibly due to a missed ACK. Poll the neighbor about its ACK status.
@@ -1305,6 +1445,7 @@ connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   int fwd;
 
   fc->poll_task = NULL;
+  GCC_check_connections ();
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
     return;
@@ -1320,9 +1461,10 @@ connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   msg.pid = htonl (fc->last_pid_sent);
   LOG (GNUNET_ERROR_TYPE_DEBUG, " last pid sent: %u\n", fc->last_pid_sent);
   fc->poll_msg =
-      GCC_send_prebuilt_message (&msg.header, 0, fc->last_pid_sent, c,
+      GCC_send_prebuilt_message (&msg.header, UINT16_MAX, fc->last_pid_sent, c,
                                  fc == &c->fwd_fc, GNUNET_YES, &poll_sent, fc);
   GNUNET_assert (NULL != fc->poll_msg);
+  GCC_check_connections ();
 }
 
 
@@ -1342,6 +1484,7 @@ resend_messages_and_destroy (struct CadetConnection *c, int fwd)
   unsigned int pending;
   int destroyed;
 
+  GCC_check_connections ();
   c->state = CADET_CONNECTION_DESTROYED;
   c->destroy = GNUNET_YES;
 
@@ -1369,88 +1512,98 @@ resend_messages_and_destroy (struct CadetConnection *c, int fwd)
     }
     GCC_destroy (c);
   }
+  GCC_check_connections ();
 }
 
 
 /**
- * Timeout function due to lack of keepalive/traffic from the owner.
+ * Generic connection timeout implementation.
+ *
+ * Timeout function due to lack of keepalive/traffic from an endpoint.
  * Destroys connection if called.
  *
- * @param cls Closure (connection to destroy).
- * @param tc TaskContext.
+ * @param c Connection to destroy.
+ * @param fwd Was the timeout from the origin? (FWD timeout)
  */
 static void
-connection_fwd_timeout (void *cls,
-                        const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_timeout (struct CadetConnection *c, int fwd)
 {
-  struct CadetConnection *c = cls;
+  struct CadetFlowControl *reverse_fc;
 
-  c->fwd_maintenance_task = NULL;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
+  GCC_check_connections ();
+  reverse_fc = fwd ? &c->bck_fc : &c->fwd_fc;
 
   LOG (GNUNET_ERROR_TYPE_INFO,
-       "Connection %s FWD timed out. Destroying.\n",
-       GCC_2s (c));
+       "Connection %s %s timed out. Destroying.\n",
+       GCC_2s (c),
+       GC_f2s (fwd));
   GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
 
-  if (GCC_is_origin (c, GNUNET_YES)) /* If local, leave. */
+  if (GCC_is_origin (c, fwd)) /* Loopback? Something is wrong! */
   {
     GNUNET_break (0);
     return;
   }
 
   /* If dest, salvage queued traffic. */
-  if (GCC_is_origin (c, GNUNET_NO) && 0 < c->bck_fc.queue_n)
+  if (GCC_is_origin (c, !fwd))
   {
-    send_broken_unknown (&c->id, &my_full_id, NULL,
-                         GCP_get_id( get_prev_hop (c)));
-    resend_messages_and_destroy (c, GNUNET_NO);
+    const struct GNUNET_PeerIdentity *next_hop;
+
+    next_hop = GCP_get_id (fwd ? get_prev_hop (c) : get_next_hop (c));
+    send_broken_unknown (&c->id, &my_full_id, NULL, next_hop);
+    if (0 < reverse_fc->queue_n)
+      resend_messages_and_destroy (c, !fwd);
+    GCC_check_connections ();
     return;
   }
 
   GCC_destroy (c);
+  GCC_check_connections ();
 }
 
 
 /**
- * Timeout function due to lack of keepalive/traffic from the destination.
+ * Timeout function due to lack of keepalive/traffic from the owner.
  * Destroys connection if called.
  *
- * FIXME refactor and merge with connection_fwd_timeout.
- *
  * @param cls Closure (connection to destroy).
- * @param tc TaskContext
+ * @param tc TaskContext.
  */
 static void
-connection_bck_timeout (void *cls,
+connection_fwd_timeout (void *cls,
                         const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct CadetConnection *c = cls;
 
-  c->bck_maintenance_task = NULL;
+  c->fwd_maintenance_task = NULL;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
+  GCC_check_connections ();
+  connection_timeout (c, GNUNET_YES);
+  GCC_check_connections ();
+}
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "Connection %s BCK timed out. Destroying.\n",
-       GCC_2s (c));
 
-  if (GCC_is_origin (c, GNUNET_NO)) /* If local, leave. */
-  {
-    GNUNET_break (0);
-    return;
-  }
+/**
+ * Timeout function due to lack of keepalive/traffic from the destination.
+ * Destroys connection if called.
+ *
+ * @param cls Closure (connection to destroy).
+ * @param tc TaskContext
+ */
+static void
+connection_bck_timeout (void *cls,
+                        const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct CadetConnection *c = cls;
 
-  /* If dest, salvage queued traffic. */
-  if (GCC_is_origin (c, GNUNET_YES) && 0 < c->fwd_fc.queue_n)
-  {
-    send_broken_unknown (&c->id, &my_full_id, NULL,
-                         GCP_get_id (get_next_hop (c)));
-    resend_messages_and_destroy (c, GNUNET_YES);
+  c->bck_maintenance_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
-  }
-
-  GCC_destroy (c);
+  GCC_check_connections ();
+  connection_timeout (c, GNUNET_NO);
+  GCC_check_connections ();
 }
 
 
@@ -1472,7 +1625,6 @@ static void
 connection_reset_timeout (struct CadetConnection *c, int fwd)
 {
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GC_f2s (fwd));
-
   if (GCC_is_origin (c, fwd)) /* Startpoint */
   {
     schedule_next_keepalive (c, fwd);
@@ -1488,7 +1640,8 @@ connection_reset_timeout (struct CadetConnection *c, int fwd)
     if (NULL != *ti)
       GNUNET_SCHEDULER_cancel (*ti);
     delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  timing out in %s\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "  timing out in %s\n",
          GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
     f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
     *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
@@ -1496,6 +1649,143 @@ connection_reset_timeout (struct CadetConnection *c, int fwd)
 }
 
 
+/**
+ * Iterator to compare each connection's path with the path of a new connection.
+ *
+ * If the connection conincides, the c member of path is set to the connection
+ * and the destroy flag of the connection is set.
+ *
+ * @param cls Closure (new path).
+ * @param c Connection in the tunnel to check.
+ */
+static void
+check_path (void *cls, struct CadetConnection *c)
+{
+  struct CadetConnection *new_conn = cls;
+  struct CadetPeerPath *path = new_conn->path;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  checking %s (%p), length %u\n",
+       GCC_2s (c), c, c->path->length);
+
+  if (c != new_conn
+      && c->destroy == GNUNET_NO
+      && c->state != CADET_CONNECTION_BROKEN
+      && c->state != CADET_CONNECTION_DESTROYED
+      && path_equivalent (path, c->path))
+  {
+    new_conn->destroy = GNUNET_YES;
+    new_conn->path->c = c;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
+  }
+}
+
+
+/**
+ * Finds out if this path is already being used by an existing connection.
+ *
+ * Checks the tunnel towards the destination to see if it contains
+ * any connection with the same path.
+ *
+ * If the existing connection is ready, it is kept.
+ * Otherwise if the sender has a smaller ID that ours, we accept it (and
+ * the peer will eventually reject our attempt).
+ *
+ * @param path Path to check.
+ * @return #GNUNET_YES if the tunnel has a connection with the same path,
+ *         #GNUNET_NO otherwise.
+ */
+static int
+does_connection_exist (struct CadetConnection *conn)
+{
+  struct CadetPeer *p;
+  struct CadetTunnel *t;
+  struct CadetConnection *c;
+
+  p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
+  if (NULL == p)
+    return GNUNET_NO;
+  t = GCP_get_tunnel (p);
+  if (NULL == t)
+    return GNUNET_NO;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n");
+
+  GCT_iterate_connections (t, &check_path, conn);
+
+  if (GNUNET_YES == conn->destroy)
+  {
+    c = conn->path->c;
+    conn->destroy = GNUNET_NO;
+    conn->path->c = conn;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
+    GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
+    if (CADET_CONNECTION_READY == c->state)
+    {
+      /* The other peer confirmed a live connection with this path,
+       * why is it trying to duplicate it. */
+      GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO);
+      return GNUNET_YES;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not valid, connection unique\n");
+    return GNUNET_NO;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
+    return GNUNET_NO;
+  }
+}
+
+
+/**
+ * @brief Check if the tunnel this connection belongs to has any other
+ * connection with the same path, and destroy one if so.
+ *
+ * @param cls Closure (connection to check).
+ * @param tc Task context.
+ */
+static void
+check_duplicates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct CadetConnection *c = cls;
+
+  c->check_duplicates_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  if (GNUNET_YES == does_connection_exist (c))
+  {
+    GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG);
+    send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES));
+    GCC_destroy (c);
+  }
+}
+
+
+
+/**
+ * Wait for enough time to let any dead connections time out and check for
+ * any remaining duplicates.
+ *
+ * @param c Connection that is a potential duplicate.
+ */
+static void
+schedule_check_duplicates (struct CadetConnection *c)
+{
+  struct GNUNET_TIME_Relative delay;
+
+  if (NULL != c->check_duplicates_task)
+    return;
+
+  delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 5);
+  c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay,
+                                                           &check_duplicates,
+                                                           c);
+}
+
+
+
 /**
  * Add the connection to the list of both neighbors.
  *
@@ -1509,7 +1799,7 @@ register_neighbors (struct CadetConnection *c)
 {
   c->next_peer = get_next_hop (c);
   c->prev_peer = get_prev_hop (c);
-  GNUNET_break (c->next_peer != c->prev_peer);
+  GNUNET_assert (c->next_peer != c->prev_peer);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "register neighbors for connection %s\n",
        GCC_2s (c));
@@ -1565,15 +1855,45 @@ register_neighbors (struct CadetConnection *c)
  */
 static void
 unregister_neighbors (struct CadetConnection *c)
+{
+//  struct CadetPeer *peer; FIXME dont use next_peer, prev_peer
+  /* Either already unregistered or never got registered, it's ok either way. */
+  if (NULL == c->path)
+    return;
+  if (NULL != c->next_peer)
+  {
+    GCP_remove_connection (c->next_peer, c);
+    c->next_peer = NULL;
+  }
+  if (NULL != c->prev_peer)
+  {
+    GCP_remove_connection (c->prev_peer, c);
+    c->prev_peer = NULL;
+  }
+}
+
+
+/**
+ * Invalidates all paths towards all peers that comprise the connection which
+ * rely on the disconnected peer.
+ *
+ * ~O(n^3) (peers in connection * paths/peer * links/path)
+ *
+ * @param c Connection whose peers' paths to clean.
+ * @param disconnected Peer that disconnected.
+ */
+static void
+invalidate_paths (struct CadetConnection *c, struct CadetPeer *disconnected)
 {
   struct CadetPeer *peer;
+  unsigned int i;
 
-  peer = get_next_hop (c);
-  GNUNET_assert (c->next_peer == peer);
-  GCP_remove_connection (peer, c, GNUNET_NO);
-  peer = get_prev_hop (c);
-  GNUNET_assert (c->prev_peer == peer);
-  GCP_remove_connection (peer, c, GNUNET_YES);
+  for (i = 0; i < c->path->length; i++)
+  {
+    peer = GCP_get_short (c->path->peers[i], GNUNET_NO);
+    if (NULL != peer)
+      GCP_notify_broken_link (peer, &my_full_id, GCP_get_id (disconnected));
+  }
 }
 
 
@@ -1596,110 +1916,6 @@ add_to_peer (struct CadetConnection *c,
 }
 
 
-
-/**
- * Iterator to compare each connection's path with the path of a new connection.
- *
- * If the connection conincides, the c member of path is set to the connection
- * and the destroy flag of the connection is set.
- *
- * @param cls Closure (new path).
- * @param c Connection in the tunnel to check.
- */
-static void
-check_path (void *cls, struct CadetConnection *c)
-{
-  struct CadetConnection *new_conn = cls;
-  struct CadetPeerPath *path = new_conn->path;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  checking %s (%p), length %u\n",
-       GCC_2s (c), c, c->path->length);
-
-  if (c != new_conn
-      && c->destroy == GNUNET_NO
-      && c->state != CADET_CONNECTION_BROKEN
-      && c->state != CADET_CONNECTION_DESTROYED
-      && path_equivalent (path, c->path))
-  {
-    new_conn->destroy = GNUNET_YES;
-    new_conn->path->c = c;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
-  }
-}
-
-/**
- * Finds out if this path is already being used by and existing connection.
- *
- * Checks the tunnel towards the first peer in the path to see if it contains
- * any connection with the same path.
- *
- * If the existing connection is ready, it is kept.
- * Otherwise if the sender has a smaller ID that ours, we accept it (and
- * the peer will eventually reject our attempt).
- *
- * @param path Path to check.
- *
- * @return GNUNET_YES if the tunnel has a connection with the same path,
- *         GNUNET_NO otherwise.
- */
-static int
-does_connection_exist (struct CadetConnection *conn)
-{
-  struct CadetPeer *p;
-  struct CadetTunnel *t;
-  struct CadetConnection *c;
-
-  p = GCP_get_short (conn->path->peers[0]);
-  t = GCP_get_tunnel (p);
-  if (NULL == t)
-    return GNUNET_NO;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Checking for duplicates\n");
-
-  GCT_iterate_connections (t, &check_path, conn);
-
-  if (GNUNET_YES == conn->destroy)
-  {
-    c = conn->path->c;
-    conn->destroy = GNUNET_NO;
-    conn->path->c = conn;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
-    GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-    if (CADET_CONNECTION_READY == c->state)
-    {
-      /* The other peer confirmed this connection,
-       * they should not try to duplicate it. */
-      GNUNET_break_op (0); /* FIXME */
-      return GNUNET_YES;
-    }
-
-    if (GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (p)) > 0)
-    {
-      struct CadetPeer *neighbor;
-
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate allowed (killing old)\n");
-      if (GCC_is_origin (c, GNUNET_YES))
-        neighbor = get_next_hop (c);
-      else
-        neighbor = get_prev_hop (c);
-      send_broken_unknown (&c->id, &my_full_id, NULL,
-                           GCP_get_id (neighbor));
-      GCC_destroy (c);
-      return GNUNET_NO;
-    }
-    else
-      return GNUNET_YES;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
-    return GNUNET_NO;
-  }
-}
-
-
 /**
  * Log receipt of message on stderr (INFO level).
  *
@@ -1713,12 +1929,24 @@ log_message (const struct GNUNET_MessageHeader *message,
              const struct GNUNET_CADET_Hash *hash)
 {
   uint16_t size;
+  uint16_t type;
+  char *arrow;
 
   size = ntohs (message->size);
-  LOG (GNUNET_ERROR_TYPE_INFO, "\n");
-  LOG (GNUNET_ERROR_TYPE_INFO, "\n");
-  LOG (GNUNET_ERROR_TYPE_INFO, "<-- %s on connection %s from %s, %6u bytes\n",
-       GC_m2s (ntohs (message->type)), GNUNET_h2s (GC_h2hc (hash)),
+  type = ntohs (message->type);
+  switch (type)
+  {
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+      arrow = "==";
+      break;
+    default:
+      arrow = "--";
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO, "<%s %s on conn %s from %s, %6u bytes\n",
+       arrow, GC_m2s (type), GNUNET_h2s (GC_h2hc (hash)),
        GNUNET_i2s (peer), (unsigned int) size);
 }
 
@@ -1732,12 +1960,12 @@ log_message (const struct GNUNET_MessageHeader *message,
  * @param cls Closure (unused).
  * @param peer Sender (neighbor).
  * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
-GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
+GCC_handle_create (void *cls,
+                   const struct GNUNET_PeerIdentity *peer,
                    const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_CADET_ConnectionCreate *msg;
@@ -1750,6 +1978,7 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
   unsigned int own_pos;
   uint16_t size;
 
+  GCC_check_connections ();
   /* Check size */
   size = ntohs (message->size);
   if (size < sizeof (struct GNUNET_CADET_ConnectionCreate))
@@ -1792,10 +2021,17 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     path = path_build_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
                                      size, myid, &own_pos);
     if (NULL == path)
+    {
+      /* Path was malformed, probably our own ID was not in it. */
+      GNUNET_STATISTICS_update (stats, "# malformed paths", 1, GNUNET_NO);
+      GNUNET_break_op (0);
       return GNUNET_OK;
+    }
 
     if (0 == own_pos)
     {
+      /* We received this request from a neighbor, we cannot be origin */
+      GNUNET_STATISTICS_update (stats, "# fake paths", 1, GNUNET_NO);
       GNUNET_break_op (0);
       path_destroy (path);
       return GNUNET_OK;
@@ -1811,12 +2047,14 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
         /* If we are destination, why did the creation fail? */
         GNUNET_break (0);
         path_destroy (path);
+        GCC_check_connections ();
         return GNUNET_OK;
       }
       send_broken_unknown (cid, &my_full_id,
                            GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
                            peer);
       path_destroy (path);
+      GCC_check_connections ();
       return GNUNET_OK;
     }
     GCP_add_path_to_all (path, GNUNET_NO);
@@ -1830,8 +2068,8 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     connection_change_state (c, CADET_CONNECTION_SENT);
 
   /* Remember peers */
-  dest_peer = GCP_get (&id[size - 1]);
-  orig_peer = GCP_get (&id[0]);
+  dest_peer = GCP_get (&id[size - 1], GNUNET_YES);
+  orig_peer = GCP_get (&id[0], GNUNET_YES);
 
   /* Is it a connection to us? */
   if (c->own_pos == path->length - 1)
@@ -1842,18 +2080,16 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     add_to_peer (c, orig_peer);
     if (GNUNET_YES == does_connection_exist (c))
     {
-      path_destroy (path);
-      GCC_destroy (c);
-      // FIXME Peer created a connection equal to one we think exists
-      //       and is fine. What should we do?
-      // Use explicit duplicate?
-      // Accept new conn and destroy the old? (interruption in higher level)
-      // Keep both and postpone disambiguation?
-      // Keep the one created by peer with higher ID?
-      // For now: reject new connection until current confirmed dead
-      send_broken_unknown (cid, &my_full_id, NULL, peer);
-
-      return GNUNET_OK;
+      /* Peer created a connection equal to one we think exists
+       * and is fine.
+       * Solution: Keep both and postpone disambiguation. In the meantime
+       * the connection will time out or peer will inform us it is broken.
+       *
+       * Other options:
+       * - Use explicit duplicate.
+       * - Accept new conn and destroy the old. (interruption in higher level)
+       * - Keep the one with higher ID / created by peer with higher ID. */
+       schedule_check_duplicates (c);
     }
 
     if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t))
@@ -1874,6 +2110,7 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
                                                       NULL, NULL));
   }
   path_destroy (path);
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -1884,12 +2121,12 @@ GCC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param cls closure
  * @param message message
  * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
-GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
+GCC_handle_confirm (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
                     const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_CADET_ConnectionACK *msg;
@@ -1899,6 +2136,7 @@ GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
   enum CadetConnectionState oldstate;
   int fwd;
 
+  GCC_check_connections ();
   msg = (struct GNUNET_CADET_ConnectionACK *) message;
   log_message (message, peer, &msg->cid);
   c = connection_get (&msg->cid);
@@ -1906,20 +2144,26 @@ GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
   {
     GNUNET_STATISTICS_update (stats, "# control on unknown connection",
                               1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  don't know the connection!\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "  don't know the connection!\n");
     send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
   if (GNUNET_NO != c->destroy)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  connection being destroyed\n");
+    GNUNET_assert (CADET_CONNECTION_DESTROYED == c->state);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "connection %s being destroyed, ignoring confirm\n",
+         GCC_2s (c));
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
   oldstate = c->state;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  via peer %s\n", GNUNET_i2s (peer));
-  pi = GCP_get (peer);
+  pi = GCP_get (peer, GNUNET_YES);
   if (get_next_hop (c) == pi)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  SYNACK\n");
@@ -1973,7 +2217,7 @@ GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
     /* Change tunnel state, trigger KX */
     if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
       GCT_change_cstate (c->t, CADET_TUNNEL_READY);
-
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -1994,13 +2238,15 @@ GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
     /* Change tunnel state */
     if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
       GCT_change_cstate (c->t, CADET_TUNNEL_READY);
-
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  not for us, retransmitting...\n");
-  GNUNET_assert (NULL == GCC_send_prebuilt_message (message, 0, 0, c, fwd,
-                                                    GNUNET_YES, NULL, NULL));
+  GNUNET_assert (NULL ==
+                 GCC_send_prebuilt_message (message, 0, 0, c, fwd,
+                                            GNUNET_YES, NULL, NULL));
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -2011,7 +2257,6 @@ GCC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param cls Closure (unused).
  * @param id Peer identity of sending neighbor.
  * @param message Message.
- *
  * @return #GNUNET_OK to keep the connection open,
  *         #GNUNET_SYSERR to close it (signal serious error)
  */
@@ -2026,6 +2271,7 @@ GCC_handle_broken (void* cls,
   int pending;
   int fwd;
 
+  GCC_check_connections ();
   msg = (struct GNUNET_CADET_ConnectionBroken *) message;
   log_message (message, id, &msg->cid);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  regarding %s\n",
@@ -2036,6 +2282,7 @@ GCC_handle_broken (void* cls,
   if (NULL == c)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  duplicate CONNECTION_BROKEN\n");
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -2054,8 +2301,9 @@ GCC_handle_broken (void* cls,
       GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
       return GNUNET_OK;
     }
-    endpoint = GCP_get_short (c->path->peers[c->path->length - 1]);
-    path_invalidate (c->path);
+    endpoint = GCP_get_short (c->path->peers[c->path->length - 1], GNUNET_YES);
+    if (2 < c->path->length)
+      path_invalidate (c->path);
     GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
 
     c->state = CADET_CONNECTION_BROKEN;
@@ -2074,7 +2322,7 @@ GCC_handle_broken (void* cls,
                                                       GNUNET_YES, NULL, NULL));
     connection_cancel_queues (c, !fwd);
   }
-
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -2097,6 +2345,7 @@ GCC_handle_destroy (void *cls,
   struct CadetConnection *c;
   int fwd;
 
+  GCC_check_connections ();
   msg = (const struct GNUNET_CADET_ConnectionDestroy *) message;
   log_message (message, peer, &msg->cid);
   c = connection_get (&msg->cid);
@@ -2106,10 +2355,12 @@ GCC_handle_destroy (void *cls,
      * destroyed the tunnel and retransmitted to children.
      * Safe to ignore.
      */
-    GNUNET_STATISTICS_update (stats, "# control on unknown connection",
+    GNUNET_STATISTICS_update (stats,
+                              "# control on unknown connection",
                               1, GNUNET_NO);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "  connection unknown: already destroyed?\n");
+    GCC_check_connections ();
     return GNUNET_OK;
   }
   fwd = is_fwd (c, peer);
@@ -2119,12 +2370,16 @@ GCC_handle_destroy (void *cls,
     return GNUNET_OK;
   }
   if (GNUNET_NO == GCC_is_terminal (c, fwd))
-    GNUNET_assert (NULL == GCC_send_prebuilt_message (message, 0, 0, c, fwd,
-                                                      GNUNET_YES, NULL, NULL));
+  {
+    GNUNET_assert (NULL ==
+                   GCC_send_prebuilt_message (message, 0, 0, c, fwd,
+                                              GNUNET_YES, NULL, NULL));
+  }
   else if (0 == c->pending_messages)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  directly destroying connection!\n");
     GCC_destroy (c);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
   c->destroy = GNUNET_YES;
@@ -2134,7 +2389,7 @@ GCC_handle_destroy (void *cls,
     GCT_remove_connection (c->t, c);
     c->t = NULL;
   }
-
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -2176,10 +2431,17 @@ check_message (const struct GNUNET_MessageHeader *message,
   /* Check connection */
   if (NULL == c)
   {
-    GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "%s on unknown connection %s\n",
-         GC_m2s (ntohs (message->type)), GNUNET_h2s (GC_h2hc (cid)));
-    send_broken_unknown (cid, &my_full_id, NULL, neighbor);
+    GNUNET_STATISTICS_update (stats,
+                              "# unknown connection",
+                              1, GNUNET_NO);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s on unknown connection %s\n",
+         GC_m2s (ntohs (message->type)),
+         GNUNET_h2s (GC_h2hc (cid)));
+    send_broken_unknown (cid,
+                         &my_full_id,
+                         NULL,
+                         neighbor);
     return GNUNET_SYSERR;
   }
 
@@ -2265,9 +2527,8 @@ check_message (const struct GNUNET_MessageHeader *message,
  *
  * @param peer Peer identity this notification is about.
  * @param msg Encrypted message.
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 static int
 handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
@@ -2277,12 +2538,13 @@ handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
   const struct GNUNET_CADET_AX *ax_msg;
   const struct GNUNET_CADET_Hash* cid;
   struct CadetConnection *c;
-  size_t minumum_size;
+  size_t minimum_size;
   size_t overhead;
   uint32_t pid;
   uint32_t ttl;
   int fwd;
 
+  GCC_check_connections ();
   if (GNUNET_MESSAGE_TYPE_CADET_AX == ntohs (message->type))
   {
     overhead = sizeof (struct GNUNET_CADET_AX);
@@ -2301,18 +2563,26 @@ handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
 
   log_message (message, peer, cid);
 
-  minumum_size = sizeof (struct GNUNET_MessageHeader) + overhead;
+  minimum_size = sizeof (struct GNUNET_MessageHeader) + overhead;
   c = connection_get (cid);
-  fwd = check_message (message, minumum_size, cid, c, peer, pid);
+  fwd = check_message (message,
+                       minimum_size,
+                       cid,
+                       c,
+                       peer,
+                       pid);
 
   /* If something went wrong, discard message. */
   if (GNUNET_SYSERR == fwd)
+  {
+    GCC_check_connections ();
     return GNUNET_OK;
+  }
 
   /* Is this message for us? */
   if (GCC_is_terminal (c, fwd))
   {
-    GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
+    GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
 
     if (NULL == c->t)
     {
@@ -2321,6 +2591,7 @@ handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
     }
     GCT_handle_encrypted (c->t, message);
     GCC_send_ack (c, fwd, GNUNET_NO);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -2335,6 +2606,7 @@ handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
       GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
       LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
       GCC_send_ack (c, fwd, GNUNET_NO);
+      GCC_check_connections ();
       return GNUNET_OK;
     }
   }
@@ -2342,18 +2614,18 @@ handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
   GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
   GNUNET_assert (NULL == GCC_send_prebuilt_message (message, 0, 0, c, fwd,
                                                     GNUNET_NO, NULL, NULL));
-
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
+
 /**
  * Generic handler for cadet network encrypted traffic.
  *
  * @param peer Peer identity this notification is about.
  * @param msg Encrypted message.
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 static int
 handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
@@ -2364,13 +2636,19 @@ handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
   size_t expected_size;
   int fwd;
 
+  GCC_check_connections ();
   cid = &msg->cid;
   log_message (&msg->header, peer, cid);
 
   expected_size = sizeof (struct GNUNET_CADET_KX)
                   + sizeof (struct GNUNET_MessageHeader);
   c = connection_get (cid);
-  fwd = check_message (&msg->header, expected_size, cid, c, peer, 0);
+  fwd = check_message (&msg->header,
+                       expected_size,
+                       cid,
+                       c,
+                       peer,
+                       0);
 
   /* If something went wrong, discard message. */
   if (GNUNET_SYSERR == fwd)
@@ -2380,13 +2658,14 @@ handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
   if (GCC_is_terminal (c, fwd))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  message for us!\n");
-    GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
+    GNUNET_STATISTICS_update (stats, "# received KX", 1, GNUNET_NO);
     if (NULL == c->t)
     {
       GNUNET_break (0);
       return GNUNET_OK;
     }
     GCT_handle_kx (c->t, &msg[1].header);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -2395,7 +2674,7 @@ handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
   GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
   GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg->header, 0, 0, c, fwd,
                                                     GNUNET_NO, NULL, NULL));
-
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -2406,14 +2685,15 @@ handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
  * @param cls Closure (unused).
  * @param message Message received.
  * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
-GCC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
+GCC_handle_kx (void *cls,
+               const struct GNUNET_PeerIdentity *peer,
                const struct GNUNET_MessageHeader *message)
 {
+  GCC_check_connections ();
   return handle_cadet_kx (peer, (struct GNUNET_CADET_KX *) message);
 }
 
@@ -2424,14 +2704,14 @@ GCC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param cls Closure (unused).
  * @param message Message received.
  * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
 GCC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
                       const struct GNUNET_MessageHeader *message)
 {
+  GCC_check_connections ();
   return handle_cadet_encrypted (peer, message);
 }
 
@@ -2442,9 +2722,8 @@ GCC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param cls closure
  * @param message message
  * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
 GCC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
@@ -2457,14 +2736,21 @@ GCC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
   uint32_t ack;
   int fwd;
 
+  GCC_check_connections ();
   msg = (struct GNUNET_CADET_ACK *) message;
   log_message (message, peer, &msg->cid);
   c = connection_get (&msg->cid);
   if (NULL == c)
   {
-    GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1,
+    GNUNET_STATISTICS_update (stats,
+                              "# ack on unknown connection",
+                              1,
                               GNUNET_NO);
-    send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+    send_broken_unknown (&msg->cid,
+                         &my_full_id,
+                         NULL,
+                         peer);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -2503,7 +2789,7 @@ GCC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
   }
 
   connection_unlock_queue (c, fwd);
-
+  GCC_check_connections ();
   return GNUNET_OK;
 }
 
@@ -2514,12 +2800,12 @@ GCC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param cls closure
  * @param message message
  * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 int
-GCC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
+GCC_handle_poll (void *cls,
+                 const struct GNUNET_PeerIdentity *peer,
                  const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_CADET_Poll *msg;
@@ -2529,6 +2815,7 @@ GCC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
   uint32_t pid;
   int fwd;
 
+  GCC_check_connections ();
   msg = (struct GNUNET_CADET_Poll *) message;
   log_message (message, peer, &msg->cid);
   c = connection_get (&msg->cid);
@@ -2536,9 +2823,14 @@ GCC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
   {
     GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
                               GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL message on unknown connection %s!\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "POLL message on unknown connection %s!\n",
          GNUNET_h2s (GC_h2hc (&msg->cid)));
-    send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+    send_broken_unknown (&msg->cid,
+                         &my_full_id,
+                         NULL,
+                         peer);
+    GCC_check_connections ();
     return GNUNET_OK;
   }
 
@@ -2569,6 +2861,7 @@ GCC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
   fc->last_pid_recv = pid;
   fwd = fc == &c->bck_fc;
   GCC_send_ack (c, fwd, GNUNET_YES);
+  GCC_check_connections ();
 
   return GNUNET_OK;
 }
@@ -2587,6 +2880,7 @@ GCC_send_ack (struct CadetConnection *c, int fwd, int force)
 {
   unsigned int buffer;
 
+  GCC_check_connections ();
   LOG (GNUNET_ERROR_TYPE_DEBUG, "GCC send %s ACK on %s\n",
        GC_f2s (fwd), GCC_2s (c));
 
@@ -2599,6 +2893,7 @@ GCC_send_ack (struct CadetConnection *c, int fwd, int force)
   if (GNUNET_NO != c->destroy)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  being destroyed, why bother...\n");
+    GCC_check_connections ();
     return;
   }
 
@@ -2615,7 +2910,10 @@ GCC_send_ack (struct CadetConnection *c, int fwd, int force)
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  buffer available: %u\n", buffer);
   if (0 == buffer && GNUNET_NO == force)
+  {
+    GCC_check_connections ();
     return;
+  }
 
   /* Send available buffer space */
   if (GCC_is_origin (c, fwd))
@@ -2629,6 +2927,7 @@ GCC_send_ack (struct CadetConnection *c, int fwd, int force)
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on connection\n");
     send_ack (c, buffer, fwd, force);
   }
+  GCC_check_connections ();
 }
 
 
@@ -2703,6 +3002,8 @@ shutdown_iterator (void *cls,
 void
 GCC_shutdown (void)
 {
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n");
+  GCC_check_connections ();
   GNUNET_CONTAINER_multihashmap_iterate (connections,
                                          &shutdown_iterator,
                                          NULL);
@@ -2728,9 +3029,11 @@ GCC_new (const struct GNUNET_CADET_Hash *cid,
          unsigned int own_pos)
 {
   struct CadetConnection *c;
-  struct CadetPeerPath *p;
+  struct CadetPeerPath *cpath;
 
-  p = path_duplicate (path);
+  GCC_check_connections ();
+  cpath = path_duplicate (path);
+  GNUNET_assert (NULL != cpath);
   c = GNUNET_new (struct CadetConnection);
   c->id = *cid;
   GNUNET_assert (GNUNET_OK ==
@@ -2743,23 +3046,34 @@ GCC_new (const struct GNUNET_CADET_Hash *cid,
   c->bck_fc.c = c;
 
   c->t = t;
-  GNUNET_assert (own_pos <= p->length - 1);
+  GNUNET_assert (own_pos <= cpath->length - 1);
   c->own_pos = own_pos;
-  c->path = p;
-  p->c = c;
-  GNUNET_assert (NULL != p);
+  c->path = cpath;
+  cpath->c = c;
   if (GNUNET_OK != register_neighbors (c))
   {
     if (0 == own_pos)
     {
-      path_invalidate (c->path);
+      /* We were the origin of this request, this means we have invalid
+       * info about the paths to reach the destination. We must invalidate
+       * the *original* path to avoid trying it again in the next minute.
+       */
+      if (2 < path->length)
+        path_invalidate (path);
+      else
+      {
+        GNUNET_break (0);
+        GCT_debug(t, GNUNET_ERROR_TYPE_WARNING);
+      }
       c->t = NULL;
-      c->path = NULL;
     }
+    path_destroy (c->path);
+    c->path = NULL;
     GCC_destroy (c);
     return NULL;
   }
   LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c));
+  GCC_check_connections ();
   return c;
 }
 
@@ -2767,6 +3081,7 @@ GCC_new (const struct GNUNET_CADET_Hash *cid,
 void
 GCC_destroy (struct CadetConnection *c)
 {
+  GCC_check_connections ();
   if (NULL == c)
   {
     GNUNET_break (0);
@@ -2795,52 +3110,33 @@ GCC_destroy (struct CadetConnection *c)
     connection_cancel_queues (c, GNUNET_NO);
   }
   unregister_neighbors (c);
-
-  /* Cancel maintainance task (keepalive/timeout) */
-  if (NULL != c->fwd_fc.poll_msg)
-  {
-    GCC_cancel (c->fwd_fc.poll_msg);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        " POLL msg FWD canceled\n");
-  }
-  if (NULL != c->bck_fc.poll_msg)
-  {
-    GCC_cancel (c->bck_fc.poll_msg);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        " POLL msg BCK canceled\n");
-  }
+  path_destroy (c->path);
+  c->path = NULL;
 
   /* Delete from tunnel */
   if (NULL != c->t)
     GCT_remove_connection (c->t, c);
 
-  if ( (GNUNET_NO == GCC_is_origin (c, GNUNET_YES)) &&
-       (NULL != c->path) )
-    path_destroy (c->path);
+  if (NULL != c->check_duplicates_task)
+    GNUNET_SCHEDULER_cancel (c->check_duplicates_task);
   if (NULL != c->fwd_maintenance_task)
     GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
   if (NULL != c->bck_maintenance_task)
     GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
-  if (NULL != c->fwd_fc.poll_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL FWD canceled\n");
-  }
-  if (NULL != c->bck_fc.poll_task)
+
+  if (GNUNET_NO == c->was_removed)
   {
-    GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL BCK canceled\n");
+    GNUNET_break (GNUNET_YES ==
+                  GNUNET_CONTAINER_multihashmap_remove (connections,
+                                                        GCC_get_h (c),
+                                                        c));
   }
-
-  GNUNET_break (GNUNET_YES ==
-                GNUNET_CONTAINER_multihashmap_remove (connections,
-                                                      GCC_get_h (c),
-                                                      c));
   GNUNET_STATISTICS_update (stats,
                             "# connections",
                             -1,
                             GNUNET_NO);
   GNUNET_free (c);
+  GCC_check_connections ();
 }
 
 
@@ -2937,6 +3233,7 @@ GCC_get_buffer (struct CadetConnection *c, int fwd)
   return (fc->queue_max - fc->queue_n);
 }
 
+
 /**
  * Get how many messages have we allowed to send to us from a direction.
  *
@@ -2959,6 +3256,7 @@ GCC_get_allowed (struct CadetConnection *c, int fwd)
   return (fc->last_ack_sent - fc->last_pid_recv);
 }
 
+
 /**
  * Get messages queued in a connection.
  *
@@ -3024,16 +3322,22 @@ GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
  * @param peer Peer that disconnected.
  */
 void
-GCC_notify_broken (struct CadetConnection *c,
-                   struct CadetPeer *peer)
+GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
 {
+  struct CadetFlowControl *fc;
   struct CadetPeer *hop;
+  char peer_name[16];
   int fwd;
 
+  GCC_check_connections ();
+  strncpy (peer_name, GCP_2s (peer), 16);
+  peer_name[15] = '\0';
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Notify broken on %s due to %s disconnect\n",
-       GCC_2s (c),
-       GCP_2s (peer));
+       "shutting down %s, %s disconnected\n",
+       GCC_2s (c), peer_name);
+
+  invalidate_paths (c, peer);
+
   hop = get_prev_hop (c);
   if (NULL == hop)
   {
@@ -3042,25 +3346,37 @@ GCC_notify_broken (struct CadetConnection *c,
     return;
   }
   fwd = (peer == hop);
-  if (GNUNET_YES == GCC_is_terminal (c, fwd))
+  if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) ||
+       (GNUNET_NO != c->destroy) )
   {
-    /* Local shutdown, no one to notify about this. */
+    /* Local shutdown, or other peer already down (hence 'c->destroy');
+       so there is no one to notify about this, just clean up. */
     GCC_destroy (c);
+    GCC_check_connections ();
     return;
   }
-  if (GNUNET_NO == c->destroy)
-    send_broken (c, &my_full_id, GCP_get_id (peer), fwd);
+  /* Mark FlowControl towards the peer as unavaliable. */
+  fc = fwd ? &c->bck_fc : &c->fwd_fc;
+  fc->queue_max = 0;
+
+  send_broken (c, &my_full_id, GCP_get_id (peer), fwd);
 
   /* Connection will have at least one pending message
-   * (the one we just scheduled), so no point in checking whether to
-   * destroy immediately. */
+   * (the one we just scheduled), so delay destruction
+   * and remove from map so we don't use accidentally. */
   c->destroy = GNUNET_YES;
   c->state = CADET_CONNECTION_DESTROYED;
-
-  /**
-   * Cancel all queues, if no message is left, connection will be destroyed.
-   */
-  connection_cancel_queues (c, !fwd);
+  GNUNET_assert (GNUNET_NO == c->was_removed);
+  c->was_removed = GNUNET_YES;
+  GNUNET_break (GNUNET_YES ==
+                GNUNET_CONTAINER_multihashmap_remove (connections,
+                                                      GCC_get_h (c),
+                                                      c));
+  /* Cancel queue in the direction that just died. */
+  connection_cancel_queues (c, ! fwd);
+  GCC_stop_poll (c, ! fwd);
+  unregister_neighbors (c);
+  GCC_check_connections ();
 }
 
 
@@ -3095,7 +3411,7 @@ GCC_is_origin (struct CadetConnection *c, int fwd)
 int
 GCC_is_terminal (struct CadetConnection *c, int fwd)
 {
-  return GCC_is_origin (c, !fwd);
+  return GCC_is_origin (c, ! fwd);
 }
 
 
@@ -3112,7 +3428,8 @@ GCC_is_sendable (struct CadetConnection *c, int fwd)
 {
   struct CadetFlowControl *fc;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       " checking sendability of %s traffic on %s\n",
        GC_f2s (fwd), GCC_2s (c));
   if (NULL == c)
   {
@@ -3146,6 +3463,7 @@ GCC_is_direct (struct CadetConnection *c)
   return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
 }
 
+
 /**
  * Sends an already built message on a connection, properly registering
  * all used resources.
@@ -3176,14 +3494,22 @@ GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   uint16_t type;
   int droppable;
 
+  GCC_check_connections ();
   size = ntohs (message->size);
   data = GNUNET_malloc (size);
   memcpy (data, message, size);
   type = ntohs (message->type);
-  LOG (GNUNET_ERROR_TYPE_INFO, "--> %s (%s %4u) on connection %s (%u bytes)\n",
-       GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), size);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n",
+       GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c,
+       GC_f2s(fwd), size);
 
   fc = fwd ? &c->fwd_fc : &c->bck_fc;
+  if (0 == fc->queue_max)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   droppable = GNUNET_NO == force;
   switch (type)
   {
@@ -3227,10 +3553,6 @@ GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
       {
         LOG (GNUNET_ERROR_TYPE_DEBUG, "  not droppable, Q_N stays the same\n");
       }
-      if (GC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
-      {
-        GCC_start_poll (c, fwd);
-      }
       break;
 
     case GNUNET_MESSAGE_TYPE_CADET_KX:
@@ -3248,7 +3570,7 @@ GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
     case GNUNET_MESSAGE_TYPE_CADET_POLL:
       pmsg = (struct GNUNET_CADET_Poll *) data;
       pmsg->cid = c->id;
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
+      LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL %u\n", ntohl (pmsg->pid));
       droppable = GNUNET_NO;
       break;
 
@@ -3301,10 +3623,12 @@ GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
     LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c));
     GNUNET_free (data);
     GNUNET_free (q);
+    GCC_check_connections ();
     return NULL;
   }
   q->cont = cont;
   q->cont_cls = cont_cls;
+  GCC_check_connections ();
   return (NULL == cont) ? NULL : q;
 }
 
@@ -3325,6 +3649,7 @@ GCC_cancel (struct CadetConnectionQueue *q)
 
   /* queue destroy calls message_sent, which calls q->cont and frees q */
   GCP_queue_destroy (q->q, GNUNET_YES, GNUNET_NO, 0);
+  GCC_check_connections ();
 }
 
 
@@ -3340,19 +3665,20 @@ GCC_send_create (struct CadetConnection *connection)
   enum CadetTunnelCState state;
   size_t size;
 
+  GCC_check_connections ();
   size = sizeof (struct GNUNET_CADET_ConnectionCreate);
   size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "---> %s on connection %s  (%u bytes)\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE),
-       GCC_2s (connection), size);
+  LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n",
+       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "",
+       GCC_2s (connection), connection, size);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  C_P+ %p %u (create)\n",
        connection, connection->pending_messages);
   connection->pending_messages++;
 
   connection->maintenance_q =
     GCP_queue_add (get_next_hop (connection), NULL,
-                   GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0, 0,
+                   GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, UINT16_MAX, 0,
                    size, connection, GNUNET_YES, &conn_message_sent, NULL);
 
   state = GCT_get_cstate (connection->t);
@@ -3360,6 +3686,7 @@ GCC_send_create (struct CadetConnection *connection)
     GCT_change_cstate (connection->t, CADET_TUNNEL_WAITING);
   if (CADET_CONNECTION_NEW == connection->state)
     connection_change_state (connection, CADET_CONNECTION_SENT);
+  GCC_check_connections ();
 }
 
 
@@ -3379,7 +3706,7 @@ GCC_send_destroy (struct CadetConnection *c)
 
   if (GNUNET_YES == c->destroy)
     return;
-
+  GCC_check_connections ();
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
   msg.cid = c->id;
@@ -3388,15 +3715,16 @@ GCC_send_destroy (struct CadetConnection *c)
               GCC_2s (c));
 
   if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES))
-    GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, 0, 0, c,
-                                                      GNUNET_YES, GNUNET_YES,
-                                                      NULL, NULL));
+    GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, UINT16_MAX,
+                                                      0, c, GNUNET_YES,
+                                                      GNUNET_YES, NULL, NULL));
   if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO))
-    GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, 0, 0, c,
-                                                      GNUNET_NO, GNUNET_YES,
-                                                      NULL, NULL));
+    GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, UINT16_MAX,
+                                                      0, c, GNUNET_NO,
+                                                      GNUNET_YES, NULL, NULL));
   c->destroy = GNUNET_YES;
   c->state = CADET_CONNECTION_DESTROYED;
+  GCC_check_connections ();
 }
 
 
@@ -3420,10 +3748,17 @@ GCC_start_poll (struct CadetConnection *c, int fwd)
        GC_f2s (fwd));
   if (NULL != fc->poll_task || NULL != fc->poll_msg)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  not needed (%p, %p)\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  POLL already in progress (t: %p, m: %p)\n",
          fc->poll_task, fc->poll_msg);
     return;
   }
+  if (0 == fc->queue_max)
+  {
+    /* Should not be needed, traffic should've been cancelled. */
+    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  POLL not possible, peer disconnected\n");
+    return;
+  }
   LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n");
   fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
                                                 &connection_poll,
@@ -3450,8 +3785,14 @@ GCC_stop_poll (struct CadetConnection *c, int fwd)
     GNUNET_SCHEDULER_cancel (fc->poll_task);
     fc->poll_task = NULL;
   }
+  if (NULL != fc->poll_msg)
+  {
+    GCC_cancel (fc->poll_msg);
+    fc->poll_msg = NULL;
+  }
 }
 
+
 /**
  * Get a (static) string for a connection.
  *
@@ -3516,7 +3857,7 @@ GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level)
   LOG2 (level, "CCC   last ACK sent: %5u, recv: %5u\n",
         c->fwd_fc.last_ack_sent, c->fwd_fc.last_ack_recv);
   LOG2 (level, "CCC   recv PID bitmap: %X\n", c->fwd_fc.recv_bitmap);
-  LOG2 (level, "CCC   POLL: task %d, msg  %p, msg_ack %p)\n",
+  LOG2 (level, "CCC   poll: task %d, msg  %p, msg_ack %p)\n",
         c->fwd_fc.poll_task, c->fwd_fc.poll_msg, c->fwd_fc.ack_msg);
 
   LOG2 (level, "CCC  BCK flow control:\n");
@@ -3526,7 +3867,7 @@ GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level)
   LOG2 (level, "CCC   last ACK sent: %5u, recv: %5u\n",
         c->bck_fc.last_ack_sent, c->bck_fc.last_ack_recv);
   LOG2 (level, "CCC   recv PID bitmap: %X\n", c->bck_fc.recv_bitmap);
-  LOG2 (level, "CCC   POLL: task %d, msg  %p, msg_ack %p)\n",
+  LOG2 (level, "CCC   poll: task %d, msg  %p, msg_ack %p)\n",
         c->bck_fc.poll_task, c->bck_fc.poll_msg, c->bck_fc.ack_msg);
 
   LOG2 (level, "CCC DEBUG CONNECTION END\n");