Don't pass NULL to destroy_route
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_connection.c
index e22202a596ad282bdc5bd761c5e459edb6da4cab..688cb1f80c1d00911b439b00204635f7bf4e5f6b 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
      This file is part of GNUnet.
      Copyright (C) 2001-2017 GNUnet e.V.
  * @author Christian Grothoff
  *
  * TODO:
- * - Optimization: keepalive messages / timeout (timeout to be done @ peer level!)
- * - Optimization: keep performance metrics (?)
+ * - keep per-connection performance metrics
+ * - in particular, interact with channel (!) to see
+ *   if we get ACKs indicating successful payload delivery.
  */
 #include "platform.h"
+#include "gnunet-service-cadet-new.h"
 #include "gnunet-service-cadet-new_channel.h"
 #include "gnunet-service-cadet-new_connection.h"
 #include "gnunet-service-cadet-new_paths.h"
 #include "gnunet-service-cadet-new_peer.h"
 #include "gnunet-service-cadet-new_tunnels.h"
 #include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
 #include "cadet_protocol.h"
 
 
@@ -118,6 +120,11 @@ struct CadetConnection
    */
   struct GNUNET_SCHEDULER_Task *task;
 
+  /**
+   * Queue entry for keepalive messages.
+   */
+  struct CadetTunnelQueueEntry *keepalive_qe;
+
   /**
    * Function to call once we are ready to transmit.
    */
@@ -138,6 +145,11 @@ struct CadetConnection
    */
   enum CadetConnectionState state;
 
+  /**
+   * Options for the route, control buffering.
+   */
+  enum GNUNET_CADET_ChannelOption options;
+
   /**
    * Offset of our @e destination in @e path.
    */
@@ -152,33 +164,71 @@ struct CadetConnection
 
 
 /**
- * Destroy a connection.
+ * Update the connection state. Also triggers the necessary
+ * MQM notifications.
+ *
+ * @param cc connection to update the state for
+ * @param new_state new state for @a cc
+ * @param new_mqm_ready new `mqm_ready` state for @a cc
+ */
+static void
+update_state (struct CadetConnection *cc,
+              enum CadetConnectionState new_state,
+              int new_mqm_ready)
+{
+  int old_ready;
+  int new_ready;
+
+  if ( (new_state == cc->state) &&
+       (new_mqm_ready == cc->mqm_ready) )
+    return; /* no change, nothing to do */
+  old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
+                (GNUNET_YES == cc->mqm_ready) );
+  new_ready = ( (CADET_CONNECTION_READY == new_state) &&
+                (GNUNET_YES == new_mqm_ready) );
+  cc->state = new_state;
+  cc->mqm_ready = new_mqm_ready;
+  if (old_ready != new_ready)
+    cc->ready_cb (cc->ready_cb_cls,
+                  new_ready);
+}
+
+
+/**
+ * Destroy a connection, part of the internal implementation.  Called
+ * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
  *
  * @param cc connection to destroy
  */
-void
+static void
 GCC_destroy (struct CadetConnection *cc)
 {
-  struct GNUNET_MQ_Envelope *env = NULL;
-
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying connection %s\n",
+       "Destroying %s\n",
        GCC_2s (cc));
-  if (CADET_CONNECTION_SENDING_CREATE != cc->state)
+  if (NULL != cc->mq_man)
   {
-    struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
-
-    /* Need to notify next hop that we are down. */
-    env = GNUNET_MQ_msg (destroy_msg,
-                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
-    destroy_msg->cid = cc->cid;
+    GCP_request_mq_cancel (cc->mq_man,
+                           NULL);
+    cc->mq_man = NULL;
+  }
+  if (NULL != cc->task)
+  {
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
+  }
+  if (NULL != cc->keepalive_qe)
+  {
+    GCT_send_cancel (cc->keepalive_qe);
+    cc->keepalive_qe = NULL;
   }
-  GCP_request_mq_cancel (cc->mq_man,
-                         env);
-  cc->mq_man = NULL;
   GCPP_del_connection (cc->path,
                        cc->off,
                        cc);
+  for (unsigned int i=0;i<cc->off;i++)
+    GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
+                                                    i),
+                           cc);
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multishortmap_remove (connections,
                                                         &GCC_get_id (cc)->connection_of_tunnel,
@@ -187,6 +237,56 @@ GCC_destroy (struct CadetConnection *cc)
 }
 
 
+
+/**
+ * Destroy a connection, called when the CORE layer is already done
+ * (i.e. has received a BROKEN message), but if we still have to
+ * communicate the destruction of the connection to the tunnel (if one
+ * exists).
+ *
+ * @param cc connection to destroy
+ */
+void
+GCC_destroy_without_core (struct CadetConnection *cc)
+{
+  if (NULL != cc->ct)
+  {
+    GCT_connection_lost (cc->ct);
+    cc->ct = NULL;
+  }
+  GCC_destroy (cc);
+}
+
+
+/**
+ * Destroy a connection, called if the tunnel association with the
+ * connection was already broken, but we still need to notify the CORE
+ * layer about the breakage.
+ *
+ * @param cc connection to destroy
+ */
+void
+GCC_destroy_without_tunnel (struct CadetConnection *cc)
+{
+  cc->ct = NULL;
+  if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
+       (NULL != cc->mq_man) )
+  {
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
+
+    /* Need to notify next hop that we are down. */
+    env = GNUNET_MQ_msg (destroy_msg,
+                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
+    destroy_msg->cid = cc->cid;
+    GCP_request_mq_cancel (cc->mq_man,
+                           env);
+    cc->mq_man = NULL;
+  }
+  GCC_destroy (cc);
+}
+
+
 /**
  * Return the tunnel associated with this connection.
  *
@@ -201,7 +301,80 @@ GCC_get_ct (struct CadetConnection *cc)
 
 
 /**
- * A connection ACK was received for this connection, implying
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+send_keepalive (void *cls);
+
+
+/**
+ * Keepalive was transmitted.  Remember this, and possibly
+ * schedule the next one.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+keepalive_done (void *cls)
+{
+  struct CadetConnection *cc = cls;
+
+  cc->keepalive_qe = NULL;
+  if ( (GNUNET_YES == cc->mqm_ready) &&
+       (NULL == cc->task) )
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
+}
+
+
+/**
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+send_keepalive (void *cls)
+{
+  struct CadetConnection *cc = cls;
+  struct GNUNET_MessageHeader msg;
+
+  cc->task = NULL;
+  if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
+  {
+    /* Tunnel not yet ready, wait with keepalives... */
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
+    return;
+  }
+  GNUNET_assert (NULL != cc->ct);
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  GNUNET_assert (NULL == cc->keepalive_qe);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Sending KEEPALIVE on behalf of %s via %s\n",
+       GCC_2s (cc),
+       GCT_2s (cc->ct->t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives sent",
+                            1,
+                            GNUNET_NO);
+  msg.size = htons (sizeof (msg));
+  msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
+
+  cc->keepalive_qe
+    = GCT_send (cc->ct->t,
+                &msg,
+                &keepalive_done,
+                cc);
+}
+
+
+/**
+ * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
  * that the end-to-end connection is up.  Process it.
  *
  * @param cc the connection that got the ACK.
@@ -210,23 +383,26 @@ void
 GCC_handle_connection_create_ack (struct CadetConnection *cc)
 {
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CREATE_ACK for connection %s in state %d\n",
+       "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
        GCC_2s (cc),
-       cc->state);
+       cc->state,
+       (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
+  if (CADET_CONNECTION_READY == cc->state)
+    return; /* Duplicate ACK, ignore */
   if (NULL != cc->task)
   {
     GNUNET_SCHEDULER_cancel (cc->task);
     cc->task = NULL;
   }
-#if FIXME_KEEPALIVE
-  cc->task = GNUNET_SCHEDULER_add_delayed (cc->keepalive_period,
-                                           &send_keepalive,
-                                           cc);
-#endif
-  cc->state = CADET_CONNECTION_READY;
-  if (GNUNET_YES == cc->mqm_ready)
-    cc->ready_cb (cc->ready_cb_cls,
-                  GNUNET_YES);
+  update_state (cc,
+                CADET_CONNECTION_READY,
+                cc->mqm_ready);
+  if ( (NULL == cc->keepalive_qe) &&
+       (GNUNET_YES == cc->mqm_ready) &&
+       (NULL == cc->task) )
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
 }
 
 
@@ -242,10 +418,10 @@ GCC_handle_kx (struct CadetConnection *cc,
 {
   if (CADET_CONNECTION_SENT == cc->state)
   {
-    /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
+    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
        clearly something is working, so pretend we got an ACK. */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Faking connection ACK for connection %s due to KX\n",
+         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
          GCC_2s (cc));
     GCC_handle_connection_create_ack (cc);
   }
@@ -254,6 +430,30 @@ GCC_handle_kx (struct CadetConnection *cc,
 }
 
 
+/**
+ * Handle KX_AUTH message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCC_handle_kx_auth (struct CadetConnection *cc,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
+{
+  if (CADET_CONNECTION_SENT == cc->state)
+  {
+    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
+       clearly something is working, so pretend we got an ACK. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
+         GCC_2s (cc));
+    GCC_handle_connection_create_ack (cc);
+  }
+  GCT_handle_kx_auth (cc->ct,
+                      msg);
+}
+
+
 /**
  * Handle encrypted message.
  *
@@ -269,7 +469,7 @@ GCC_handle_encrypted (struct CadetConnection *cc,
     /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
        clearly something is working, so pretend we got an ACK. */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Faking connection ACK for connection %s due to ENCRYPTED payload\n",
+         "Faking connection ACK for %s due to ENCRYPTED payload\n",
          GCC_2s (cc));
     GCC_handle_connection_create_ack (cc);
   }
@@ -279,7 +479,8 @@ GCC_handle_encrypted (struct CadetConnection *cc,
 
 
 /**
- * Send a CREATE message to the first hop.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
+ * first hop.
  *
  * @param cls the `struct CadetConnection` to initiate
  */
@@ -294,22 +495,24 @@ send_create (void *cls)
 
   cc->task = NULL;
   GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  path_length = GCPP_get_length (cc->path) + 1;
+  path_length = GCPP_get_length (cc->path);
   env = GNUNET_MQ_msg_extra (create_msg,
-                             path_length * sizeof (struct GNUNET_PeerIdentity),
+                             (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
+  create_msg->options = htonl ((uint32_t) cc->options);
   create_msg->cid = cc->cid;
   pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
   pids[0] = my_full_id;
-  for (unsigned int i=1;i<=path_length;i++)
-    pids[i] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
-                                                    i - 1));
+  for (unsigned int i=0;i<path_length;i++)
+    pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
+                                                        i));
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CONNECTION_CREATE message for connection %s\n",
+       "Sending CADET_CONNECTION_CREATE message for %s\n",
        GCC_2s (cc));
   cc->env = env;
-  cc->mqm_ready = GNUNET_NO;
-  cc->state = CADET_CONNECTION_SENT;
+  update_state (cc,
+                CADET_CONNECTION_SENT,
+                GNUNET_NO);
   GCP_send (cc->mq_man,
             env);
 }
@@ -328,16 +531,18 @@ send_create_ack (void *cls)
   struct GNUNET_MQ_Envelope *env;
 
   cc->task = NULL;
+  GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CONNECTION_CREATE_ACK message for connection %s\n",
+       "Sending CONNECTION_CREATE_ACK message for %s\n",
        GCC_2s (cc));
   GNUNET_assert (GNUNET_YES == cc->mqm_ready);
   env = GNUNET_MQ_msg (ack_msg,
                        GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
   ack_msg->cid = cc->cid;
   cc->env = env;
-  cc->mqm_ready = GNUNET_NO;
-  cc->state = CADET_CONNECTION_READY;
+  update_state (cc,
+                CADET_CONNECTION_READY,
+                GNUNET_NO);
   GCP_send (cc->mq_man,
             env);
 }
@@ -356,15 +561,16 @@ GCC_handle_duplicate_create (struct CadetConnection *cc)
   if (GNUNET_YES == cc->mqm_ready)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate CREATE for connection %s, scheduling another ACK\n",
-         GCC_2s (cc));
-    /* Tell tunnel that we are not ready for transmission anymore
-       (until CREATE_ACK is done) */
-    cc->ready_cb (cc->ready_cb_cls,
-                  GNUNET_NO);
+         "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
+         GCC_2s (cc),
+         (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
     /* Revert back to the state of having only received the 'CREATE',
        and immediately proceed to send the CREATE_ACK. */
-    cc->state = CADET_CONNECTION_CREATE_RECEIVED;
+    update_state (cc,
+                  CADET_CONNECTION_CREATE_RECEIVED,
+                  cc->mqm_ready);
+    if (NULL != cc->task)
+      GNUNET_SCHEDULER_cancel (cc->task);
     cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
                                          cc);
   }
@@ -374,7 +580,7 @@ GCC_handle_duplicate_create (struct CadetConnection *cc)
        can only be an ACK or payload, either of which would
        do. So actually no need to do anything. */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate CREATE for connection %s. MQ is busy, not queueing another ACK\n",
+         "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
          GCC_2s (cc));
   }
 }
@@ -400,24 +606,25 @@ manage_first_hop_mq (void *cls,
   {
     /* Connection is down, for now... */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Core MQ for connection %s went down\n",
+         "Core MQ for %s went down\n",
          GCC_2s (cc));
-    cc->mqm_ready = GNUNET_NO;
-    cc->state = CADET_CONNECTION_NEW;
+    update_state (cc,
+                  CADET_CONNECTION_NEW,
+                  GNUNET_NO);
     cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
     if (NULL != cc->task)
     {
       GNUNET_SCHEDULER_cancel (cc->task);
       cc->task = NULL;
     }
-    cc->ready_cb (cc->ready_cb_cls,
-                  GNUNET_NO);
     return;
   }
 
-  cc->mqm_ready = GNUNET_YES;
+  update_state (cc,
+                cc->state,
+                GNUNET_YES);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Core MQ for connection %s became available in state %d\n",
+       "Core MQ for %s became available in state %d\n",
        GCC_2s (cc),
        cc->state);
   switch (cc->state)
@@ -444,8 +651,19 @@ manage_first_hop_mq (void *cls,
                                          cc);
     break;
   case CADET_CONNECTION_READY:
-    cc->ready_cb (cc->ready_cb_cls,
-                  GNUNET_YES);
+    if ( (NULL == cc->keepalive_qe) &&
+         (GNUNET_YES == cc->mqm_ready) &&
+         (NULL == cc->task) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Scheduling keepalive for %s in %s\n",
+           GCC_2s (cc),
+           GNUNET_STRINGS_relative_time_to_string (keepalive_period,
+                                                   GNUNET_YES));
+      cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                               &send_keepalive,
+                                               cc);
+    }
     break;
   }
 }
@@ -458,6 +676,7 @@ manage_first_hop_mq (void *cls,
  *
  * @param destination where to go
  * @param path which path to take (may not be the full path)
+ * @param options options for the connection
  * @param ct which tunnel uses this connection
  * @param init_state initial state for the connection
  * @param ready_cb function to call when ready to transmit
@@ -467,6 +686,7 @@ manage_first_hop_mq (void *cls,
 static struct CadetConnection *
 connection_create (struct CadetPeer *destination,
                    struct CadetPeerPath *path,
+                   enum GNUNET_CADET_ChannelOption options,
                    struct CadetTConnection *ct,
                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
                    enum CadetConnectionState init_state,
@@ -481,6 +701,7 @@ connection_create (struct CadetPeer *destination,
                         destination);
   GNUNET_assert (UINT_MAX > off);
   cc = GNUNET_new (struct CadetConnection);
+  cc->options = options;
   cc->state = init_state;
   cc->ct = ct;
   cc->cid = *cid;
@@ -493,12 +714,16 @@ connection_create (struct CadetPeer *destination,
   cc->ready_cb_cls = ready_cb_cls;
   cc->path = path;
   cc->off = off;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating %s using path %s\n",
+       GCC_2s (cc),
+       GCPP_2s (path));
   GCPP_add_connection (path,
                        off,
                        cc);
   for (unsigned int i=0;i<off;i++)
     GCP_add_connection (GCPP_get_peer_at_offset (path,
-                                                 off),
+                                                 i),
                         cc);
 
   first_hop = GCPP_get_peer_at_offset (path,
@@ -506,10 +731,6 @@ connection_create (struct CadetPeer *destination,
   cc->mq_man = GCP_request_mq (first_hop,
                                &manage_first_hop_mq,
                                cc);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created connection %s using path %s\n",
-       GCC_2s (cc),
-       GCPP_2s (path));
   return cc;
 }
 
@@ -521,21 +742,73 @@ connection_create (struct CadetPeer *destination,
  *
  * @param destination where to go
  * @param path which path to take (may not be the full path)
+ * @param options options for the connection
  * @param ct which tunnel uses this connection
  * @param ready_cb function to call when ready to transmit
  * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
+ * @return handle to the connection, NULL if we already have
+ *         a connection that takes precedence on @a path
  */
 struct CadetConnection *
 GCC_create_inbound (struct CadetPeer *destination,
                     struct CadetPeerPath *path,
+                   enum GNUNET_CADET_ChannelOption options,
                     struct CadetTConnection *ct,
                     const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
                     GCC_ReadyCallback ready_cb,
                     void *ready_cb_cls)
 {
+  struct CadetConnection *cc;
+  unsigned int off;
+
+  off = GCPP_find_peer (path,
+                        destination);
+  GNUNET_assert (UINT_MAX != off);
+  cc = GCPP_get_connection (path,
+                            destination,
+                            off);
+  if (NULL != cc)
+  {
+    int cmp;
+
+    cmp = memcmp (cid,
+                  &cc->cid,
+                  sizeof (*cid));
+    if (0 == cmp)
+    {
+      /* Two peers picked the SAME random connection identifier at the
+         same time for the same path? Must be malicious.  Drop
+         connection (existing and inbound), even if it is the only
+         one. */
+      GNUNET_break_op (0);
+      GCT_connection_lost (cc->ct);
+      GCC_destroy_without_tunnel (cc);
+      return NULL;
+    }
+    if (0 < cmp)
+    {
+      /* drop existing */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got two connections on %s, dropping my existing %s\n",
+           GCPP_2s (path),
+           GCC_2s (cc));
+      GCT_connection_lost (cc->ct);
+      GCC_destroy_without_tunnel (cc);
+    }
+    else
+    {
+      /* keep existing */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got two connections on %s, keeping my existing %s\n",
+           GCPP_2s (path),
+           GCC_2s (cc));
+      return NULL;
+    }
+  }
+
   return connection_create (destination,
                             path,
+                            options,
                             ct,
                             cid,
                             CADET_CONNECTION_CREATE_RECEIVED,
@@ -550,6 +823,7 @@ GCC_create_inbound (struct CadetPeer *destination,
  *
  * @param destination where to go
  * @param path which path to take (may not be the full path)
+ * @param options options for the connection
  * @param ct tunnel that uses the connection
  * @param ready_cb function to call when ready to transmit
  * @param ready_cb_cls closure for @a cb
@@ -558,6 +832,7 @@ GCC_create_inbound (struct CadetPeer *destination,
 struct CadetConnection *
 GCC_create (struct CadetPeer *destination,
             struct CadetPeerPath *path,
+            enum GNUNET_CADET_ChannelOption options,
             struct CadetTConnection *ct,
             GCC_ReadyCallback ready_cb,
             void *ready_cb_cls)
@@ -569,6 +844,7 @@ GCC_create (struct CadetPeer *destination,
                               sizeof (cid));
   return connection_create (destination,
                             path,
+                            options,
                             ct,
                             &cid,
                             CADET_CONNECTION_NEW,
@@ -597,6 +873,11 @@ GCC_transmit (struct CadetConnection *cc,
   GNUNET_assert (GNUNET_YES == cc->mqm_ready);
   GNUNET_assert (CADET_CONNECTION_READY == cc->state);
   cc->mqm_ready = GNUNET_NO;
+  if (NULL != cc->task)
+  {
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
+  }
   GCP_send (cc->mq_man,
             env);
 }
@@ -645,14 +926,14 @@ GCC_2s (const struct CadetConnection *cc)
   {
     GNUNET_snprintf (buf,
                      sizeof (buf),
-                     "Connection(%s(Tunnel(%s)))",
+                     "Connection %s (%s)",
                      GNUNET_sh2s (&cc->cid.connection_of_tunnel),
                      GCT_2s (cc->ct->t));
     return buf;
   }
   GNUNET_snprintf (buf,
                    sizeof (buf),
-                   "Connection(%s(Tunnel(NULL)))",
+                   "Connection %s",
                    GNUNET_sh2s (&cc->cid.connection_of_tunnel));
   return buf;
 }
@@ -672,7 +953,6 @@ GCC_debug (struct CadetConnection *cc,
            enum GNUNET_ErrorType level)
 {
   int do_log;
-  char *s;
 
   do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
                                        "cadet-con",
@@ -685,15 +965,13 @@ GCC_debug (struct CadetConnection *cc,
           "Connection (NULL)\n");
     return;
   }
-  s = GCPP_2s (cc->path);
   LOG2 (level,
-        "Connection %s to %s via path %s in state %d is %s\n",
+        "%s to %s via path %s in state %d is %s\n",
         GCC_2s (cc),
         GCP_2s (cc->destination),
-        s,
+        GCPP_2s (cc->path),
         cc->state,
         (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
-  GNUNET_free (s);
 }
 
 /* end of gnunet-service-cadet-new_connection.c */