Fix for #4553
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_connection.c
index 8c25a46b7815779a523be45e6cf638c5a38a51c3..188041feb235a536aa65c0f6e826b45c33bff3a5 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
@@ -71,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;
 
@@ -452,6 +453,8 @@ fc_init (struct CadetFlowControl *fc)
  * Find a connection.
  *
  * @param cid Connection ID.
+ *
+ * @return conntection with the given ID @cid or NULL if not found.
  */
 static struct CadetConnection *
 connection_get (const struct GNUNET_CADET_Hash *cid)
@@ -460,6 +463,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)
@@ -478,6 +487,20 @@ connection_change_state (struct CadetConnection* c,
 }
 
 
+/**
+ * Mark a connection as "destroyed", to send all pending traffic and freeing
+ * all associated resources, without accepting new status changes on it.
+ *
+ * @param c Connection to mark as destroyed.
+ */
+static void
+mark_destroyed (struct CadetConnection *c)
+{
+  c->destroy = GNUNET_YES;
+  connection_change_state (c, CADET_CONNECTION_DESTROYED);
+}
+
+
 /**
  * Callback called when a queued ACK message is sent.
  *
@@ -589,8 +612,8 @@ send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
   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 ();
@@ -839,7 +862,7 @@ check_neighbours (const struct CadetConnection *c)
 
 
 /**
- * Helper for #check_connections().  Calls #check_neighbours().
+ * Helper for #GCC_check_connections().  Calls #check_neighbours().
  *
  * @param cls NULL
  * @param key ignored
@@ -966,15 +989,16 @@ 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 conn %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);
@@ -1007,7 +1031,7 @@ send_broken (struct CadetConnection *c,
   msg.peer1 = *id1;
   msg.peer2 = *id2;
   GNUNET_assert (NULL ==
-                 GCC_send_prebuilt_message (&msg.header, 0, 0, c, fwd,
+                 GCC_send_prebuilt_message (&msg.header, UINT16_MAX, 0, c, fwd,
                                             GNUNET_YES, NULL, NULL));
   GCC_check_connections ();
 }
@@ -1029,6 +1053,7 @@ send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
                      const struct GNUNET_PeerIdentity *peer_id)
 {
   struct GNUNET_CADET_ConnectionBroken *msg;
+  struct CadetPeerQueue *q;
   struct CadetPeer *neighbor;
 
   GCC_check_connections ();
@@ -1046,10 +1071,12 @@ send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
     memset (&msg->peer2, 0, sizeof (msg->peer2));
   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),
-                 NULL, GNUNET_SYSERR, /* connection, fwd */
-                 NULL, NULL); /* continuation */
+  q = GCP_queue_add (neighbor, msg, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
+                     UINT16_MAX, 2,
+                     sizeof (struct GNUNET_CADET_ConnectionBroken),
+                     NULL, GNUNET_SYSERR, /* connection, fwd */
+                     NULL, NULL); /* continuation */
+  GNUNET_assert (NULL != q);
   GCC_check_connections ();
 }
 
@@ -1165,11 +1192,10 @@ connection_maintain (struct CadetConnection *c, int fwd)
  *
  * @param c Connection to keep alive.
  * @param fwd Direction.
- * @param shutdown Are we shutting down? (Don't send traffic)
- *                 Non-zero value for true, not necessarily GNUNET_YES.
  */
 static void
-connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
+connection_keepalive (struct CadetConnection *c,
+                     int fwd)
 {
   GCC_check_connections ();
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1180,10 +1206,6 @@ connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
     c->fwd_maintenance_task = NULL;
   else
     c->bck_maintenance_task = NULL;
-
-  if (GNUNET_NO != shutdown)
-    return;
-
   connection_maintain (c, fwd);
   GCC_check_connections ();
   /* Next execution will be scheduled by message_sent or _maintain*/
@@ -1194,16 +1216,15 @@ connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
  * Keep the connection alive in the FWD direction.
  *
  * @param cls Closure (connection to keepalive).
- * @param tc TaskContext.
  */
 static void
-connection_fwd_keepalive (void *cls,
-                          const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_fwd_keepalive (void *cls)
 {
+  struct CadetConnection *c = cls;
+
   GCC_check_connections ();
-  connection_keepalive ((struct CadetConnection *) cls,
-                        GNUNET_YES,
-                        tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+  connection_keepalive (c,
+                        GNUNET_YES);
   GCC_check_connections ();
 }
 
@@ -1212,16 +1233,15 @@ connection_fwd_keepalive (void *cls,
  * Keep the connection alive in the BCK direction.
  *
  * @param cls Closure (connection to keepalive).
- * @param tc TaskContext.
  */
 static void
-connection_bck_keepalive (void *cls,
-                          const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_bck_keepalive (void *cls)
 {
+  struct CadetConnection *c = cls;
+
   GCC_check_connections ();
-  connection_keepalive ((struct CadetConnection *) cls,
-                        GNUNET_NO,
-                        tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+  connection_keepalive (c,
+                        GNUNET_NO);
   GCC_check_connections ();
 }
 
@@ -1285,7 +1305,8 @@ schedule_next_keepalive (struct CadetConnection *c, int fwd)
   *task_id = GNUNET_SCHEDULER_add_delayed (delay,
                                            keepalive_task,
                                            c);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "next keepalive in %s\n",
        GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
   GCC_check_connections ();
 }
@@ -1372,17 +1393,15 @@ connection_cancel_queues (struct CadetConnection *c,
  * possibly due to a missed ACK. Poll the neighbor about its ACK status.
  *
  * @param cls Closure (poll ctx).
- * @param tc TaskContext.
  */
 static void
-connection_poll (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc);
+connection_poll (void *cls);
 
 
 /**
  * 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.
@@ -1397,14 +1416,21 @@ 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,
@@ -1418,10 +1444,9 @@ poll_sent (void *cls,
  * possibly due to a missed ACK. Poll the neighbor about its ACK status.
  *
  * @param cls Closure (poll ctx).
- * @param tc TaskContext.
  */
 static void
-connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_poll (void *cls)
 {
   struct CadetFlowControl *fc = cls;
   struct GNUNET_CADET_Poll msg;
@@ -1430,11 +1455,6 @@ connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   fc->poll_task = NULL;
   GCC_check_connections ();
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-  {
-    return;
-  }
-
   c = fc->c;
   fwd = fc == &c->fwd_fc;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Polling connection %s %s\n",
@@ -1445,7 +1465,7 @@ 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 ();
@@ -1469,8 +1489,7 @@ resend_messages_and_destroy (struct CadetConnection *c, int fwd)
   int destroyed;
 
   GCC_check_connections ();
-  c->state = CADET_CONNECTION_DESTROYED;
-  c->destroy = GNUNET_YES;
+  mark_destroyed (c);
 
   destroyed = GNUNET_NO;
   neighbor = get_hop (c, fwd);
@@ -1530,7 +1549,7 @@ connection_timeout (struct CadetConnection *c, int fwd)
   }
 
   /* If dest, salvage queued traffic. */
-  if (GCC_is_origin (c, !fwd))
+  if (GCC_is_terminal (c, fwd))
   {
     const struct GNUNET_PeerIdentity *next_hop;
 
@@ -1552,17 +1571,13 @@ connection_timeout (struct CadetConnection *c, int fwd)
  * Destroys connection if called.
  *
  * @param cls Closure (connection to destroy).
- * @param tc TaskContext.
  */
 static void
-connection_fwd_timeout (void *cls,
-                        const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_fwd_timeout (void *cls)
 {
   struct CadetConnection *c = cls;
 
   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 ();
@@ -1574,17 +1589,13 @@ connection_fwd_timeout (void *cls,
  * 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)
+connection_bck_timeout (void *cls)
 {
   struct CadetConnection *c = cls;
 
   c->bck_maintenance_task = NULL;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
   GCC_check_connections ();
   connection_timeout (c, GNUNET_NO);
   GCC_check_connections ();
@@ -1624,7 +1635,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);
@@ -1635,7 +1647,7 @@ 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
+ * If the connection coincides, the c member of path is set to the connection
  * and the destroy flag of the connection is set.
  *
  * @param cls Closure (new path).
@@ -1651,13 +1663,13 @@ check_path (void *cls, struct CadetConnection *c)
        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
+      && GNUNET_NO == c->destroy
+      && CADET_CONNECTION_BROKEN != c->state
+      && CADET_CONNECTION_DESTROYED != c->state
       && path_equivalent (path, c->path))
   {
-    new_conn->destroy = GNUNET_YES;
-    new_conn->path->c = c;
+    new_conn->destroy = GNUNET_YES; /* Do not mark_destroyed, */
+    new_conn->path->c = c;          /* this is only a flag for the Iterator. */
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
   }
 }
@@ -1706,7 +1718,7 @@ does_connection_exist (struct CadetConnection *conn)
     if (CADET_CONNECTION_READY == c->state)
     {
       /* The other peer confirmed a live connection with this path,
-       * why is it trying to duplicate it. */
+       * why are they trying to duplicate it? */
       GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO);
       return GNUNET_YES;
     }
@@ -1726,17 +1738,13 @@ does_connection_exist (struct CadetConnection *conn)
  * 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)
+check_duplicates (void *cls)
 {
   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);
@@ -1746,7 +1754,6 @@ check_duplicates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 }
 
 
-
 /**
  * Wait for enough time to let any dead connections time out and check for
  * any remaining duplicates.
@@ -1760,7 +1767,6 @@ schedule_check_duplicates (struct CadetConnection *c)
 
   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,
@@ -1768,7 +1774,6 @@ schedule_check_duplicates (struct CadetConnection *c)
 }
 
 
-
 /**
  * Add the connection to the list of both neighbors.
  *
@@ -1866,7 +1871,8 @@ unregister_neighbors (struct CadetConnection *c)
  * @param disconnected Peer that disconnected.
  */
 static void
-invalidate_paths (struct CadetConnection *c, struct CadetPeer *disconnected)
+invalidate_paths (struct CadetConnection *c,
+                 struct CadetPeer *disconnected)
 {
   struct CadetPeer *peer;
   unsigned int i;
@@ -1912,12 +1918,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 conn %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);
 }
 
@@ -2122,6 +2140,16 @@ GCC_handle_confirm (void *cls,
     return GNUNET_OK;
   }
 
+  if (GNUNET_NO != c->destroy)
+  {
+    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, GNUNET_YES);
@@ -2250,7 +2278,7 @@ GCC_handle_broken (void* cls,
   t = c->t;
 
   fwd = is_fwd (c, id);
-  c->destroy = GNUNET_YES;
+  mark_destroyed (c);
   if (GCC_is_terminal (c, fwd))
   {
     struct CadetPeer *endpoint;
@@ -2267,7 +2295,7 @@ GCC_handle_broken (void* cls,
       path_invalidate (c->path);
     GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
 
-    c->state = CADET_CONNECTION_BROKEN;
+    connection_change_state (c, CADET_CONNECTION_BROKEN);
     GCT_remove_connection (t, c);
     c->t = NULL;
 
@@ -2338,14 +2366,12 @@ GCC_handle_destroy (void *cls,
   }
   else if (0 == c->pending_messages)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  directly destroying connection!\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  directly destroying connection!\n");
     GCC_destroy (c);
     GCC_check_connections ();
     return GNUNET_OK;
   }
-  c->destroy = GNUNET_YES;
-  c->state = CADET_CONNECTION_DESTROYED;
+  mark_destroyed (c);
   if (NULL != c->t)
   {
     GCT_remove_connection (c->t, c);
@@ -2500,7 +2526,7 @@ 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;
@@ -2525,10 +2551,10 @@ 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,
+                       minimum_size,
                        cid,
                        c,
                        peer,
@@ -2964,6 +2990,7 @@ 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,
@@ -3285,6 +3312,7 @@ GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
 void
 GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
 {
+  struct CadetFlowControl *fc;
   struct CadetPeer *hop;
   char peer_name[16];
   int fwd;
@@ -3315,12 +3343,16 @@ GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
     GCC_check_connections ();
     return;
   }
+  /* 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 delay destruction
    * and remove from map so we don't use accidentally. */
-  c->destroy = GNUNET_YES;
-  c->state = CADET_CONNECTION_DESTROYED;
+  mark_destroyed (c);
   GNUNET_assert (GNUNET_NO == c->was_removed);
   c->was_removed = GNUNET_YES;
   GNUNET_break (GNUNET_YES ==
@@ -3455,11 +3487,16 @@ GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   memcpy (data, message, size);
   type = ntohs (message->type);
   LOG (GNUNET_ERROR_TYPE_INFO,
-       "--> %s (%s %4u) on conn %s (%p) %s (%u bytes)\n",
+       "--> %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)
   {
@@ -3619,16 +3656,16 @@ GCC_send_create (struct CadetConnection *connection)
   size = sizeof (struct GNUNET_CADET_ConnectionCreate);
   size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "--> %s on conn %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);
@@ -3665,15 +3702,14 @@ 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));
-  c->destroy = GNUNET_YES;
-  c->state = CADET_CONNECTION_DESTROYED;
+    GNUNET_assert (NULL == GCC_send_prebuilt_message (&msg.header, UINT16_MAX,
+                                                      0, c, GNUNET_NO,
+                                                      GNUNET_YES, NULL, NULL));
+  mark_destroyed (c);
   GCC_check_connections ();
 }
 
@@ -3698,10 +3734,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, "  POLL 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,
@@ -3728,6 +3771,11 @@ 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;
+  }
 }