must delay iteration over paths until later, as we may be right now creating a connection
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_tunnels.c
index 8f1a19d5bdd03caa4cef8742d480f7d382bb09a5..d63da29d4c6c65c2acabf4f363dd738651f35acc 100644 (file)
@@ -342,7 +342,7 @@ struct CadetTunnel
   /**
    * Channel ID for the next created channel in this tunnel.
    */
-  struct GNUNET_CADET_ChannelTunnelNumber next_chid;
+  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
 
   /**
    * Queued messages, to transmit once tunnel gets connected.
@@ -407,15 +407,45 @@ GCT_2s (const struct CadetTunnel *t)
 
   if (NULL == t)
     return "T(NULL)";
-
   GNUNET_snprintf (buf,
                    sizeof (buf),
                    "T(%s)",
-                   GCP_2s (t->destination));
+                   GNUNET_i2s (GCP_get_id (t->destination)));
   return buf;
 }
 
 
+/**
+ * Get string description for tunnel encryption state.
+ *
+ * @param es Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+estate2s (enum CadetTunnelEState es)
+{
+  static char buf[32];
+
+  switch (es)
+  {
+    case CADET_TUNNEL_KEY_UNINITIALIZED:
+      return "CADET_TUNNEL_KEY_UNINITIALIZED";
+    case CADET_TUNNEL_KEY_SENT:
+      return "CADET_TUNNEL_KEY_SENT";
+    case CADET_TUNNEL_KEY_PING:
+      return "CADET_TUNNEL_KEY_PING";
+    case CADET_TUNNEL_KEY_OK:
+      return "CADET_TUNNEL_KEY_OK";
+    case CADET_TUNNEL_KEY_REKEY:
+      return "CADET_TUNNEL_KEY_REKEY";
+    default:
+      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
+      return buf;
+  }
+}
+
+
 /**
  * Return the peer to which this tunnel goes.
  *
@@ -444,18 +474,18 @@ GCT_count_channels (struct CadetTunnel *t)
 
 
 /**
- * Lookup a channel by its @a chid.
+ * Lookup a channel by its @a ctn.
  *
  * @param t tunnel to look in
- * @param chid number of channel to find
+ * @param ctn number of channel to find
  * @return NULL if channel does not exist
  */
 struct CadetChannel *
 lookup_channel (struct CadetTunnel *t,
-                struct GNUNET_CADET_ChannelTunnelNumber chid)
+                struct GNUNET_CADET_ChannelTunnelNumber ctn)
 {
   return GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              ntohl (chid.cn));
+                                              ntohl (ctn.cn));
 }
 
 
@@ -1142,6 +1172,27 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
 }
 
 
+/**
+ * Our tunnel became ready for the first time, notify channels
+ * that have been waiting.
+ *
+ * @param cls our tunnel, not used
+ * @param key unique ID of the channel, not used
+ * @param value the `struct CadetChannel` to notify
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+notify_tunnel_up_cb (void *cls,
+                     uint32_t key,
+                     void *value)
+{
+  struct CadetChannel *ch = value;
+
+  GCCH_tunnel_up (ch);
+  return GNUNET_OK;
+}
+
+
 /**
  * Change the tunnel encryption state.
  * If the encryption state changes to OK, stop the rekey task.
@@ -1170,6 +1221,14 @@ GCT_change_estate (struct CadetTunnel *t,
       GNUNET_SCHEDULER_cancel (t->kx_task);
       t->kx_task = NULL;
     }
+    if (CADET_TUNNEL_KEY_REKEY != old)
+    {
+      /* notify all channels that have been waiting */
+      GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                               &notify_tunnel_up_cb,
+                                               t);
+    }
+
     /* FIXME: schedule rekey task! */
   }
 }
@@ -1196,8 +1255,17 @@ send_kx (struct CadetTunnel *t,
 
   ct = get_ready_connection (t);
   if (NULL == ct)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Wanted to send KX on tunnel %s, but no connection is ready, deferring\n",
+                GCT_2s (t));
     return;
+  }
   cc = ct->cc;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending KX on tunnel %s using connection %s\n",
+              GCT_2s (t),
+              GCC_2s (ct->cc));
 
   // GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
   env = GNUNET_MQ_msg (msg,
@@ -1327,6 +1395,10 @@ GCT_handle_kx (struct CadetTConnection *ct,
          " known handshake key, exit\n");
     return;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Handling KX message for tunnel %s\n",
+              GCT_2s (t));
+
   ax->RK = keys[0];
   if (GNUNET_YES == am_I_alice)
   {
@@ -1389,28 +1461,30 @@ GCT_handle_kx (struct CadetTConnection *ct,
  * @return unused number that can uniquely identify a channel in the tunnel
  */
 static struct GNUNET_CADET_ChannelTunnelNumber
-get_next_free_chid (struct CadetTunnel *t)
+get_next_free_ctn (struct CadetTunnel *t)
 {
   struct GNUNET_CADET_ChannelTunnelNumber ret;
-  uint32_t chid;
+  uint32_t ctn;
 
   /* FIXME: this logic does NOT prevent both ends of the
-     channel from picking the same CHID!
-     Need to reserve one bit of the CHID for the
+     channel from picking the same CTN!
+     Need to reserve one bit of the CTN for the
      direction, i.e. which side established the connection! */
-  chid = ntohl (t->next_chid.cn);
+  ctn = ntohl (t->next_ctn.cn);
   while (NULL !=
          GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              chid))
-    chid++;
-  t->next_chid.cn = htonl (chid + 1);
-  ret.cn = ntohl (chid);
+                                              ctn))
+    ctn++;
+  t->next_ctn.cn = htonl (ctn + 1);
+  ret.cn = ntohl (ctn);
   return ret;
 }
 
 
 /**
- * Add a channel to a tunnel.
+ * Add a channel to a tunnel, and notify channel that we are ready
+ * for transmission if we are already up.  Otherwise that notification
+ * will be done later in #notify_tunnel_up_cb().
  *
  * @param t Tunnel.
  * @param ch Channel
@@ -1420,15 +1494,22 @@ struct GNUNET_CADET_ChannelTunnelNumber
 GCT_add_channel (struct CadetTunnel *t,
                  struct CadetChannel *ch)
 {
-  struct GNUNET_CADET_ChannelTunnelNumber chid;
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
 
-  chid = get_next_free_chid (t);
+  ctn = get_next_free_ctn (t);
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (chid.cn),
+                                                      ntohl (ctn.cn),
                                                       ch,
                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  return chid;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Adding channel %s to tunnel %s\n",
+              GCCH_2s (ch),
+              GCT_2s (t));
+  if ( (CADET_TUNNEL_KEY_OK == t->estate) ||
+       (CADET_TUNNEL_KEY_REKEY == t->estate) )
+    GCCH_tunnel_up (ch);
+  return ctn;
 }
 
 
@@ -1442,9 +1523,12 @@ destroy_tunnel (void *cls)
 {
   struct CadetTunnel *t = cls;
   struct CadetTConnection *ct;
-  struct CadetTunnelQueueEntry *tqe;
+  struct CadetTunnelQueueEntry *tq;
 
   t->destroy_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Destroying idle tunnel %s\n",
+              GCT_2s (t));
   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (t->channels));
   while (NULL != (ct = t->connection_head))
   {
@@ -1455,14 +1539,8 @@ destroy_tunnel (void *cls)
     GCC_destroy (ct->cc);
     GNUNET_free (ct);
   }
-  while (NULL != (tqe = t->tq_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                                 t->tq_tail,
-                                 tqe);
-    GNUNET_MQ_discard (tqe->env);
-    GNUNET_free (tqe);
-  }
+  while (NULL != (tq = t->tq_head))
+    GCT_send_cancel (tq);
   GCP_drop_tunnel (t->destination,
                    t);
   GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
@@ -1473,10 +1551,61 @@ destroy_tunnel (void *cls)
   }
   GNUNET_MST_destroy (t->mst);
   GNUNET_MQ_destroy (t->mq);
+  while (NULL != t->ax.skipped_head)
+    delete_skipped_key (t,
+                        t->ax.skipped_head);
+  GNUNET_assert (0 == t->ax.skipped);
+  GNUNET_free_non_null (t->ax.kx_0);
+  GNUNET_free_non_null (t->ax.DHRs);
   GNUNET_free (t);
 }
 
 
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param ctn unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Removing channel %s from tunnel %s\n",
+              GCCH_2s (ch),
+              GCT_2s (t));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+                                                         ntohl (ctn.cn),
+                                                         ch));
+  if (0 ==
+      GNUNET_CONTAINER_multihashmap32_size (t->channels))
+  {
+    t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+                                                    &destroy_tunnel,
+                                                    t);
+  }
+}
+
+
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t)
+{
+  GNUNET_assert (0 ==
+                 GNUNET_CONTAINER_multihashmap32_size (t->channels));
+  GNUNET_SCHEDULER_cancel (t->destroy_task);
+  destroy_tunnel (t);
+}
+
+
 /**
  * It's been a while, we should try to redo the KX, if we can.
  *
@@ -1496,6 +1625,50 @@ retry_kx (void *cls)
 }
 
 
+/**
+ * Send normal payload from queue in @a t via connection @a ct.
+ * Does nothing if our payload queue is empty.
+ *
+ * @param t tunnel to send data from
+ * @param ct connection to use for transmission (is ready)
+ */
+static void
+try_send_normal_payload (struct CadetTunnel *t,
+                         struct CadetTConnection *ct)
+{
+  struct CadetTunnelQueueEntry *tq;
+
+  GNUNET_assert (GNUNET_YES == ct->is_ready);
+  tq = t->tq_head;
+  if (NULL == tq)
+  {
+    /* no messages pending right now */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Not sending payload of tunnel %s on ready connection %s (nothing pending)\n",
+                GCT_2s (t),
+                GCC_2s (ct->cc));
+    return;
+  }
+  /* ready to send message 'tq' on tunnel 'ct' */
+  GNUNET_assert (t == tq->t);
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  if (NULL != tq->cid)
+    *tq->cid = *GCC_get_id (ct->cc);
+  ct->is_ready = GNUNET_NO;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending payload of tunnel %s on connection %s\n",
+              GCT_2s (t),
+              GCC_2s (ct->cc));
+  GCC_transmit (ct->cc,
+                tq->env);
+  if (NULL != tq->cont)
+    tq->cont (tq->cont_cls);
+  GNUNET_free (tq);
+}
+
+
 /**
  * A connection is @a is_ready for transmission.  Looks at our message
  * queue and if there is a message, sends it out via the connection.
@@ -1510,14 +1683,22 @@ connection_ready_cb (void *cls,
 {
   struct CadetTConnection *ct = cls;
   struct CadetTunnel *t = ct->t;
-  struct CadetTunnelQueueEntry *tq = t->tq_head;
 
-  if (GNUNET_NO == ct->is_ready)
+  if (GNUNET_NO == is_ready)
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Connection %s no longer ready for tunnel %s\n",
+                GCC_2s (ct->cc),
+                GCT_2s (t));
     ct->is_ready = GNUNET_NO;
     return;
   }
   ct->is_ready = GNUNET_YES;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connection %s now ready for tunnel %s in state %s\n",
+              GCC_2s (ct->cc),
+              GCT_2s (t),
+              estate2s (t->estate));
   switch (t->estate)
   {
   case CADET_TUNNEL_KEY_UNINITIALIZED:
@@ -1530,28 +1711,14 @@ connection_ready_cb (void *cls,
     if (NULL == t->kx_task)
     {
       t->kx_task
-        = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt),
-                                        &retry_kx,
-                                        t);
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
     }
     break;
   case CADET_TUNNEL_KEY_OK:
-    /* send normal payload */
-    if (NULL == tq)
-      return; /* no messages pending right now */
-    /* ready to send message 'tq' on tunnel 'ct' */
-    GNUNET_assert (t == tq->t);
-    GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                                 t->tq_tail,
-                                 tq);
-    if (NULL != tq->cid)
-      *tq->cid = *GCC_get_id (ct->cc);
-    ct->is_ready = GNUNET_NO;
-    GCC_transmit (ct->cc,
-                  tq->env);
-    if (NULL != tq->cont)
-      tq->cont (tq->cont_cls);
-    GNUNET_free (tq);
+    try_send_normal_payload (t,
+                             ct);
     break;
   case CADET_TUNNEL_KEY_REKEY:
     send_kx (t,
@@ -1580,32 +1747,8 @@ trigger_transmissions (struct CadetTunnel *t)
   ct = get_ready_connection (t);
   if (NULL == ct)
     return; /* no connections ready */
-
-  /* FIXME: a bit hackish to do it like this... */
-  connection_ready_cb (ct,
-                       GNUNET_YES);
-}
-
-
-/**
- * Function called to maintain the connections underlying our tunnel.
- * Tries to maintain (incl. tear down) connections for the tunnel, and
- * if there is a significant change, may trigger transmissions.
- *
- * Basically, needs to check if there are connections that perform
- * badly, and if so eventually kill them and trigger a replacement.
- * The strategy is to open one more connection than
- * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
- * least-performing one, and then inquire for new ones.
- *
- * @param cls the `struct CadetTunnel`
- */
-static void
-maintain_connections_cb (void *cls)
-{
-  struct CadetTunnel *t = cls;
-
-  GNUNET_break (0); // FIXME: implement!
+  try_send_normal_payload (t,
+                           ct);
 }
 
 
@@ -1637,7 +1780,13 @@ consider_path_cb (void *cls,
 
     ps = GCC_get_path (ct->cc);
     if (ps == path)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Ignoring duplicate path %s for tunnel %s.\n",
+                  GCPP_2s (path),
+                  GCT_2s (t));
       return GNUNET_YES; /* duplicate */
+    }
     min_length = GNUNET_MIN (min_length,
                              GCPP_get_length (ps));
     max_desire = GNUNET_MAX (max_desire,
@@ -1690,10 +1839,46 @@ consider_path_cb (void *cls,
                                t->connection_tail,
                                ct);
   t->num_connections++;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Found interesting path %s for tunnel %s, created connection %s\n",
+              GCPP_2s (path),
+              GCT_2s (t),
+              GCC_2s (ct->cc));
   return GNUNET_YES;
 }
 
 
+/**
+ * Function called to maintain the connections underlying our tunnel.
+ * Tries to maintain (incl. tear down) connections for the tunnel, and
+ * if there is a significant change, may trigger transmissions.
+ *
+ * Basically, needs to check if there are connections that perform
+ * badly, and if so eventually kill them and trigger a replacement.
+ * The strategy is to open one more connection than
+ * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
+ * least-performing one, and then inquire for new ones.
+ *
+ * @param cls the `struct CadetTunnel`
+ */
+static void
+maintain_connections_cb (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  t->maintain_connections_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing connection maintenance for tunnel %s.\n",
+              GCT_2s (t));
+
+  (void) GCP_iterate_paths (t->destination,
+                            &consider_path_cb,
+                            t);
+
+  GNUNET_break (0); // FIXME: implement!
+}
+
+
 /**
  * Consider using the path @a p for the tunnel @a t.
  * The tunnel destination is at offset @a off in path @a p.
@@ -1714,7 +1899,7 @@ GCT_consider_path (struct CadetTunnel *t,
 
 
 /**
- *
+ * NOT IMPLEMENTED.
  *
  * @param cls the `struct CadetTunnel` for which we decrypted the message
  * @param msg  the message we received on the tunnel
@@ -1724,6 +1909,7 @@ handle_plaintext_keepalive (void *cls,
                             const struct GNUNET_MessageHeader *msg)
 {
   struct CadetTunnel *t = cls;
+
   GNUNET_break (0); // FIXME
 }
 
@@ -1758,13 +1944,17 @@ handle_plaintext_data (void *cls,
   struct CadetChannel *ch;
 
   ch = lookup_channel (t,
-                       msg->chid);
+                       msg->ctn);
   if (NULL == ch)
   {
     /* We don't know about such a channel, might have been destroyed on our
        end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receicved %u bytes of application data for unknown channel %u, sending DESTROY\n",
+         (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
+         ntohl (msg->ctn.cn));
     GCT_send_channel_destroy (t,
-                              msg->chid);
+                              msg->ctn);
     return;
   }
   GCCH_handle_channel_plaintext_data (ch,
@@ -1788,13 +1978,16 @@ handle_plaintext_data_ack (void *cls,
   struct CadetChannel *ch;
 
   ch = lookup_channel (t,
-                       ack->chid);
+                       ack->ctn);
   if (NULL == ch)
   {
     /* We don't know about such a channel, might have been destroyed on our
        end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receicved DATA_ACK for unknown channel %u, sending DESTROY\n",
+         ntohl (ack->ctn.cn));
     GCT_send_channel_destroy (t,
-                              ack->chid);
+                              ack->ctn);
     return;
   }
   GCCH_handle_channel_plaintext_data_ack (ch,
@@ -1810,21 +2003,25 @@ handle_plaintext_data_ack (void *cls,
  * @param cc the message we received on the tunnel
  */
 static void
-handle_plaintext_channel_create (void *cls,
-                                 const struct GNUNET_CADET_ChannelOpenMessage *cc)
+handle_plaintext_channel_open (void *cls,
+                               const struct GNUNET_CADET_ChannelOpenMessage *cc)
 {
   struct CadetTunnel *t = cls;
   struct CadetChannel *ch;
-  struct GNUNET_CADET_ChannelTunnelNumber chid;
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
 
-  chid = get_next_free_chid (t);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Receicved channel OPEN on port %s from peer %s\n",
+       GNUNET_h2s (&cc->port),
+       GCP_2s (GCT_get_destination (t)));
+  ctn = get_next_free_ctn (t);
   ch = GCCH_channel_incoming_new (t,
-                                  chid,
+                                  ctn,
                                   &cc->port,
                                   ntohl (cc->opt));
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (chid.cn),
+                                                      ntohl (ctn.cn),
                                                       ch,
                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
 }
@@ -1834,18 +2031,21 @@ handle_plaintext_channel_create (void *cls,
  * Send a DESTROY message via the tunnel.
  *
  * @param t the tunnel to transmit over
- * @param chid ID of the channel to destroy
+ * @param ctn ID of the channel to destroy
  */
 void
 GCT_send_channel_destroy (struct CadetTunnel *t,
-                          struct GNUNET_CADET_ChannelTunnelNumber chid)
+                          struct GNUNET_CADET_ChannelTunnelNumber ctn)
 {
   struct GNUNET_CADET_ChannelManageMessage msg;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending DESTORY message for channel ID %u\n",
+       ntohl (ctn.cn));
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
   msg.reserved = htonl (0);
-  msg.chid = chid;
+  msg.ctn = ctn;
   GCT_send (t,
             &msg.header,
             NULL,
@@ -1862,23 +2062,26 @@ GCT_send_channel_destroy (struct CadetTunnel *t,
  * @param cm the message we received on the tunnel
  */
 static void
-handle_plaintext_channel_ack (void *cls,
-                              const struct GNUNET_CADET_ChannelManageMessage *cm)
+handle_plaintext_channel_open_ack (void *cls,
+                                   const struct GNUNET_CADET_ChannelManageMessage *cm)
 {
   struct CadetTunnel *t = cls;
   struct CadetChannel *ch;
 
   ch = lookup_channel (t,
-                       cm->chid);
+                       cm->ctn);
   if (NULL == ch)
   {
     /* We don't know about such a channel, might have been destroyed on our
        end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel OPEN_ACK for unknown channel, sending DESTROY\n",
+         GCCH_2s (ch));
     GCT_send_channel_destroy (t,
-                              cm->chid);
+                              cm->ctn);
     return;
   }
-  GCCH_handle_channel_create_ack (ch);
+  GCCH_handle_channel_open_ack (ch);
 }
 
 
@@ -1894,10 +2097,20 @@ handle_plaintext_channel_destroy (void *cls,
                                   const struct GNUNET_CADET_ChannelManageMessage *cm)
 {
   struct CadetTunnel *t = cls;
-  struct CadetChannel *cc = lookup_channel (t,
-                                            cm->chid);
+  struct CadetChannel *ch;
 
-  GCCH_handle_remote_destroy (cc);
+  ch = lookup_channel (t,
+                       cm->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel DESTORY for unknown channel. Ignoring.\n",
+         GCCH_2s (ch));
+    return;
+  }
+  GCCH_handle_remote_destroy (ch);
 }
 
 
@@ -1959,11 +2172,11 @@ GCT_create_tunnel (struct CadetPeer *destination)
                              GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
                              struct GNUNET_CADET_ChannelDataAckMessage,
                              NULL),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_create,
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
                              GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
                              struct GNUNET_CADET_ChannelOpenMessage,
                              NULL),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_ack,
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
                              GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
                              struct GNUNET_CADET_ChannelManageMessage,
                              NULL),
@@ -1976,11 +2189,10 @@ GCT_create_tunnel (struct CadetPeer *destination)
   struct CadetTunnel *t;
 
   t = GNUNET_new (struct CadetTunnel);
+  new_ephemeral (t);
+  t->ax.kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
   t->destination = destination;
   t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-  (void) GCP_iterate_paths (destination,
-                            &consider_path_cb,
-                            t);
   t->maintain_connections_task
     = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
                                 t);
@@ -1997,32 +2209,6 @@ GCT_create_tunnel (struct CadetPeer *destination)
 }
 
 
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel
- * @param gid unique number identifying @a ch within @a t
- */
-void
-GCT_remove_channel (struct CadetTunnel *t,
-                    struct CadetChannel *ch,
-                    struct GNUNET_CADET_ChannelTunnelNumber gid)
-{
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
-                                                         ntohl (gid.cn),
-                                                         ch));
-  if (0 ==
-      GNUNET_CONTAINER_multihashmap32_size (t->channels))
-  {
-    t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
-                                                    &destroy_tunnel,
-                                                    t);
-  }
-}
-
-
 /**
  * Add a @a connection to the @a tunnel.
  *
@@ -2054,6 +2240,10 @@ GCT_add_inbound_connection (struct CadetTunnel *t,
                                t->connection_tail,
                                ct);
   t->num_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel %s has new connection %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
 }
 
 
@@ -2072,6 +2262,12 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
   char cbuf [size] GNUNET_ALIGN;
   ssize_t decrypted_size;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel %s received %u bytes of encrypted data in state %d\n",
+       GCT_2s (t),
+       (unsigned int) size,
+       t->estate);
+
   switch (t->estate)
   {
   case CADET_TUNNEL_KEY_UNINITIALIZED:
@@ -2109,17 +2305,14 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
 
   if (-1 == decrypted_size)
   {
+    GNUNET_break_op (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Tunnel %s failed to decrypt and validate encrypted data\n",
+         GCT_2s (t));
     GNUNET_STATISTICS_update (stats,
                               "# unable to decrypt",
                               1,
                               GNUNET_NO);
-    if (CADET_TUNNEL_KEY_PING <= t->estate)
-    {
-      GNUNET_break_op (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           "Failed to decrypt message on tunnel %s\n",
-           GCT_2s (t));
-    }
     return;
   }
   if (CADET_TUNNEL_KEY_PING == t->estate)
@@ -2160,6 +2353,10 @@ GCT_send (struct CadetTunnel *t,
   struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
 
   payload_size = ntohs (message->size);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Encrypting %u bytes of for tunnel %s\n",
+       (unsigned int) payload_size,
+       GCT_2s (t));
   env = GNUNET_MQ_msg_extra (ax_msg,
                              payload_size,
                              GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
@@ -2200,17 +2397,18 @@ GCT_send (struct CadetTunnel *t,
  * function is called. Once the continuation is called, the message is
  * no longer in the queue!
  *
- * @param q Handle to the queue entry to cancel.
+ * @param tq Handle to the queue entry to cancel.
  */
 void
-GCT_send_cancel (struct CadetTunnelQueueEntry *q)
+GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
 {
-  struct CadetTunnel *t = q->t;
+  struct CadetTunnel *t = tq->t;
 
   GNUNET_CONTAINER_DLL_remove (t->tq_head,
                                t->tq_tail,
-                               q);
-  GNUNET_free (q);
+                               tq);
+  GNUNET_MQ_discard (tq->env);
+  GNUNET_free (tq);
 }
 
 
@@ -2317,37 +2515,6 @@ debug_channel (void *cls,
 }
 
 
-/**
- * Get string description for tunnel encryption state.
- *
- * @param es Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-estate2s (enum CadetTunnelEState es)
-{
-  static char buf[32];
-
-  switch (es)
-  {
-    case CADET_TUNNEL_KEY_UNINITIALIZED:
-      return "CADET_TUNNEL_KEY_UNINITIALIZED";
-    case CADET_TUNNEL_KEY_SENT:
-      return "CADET_TUNNEL_KEY_SENT";
-    case CADET_TUNNEL_KEY_PING:
-      return "CADET_TUNNEL_KEY_PING";
-    case CADET_TUNNEL_KEY_OK:
-      return "CADET_TUNNEL_KEY_OK";
-    case CADET_TUNNEL_KEY_REKEY:
-      return "CADET_TUNNEL_KEY_REKEY";
-    default:
-      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
-      return buf;
-  }
-}
-
-
 #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)