rename cadet*new to just cadet, except for libgnunetcadetnew-logic (where the 'old...
authorChristian Grothoff <christian@grothoff.org>
Sat, 11 Mar 2017 12:15:25 +0000 (13:15 +0100)
committerChristian Grothoff <christian@grothoff.org>
Sat, 11 Mar 2017 12:15:25 +0000 (13:15 +0100)
46 files changed:
src/cadet/Makefile.am
src/cadet/cadet.conf.in
src/cadet/cadet.h
src/cadet/cadet_protocol.h
src/cadet/cadet_test_lib.c [new file with mode: 0644]
src/cadet/cadet_test_lib.h [new file with mode: 0644]
src/cadet/cadet_test_lib_new.c [deleted file]
src/cadet/cadet_test_lib_new.h [deleted file]
src/cadet/gnunet-service-cadet-new.c [deleted file]
src/cadet/gnunet-service-cadet-new.h [deleted file]
src/cadet/gnunet-service-cadet-new_channel.c [deleted file]
src/cadet/gnunet-service-cadet-new_channel.h [deleted file]
src/cadet/gnunet-service-cadet-new_connection.c [deleted file]
src/cadet/gnunet-service-cadet-new_connection.h [deleted file]
src/cadet/gnunet-service-cadet-new_core.c [deleted file]
src/cadet/gnunet-service-cadet-new_core.h [deleted file]
src/cadet/gnunet-service-cadet-new_dht.c [deleted file]
src/cadet/gnunet-service-cadet-new_dht.h [deleted file]
src/cadet/gnunet-service-cadet-new_hello.c [deleted file]
src/cadet/gnunet-service-cadet-new_hello.h [deleted file]
src/cadet/gnunet-service-cadet-new_paths.c [deleted file]
src/cadet/gnunet-service-cadet-new_paths.h [deleted file]
src/cadet/gnunet-service-cadet-new_peer.c [deleted file]
src/cadet/gnunet-service-cadet-new_peer.h [deleted file]
src/cadet/gnunet-service-cadet-new_tunnels.c [deleted file]
src/cadet/gnunet-service-cadet-new_tunnels.h [deleted file]
src/cadet/gnunet-service-cadet.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_channel.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_channel.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_connection.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_connection.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_core.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_core.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_dht.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_dht.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_hello.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_hello.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_paths.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_paths.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_peer.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_peer.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_tunnels.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_tunnels.h [new file with mode: 0644]
src/cadet/test_cadet.c [new file with mode: 0644]
src/cadet/test_cadet_new.c [deleted file]

index d7208d601d72d03f17d76a0023e137b33064d764..1fe9123057e11abc911c78a424f19db871740c80 100644 (file)
@@ -22,7 +22,7 @@ plugindir = $(libdir)/gnunet
 AM_CLFAGS = -g
 
 libexec_PROGRAMS = \
- gnunet-service-cadet-new \
+ gnunet-service-cadet \
  $(EXP_LIBEXEC)
 
 bin_PROGRAMS = \
@@ -60,17 +60,17 @@ gnunet_cadet_LDADD = \
   libgnunetcadetnew.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
-gnunet_service_cadet_new_SOURCES = \
- gnunet-service-cadet-new.c gnunet-service-cadet-new.h \
- gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \
- gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \
- gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \
- gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \
- gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \
- gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \
- gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \
- gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h
-gnunet_service_cadet_new_LDADD = \
+gnunet_service_cadet_SOURCES = \
+ gnunet-service-cadet.c gnunet-service-cadet.h \
+ gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
+ gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
+ gnunet-service-cadet_core.c gnunet-service-cadet_core.h \
+ gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
+ gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
+ gnunet-service-cadet_tunnels.c gnunet-service-cadet_tunnels.h \
+ gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \
+ gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
+gnunet_service_cadet_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/ats/libgnunetats.la \
   $(top_builddir)/src/core/libgnunetcore.la \
@@ -87,7 +87,7 @@ endif
 
 if HAVE_TESTING
  noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
- noinst_PROGRAMS = gnunet-cadet-profiler
+# noinst_PROGRAMS = gnunet-cadet-profiler
 endif
 
 if HAVE_TESTING
@@ -112,23 +112,10 @@ check_PROGRAMS = \
   test_cadet_5_speed_backwards
 endif
 
-ld_cadet_test_lib = \
-  $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/testing/libgnunettesting.la \
-  libgnunetcadettest.la \
-  libgnunetcadet.la \
-  $(top_builddir)/src/testbed/libgnunettestbed.la \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la
 
-dep_cadet_test_lib = \
-  libgnunetcadet.la \
-  libgnunetcadettest.la \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-
-gnunet_cadet_profiler_SOURCES = \
-  gnunet-cadet-profiler.c
-gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
+#gnunet_cadet_profiler_SOURCES = \
+#  gnunet-cadet-profiler.c
+#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
 
 
 test_cadet_local_mq_SOURCES = \
@@ -140,7 +127,7 @@ test_cadet_local_mq_LDADD = \
 
 
 libgnunetcadettest_la_SOURCES = \
-  cadet_test_lib_new.c cadet_test_lib_new.h
+  cadet_test_lib.c cadet_test_lib.h
 libgnunetcadettest_la_LIBADD = \
  $(top_builddir)/src/util/libgnunetutil.la \
  $(top_builddir)/src/testbed/libgnunettestbed.la \
@@ -159,68 +146,67 @@ dep_cadet_test_lib = \
   $(top_builddir)/src/statistics/libgnunetstatistics.la
 
 test_cadet_2_forward_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_signal_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_signal_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_keepalive_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_keepalive_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_speed_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_speed_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_speed_ack_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_speed_ack_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_speed_backwards_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_speed_backwards_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_speed_reliable_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_speed_reliable_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_2_speed_reliable_backwards_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
 
-
 test_cadet_5_forward_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_signal_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_signal_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_keepalive_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_keepalive_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_speed_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_speed_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_speed_ack_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_speed_ack_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_speed_backwards_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_speed_backwards_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_speed_reliable_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_speed_reliable_LDADD = $(ld_cadet_test_lib)
 
 test_cadet_5_speed_reliable_backwards_SOURCES = \
-  test_cadet_new.c
+  test_cadet.c
 test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
 
 
index 86ba2e535d0a2b6e839c2ccd52a8a4b027822930..d50e168f0938b8f3bd7a8699cdd34ed3fc2e4a08 100644 (file)
@@ -3,7 +3,7 @@ FORCESTART = YES
 AUTOSTART = @AUTOSTART@
 @JAVAPORT@PORT = 2096
 HOSTNAME = localhost
-BINARY = gnunet-service-cadet-new
+BINARY = gnunet-service-cadet
 # PREFIX = valgrind --leak-check=yes
 ACCEPT_FROM = 127.0.0.1;
 ACCEPT_FROM6 = ::1;
index 451d1f354363f18627781e57b95a1879dac995b0..99f9f265310d43645caf768b1a488953e75b1d02 100644 (file)
@@ -59,7 +59,7 @@ extern "C"
 #include "gnunet_core_service.h"
 #include "gnunet_cadet_service.h"
 #include "gnunet_protocols.h"
-#include <gnunet_cadet_service.h>
+#include "gnunet_cadet_service.h"
 
 /******************************************************************************/
 /**************************       CONSTANTS      ******************************/
index d2426addbd67cad26531acdea192034093c3f244..560c186cd5a555fed27b2c4e61025704069dac91 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001 - 2011 GNUnet e.V.
+     Copyright (C) 2007 - 2017 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
 */
 
 /**
- * @author Bartlomiej Polot
  * @file cadet/cadet_protocol.h
+ * @brief P2P messages used by CADET
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
  */
 
 #ifndef CADET_PROTOCOL_H_
@@ -298,17 +300,10 @@ struct GNUNET_CADET_TunnelEncryptedMessage
    */
   struct GNUNET_MessageHeader header;
 
-#if NEW_CADET
   /**
    * Reserved, for alignment.
    */
   uint32_t reserved GNUNET_PACKED;
-#else
-  /**
-   * Maximum packet ID authorized.
-   */
-  struct CadetEncryptedMessageIdentifier cemi;
-#endif
 
   /**
    * ID of the connection.
@@ -322,89 +317,18 @@ struct GNUNET_CADET_TunnelEncryptedMessage
    */
   struct GNUNET_ShortHashCode hmac;
 
-  #if NEW_CADET
   /**
    * Axolotl-header that specifies which keys to use in which ratchet
    * to decrypt the body that follows.
    */
   struct GNUNET_CADET_AxHeader ax_header;
-#else
-  /**
-   * Number of messages sent with the current ratchet key.
-   */
-  uint32_t Ns GNUNET_PACKED;
-
-  /**
-   * Number of messages sent with the previous ratchet key.
-   */
-  uint32_t PNs GNUNET_PACKED;
 
-  /**
-   * Current ratchet key.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHRs;
-#endif
   /**
    * Encrypted content follows.
    */
 };
 
 
-#ifndef NEW_CADET
-
-/**
- * Message to query a peer about its Flow Control status regarding a tunnel.
- *
- * It is NOT yet clear if we need this.
- */
-struct GNUNET_CADET_ConnectionHopByHopPollMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Last packet sent.
-   */
-  struct CadetEncryptedMessageIdentifier cemi;
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-};
-
-
-/**
- * Message to acknowledge cadet encrypted traffic, used for
- * flow-control on a hop-by-hop basis on the connection-level. Note
- * that we do use the @e cemi from the tunnel layer as the connection
- * layer's header is included/shared with the tunnel layer messages,
- * and we only do flow control for the payload.
- */
-struct GNUNET_CADET_ConnectionEncryptedAckMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Maximum packet ID authorized.
-   */
-  struct CadetEncryptedMessageIdentifier cemi_max;
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-};
-
-#endif
-
-
 /******************************************************************************/
 /*******************************   CHANNEL  ***********************************/
 /******************************************************************************/
@@ -450,82 +374,18 @@ struct GNUNET_CADET_ChannelManageMessage
    */
   struct GNUNET_MessageHeader header;
 
-#ifdef NEW_CADET
   /**
    * For alignment.
    */
   uint32_t reserved GNUNET_PACKED;
-#endif
-
-  /**
-   * ID of the channel
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-};
-
-
-#ifndef NEW_CADET
-
-/**
- * Message for cadet data traffic.
- */
-struct GNUNET_CADET_ChannelAppDataMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
-   *       #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Unique ID of the payload message
-   */
-  /* NEW: struct ChannelMessageIdentifier */
-  uint32_t mid GNUNET_PACKED;
 
   /**
    * ID of the channel
    */
   struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Payload follows
-   */
 };
 
 
-/**
- * Message to acknowledge end-to-end data.
- */
-struct GNUNET_CADET_ChannelDataAckMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * ID of the channel
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Bitfield of already-received messages past @e mid.
-   * pid +  1 @ LSB
-   * pid + 64 @ MSB
-   */
-  uint64_t futures GNUNET_PACKED;
-
-  /**
-   * Last message ID received.
-   */
-  /* NEW: struct ChannelMessageIdentifier */
-  uint32_t mid GNUNET_PACKED;
-};
-
-#else
-
-
 /**
  * Number used to uniquely identify messages in a CADET Channel.
  */
@@ -595,8 +455,6 @@ struct GNUNET_CADET_ChannelDataAckMessage
 };
 
 
-#endif
-
 GNUNET_NETWORK_STRUCT_END
 
 #if 0                           /* keep Emacsens' auto-indent happy */
diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c
new file mode 100644 (file)
index 0000000..c3a1540
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2012, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/cadet_test_lib.c
+ * @author Bartlomiej Polot
+ * @brief library for writing CADET tests
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet_test_lib_new.h"
+#include "gnunet_cadet_service.h"
+
+
+/**
+ * Test context for a CADET Test.
+ */
+struct GNUNET_CADET_TEST_Context
+{
+  /**
+   * Array of running peers.
+   */
+  struct GNUNET_TESTBED_Peer **peers;
+
+  /**
+   * Array of handles to the CADET for each peer.
+   */
+  struct GNUNET_CADET_Handle **cadets;
+
+  /**
+   * Operation associated with the connection to the CADET.
+   */
+  struct GNUNET_TESTBED_Operation **ops;
+
+  /**
+   * Number of peers running, size of the arrays above.
+   */
+  unsigned int num_peers;
+
+  /**
+   * Main function of the test to run once all CADETs are available.
+   */
+  GNUNET_CADET_TEST_AppMain app_main;
+
+  /**
+   * Closure for 'app_main'.
+   */
+  void *app_main_cls;
+
+  /**
+   * Handler for incoming tunnels.
+   */
+  GNUNET_CADET_ConnectEventHandler connects;
+
+  /**
+   * Function called when the transmit window size changes.
+   */
+  GNUNET_CADET_WindowSizeEventHandler window_changes;
+
+  /**
+   * Cleaner for destroyed incoming tunnels.
+   */
+  GNUNET_CADET_DisconnectEventHandler disconnects;
+
+  /**
+   * Message handlers.
+   */
+  struct GNUNET_MQ_MessageHandler *handlers;
+
+  /**
+   * Application ports.
+   */
+  const struct GNUNET_HashCode **ports;
+
+  /**
+   * Number of ports in #ports.
+   */
+  unsigned int port_count;
+
+};
+
+
+/**
+ * Context for a cadet adapter callback.
+ */
+struct GNUNET_CADET_TEST_AdapterContext
+{
+  /**
+   * Peer number for the particular peer.
+   */
+  unsigned int peer;
+
+  /**
+   * Port handlers for open ports.
+   */
+  struct GNUNET_CADET_Port **ports;
+  /**
+   * General context.
+   */
+  struct GNUNET_CADET_TEST_Context *ctx;
+};
+
+
+/**
+ * Adapter function called to establish a connection to
+ * the CADET service.
+ *
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+cadet_connect_adapter (void *cls,
+                       const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
+  struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
+  struct GNUNET_CADET_Handle *h;
+  unsigned int i;
+
+  h = GNUNET_CADET_connecT (cfg);
+  if (NULL == ctx->ports)
+    return h;
+
+  actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
+  for (i = 0; i < ctx->port_count; i++)
+  {
+    actx->ports[i] = GNUNET_CADET_open_porT (h,
+                                             ctx->ports[i],
+                                             ctx->connects,
+                                             (void *) (long) actx->peer,
+                                             ctx->window_changes,
+                                             ctx->disconnects,
+                                             ctx->handlers);
+  }
+  return h;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * the CADET service.
+ *
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+cadet_disconnect_adapter (void *cls,
+                         void *op_result)
+{
+  struct GNUNET_CADET_Handle *cadet = op_result;
+  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
+
+  if (NULL != actx->ports)
+  {
+    for (int i = 0; i < actx->ctx->port_count; i++)
+    {
+      GNUNET_CADET_close_port (actx->ports[i]);
+      actx->ports[i] = NULL;
+    }
+    GNUNET_free (actx->ports);
+  }
+  GNUNET_free (actx);
+  GNUNET_CADET_disconnect (cadet);
+}
+
+
+/**
+ * Callback to be called when a service connect operation is completed.
+ *
+ * @param cls The callback closure from functions generating an operation.
+ * @param op The operation that has been finished.
+ * @param ca_result The service handle returned from
+ *                  GNUNET_TESTBED_ConnectAdapter() (cadet handle).
+ * @param emsg Error message in case the operation has failed.
+ *             NULL if operation has executed successfully.
+ */
+static void
+cadet_connect_cb (void *cls,
+                 struct GNUNET_TESTBED_Operation *op,
+                 void *ca_result,
+                 const char *emsg)
+{
+  struct GNUNET_CADET_TEST_Context *ctx = cls;
+  unsigned int i;
+
+  if (NULL != emsg)
+  {
+    fprintf (stderr, "Failed to connect to CADET service: %s\n",
+             emsg);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  for (i = 0; i < ctx->num_peers; i++)
+    if (op == ctx->ops[i])
+    {
+      ctx->cadets[i] = ca_result;
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
+    }
+  for (i = 0; i < ctx->num_peers; i++)
+    if (NULL == ctx->cadets[i])
+      return; /* still some CADET connections missing */
+  /* all CADET connections ready! */
+  ctx->app_main (ctx->app_main_cls,
+                 ctx,
+                 ctx->num_peers,
+                 ctx->peers,
+                 ctx->cadets);
+}
+
+
+void
+GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
+{
+  unsigned int i;
+
+  for (i = 0; i < ctx->num_peers; i++)
+  {
+    GNUNET_assert (NULL != ctx->ops[i]);
+    GNUNET_TESTBED_operation_done (ctx->ops[i]);
+    ctx->ops[i] = NULL;
+  }
+  GNUNET_free (ctx->ops);
+  GNUNET_free (ctx->cadets);
+  GNUNET_free (ctx);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Callback run when the testbed is ready (peers running and connected to
+ * each other)
+ *
+ * @param cls Closure (context).
+ * @param h the run handle
+ * @param num_peers Number of peers that are running.
+ * @param peers Handles to each one of the @c num_peers peers.
+ * @param links_succeeded the number of overlay link connection attempts that
+ *          succeeded
+ * @param links_failed the number of overlay link connection attempts that
+ *          failed
+ */
+static void
+cadet_test_run (void *cls,
+               struct GNUNET_TESTBED_RunHandle *h,
+               unsigned int num_peers,
+               struct GNUNET_TESTBED_Peer **peers,
+               unsigned int links_succeeded,
+               unsigned int links_failed)
+{
+  struct GNUNET_CADET_TEST_Context *ctx = cls;
+  unsigned int i;
+
+  if (0 != links_failed)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
+                links_failed);
+    exit (2);
+  }
+
+  if  (num_peers != ctx->num_peers)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
+                num_peers, ctx->num_peers);
+    exit (1);
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Testbed up, %u peers and %u links\n",
+              num_peers, links_succeeded);
+  ctx->peers = peers;
+  for (i = 0; i < num_peers; i++)
+  {
+    struct GNUNET_CADET_TEST_AdapterContext *newctx;
+    newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
+    newctx->peer = i;
+    newctx->ctx = ctx;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
+    ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
+                                                  peers[i],
+                                                  "cadet",
+                                                  &cadet_connect_cb,
+                                                  ctx,
+                                                  &cadet_connect_adapter,
+                                                  &cadet_disconnect_adapter,
+                                                  newctx);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
+  }
+}
+
+
+/**
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
+ *
+ * @param testname Name of the test (for logging).
+ * @param cfgfile Name of the configuration file.
+ * @param num_peers Number of peers to start.
+ * @param tmain Main function to run once the testbed is ready.
+ * @param tmain_cls Closure for @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
+ * @param handlers Message handlers.
+ * @param ports Ports the peers offer, NULL-terminated.
+ */
+void
+GNUNET_CADET_TEST_ruN (const char *testname,
+                       const char *cfgfile,
+                       unsigned int num_peers,
+                       GNUNET_CADET_TEST_AppMain tmain,
+                       void *tmain_cls,
+                       GNUNET_CADET_ConnectEventHandler connects,
+                       GNUNET_CADET_WindowSizeEventHandler window_changes,
+                       GNUNET_CADET_DisconnectEventHandler disconnects,
+                       struct GNUNET_MQ_MessageHandler *handlers,
+                       const struct GNUNET_HashCode **ports)
+{
+  struct GNUNET_CADET_TEST_Context *ctx;
+
+  ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
+  ctx->num_peers = num_peers;
+  ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
+  ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
+  ctx->app_main = tmain;
+  ctx->app_main_cls = tmain_cls;
+  ctx->connects = connects;
+  ctx->window_changes = window_changes;
+  ctx->disconnects = disconnects;
+  ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
+  ctx->ports = ports;
+  ctx->port_count = 0;
+  while (NULL != ctx->ports[ctx->port_count])
+    ctx->port_count++;
+
+  GNUNET_TESTBED_test_run (testname,
+                           cfgfile,
+                           num_peers,
+                           0LL, NULL, NULL,
+                           &cadet_test_run, ctx);
+}
+
+/* end of cadet_test_lib.c */
diff --git a/src/cadet/cadet_test_lib.h b/src/cadet/cadet_test_lib.h
new file mode 100644 (file)
index 0000000..4b3a6b1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2012,2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/cadet_test_lib.h
+ * @author Bartlomiej Polot
+ * @brief library for writing CADET tests
+ */
+#ifndef CADET_TEST_LIB_H
+#define CADET_TEST_LIB_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "gnunet_testbed_service.h"
+#include "gnunet_cadet_service.h"
+
+/**
+ * Test context for a CADET Test.
+ */
+struct GNUNET_CADET_TEST_Context;
+
+
+/**
+ * Main function of a CADET test.
+ *
+ * @param cls Closure.
+ * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
+ * @param num_peers Number of peers that are running.
+ * @param peers Array of peers.
+ * @param cadets Handle to each of the CADETs of the peers.
+ */
+typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
+                                          struct GNUNET_CADET_TEST_Context *ctx,
+                                          unsigned int num_peers,
+                                          struct GNUNET_TESTBED_Peer **peers,
+                                          struct GNUNET_CADET_Handle **cadets);
+
+
+/**
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
+ *
+ * @param testname Name of the test (for logging).
+ * @param cfgfile Name of the configuration file.
+ * @param num_peers Number of peers to start.
+ * @param tmain Main function to run once the testbed is ready.
+ * @param tmain_cls Closure for @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
+ * @param handlers Message handlers.
+ * @param ports Ports the peers offer, NULL-terminated.
+ */
+void
+GNUNET_CADET_TEST_ruN (const char *testname,
+                       const char *cfgfile,
+                       unsigned int num_peers,
+                       GNUNET_CADET_TEST_AppMain tmain,
+                       void *tmain_cls,
+                       GNUNET_CADET_ConnectEventHandler connects,
+                       GNUNET_CADET_WindowSizeEventHandler window_changes,
+                       GNUNET_CADET_DisconnectEventHandler disconnects,
+                       struct GNUNET_MQ_MessageHandler *handlers,
+                       const struct GNUNET_HashCode **ports);
+
+/**
+ * Clean up the testbed.
+ *
+ * @param ctx handle for the testbed
+ */
+void
+GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+
+/* ifndef CADET_TEST_LIB_H */
+#endif
diff --git a/src/cadet/cadet_test_lib_new.c b/src/cadet/cadet_test_lib_new.c
deleted file mode 100644 (file)
index c3a1540..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2012, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.c
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet_test_lib_new.h"
-#include "gnunet_cadet_service.h"
-
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context
-{
-  /**
-   * Array of running peers.
-   */
-  struct GNUNET_TESTBED_Peer **peers;
-
-  /**
-   * Array of handles to the CADET for each peer.
-   */
-  struct GNUNET_CADET_Handle **cadets;
-
-  /**
-   * Operation associated with the connection to the CADET.
-   */
-  struct GNUNET_TESTBED_Operation **ops;
-
-  /**
-   * Number of peers running, size of the arrays above.
-   */
-  unsigned int num_peers;
-
-  /**
-   * Main function of the test to run once all CADETs are available.
-   */
-  GNUNET_CADET_TEST_AppMain app_main;
-
-  /**
-   * Closure for 'app_main'.
-   */
-  void *app_main_cls;
-
-  /**
-   * Handler for incoming tunnels.
-   */
-  GNUNET_CADET_ConnectEventHandler connects;
-
-  /**
-   * Function called when the transmit window size changes.
-   */
-  GNUNET_CADET_WindowSizeEventHandler window_changes;
-
-  /**
-   * Cleaner for destroyed incoming tunnels.
-   */
-  GNUNET_CADET_DisconnectEventHandler disconnects;
-
-  /**
-   * Message handlers.
-   */
-  struct GNUNET_MQ_MessageHandler *handlers;
-
-  /**
-   * Application ports.
-   */
-  const struct GNUNET_HashCode **ports;
-
-  /**
-   * Number of ports in #ports.
-   */
-  unsigned int port_count;
-
-};
-
-
-/**
- * Context for a cadet adapter callback.
- */
-struct GNUNET_CADET_TEST_AdapterContext
-{
-  /**
-   * Peer number for the particular peer.
-   */
-  unsigned int peer;
-
-  /**
-   * Port handlers for open ports.
-   */
-  struct GNUNET_CADET_Port **ports;
-  /**
-   * General context.
-   */
-  struct GNUNET_CADET_TEST_Context *ctx;
-};
-
-
-/**
- * Adapter function called to establish a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param cfg configuration of the peer to connect to; will be available until
- *          GNUNET_TESTBED_operation_done() is called on the operation returned
- *          from GNUNET_TESTBED_service_connect()
- * @return service handle to return in 'op_result', NULL on error
- */
-static void *
-cadet_connect_adapter (void *cls,
-                       const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
-  struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
-  struct GNUNET_CADET_Handle *h;
-  unsigned int i;
-
-  h = GNUNET_CADET_connecT (cfg);
-  if (NULL == ctx->ports)
-    return h;
-
-  actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
-  for (i = 0; i < ctx->port_count; i++)
-  {
-    actx->ports[i] = GNUNET_CADET_open_porT (h,
-                                             ctx->ports[i],
-                                             ctx->connects,
-                                             (void *) (long) actx->peer,
-                                             ctx->window_changes,
-                                             ctx->disconnects,
-                                             ctx->handlers);
-  }
-  return h;
-}
-
-
-/**
- * Adapter function called to destroy a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param op_result service handle returned from the connect adapter
- */
-static void
-cadet_disconnect_adapter (void *cls,
-                         void *op_result)
-{
-  struct GNUNET_CADET_Handle *cadet = op_result;
-  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
-
-  if (NULL != actx->ports)
-  {
-    for (int i = 0; i < actx->ctx->port_count; i++)
-    {
-      GNUNET_CADET_close_port (actx->ports[i]);
-      actx->ports[i] = NULL;
-    }
-    GNUNET_free (actx->ports);
-  }
-  GNUNET_free (actx);
-  GNUNET_CADET_disconnect (cadet);
-}
-
-
-/**
- * Callback to be called when a service connect operation is completed.
- *
- * @param cls The callback closure from functions generating an operation.
- * @param op The operation that has been finished.
- * @param ca_result The service handle returned from
- *                  GNUNET_TESTBED_ConnectAdapter() (cadet handle).
- * @param emsg Error message in case the operation has failed.
- *             NULL if operation has executed successfully.
- */
-static void
-cadet_connect_cb (void *cls,
-                 struct GNUNET_TESTBED_Operation *op,
-                 void *ca_result,
-                 const char *emsg)
-{
-  struct GNUNET_CADET_TEST_Context *ctx = cls;
-  unsigned int i;
-
-  if (NULL != emsg)
-  {
-    fprintf (stderr, "Failed to connect to CADET service: %s\n",
-             emsg);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  for (i = 0; i < ctx->num_peers; i++)
-    if (op == ctx->ops[i])
-    {
-      ctx->cadets[i] = ca_result;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
-    }
-  for (i = 0; i < ctx->num_peers; i++)
-    if (NULL == ctx->cadets[i])
-      return; /* still some CADET connections missing */
-  /* all CADET connections ready! */
-  ctx->app_main (ctx->app_main_cls,
-                 ctx,
-                 ctx->num_peers,
-                 ctx->peers,
-                 ctx->cadets);
-}
-
-
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
-{
-  unsigned int i;
-
-  for (i = 0; i < ctx->num_peers; i++)
-  {
-    GNUNET_assert (NULL != ctx->ops[i]);
-    GNUNET_TESTBED_operation_done (ctx->ops[i]);
-    ctx->ops[i] = NULL;
-  }
-  GNUNET_free (ctx->ops);
-  GNUNET_free (ctx->cadets);
-  GNUNET_free (ctx);
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Callback run when the testbed is ready (peers running and connected to
- * each other)
- *
- * @param cls Closure (context).
- * @param h the run handle
- * @param num_peers Number of peers that are running.
- * @param peers Handles to each one of the @c num_peers peers.
- * @param links_succeeded the number of overlay link connection attempts that
- *          succeeded
- * @param links_failed the number of overlay link connection attempts that
- *          failed
- */
-static void
-cadet_test_run (void *cls,
-               struct GNUNET_TESTBED_RunHandle *h,
-               unsigned int num_peers,
-               struct GNUNET_TESTBED_Peer **peers,
-               unsigned int links_succeeded,
-               unsigned int links_failed)
-{
-  struct GNUNET_CADET_TEST_Context *ctx = cls;
-  unsigned int i;
-
-  if (0 != links_failed)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
-                links_failed);
-    exit (2);
-  }
-
-  if  (num_peers != ctx->num_peers)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
-                num_peers, ctx->num_peers);
-    exit (1);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Testbed up, %u peers and %u links\n",
-              num_peers, links_succeeded);
-  ctx->peers = peers;
-  for (i = 0; i < num_peers; i++)
-  {
-    struct GNUNET_CADET_TEST_AdapterContext *newctx;
-    newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
-    newctx->peer = i;
-    newctx->ctx = ctx;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
-    ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
-                                                  peers[i],
-                                                  "cadet",
-                                                  &cadet_connect_cb,
-                                                  ctx,
-                                                  &cadet_connect_adapter,
-                                                  &cadet_disconnect_adapter,
-                                                  newctx);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
-  }
-}
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile Name of the configuration file.
- * @param num_peers Number of peers to start.
- * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
-                       const char *cfgfile,
-                       unsigned int num_peers,
-                       GNUNET_CADET_TEST_AppMain tmain,
-                       void *tmain_cls,
-                       GNUNET_CADET_ConnectEventHandler connects,
-                       GNUNET_CADET_WindowSizeEventHandler window_changes,
-                       GNUNET_CADET_DisconnectEventHandler disconnects,
-                       struct GNUNET_MQ_MessageHandler *handlers,
-                       const struct GNUNET_HashCode **ports)
-{
-  struct GNUNET_CADET_TEST_Context *ctx;
-
-  ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
-  ctx->num_peers = num_peers;
-  ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
-  ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
-  ctx->app_main = tmain;
-  ctx->app_main_cls = tmain_cls;
-  ctx->connects = connects;
-  ctx->window_changes = window_changes;
-  ctx->disconnects = disconnects;
-  ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
-  ctx->ports = ports;
-  ctx->port_count = 0;
-  while (NULL != ctx->ports[ctx->port_count])
-    ctx->port_count++;
-
-  GNUNET_TESTBED_test_run (testname,
-                           cfgfile,
-                           num_peers,
-                           0LL, NULL, NULL,
-                           &cadet_test_run, ctx);
-}
-
-/* end of cadet_test_lib.c */
diff --git a/src/cadet/cadet_test_lib_new.h b/src/cadet/cadet_test_lib_new.h
deleted file mode 100644 (file)
index 4b3a6b1..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2012,2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.h
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#ifndef CADET_TEST_LIB_H
-#define CADET_TEST_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_testbed_service.h"
-#include "gnunet_cadet_service.h"
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context;
-
-
-/**
- * Main function of a CADET test.
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadets Handle to each of the CADETs of the peers.
- */
-typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
-                                          struct GNUNET_CADET_TEST_Context *ctx,
-                                          unsigned int num_peers,
-                                          struct GNUNET_TESTBED_Peer **peers,
-                                          struct GNUNET_CADET_Handle **cadets);
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile Name of the configuration file.
- * @param num_peers Number of peers to start.
- * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
-                       const char *cfgfile,
-                       unsigned int num_peers,
-                       GNUNET_CADET_TEST_AppMain tmain,
-                       void *tmain_cls,
-                       GNUNET_CADET_ConnectEventHandler connects,
-                       GNUNET_CADET_WindowSizeEventHandler window_changes,
-                       GNUNET_CADET_DisconnectEventHandler disconnects,
-                       struct GNUNET_MQ_MessageHandler *handlers,
-                       const struct GNUNET_HashCode **ports);
-
-/**
- * Clean up the testbed.
- *
- * @param ctx handle for the testbed
- */
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-
-/* ifndef CADET_TEST_LIB_H */
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
deleted file mode 100644 (file)
index 93f53de..0000000
+++ /dev/null
@@ -1,1496 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2013, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new.c
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * Dictionary:
- * - peer: other cadet instance. If there is direct connection it's a neighbor.
- * - path: series of directly connected peer from one peer to another.
- * - connection: path which is being used in a tunnel.
- * - tunnel: encrypted connection to a peer, neighbor or not.
- * - channel: logical link between two clients, on the same or different peers.
- *            have properties like reliability.
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.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_core.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
-
-
-/**
- * Struct containing information about a client of the service
- */
-struct CadetClient
-{
-  /**
-   * Linked list next
-   */
-  struct CadetClient *next;
-
-  /**
-   * Linked list prev
-   */
-  struct CadetClient *prev;
-
-  /**
-   * Tunnels that belong to this client, indexed by local id,
-   * value is a `struct CadetChannel`.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
-  /**
-   * Handle to communicate with the client
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Client handle.
-   */
-  struct GNUNET_SERVICE_Client *client;
-
-  /**
-   * Ports that this client has declared interest in.
-   * Indexed by port, contains *Client.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *ports;
-
-  /**
-   * Channel ID to use for the next incoming channel for this client.
-   * Wraps around (in theory).
-   */
-  struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
-  /**
-   * ID of the client, mainly for debug messages. Purely internal to this file.
-   */
-  unsigned int id;
-};
-
-/******************************************************************************/
-/***********************      GLOBAL VARIABLES     ****************************/
-/******************************************************************************/
-
-/****************************** Global variables ******************************/
-
-/**
- * Handle to our configuration.
- */
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Handle to the statistics service.
- */
-struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to communicate with ATS.
- */
-struct GNUNET_ATS_ConnectivityHandle *ats_ch;
-
-/**
- * Local peer own ID.
- */
-struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Own private key.
- */
-struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * Signal that shutdown is happening: prevent recovery measures.
- */
-int shutting_down;
-
-/**
- * DLL with all the clients, head.
- */
-static struct CadetClient *clients_head;
-
-/**
- * DLL with all the clients, tail.
- */
-static struct CadetClient *clients_tail;
-
-/**
- * Next ID to assign to a client.
- */
-static unsigned int next_client_id;
-
-/**
- * All ports clients of this peer have opened.
- */
-struct GNUNET_CONTAINER_MultiHashMap *open_ports;
-
-/**
- * Map from ports to channels where the ports were closed at the
- * time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
- */
-struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
-
-/**
- * Map from PIDs to `struct CadetPeer` entries.
- */
-struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
- * hash codes to `struct CadetConnection` objects.
- */
-struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * How many messages are needed to trigger an AXOLOTL ratchet advance.
- */
-unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance due to time.
- */
-struct GNUNET_TIME_Relative ratchet_time;
-
-/**
- * How frequently do we send KEEPALIVE messages on idle connections?
- */
-struct GNUNET_TIME_Relative keepalive_period;
-
-/**
- * Set to non-zero values to create random drops to test retransmissions.
- */
-unsigned long long drop_percent;
-
-
-/**
- * Send a message to a client.
- *
- * @param c client to get the message
- * @param env envelope with the message
- */
-void
-GSC_send_to_client (struct CadetClient *c,
-                    struct GNUNET_MQ_Envelope *env)
-{
-  GNUNET_MQ_send (c->mq,
-                  env);
-}
-
-
-/**
- * Return identifier for a client as a string.
- *
- * @param c client to identify
- * @return string for debugging
- */
-const char *
-GSC_2s (struct CadetClient *c)
-{
-  static char buf[32];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Client(%u)",
-                   c->id);
-  return buf;
-}
-
-
-/**
- * Lookup channel of client @a c by @a ccn.
- *
- * @param c client to look in
- * @param ccn channel ID to look up
- * @return NULL if no such channel exists
- */
-static struct CadetChannel *
-lookup_channel (struct CadetClient *c,
-                struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  return GNUNET_CONTAINER_multihashmap32_get (c->channels,
-                                              ntohl (ccn.channel_of_client));
-}
-
-
-/**
- * Obtain the next LID to use for incoming connections to
- * the given client.
- *
- * @param c client handle
- */
-static struct GNUNET_CADET_ClientChannelNumber
-client_get_next_ccn (struct CadetClient *c)
-{
-  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
-
-  /* increment until we have a free one... */
-  while (NULL !=
-         lookup_channel (c,
-                         ccn))
-  {
-    ccn.channel_of_client
-      = htonl (1 + (ntohl (ccn.channel_of_client)));
-    if (ntohl (ccn.channel_of_client) >=
-        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-      ccn.channel_of_client = htonl (0);
-  }
-  c->next_ccn.channel_of_client
-    = htonl (1 + (ntohl (ccn.channel_of_client)));
-  return ccn;
-}
-
-
-/**
- * Bind incoming channel to this client, and notify client about
- * incoming connection.  Caller is responsible for notifying the other
- * peer about our acceptance of the channel.
- *
- * @param c client to bind to
- * @param ch channel to be bound
- * @param dest peer that establishes the connection
- * @param port port number
- * @param options options
- * @return local channel number assigned to the new client
- */
-struct GNUNET_CADET_ClientChannelNumber
-GSC_bind (struct CadetClient *c,
-          struct CadetChannel *ch,
-          struct CadetPeer *dest,
-          const struct GNUNET_HashCode *port,
-          uint32_t options)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalChannelCreateMessage *cm;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ccn = client_get_next_ccn (c);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
-                                                      ntohl (ccn.channel_of_client),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
-       GCCH_2s (ch),
-       GCP_2s (dest),
-       GNUNET_h2s (port),
-       (uint32_t) ntohl (options),
-       (uint32_t) ntohl (ccn.channel_of_client));
-  /* notify local client about incoming connection! */
-  env = GNUNET_MQ_msg (cm,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
-  cm->ccn = ccn;
-  cm->port = *port;
-  cm->opt = htonl (options);
-  cm->peer = *GCP_get_id (dest);
-  GSC_send_to_client (c,
-                      env);
-  return ccn;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_tunnels_now (void *cls,
-                     const struct GNUNET_PeerIdentity *pid,
-                     void *value)
-{
-  struct CadetPeer *cp = value;
-  struct CadetTunnel *t = GCP_get_tunnel (cp,
-                                          GNUNET_NO);
-
-  if (NULL != t)
-    GCT_destroy_tunnel_now (t);
-  return GNUNET_OK;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_paths_now (void *cls,
-                   const struct GNUNET_PeerIdentity *pid,
-                   void *value)
-{
-  struct CadetPeer *cp = value;
-
-  GCP_drop_owned_paths (cp);
-  return GNUNET_OK;
-}
-
-
-/**
- * Shutdown everything once the clients have disconnected.
- */
-static void
-shutdown_rest ()
-{
-  if (NULL != stats)
-  {
-    GNUNET_STATISTICS_destroy (stats,
-                               GNUNET_NO);
-    stats = NULL;
-  }
-  if (NULL != open_ports)
-  {
-    GNUNET_CONTAINER_multihashmap_destroy (open_ports);
-    open_ports = NULL;
-  }
-  if (NULL != loose_channels)
-  {
-    GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
-    loose_channels = NULL;
-  }
-  /* Destroy tunnels.  Note that all channels must be destroyed first! */
-  GCP_iterate_all (&destroy_tunnels_now,
-                   NULL);
-  /* All tunnels, channels, connections and CORE must be down before this point. */
-  GCP_iterate_all (&destroy_paths_now,
-                   NULL);
-  /* All paths, tunnels, channels, connections and CORE must be down before this point. */
-  GCP_destroy_all_peers ();
-  if (NULL != peers)
-  {
-    GNUNET_CONTAINER_multipeermap_destroy (peers);
-    peers = NULL;
-  }
-  if (NULL != connections)
-  {
-    GNUNET_CONTAINER_multishortmap_destroy (connections);
-    connections = NULL;
-  }
-  if (NULL != ats_ch)
-  {
-    GNUNET_ATS_connectivity_done (ats_ch);
-    ats_ch = NULL;
-  }
-  GCD_shutdown ();
-  GCH_shutdown ();
-  GNUNET_free_non_null (my_private_key);
-  my_private_key = NULL;
-}
-
-
-/**
- * Task run during shutdown.
- *
- * @param cls unused
- */
-static void
-shutdown_task (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Shutting down\n");
-  shutting_down = GNUNET_YES;
-  GCO_shutdown ();
-  if (NULL == clients_head)
-    shutdown_rest ();
-}
-
-
-/**
- * We had a remote connection @a value to port @a port before
- * client @a cls opened port @a port.  Bind them now.
- *
- * @param cls the `struct CadetClient`
- * @param port the port
- * @param value the `struct CadetChannel`
- * @return #GNUNET_YES (iterate over all such channels)
- */
-static int
-bind_loose_channel (void *cls,
-                    const struct GNUNET_HashCode *port,
-                    void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch = value;
-
-  GCCH_bind (ch,
-             c);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
-                                                       port,
-                                                       value));
-  return GNUNET_YES;
-}
-
-
-/**
- * Handle port open request.  Creates a mapping from the
- * port to the respective client and checks whether we have
- * loose channels trying to bind to the port.  If so, those
- * are bound.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_open (void *cls,
-                  const struct GNUNET_CADET_PortMessage *pmsg)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Open port %s requested by %s\n",
-       GNUNET_h2s (&pmsg->port),
-       GSC_2s (c));
-  if (NULL == c->ports)
-    c->ports = GNUNET_CONTAINER_multihashmap_create (4,
-                                                      GNUNET_NO);
-  if (GNUNET_OK !=
-      GNUNET_CONTAINER_multihashmap_put (c->ports,
-                                         &pmsg->port,
-                                         c,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
-                                            &pmsg->port,
-                                            c,
-                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
-                                              &pmsg->port,
-                                              &bind_loose_channel,
-                                              c);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for port close requests.  Marks this port as closed
- * (unless of course we have another client with the same port
- * open).  Note that existing channels accepted on the port are
- * not affected.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_close (void *cls,
-                   const struct GNUNET_CADET_PortMessage *pmsg)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing port %s as requested by %s\n",
-       GNUNET_h2s (&pmsg->port),
-       GSC_2s (c));
-  if (GNUNET_YES !=
-      GNUNET_CONTAINER_multihashmap_remove (c->ports,
-                                            &pmsg->port,
-                                            c))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
-                                                       &pmsg->port,
-                                                       c));
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests for us creating a new channel to another peer and port.
- *
- * @param cls Identification of the client.
- * @param tcm The actual message.
- */
-static void
-handle_channel_create (void *cls,
-                       const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-  {
-    /* Channel ID not in allowed range. */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  ch = lookup_channel (c,
-                       tcm->ccn);
-  if (NULL != ch)
-  {
-    /* Channel ID already in use. Not allowed. */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "New channel to %s at port %s requested by %s\n",
-       GNUNET_i2s (&tcm->peer),
-       GNUNET_h2s (&tcm->port),
-       GSC_2s (c));
-
-  /* Create channel */
-  ch = GCCH_channel_local_new (c,
-                               tcm->ccn,
-                               GCP_get (&tcm->peer,
-                                        GNUNET_YES),
-                               &tcm->port,
-                               ntohl (tcm->opt));
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
-                                                      ntohl (tcm->ccn.channel_of_client),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests of destroying an existing channel.
- *
- * @param cls client identification of the client
- * @param msg the actual message
- */
-static void
-handle_channel_destroy (void *cls,
-                        const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Client attempted to destroy unknown channel.
-       Can happen if the other side went down at the same time.*/
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s tried to destroy unknown channel %X\n",
-         GSC_2s(c),
-         (uint32_t) ntohl (msg->ccn.channel_of_client));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s is destroying %s\n",
-       GSC_2s(c),
-       GCCH_2s (ch));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         ntohl (msg->ccn.channel_of_client),
-                                                         ch));
-  GCCH_channel_local_destroy (ch,
-                              c,
-                              msg->ccn);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Check for client traffic data message is well-formed.
- *
- * @param cls identification of the client
- * @param msg the actual message
- * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
- */
-static int
-check_local_data (void *cls,
-                  const struct GNUNET_CADET_LocalData *msg)
-{
-  size_t payload_size;
-  size_t payload_claimed_size;
-  const char *buf;
-  struct GNUNET_MessageHeader pa;
-
-  /* FIXME: what is the format we shall allow for @a msg?
-     ONE payload item or multiple? Seems current cadet_api
-     at least in theory allows more than one. Next-gen
-     cadet_api will likely no more, so we could then
-     simplify this mess again. */
-  /* Sanity check for message size */
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  buf = (const char *) &msg[1];
-  while (payload_size >= sizeof (struct GNUNET_MessageHeader))
-  {
-    /* need to memcpy() for alignment */
-    GNUNET_memcpy (&pa,
-                   buf,
-                   sizeof (pa));
-    payload_claimed_size = ntohs (pa.size);
-    if ( (payload_size < payload_claimed_size) ||
-         (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
-         (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
-    {
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Local data of %u total size had sub-message %u at %u with %u bytes\n",
-           ntohs (msg->header.size),
-           ntohs (pa.type),
-           (unsigned int) (buf - (const char *) &msg[1]),
-           (unsigned int) payload_claimed_size);
-      return GNUNET_SYSERR;
-    }
-    payload_size -= payload_claimed_size;
-    buf += payload_claimed_size;
-  }
-  if (0 != payload_size)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Handler for client payload traffic to be send on a channel to
- * another peer.
- *
- * @param cls identification of the client
- * @param msg the actual message
- */
-static void
-handle_local_data (void *cls,
-                   const struct GNUNET_CADET_LocalData *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-  size_t payload_size;
-  const char *buf;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Channel does not exist (anymore) */
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
-         (unsigned int) ntohl (msg->ccn.channel_of_client));
-    GNUNET_SERVICE_client_continue (c->client);
-    return;
-  }
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  GNUNET_STATISTICS_update (stats,
-                            "# payload received from clients",
-                            payload_size,
-                            GNUNET_NO);
-  buf = (const char *) &msg[1];
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received %u bytes payload from %s for %s\n",
-       (unsigned int) payload_size,
-       GSC_2s (c),
-       GCCH_2s (ch));
-  if (GNUNET_OK !=
-      GCCH_handle_local_data (ch,
-                              msg->ccn,
-                              buf,
-                              payload_size))
-  {
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for client's ACKs for payload traffic.
- *
- * @param cls identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_local_ack (void *cls,
-                  const struct GNUNET_CADET_LocalAck *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Channel does not exist (anymore) */
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
-         (unsigned int) ntohl (msg->ccn.channel_of_client));
-    GNUNET_SERVICE_client_continue (c->client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got a local ACK from %s for %s\n",
-       GSC_2s(c),
-       GCCH_2s (ch));
-  GCCH_handle_local_ack (ch,
-                         msg->ccn);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all peers to send a monitoring client info about each peer.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_peers_iterator (void *cls,
-                        const struct GNUNET_PeerIdentity *peer,
-                        void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p = value;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoPeer *msg;
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  msg->destination = *peer;
-  msg->paths = htons (GCP_count_paths (p));
-  msg->tunnel = htons (NULL != GCP_get_tunnel (p,
-                                               GNUNET_NO));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO PEERS request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_peers (void *cls,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *reply;
-
-  GCP_iterate_all (&get_all_peers_iterator,
-                   c);
-  env = GNUNET_MQ_msg (reply,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all paths of a peer to build an InfoPeer message.
- * Message contains blocks of peers, first not included.
- *
- * @param cls message queue for transmission
- * @param path Path itself
- * @param off offset of the peer on @a path
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-static int
-path_info_iterator (void *cls,
-                    struct CadetPeerPath *path,
-                    unsigned int off)
-{
-  struct GNUNET_MQ_Handle *mq = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *resp;
-  struct GNUNET_PeerIdentity *id;
-  uint16_t path_size;
-  unsigned int i;
-  unsigned int path_length;
-
-  path_length = GCPP_get_length (path);
-  path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
-  if (sizeof (*resp) + path_size > UINT16_MAX)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Path of %u entries is too long for info message\n",
-         path_length);
-    return GNUNET_YES;
-  }
-  env = GNUNET_MQ_msg_extra (resp,
-                             path_size,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
-  id = (struct GNUNET_PeerIdentity *) &resp[1];
-
-  /* Don't copy first peer.  First peer is always the local one.  Last
-   * peer is always the destination (leave as 0, EOL).
-   */
-  for (i = 0; i < off; i++)
-    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
-                                                  i + 1));
-  GNUNET_MQ_send (mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's SHOW_PEER request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_show_peer (void *cls,
-                  const struct GNUNET_CADET_LocalInfo *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *resp;
-
-  p = GCP_get (&msg->peer,
-               GNUNET_NO);
-  if (NULL != p)
-    GCP_iterate_paths (p,
-                       &path_info_iterator,
-                       c->mq);
-  /* Send message with 0/0 to indicate the end */
-  env = GNUNET_MQ_msg (resp,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all tunnels to send a monitoring client info about each tunnel.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value a `struct CadetPeer`
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_tunnels_iterator (void *cls,
-                          const struct GNUNET_PeerIdentity *peer,
-                          void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p = value;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoTunnel *msg;
-  struct CadetTunnel *t;
-
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL == t)
-    return GNUNET_YES;
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  msg->destination = *peer;
-  msg->channels = htonl (GCT_count_channels (t));
-  msg->connections = htonl (GCT_count_any_connections (t));
-  msg->cstate = htons (0);
-  msg->estate = htons ((uint16_t) GCT_get_estate (t));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
- *
- * @param cls client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_tunnels (void *cls,
-                     const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *reply;
-
-  GCP_iterate_all (&get_all_tunnels_iterator,
-                   c);
-  env = GNUNET_MQ_msg (reply,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Update the message with information about the connection.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ct a connection about which we should store information in @a cls
- */
-static void
-iter_connection (void *cls,
-                 struct CadetTConnection *ct)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct CadetConnection *cc = ct->cc;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
-
-  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  h[msg->connections++] = *(GCC_get_id (cc));
-}
-
-
-/**
- * Update the message with information about the channel.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ch a channel about which we should store information in @a cls
- */
-static void
-iter_channel (void *cls,
-              struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  struct GNUNET_CADET_ChannelTunnelNumber *chn
-    = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
-
-  chn[msg->channels++] = GCCH_get_id (ch);
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_info_tunnel (void *cls,
-                    const struct GNUNET_CADET_LocalInfo *msg)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoTunnel *resp;
-  struct CadetTunnel *t;
-  struct CadetPeer *p;
-  unsigned int ch_n;
-  unsigned int c_n;
-
-  p = GCP_get (&msg->peer,
-               GNUNET_NO);
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL == t)
-  {
-    /* We don't know the tunnel */
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_LocalInfoTunnel *warn;
-
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         "Tunnel to %s unknown\n",
-         GNUNET_i2s_full (&msg->peer));
-    env = GNUNET_MQ_msg (warn,
-                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-    warn->destination = msg->peer;
-    GNUNET_MQ_send (c->mq,
-                    env);
-    GNUNET_SERVICE_client_continue (c->client);
-    return;
-  }
-
-  /* Initialize context */
-  ch_n = GCT_count_channels (t);
-  c_n = GCT_count_any_connections (t);
-  env = GNUNET_MQ_msg_extra (resp,
-                             c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
-                             ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-  resp->destination = msg->peer;
-  /* Do not reorder! #iter_channel needs counters in HBO! */
-  GCT_iterate_connections (t,
-                           &iter_connection,
-                           resp);
-  GCT_iterate_channels (t,
-                        &iter_channel,
-                        resp);
-  resp->connections = htonl (resp->connections);
-  resp->channels = htonl (resp->channels);
-  resp->cstate = htons (0);
-  resp->estate = htons (GCT_get_estate (t));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all peers to dump info for each peer.
- *
- * @param cls Closure (unused).
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-show_peer_iterator (void *cls,
-                    const struct GNUNET_PeerIdentity *peer,
-                    void *value)
-{
-  struct CadetPeer *p = value;
-  struct CadetTunnel *t;
-
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL != t)
-    GCT_debug (t,
-               GNUNET_ERROR_TYPE_ERROR);
-  LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO_DUMP request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_dump (void *cls,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Received dump info request from client %u\n",
-       c->id);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "*************************** DUMP START ***************************\n");
-  for (struct CadetClient *ci = clients_head;
-       NULL != ci;
-       ci = ci->next)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
-         ci->id,
-         ci,
-         ci->client,
-         (NULL != c->ports)
-         ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
-         : 0,
-         GNUNET_CONTAINER_multihashmap32_size (ci->channels));
-  }
-  LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
-  GCP_iterate_all (&show_peer_iterator,
-                   NULL);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "**************************** DUMP END ****************************\n");
-
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param client the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
-static void *
-client_connect_cb (void *cls,
-                  struct GNUNET_SERVICE_Client *client,
-                  struct GNUNET_MQ_Handle *mq)
-{
-  struct CadetClient *c;
-
-  c = GNUNET_new (struct CadetClient);
-  c->client = client;
-  c->mq = mq;
-  c->id = next_client_id++; /* overflow not important: just for debug */
-  c->channels
-    = GNUNET_CONTAINER_multihashmap32_create (32);
-  GNUNET_CONTAINER_DLL_insert (clients_head,
-                               clients_tail,
-                               c);
-  GNUNET_STATISTICS_update (stats,
-                            "# clients",
-                            +1,
-                            GNUNET_NO);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s connected\n",
-       GSC_2s (c));
-  return c;
-}
-
-
-/**
- * A channel was destroyed by the other peer. Tell our client.
- *
- * @param c client that lost a channel
- * @param ccn channel identification number for the client
- * @param ch the channel object
- */
-void
-GSC_handle_remote_channel_destroy (struct CadetClient *c,
-                                   struct GNUNET_CADET_ClientChannelNumber ccn,
-                                   struct CadetChannel *ch)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
-
-  env = GNUNET_MQ_msg (tdm,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-  tdm->ccn = ccn;
-  GSC_send_to_client (c,
-                      env);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         ntohl (ccn.channel_of_client),
-                                                         ch));
-}
-
-
-/**
- * A client that created a loose channel that was not bound to a port
- * disconnected, drop it from the #loose_channels list.
- *
- * @param port the port the channel was trying to bind to
- * @param ch the channel that was lost
- */
-void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
-                        struct CadetChannel *ch)
-{
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
-                                                       port,
-                                                       ch));
-}
-
-
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id in host byte order
- * @param value The value stored at the key (channel to destroy).
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-channel_destroy_iterator (void *cls,
-                          uint32_t key,
-                          void *value)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  struct CadetChannel *ch = value;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying %s, due to %s disconnecting.\n",
-       GCCH_2s (ch),
-       GSC_2s (c));
-  ccn.channel_of_client = htonl (key);
-  GCCH_channel_local_destroy (ch,
-                              c,
-                              ccn);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         key,
-                                                         ch));
-  return GNUNET_OK;
-}
-
-
-/**
- * Remove client's ports from the global hashmap on disconnect.
- *
- * @param cls Closure (unused).
- * @param key the port.
- * @param value the `struct CadetClient` to remove
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-client_release_ports (void *cls,
-                      const struct GNUNET_HashCode *key,
-                      void *value)
-{
-  struct CadetClient *c = value;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing port %s due to %s disconnect.\n",
-       GNUNET_h2s (key),
-       GSC_2s (c));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
-                                                       key,
-                                                       value));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (c->ports,
-                                                       key,
-                                                       value));
-  return GNUNET_OK;
-}
-
-
-/**
- * Callback called when a client disconnected from the service
- *
- * @param cls closure for the service
- * @param client the client that disconnected
- * @param internal_cls should be equal to @a c
- */
-static void
-client_disconnect_cb (void *cls,
-                     struct GNUNET_SERVICE_Client *client,
-                     void *internal_cls)
-{
-  struct CadetClient *c = internal_cls;
-
-  GNUNET_assert (c->client == client);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s is disconnecting.\n",
-       GSC_2s (c));
-  if (NULL != c->channels)
-  {
-    GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
-                                             &channel_destroy_iterator,
-                                             c);
-    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
-    GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
-  }
-  if (NULL != c->ports)
-  {
-    GNUNET_CONTAINER_multihashmap_iterate (c->ports,
-                                           &client_release_ports,
-                                           c);
-    GNUNET_CONTAINER_multihashmap_destroy (c->ports);
-  }
-  GNUNET_CONTAINER_DLL_remove (clients_head,
-                               clients_tail,
-                               c);
-  GNUNET_STATISTICS_update (stats,
-                            "# clients",
-                            -1,
-                            GNUNET_NO);
-  GNUNET_free (c);
-  if ( (NULL == clients_head) &&
-       (GNUNET_YES == shutting_down) )
-    shutdown_rest ();
-}
-
-
-/**
- * Setup CADET internals.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls,
-     const struct GNUNET_CONFIGURATION_Handle *c,
-     struct GNUNET_SERVICE_Handle *service)
-{
-  cfg = c;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "RATCHET_MESSAGES",
-                                             &ratchet_messages))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "RATCHET_MESSAGES",
-                               "needs to be a number");
-    ratchet_messages = 64;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "RATCHET_TIME",
-                                           &ratchet_time))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "RATCHET_TIME",
-                               "need delay value");
-    ratchet_time = GNUNET_TIME_UNIT_HOURS;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "REFRESH_CONNECTION_TIME",
-                                           &keepalive_period))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "REFRESH_CONNECTION_TIME",
-                               "need delay value");
-    keepalive_period = GNUNET_TIME_UNIT_MINUTES;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "DROP_PERCENT",
-                                             &drop_percent))
-  {
-    drop_percent = 0;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-  }
-  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
-  if (NULL == my_private_key)
-  {
-    GNUNET_break (0);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
-                                      &my_full_id.public_key);
-  stats = GNUNET_STATISTICS_create ("cadet",
-                                    c);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                NULL);
-  ats_ch = GNUNET_ATS_connectivity_init (c);
-  /* FIXME: optimize code to allow GNUNET_YES here! */
-  open_ports = GNUNET_CONTAINER_multihashmap_create (16,
-                                                     GNUNET_NO);
-  loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
-                                                         GNUNET_NO);
-  peers = GNUNET_CONTAINER_multipeermap_create (16,
-                                                GNUNET_YES);
-  connections = GNUNET_CONTAINER_multishortmap_create (256,
-                                                       GNUNET_YES);
-  GCH_init (c);
-  GCD_init (c);
-  GCO_init (c);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "CADET started for peer %s\n",
-              GNUNET_i2s (&my_full_id));
-
-}
-
-
-/**
- * Define "main" method using service macro.
- */
-GNUNET_SERVICE_MAIN
-("cadet",
- GNUNET_SERVICE_OPTION_NONE,
- &run,
- &client_connect_cb,
- &client_disconnect_cb,
- NULL,
- GNUNET_MQ_hd_fixed_size (port_open,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
-                          struct GNUNET_CADET_PortMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (port_close,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
-                          struct GNUNET_CADET_PortMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (channel_create,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
-                          struct GNUNET_CADET_LocalChannelCreateMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (channel_destroy,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
-                          struct GNUNET_CADET_LocalChannelDestroyMessage,
-                          NULL),
- GNUNET_MQ_hd_var_size (local_data,
-                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
-                        struct GNUNET_CADET_LocalData,
-                        NULL),
- GNUNET_MQ_hd_fixed_size (local_ack,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
-                          struct GNUNET_CADET_LocalAck,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (get_peers,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (show_peer,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
-                          struct GNUNET_CADET_LocalInfo,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnels,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnel,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
-                          struct GNUNET_CADET_LocalInfo,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_dump,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_handler_end ());
-
-/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet-new.h
deleted file mode 100644 (file)
index bee5c67..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new.h
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_H
-#define GNUNET_SERVICE_CADET_H
-
-#include "gnunet_util_lib.h"
-#define NEW_CADET 1
-#include "cadet_protocol.h"
-
-/**
- * A client to the CADET service.  Each client gets a unique handle.
- */
-struct CadetClient;
-
-/**
- * A peer in the GNUnet network.  Each peer we care about must have one globally
- * unique such handle within this process.
- */
-struct CadetPeer;
-
-/**
- * Tunnel from us to another peer.  There can only be at most one
- * tunnel per peer.
- */
-struct CadetTunnel;
-
-/**
- * Entry in the message queue of a `struct CadetTunnel`.
- */
-struct CadetTunnelQueueEntry;
-
-/**
- * A path of peer in the GNUnet network.  There must only be at most
- * once such path.  Paths may share disjoint prefixes, but must all
- * end at a unique suffix.  Paths must also not be proper subsets of
- * other existing paths.
- */
-struct CadetPeerPath;
-
-/**
- * Entry in a peer path.
- */
-struct CadetPeerPathEntry
-{
-  /**
-   * DLL of paths where the same @e peer is at the same offset.
-   */
-  struct CadetPeerPathEntry *next;
-
-  /**
-   * DLL of paths where the same @e peer is at the same offset.
-   */
-  struct CadetPeerPathEntry *prev;
-
-  /**
-   * The peer at this offset of the path.
-   */
-  struct CadetPeer *peer;
-
-  /**
-   * Path this entry belongs to.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Connection using this path, or NULL for none.
-   */
-  struct CadetConnection *cc;
-
-  /**
-   * Path's historic score up to this point.  Basically, how often did
-   * we succeed or fail to use the path up to this entry in a
-   * connection.  Positive values indicate good experiences, negative
-   * values bad experiences.  Code updating the score must guard
-   * against overflows.
-   */
-  int score;
-
-};
-
-/**
- * Entry in list of connections used by tunnel, with metadata.
- */
-struct CadetTConnection
-{
-  /**
-   * Next in DLL.
-   */
-  struct CadetTConnection *next;
-
-  /**
-   * Prev in DLL.
-   */
-  struct CadetTConnection *prev;
-
-  /**
-   * Connection handle.
-   */
-  struct CadetConnection *cc;
-
-  /**
-   * Tunnel this connection belongs to.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Creation time, to keep oldest connection alive.
-   */
-  struct GNUNET_TIME_Absolute created;
-
-  /**
-   * Connection throughput, to keep fastest connection alive.
-   */
-  uint32_t throughput;
-
-  /**
-   * Is the connection currently ready for transmission?
-   */
-  int is_ready;
-};
-
-
-/**
- * Active path through the network (used by a tunnel).  There may
- * be at most one connection per path.
- */
-struct CadetConnection;
-
-/**
- * Description of a segment of a `struct CadetConnection` at the
- * intermediate peers.  Routes are basically entries in a peer's
- * routing table for forwarding traffic.  At both endpoints, the
- * routes are terminated by a `struct CadetConnection`, which knows
- * the complete `struct CadetPath` that is formed by the individual
- * routes.
- */
-struct CadetRoute;
-
-/**
- * Logical end-to-end conenction between clients.  There can be
- * any number of channels between clients.
- */
-struct CadetChannel;
-
-/**
- * Handle to our configuration.
- */
-extern const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to communicate with ATS.
- */
-extern struct GNUNET_ATS_ConnectivityHandle *ats_ch;
-
-/**
- * Local peer own ID.
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Own private key.
- */
-extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * All ports clients of this peer have opened.
- */
-extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
-
-/**
- * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
- * hash codes to `struct CadetConnection` objects.
- */
-extern struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * Map from ports to channels where the ports were closed at the
- * time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
- */
-extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
-
-/**
- * Map from PIDs to `struct CadetPeer` entries.
- */
-extern struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * How many messages are needed to trigger an AXOLOTL ratchet advance.
- */
-extern unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance due to time.
- */
-extern struct GNUNET_TIME_Relative ratchet_time;
-
-/**
- * How frequently do we send KEEPALIVE messages on idle connections?
- */
-extern struct GNUNET_TIME_Relative keepalive_period;
-
-/**
- * Signal that shutdown is happening: prevent recovery measures.
- */
-extern int shutting_down;
-
-/**
- * Set to non-zero values to create random drops to test retransmissions.
- */
-extern unsigned long long drop_percent;
-
-
-/**
- * Send a message to a client.
- *
- * @param c client to get the message
- * @param env envelope with the message
- */
-void
-GSC_send_to_client (struct CadetClient *c,
-                    struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * A channel was destroyed by the other peer. Tell our client.
- *
- * @param c client that lost a channel
- * @param ccn channel identification number for the client
- * @param ch the channel object
- */
-void
-GSC_handle_remote_channel_destroy (struct CadetClient *c,
-                                   struct GNUNET_CADET_ClientChannelNumber ccn,
-                                   struct CadetChannel *ch);
-
-/**
- * A client that created a loose channel that was not bound to a port
- * disconnected, drop it from the #loose_channels list.
- *
- * @param port the port the channel was trying to bind to
- * @param ch the channel that was lost
- */
-void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
-                        struct CadetChannel *ch);
-
-
-/**
- * Bind incoming channel to this client, and notify client
- * about incoming connection.
- *
- * @param c client to bind to
- * @param ch channel to be bound
- * @param dest peer that establishes the connection
- * @param port port number
- * @param options options
- * @return local channel number assigned to the new client
- */
-struct GNUNET_CADET_ClientChannelNumber
-GSC_bind (struct CadetClient *c,
-          struct CadetChannel *ch,
-          struct CadetPeer *dest,
-          const struct GNUNET_HashCode *port,
-          uint32_t options);
-
-
-/**
- * Return identifier for a client as a string.
- *
- * @param c client to identify
- * @return string for debugging
- */
-const char *
-GSC_2s (struct CadetClient *c);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
deleted file mode 100644 (file)
index 43c9058..0000000
+++ /dev/null
@@ -1,2040 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_channel.c
- * @brief logical links between CADET clients
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - Congestion/flow control:
- *   + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
- *     (and figure out how/where to use this!)
- *   + figure out flow control without ACKs (unreliable traffic!)
- * - revisit handling of 'unbuffered' traffic!
- *   (need to push down through tunnel into connection selection)
- * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
- *   reserve more bits in 'options' to allow for buffer size control?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.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_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
-
-/**
- * How long do we initially wait before retransmitting?
- */
-#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-/**
- * How long do we wait before dropping state about incoming
- * connection to closed port?
- */
-#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
-
-/**
- * How long do we wait at least before retransmitting ever?
- */
-#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
-
-/**
- * Maximum message ID into the future we accept for out-of-order messages.
- * If the message is more than this into the future, we drop it.  This is
- * important both to detect values that are actually in the past, as well
- * as to limit adversarially triggerable memory consumption.
- *
- * Note that right now we have "max_pending_messages = 4" hard-coded in
- * the logic below, so a value of 4 would suffice here. But we plan to
- * allow larger windows in the future...
- */
-#define MAX_OUT_OF_ORDER_DISTANCE 1024
-
-
-/**
- * All the states a channel can be in.
- */
-enum CadetChannelState
-{
-  /**
-   * Uninitialized status, should never appear in operation.
-   */
-  CADET_CHANNEL_NEW,
-
-  /**
-   * Channel is to a port that is not open, we're waiting for the
-   * port to be opened.
-   */
-  CADET_CHANNEL_LOOSE,
-
-  /**
-   * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
-   */
-  CADET_CHANNEL_OPEN_SENT,
-
-  /**
-   * Connection confirmed, ready to carry traffic.
-   */
-  CADET_CHANNEL_READY
-};
-
-
-/**
- * Info needed to retry a message in case it gets lost.
- * Note that we DO use this structure also for unreliable
- * messages.
- */
-struct CadetReliableMessage
-{
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetReliableMessage *next;
-
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetReliableMessage *prev;
-
-  /**
-   * Which channel is this message in?
-   */
-  struct CadetChannel *ch;
-
-  /**
-   * Entry in the tunnels queue for this message, NULL if it has left
-   * the tunnel.  Used to cancel transmission in case we receive an
-   * ACK in time.
-   */
-  struct CadetTunnelQueueEntry *qe;
-
-  /**
-   * Data message we are trying to send.
-   */
-  struct GNUNET_CADET_ChannelAppDataMessage *data_message;
-
-  /**
-   * How soon should we retry if we fail to get an ACK?
-   * Messages in the queue are sorted by this value.
-   */
-  struct GNUNET_TIME_Absolute next_retry;
-
-  /**
-   * How long do we wait for an ACK after transmission?
-   * Use for the back-off calculation.
-   */
-  struct GNUNET_TIME_Relative retry_delay;
-
-  /**
-   * Time when we first successfully transmitted the message
-   * (that is, set @e num_transmissions to 1).
-   */
-  struct GNUNET_TIME_Absolute first_transmission_time;
-
-  /**
-   * Identifier of the connection that this message took when it
-   * was first transmitted.  Only useful if @e num_transmissions is 1.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
-
-  /**
-   * How often was this message transmitted?  #GNUNET_SYSERR if there
-   * was an error transmitting the message, #GNUNET_NO if it was not
-   * yet transmitted ever, otherwise the number of (re) transmissions.
-   */
-  int num_transmissions;
-
-};
-
-
-/**
- * List of received out-of-order data messages.
- */
-struct CadetOutOfOrderMessage
-{
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetOutOfOrderMessage *next;
-
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetOutOfOrderMessage *prev;
-
-  /**
-   * ID of the message (messages up to this point needed
-   * before we give this one to the client).
-   */
-  struct ChannelMessageIdentifier mid;
-
-  /**
-   * The envelope with the payload of the out-of-order message
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Client endpoint of a `struct CadetChannel`.  A channel may be a
- * loopback channel, in which case it has two of these endpoints.
- * Note that flow control also is required in both directions.
- */
-struct CadetChannelClient
-{
-  /**
-   * Client handle.  Not by itself sufficient to designate
-   * the client endpoint, as the same client handle may
-   * be used for both the owner and the destination, and
-   * we thus also need the channel ID to identify the client.
-   */
-  struct CadetClient *c;
-
-  /**
-   * Head of DLL of messages received out of order or while client was unready.
-   */
-  struct CadetOutOfOrderMessage *head_recv;
-
-  /**
-   * Tail DLL of messages received out of order or while client was unready.
-   */
-  struct CadetOutOfOrderMessage *tail_recv;
-
-  /**
-   * Local tunnel number for this client.
-   * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
-   *  otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-   */
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  /**
-   * Number of entries currently in @a head_recv DLL.
-   */
-  unsigned int num_recv;
-
-  /**
-   * Can we send data to the client?
-   */
-  int client_ready;
-
-};
-
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel
-{
-  /**
-   * Tunnel this channel is in.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Client owner of the tunnel, if any.
-   * (Used if this channel represends the initiating end of the tunnel.)
-   */
-  struct CadetChannelClient *owner;
-
-  /**
-   * Client destination of the tunnel, if any.
-   * (Used if this channel represents the listening end of the tunnel.)
-   */
-  struct CadetChannelClient *dest;
-
-  /**
-   * Last entry in the tunnel's queue relating to control messages
-   * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
-   * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK).  Used to cancel
-   * transmission in case we receive updated information.
-   */
-  struct CadetTunnelQueueEntry *last_control_qe;
-
-  /**
-   * Head of DLL of messages sent and not yet ACK'd.
-   */
-  struct CadetReliableMessage *head_sent;
-
-  /**
-   * Tail of DLL of messages sent and not yet ACK'd.
-   */
-  struct CadetReliableMessage *tail_sent;
-
-  /**
-   * Task to resend/poll in case no ACK is received.
-   */
-  struct GNUNET_SCHEDULER_Task *retry_control_task;
-
-  /**
-   * Task to resend/poll in case no ACK is received.
-   */
-  struct GNUNET_SCHEDULER_Task *retry_data_task;
-
-  /**
-   * Last time the channel was used
-   */
-  struct GNUNET_TIME_Absolute timestamp;
-
-  /**
-   * Destination port of the channel.
-   */
-  struct GNUNET_HashCode port;
-
-  /**
-   * Counter for exponential backoff.
-   */
-  struct GNUNET_TIME_Relative retry_time;
-
-  /**
-   * Bitfield of already-received messages past @e mid_recv.
-   */
-  uint64_t mid_futures;
-
-  /**
-   * Next MID expected for incoming traffic.
-   */
-  struct ChannelMessageIdentifier mid_recv;
-
-  /**
-   * Next MID to use for outgoing traffic.
-   */
-  struct ChannelMessageIdentifier mid_send;
-
-  /**
-   * Total (reliable) messages pending ACK for this channel.
-   */
-  unsigned int pending_messages;
-
-  /**
-   * Maximum (reliable) messages pending ACK for this channel
-   * before we throttle the client.
-   */
-  unsigned int max_pending_messages;
-
-  /**
-   * Number identifying this channel in its tunnel.
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Channel state.
-   */
-  enum CadetChannelState state;
-
-  /**
-   * Count how many ACKs we skipped, used to prevent long
-   * sequences of ACK skipping.
-   */
-  unsigned int skip_ack_series;
-
-  /**
-   * Is the tunnel bufferless (minimum latency)?
-   */
-  int nobuffer;
-
-  /**
-   * Is the tunnel reliable?
-   */
-  int reliable;
-
-  /**
-   * Is the tunnel out-of-order?
-   */
-  int out_of_order;
-
-  /**
-   * Is this channel a loopback channel, where the destination is us again?
-   */
-  int is_loopback;
-
-  /**
-   * Flag to signal the destruction of the channel.  If this is set to
-   * #GNUNET_YES the channel will be destroyed once the queue is
-   * empty.
-   */
-  int destroy;
-
-};
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch)
-{
-  static char buf[128];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Channel %s:%s ctn:%X(%X/%X)",
-                   (GNUNET_YES == ch->is_loopback)
-                   ? "loopback"
-                   : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
-                   GNUNET_h2s (&ch->port),
-                   ch->ctn,
-                   (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
-                   (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
-  return buf;
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch)
-{
-  return ch->ctn;
-}
-
-
-/**
- * Release memory associated with @a ccc
- *
- * @param ccc data structure to clean up
- */
-static void
-free_channel_client (struct CadetChannelClient *ccc)
-{
-  struct CadetOutOfOrderMessage *com;
-
-  while (NULL != (com = ccc->head_recv))
-  {
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GNUNET_MQ_discard (com->env);
-    GNUNET_free (com);
-  }
-  GNUNET_free (ccc);
-}
-
-
-/**
- * Destroy the given channel.
- *
- * @param ch channel to destroy
- */
-static void
-channel_destroy (struct CadetChannel *ch)
-{
-  struct CadetReliableMessage *crm;
-
-  while (NULL != (crm = ch->head_sent))
-  {
-    GNUNET_assert (ch == crm->ch);
-    if (NULL != crm->qe)
-    {
-      GCT_send_cancel (crm->qe);
-      crm->qe = NULL;
-    }
-    GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                                 ch->tail_sent,
-                                 crm);
-    GNUNET_free (crm->data_message);
-    GNUNET_free (crm);
-  }
-  if (NULL != ch->owner)
-  {
-    free_channel_client (ch->owner);
-    ch->owner = NULL;
-  }
-  if (NULL != ch->dest)
-  {
-    free_channel_client (ch->dest);
-    ch->dest = NULL;
-  }
-  if (NULL != ch->last_control_qe)
-  {
-    GCT_send_cancel (ch->last_control_qe);
-    ch->last_control_qe = NULL;
-  }
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  if (NULL != ch->retry_control_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task = NULL;
-  }
-  if (GNUNET_NO == ch->is_loopback)
-  {
-    GCT_remove_channel (ch->t,
-                        ch,
-                        ch->ctn);
-    ch->t = NULL;
-  }
-  GNUNET_free (ch);
-}
-
-
-/**
- * Send a channel create message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls);
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * create message.  Delays for a bit until we retry.
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-channel_open_sent_cb (void *cls,
-                      const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetChannel *ch = cls;
-
-  GNUNET_assert (NULL != ch->last_control_qe);
-  ch->last_control_qe = NULL;
-  ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
-       GCCH_2s (ch),
-       GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
-                                               GNUNET_YES));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
-                                    &send_channel_open,
-                                    ch);
-}
-
-
-/**
- * Send a channel open message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct GNUNET_CADET_ChannelOpenMessage msgcc;
-  uint32_t options;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CHANNEL_OPEN message for %s\n",
-       GCCH_2s (ch));
-  options = 0;
-  if (ch->nobuffer)
-    options |= GNUNET_CADET_OPTION_NOBUFFER;
-  if (ch->reliable)
-    options |= GNUNET_CADET_OPTION_RELIABLE;
-  if (ch->out_of_order)
-    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
-  msgcc.header.size = htons (sizeof (msgcc));
-  msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
-  msgcc.opt = htonl (options);
-  msgcc.port = ch->port;
-  msgcc.ctn = ch->ctn;
-  ch->state = CADET_CHANNEL_OPEN_SENT;
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msgcc.header,
-                                  &channel_open_sent_cb,
-                                  ch);
-  GNUNET_assert (NULL == ch->retry_control_task);
-}
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message.  Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch)
-{
-  GNUNET_assert (NULL == ch->retry_control_task);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Tunnel up, sending CHANNEL_OPEN on %s now\n",
-       GCCH_2s (ch));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_now (&send_channel_open,
-                                ch);
-}
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param ccn local number of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
-                        struct GNUNET_CADET_ClientChannelNumber ccn,
-                        struct CadetPeer *destination,
-                        const struct GNUNET_HashCode *port,
-                        uint32_t options)
-{
-  struct CadetChannel *ch;
-  struct CadetChannelClient *ccco;
-
-  ccco = GNUNET_new (struct CadetChannelClient);
-  ccco->c = owner;
-  ccco->ccn = ccn;
-  ccco->client_ready = GNUNET_YES;
-
-  ch = GNUNET_new (struct CadetChannel);
-  ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
-  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
-  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
-  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
-  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
-  ch->owner = ccco;
-  ch->port = *port;
-  if (0 == memcmp (&my_full_id,
-                   GCP_get_id (destination),
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    struct CadetClient *c;
-
-    ch->is_loopback = GNUNET_YES;
-    c = GNUNET_CONTAINER_multihashmap_get (open_ports,
-                                           port);
-    if (NULL == c)
-    {
-      /* port closed, wait for it to possibly open */
-      ch->state = CADET_CHANNEL_LOOSE;
-      (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
-                                                port,
-                                                ch,
-                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Created loose incoming loopback channel to port %s\n",
-           GNUNET_h2s (&ch->port));
-    }
-    else
-    {
-      GCCH_bind (ch,
-                 c);
-    }
-  }
-  else
-  {
-    ch->t = GCP_get_tunnel (destination,
-                            GNUNET_YES);
-    ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
-    ch->ctn = GCT_add_channel (ch->t,
-                               ch);
-  }
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created channel to port %s at peer %s for %s using %s\n",
-       GNUNET_h2s (port),
-       GCP_2s (destination),
-       GSC_2s (owner),
-       (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
-  return ch;
-}
-
-
-/**
- * We had an incoming channel to a port that is closed.
- * It has not been opened for a while, drop it.
- *
- * @param cls the channel to drop
- */
-static void
-timeout_closed_cb (void *cls)
-{
-  struct CadetChannel *ch = cls;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing incoming channel to port %s from peer %s due to timeout\n",
-       GNUNET_h2s (&ch->port),
-       GCP_2s (GCT_get_destination (ch->t)));
-  channel_destroy (ch);
-}
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param ctn identifier of this channel in the tunnel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
-                           struct GNUNET_CADET_ChannelTunnelNumber ctn,
-                           const struct GNUNET_HashCode *port,
-                           uint32_t options)
-{
-  struct CadetChannel *ch;
-  struct CadetClient *c;
-
-  ch = GNUNET_new (struct CadetChannel);
-  ch->port = *port;
-  ch->t = t;
-  ch->ctn = ctn;
-  ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
-  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
-  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
-  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
-  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-
-  c = GNUNET_CONTAINER_multihashmap_get (open_ports,
-                                         port);
-  if (NULL == c)
-  {
-    /* port closed, wait for it to possibly open */
-    ch->state = CADET_CHANNEL_LOOSE;
-    (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
-                                              port,
-                                              ch,
-                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-    GNUNET_assert (NULL == ch->retry_control_task);
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
-                                      &timeout_closed_cb,
-                                      ch);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Created loose incoming channel to port %s from peer %s\n",
-         GNUNET_h2s (&ch->port),
-         GCP_2s (GCT_get_destination (ch->t)));
-  }
-  else
-  {
-    GCCH_bind (ch,
-               c);
-  }
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-  return ch;
-}
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * ACK message.  Just remembers it was sent, we do not expect
- * ACKs for ACKs ;-).
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-send_ack_cb (void *cls,
-             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetChannel *ch = cls;
-
-  GNUNET_assert (NULL != ch->last_control_qe);
-  ch->last_control_qe = NULL;
-}
-
-
-/**
- * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
- *
- * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
- */
-static void
-send_channel_data_ack (struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_ChannelDataAckMessage msg;
-
-  if (GNUNET_NO == ch->reliable)
-    return; /* no ACKs */
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
-  msg.header.size = htons (sizeof (msg));
-  msg.ctn = ch->ctn;
-  msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
-  msg.futures = GNUNET_htonll (ch->mid_futures);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending DATA_ACK %u:%llX via %s\n",
-       (unsigned int) ntohl (msg.mid.mid),
-       (unsigned long long) ch->mid_futures,
-       GCCH_2s (ch));
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msg.header,
-                                  &send_ack_cb,
-                                  ch);
-}
-
-
-/**
- * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
- * connection is up.
- *
- * @param cls the `struct CadetChannel`
- */
-static void
-send_open_ack (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CHANNEL_OPEN_ACK on %s\n",
-       GCCH_2s (ch));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
-  msg.header.size = htons (sizeof (msg));
-  msg.reserved = htonl (0);
-  msg.ctn = ch->ctn;
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msg.header,
-                                  &send_ack_cb,
-                                  ch);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel.  If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  if (NULL == ch->dest)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
-         GCCH_2s (ch));
-    return;
-  }
-  if (NULL != ch->retry_control_task)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
-         GCCH_2s (ch));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Retransmitting CHANNEL_OPEN_ACK on %s\n",
-       GCCH_2s (ch));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_now (&send_open_ack,
-                                ch);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
- *
- * @param ch channel the ack is for
- * @param to_owner #GNUNET_YES to send to owner,
- *                 #GNUNET_NO to send to dest
- */
-static void
-send_ack_to_client (struct CadetChannel *ch,
-                    int to_owner)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalAck *ack;
-  struct CadetChannelClient *ccc;
-
-  ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
-  if (NULL == ccc)
-  {
-    /* This can happen if we are just getting ACKs after
-       our local client already disconnected. */
-    GNUNET_assert (GNUNET_YES == ch->destroy);
-    return;
-  }
-  env = GNUNET_MQ_msg (ack,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-  ack->ccn = ccc->ccn;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
-       GSC_2s (ccc->c),
-       (GNUNET_YES == to_owner) ? "owner" : "dest",
-       ntohl (ack->ccn.channel_of_client),
-       ch->pending_messages,
-       ch->max_pending_messages);
-  GSC_send_to_client (ccc->c,
-                      env);
-}
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to.  Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
-           struct CadetClient *c)
-{
-  uint32_t options;
-  struct CadetChannelClient *cccd;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Binding %s from %s to port %s of %s\n",
-       GCCH_2s (ch),
-       GCT_2s (ch->t),
-       GNUNET_h2s (&ch->port),
-       GSC_2s (c));
-  if (NULL != ch->retry_control_task)
-  {
-    /* there might be a timeout task here */
-    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task = NULL;
-  }
-  options = 0;
-  if (ch->nobuffer)
-    options |= GNUNET_CADET_OPTION_NOBUFFER;
-  if (ch->reliable)
-    options |= GNUNET_CADET_OPTION_RELIABLE;
-  if (ch->out_of_order)
-    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
-  cccd = GNUNET_new (struct CadetChannelClient);
-  GNUNET_assert (NULL == ch->dest);
-  ch->dest = cccd;
-  cccd->c = c;
-  cccd->client_ready = GNUNET_YES;
-  cccd->ccn = GSC_bind (c,
-                        ch,
-                        (GNUNET_YES == ch->is_loopback)
-                        ? GCP_get (&my_full_id,
-                                   GNUNET_YES)
-                        : GCT_get_destination (ch->t),
-                        &ch->port,
-                        options);
-  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
-                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    ch->state = CADET_CHANNEL_OPEN_SENT;
-    GCCH_handle_channel_open_ack (ch,
-                                  NULL);
-  }
-  else
-  {
-    /* notify other peer that we accepted the connection */
-    ch->state = CADET_CHANNEL_READY;
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_now (&send_open_ack,
-                                  ch);
-  }
-  /* give client it's initial supply of ACKs */
-  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
-                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  for (unsigned int i=0;i<ch->max_pending_messages;i++)
-    send_ack_to_client (ch,
-                        GNUNET_NO);
-}
-
-
-/**
- * One of our clients has disconnected, tell the other one that we
- * are finished. Done asynchronously to avoid concurrent modification
- * issues if this is the same client.
- *
- * @param cls the `struct CadetChannel` where one of the ends is now dead
- */
-static void
-signal_remote_destroy_cb (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct CadetChannelClient *ccc;
-
-  /* Find which end is left... */
-  ch->retry_control_task = NULL;
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  GSC_handle_remote_channel_destroy (ccc->c,
-                                     ccc->ccn,
-                                     ch);
-  channel_destroy (ch);
-}
-
-
-/**
- * Destroy locally created channel.  Called by the local client, so no
- * need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
-                            struct CadetClient *c,
-                            struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s asks for destruction of %s\n",
-       GSC_2s (c),
-       GCCH_2s (ch));
-  GNUNET_assert (NULL != c);
-  if ( (NULL != ch->owner) &&
-       (c == ch->owner->c) &&
-       (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
-  {
-    free_channel_client (ch->owner);
-    ch->owner = NULL;
-  }
-  else if ( (NULL != ch->dest) &&
-            (c == ch->dest->c) &&
-            (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
-  {
-    free_channel_client (ch->dest);
-    ch->dest = NULL;
-  }
-  else
-  {
-    GNUNET_assert (0);
-  }
-
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* other end already destroyed, with the local client gone, no need
-       to finish transmissions, just destroy immediately. */
-    channel_destroy (ch);
-    return;
-  }
-  if ( (NULL != ch->head_sent) &&
-       ( (NULL != ch->owner) ||
-         (NULL != ch->dest) ) )
-  {
-    /* Wait for other end to destroy us as well,
-       and otherwise allow send queue to be transmitted first */
-    ch->destroy = GNUNET_YES;
-    return;
-  }
-  if ( (GNUNET_YES == ch->is_loopback) &&
-       ( (NULL != ch->owner) ||
-         (NULL != ch->dest) ) )
-  {
-    if (NULL != ch->retry_control_task)
-      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
-                                  ch);
-    return;
-  }
-  if (GNUNET_NO == ch->is_loopback)
-  {
-    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
-    switch (ch->state)
-    {
-    case CADET_CHANNEL_NEW:
-      /* We gave up on a channel that we created as a client to a remote
-         target, but that never went anywhere. Nothing to do here. */
-      break;
-    case CADET_CHANNEL_LOOSE:
-      GSC_drop_loose_channel (&ch->port,
-                              ch);
-      break;
-    default:
-      GCT_send_channel_destroy (ch->t,
-                                ch->ctn);
-    }
-  }
-  /* Nothing left to do, just finish destruction */
-  channel_destroy (ch);
-}
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
-                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  switch (ch->state)
-  {
-  case CADET_CHANNEL_NEW:
-    /* this should be impossible */
-    GNUNET_break (0);
-    break;
-  case CADET_CHANNEL_LOOSE:
-    /* This makes no sense. */
-    GNUNET_break_op (0);
-    break;
-  case CADET_CHANNEL_OPEN_SENT:
-    if (NULL == ch->owner)
-    {
-      /* We're not the owner, wrong direction! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
-         GCCH_2s (ch));
-    if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
-    {
-      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-      ch->retry_control_task = NULL;
-    }
-    ch->state = CADET_CHANNEL_READY;
-    /* On first connect, send client as many ACKs as we allow messages
-       to be buffered! */
-    for (unsigned int i=0;i<ch->max_pending_messages;i++)
-      send_ack_to_client (ch,
-                          GNUNET_YES);
-    break;
-  case CADET_CHANNEL_READY:
-    /* duplicate ACK, maybe we retried the CREATE. Ignore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received duplicate channel OPEN_ACK for %s\n",
-         GCCH_2s (ch));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate CREATE_ACKs",
-                              1,
-                              GNUNET_NO);
-    break;
-  }
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param m1 a message of to sort
- * @param m2 another message to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-is_before (void *cls,
-           struct CadetOutOfOrderMessage *m1,
-           struct CadetOutOfOrderMessage *m2)
-{
-  int *duplicate = cls;
-  uint32_t v1 = ntohl (m1->mid.mid);
-  uint32_t v2 = ntohl (m2->mid.mid);
-  uint32_t delta;
-
-  delta = v2 - v1;
-  if (0 == delta)
-    *duplicate = GNUNET_YES;
-  if (delta > (uint32_t) INT_MAX)
-  {
-    /* in overflow range, we can safely assume we wrapped around */
-    return GNUNET_NO;
-  }
-  else
-  {
-    /* result is small, thus v2 > v1, thus m1 < m2 */
-    return GNUNET_YES;
-  }
-}
-
-
-/**
- * We got payload data for a channel.  Pass it on to the client
- * and send an ACK to the other end (once flow control allows it!)
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
-                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalData *ld;
-  struct CadetChannelClient *ccc;
-  size_t payload_size;
-  struct CadetOutOfOrderMessage *com;
-  int duplicate;
-  uint32_t mid_min;
-  uint32_t mid_max;
-  uint32_t mid_msg;
-  uint32_t delta;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  if ( (GNUNET_YES == ch->destroy) &&
-       (NULL == ch->owner) &&
-       (NULL == ch->dest) )
-  {
-    /* This client is gone, but we still have messages to send to
-       the other end (which is why @a ch is not yet dead).  However,
-       we cannot pass messages to our client anymore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Dropping incoming payload on %s as this end is already closed\n",
-         GCCH_2s (ch));
-    /* send back DESTROY notification to stop further retransmissions! */
-    GCT_send_channel_destroy (ch->t,
-                              ch->ctn);
-    return;
-  }
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  env = GNUNET_MQ_msg_extra (ld,
-                             payload_size,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
-  GNUNET_memcpy (&ld[1],
-                 &msg[1],
-                 payload_size);
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if ( (GNUNET_YES == ccc->client_ready) &&
-       ( (GNUNET_YES == ch->out_of_order) ||
-         (msg->mid.mid == ch->mid_recv.mid) ) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Giving %u bytes of payload with MID %u from %s to client %s\n",
-         (unsigned int) payload_size,
-         ntohl (msg->mid.mid),
-         GCCH_2s (ch),
-         GSC_2s (ccc->c));
-    ccc->client_ready = GNUNET_NO;
-    GSC_send_to_client (ccc->c,
-                        env);
-    ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
-    ch->mid_futures >>= 1;
-    send_channel_data_ack (ch);
-    return;
-  }
-
-  if (GNUNET_YES == ch->reliable)
-  {
-    /* check if message ought to be dropped because it is ancient/too distant/duplicate */
-    mid_min = ntohl (ch->mid_recv.mid);
-    mid_max = mid_min + ch->max_pending_messages;
-    mid_msg = ntohl (msg->mid.mid);
-    if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
-         ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "%s at %u drops ancient or far-future message %u\n",
-           GCCH_2s (ch),
-           (unsigned int) mid_min,
-           ntohl (msg->mid.mid));
-
-      GNUNET_STATISTICS_update (stats,
-                                "# duplicate DATA (ancient or future)",
-                                1,
-                                GNUNET_NO);
-      GNUNET_MQ_discard (env);
-      send_channel_data_ack (ch);
-      return;
-    }
-    /* mark bit for future ACKs */
-    delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
-    if (delta < 64)
-    {
-      if (0 != (ch->mid_futures & (1LLU << delta)))
-      {
-        /* Duplicate within the queue, drop also */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
-             (unsigned int) payload_size,
-             GCCH_2s (ch),
-             ntohl (msg->mid.mid));
-        GNUNET_STATISTICS_update (stats,
-                                  "# duplicate DATA",
-                                  1,
-                                  GNUNET_NO);
-        GNUNET_MQ_discard (env);
-        send_channel_data_ack (ch);
-        return;
-      }
-      ch->mid_futures |= (1LLU << delta);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Marked bit %llX for mid %u (base: %u); now: %llX\n",
-           (1LLU << delta),
-           mid_msg,
-           mid_min,
-           ch->mid_futures);
-    }
-  }
-  else /* ! ch->reliable */
-  {
-    /* Channel is unreliable, so we do not ACK. But we also cannot
-       allow buffering everything, so check if we have space... */
-    if (ccc->num_recv >= ch->max_pending_messages)
-    {
-      struct CadetOutOfOrderMessage *drop;
-
-      /* Yep, need to drop. Drop the oldest message in
-         the buffer. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Queue full due slow client on %s, dropping oldest message\n",
-           GCCH_2s (ch));
-      GNUNET_STATISTICS_update (stats,
-                                "# messages dropped due to slow client",
-                                1,
-                                GNUNET_NO);
-      drop = ccc->head_recv;
-      GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                   ccc->tail_recv,
-                                   drop);
-      ccc->num_recv--;
-      GNUNET_MQ_discard (drop->env);
-      GNUNET_free (drop);
-    }
-  }
-
-  /* Insert message into sorted out-of-order queue */
-  com = GNUNET_new (struct CadetOutOfOrderMessage);
-  com->mid = msg->mid;
-  com->env = env;
-  duplicate = GNUNET_NO;
-  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
-                                      is_before,
-                                      &duplicate,
-                                      ccc->head_recv,
-                                      ccc->tail_recv,
-                                      com);
-  ccc->num_recv++;
-  if (GNUNET_YES == duplicate)
-  {
-    /* Duplicate within the queue, drop also (this is not covered by
-       the case above if "delta" >= 64, which could be the case if
-       max_pending_messages is also >= 64 or if our client is unready
-       and we are seeing retransmissions of the message our client is
-       blocked on. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
-         (unsigned int) payload_size,
-         GCCH_2s (ch),
-         ntohl (msg->mid.mid));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate DATA",
-                              1,
-                              GNUNET_NO);
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GNUNET_MQ_discard (com->env);
-    GNUNET_free (com);
-    send_channel_data_ack (ch);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
-       (GNUNET_YES == ccc->client_ready)
-       ? "out-of-order"
-       : "client-not-ready",
-       (unsigned int) payload_size,
-       GCCH_2s (ch),
-       ntohl (ccc->ccn.channel_of_client),
-       ccc,
-       ntohl (msg->mid.mid),
-       ntohl (ch->mid_recv.mid));
-  /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
-     the sender may already be transmitting the previous one.  Needs
-     experimental evaluation to see if/when this ACK helps or
-     hurts. (We might even want another option.) */
-  send_channel_data_ack (ch);
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-data_sent_cb (void *cls,
-              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We need to retry a transmission, the last one took too long to
- * be acknowledged.
- *
- * @param cls the `struct CadetChannel` where we need to retransmit
- */
-static void
-retry_transmission (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct CadetReliableMessage *crm = ch->head_sent;
-
-  ch->retry_data_task = NULL;
-  GNUNET_assert (NULL == crm->qe);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Retrying transmission on %s of message %u\n",
-       GCCH_2s (ch),
-       (unsigned int) ntohl (crm->data_message->mid.mid));
-  crm->qe = GCT_send (ch->t,
-                      &crm->data_message->header,
-                      &data_sent_cb,
-                      crm);
-  GNUNET_assert (NULL == ch->retry_data_task);
-}
-
-
-/**
- * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
- * the queue and tell our client that it can send more.
- *
- * @param ch the channel that got the PLAINTEXT_DATA_ACK
- * @param cti identifier of the connection that delivered the message
- * @param crm the message that got acknowledged
- */
-static void
-handle_matching_ack (struct CadetChannel *ch,
-                     const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                     struct CadetReliableMessage *crm)
-{
-  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                               ch->tail_sent,
-                               crm);
-  ch->pending_messages--;
-  GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
-       GCCH_2s (ch),
-       (unsigned int) ntohl (crm->data_message->mid.mid),
-       ch->pending_messages);
-  if (NULL != crm->qe)
-  {
-    GCT_send_cancel (crm->qe);
-    crm->qe = NULL;
-  }
-  if ( (1 == crm->num_transmissions) &&
-       (NULL != cti) )
-  {
-    GCC_ack_observed (cti);
-    if (0 == memcmp (cti,
-                     &crm->connection_taken,
-                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
-    {
-      GCC_latency_observed (cti,
-                            GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
-    }
-  }
-  GNUNET_free (crm->data_message);
-  GNUNET_free (crm);
-  send_ack_to_client (ch,
-                      (NULL == ch->owner)
-                      ? GNUNET_NO
-                      : GNUNET_YES);
-}
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
-                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack)
-{
-  struct CadetReliableMessage *crm;
-  struct CadetReliableMessage *crmn;
-  int found;
-  uint32_t mid_base;
-  uint64_t mid_mask;
-  unsigned int delta;
-
-  GNUNET_break (GNUNET_NO == ch->is_loopback);
-  if (GNUNET_NO == ch->reliable)
-  {
-    /* not expecting ACKs on unreliable channel, odd */
-    GNUNET_break_op (0);
-    return;
-  }
-  /* mid_base is the MID of the next message that the
-     other peer expects (i.e. that is missing!), everything
-     LOWER (but excluding mid_base itself) was received. */
-  mid_base = ntohl (ack->mid.mid);
-  mid_mask = GNUNET_htonll (ack->futures);
-  found = GNUNET_NO;
-  for (crm = ch->head_sent;
-        NULL != crm;
-       crm = crmn)
-  {
-    crmn = crm->next;
-    delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
-    if (delta >= UINT_MAX - ch->max_pending_messages)
-    {
-      /* overflow, means crm was a bit in the past, so this ACK counts for it. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got DATA_ACK with base %u satisfying past message %u on %s\n",
-           (unsigned int) mid_base,
-           ntohl (crm->data_message->mid.mid),
-           GCCH_2s (ch));
-      handle_matching_ack (ch,
-                           cti,
-                           crm);
-      found = GNUNET_YES;
-      continue;
-    }
-    delta--;
-    if (delta >= 64)
-      continue;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Testing bit %llX for mid %u (base: %u)\n",
-         (1LLU << delta),
-         ntohl (crm->data_message->mid.mid),
-         mid_base);
-    if (0 != (mid_mask & (1LLU << delta)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got DATA_ACK with mask for %u on %s\n",
-           ntohl (crm->data_message->mid.mid),
-           GCCH_2s (ch));
-      handle_matching_ack (ch,
-                           cti,
-                           crm);
-      found = GNUNET_YES;
-    }
-  }
-  if (GNUNET_NO == found)
-  {
-    /* ACK for message we already dropped, might have been a
-       duplicate ACK? Ignore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Duplicate DATA_ACK on %s, ignoring\n",
-         GCCH_2s (ch));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate DATA_ACKs",
-                              1,
-                              GNUNET_NO);
-    return;
-  }
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  if ( (NULL != ch->head_sent) &&
-       (NULL == ch->head_sent->qe) )
-    ch->retry_data_task
-      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
-                                 &retry_transmission,
-                                 ch);
-}
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection.  Also needs to remove this channel from
- * the tunnel.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *            NULL if we are simulating receiving a destroy due to shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  struct CadetChannelClient *ccc;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received remote channel DESTROY for %s\n",
-       GCCH_2s (ch));
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* Local client already gone, this is instant-death. */
-    channel_destroy (ch);
-    return;
-  }
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if ( (NULL != ccc) &&
-       (NULL != ccc->head_recv) )
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Lost end of transmission due to remote shutdown on %s\n",
-         GCCH_2s (ch));
-    /* FIXME: change API to notify client about truncated transmission! */
-  }
-  ch->destroy = GNUNET_YES;
-  if (NULL != ccc)
-    GSC_handle_remote_channel_destroy (ccc->c,
-                                       ccc->ccn,
-                                       ch);
-  channel_destroy (ch);
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param crm1 an element of to sort
- * @param crm2 another element to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-cmp_crm_by_next_retry (void *cls,
-                       struct CadetReliableMessage *crm1,
-                       struct CadetReliableMessage *crm2)
-{
-  if (crm1->next_retry.abs_value_us <
-      crm2->next_retry.abs_value_us)
-    return GNUNET_YES;
-  return GNUNET_NO;
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-data_sent_cb (void *cls,
-              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetReliableMessage *crm = cls;
-  struct CadetChannel *ch = crm->ch;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  GNUNET_assert (NULL != crm->qe);
-  crm->qe = NULL;
-  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                               ch->tail_sent,
-                               crm);
-  if (GNUNET_NO == ch->reliable)
-  {
-    GNUNET_free (crm->data_message);
-    GNUNET_free (crm);
-    ch->pending_messages--;
-    send_ack_to_client (ch,
-                        (NULL == ch->owner)
-                        ? GNUNET_NO
-                        : GNUNET_YES);
-    return;
-  }
-  if (NULL == cid)
-  {
-    /* There was an error sending. */
-    crm->num_transmissions = GNUNET_SYSERR;
-  }
-  else if (GNUNET_SYSERR != crm->num_transmissions)
-  {
-    /* Increment transmission counter, and possibly store @a cid
-       if this was the first transmission. */
-    crm->num_transmissions++;
-    if (1 == crm->num_transmissions)
-    {
-      crm->first_transmission_time = GNUNET_TIME_absolute_get ();
-      crm->connection_taken = *cid;
-      GCC_ack_expected (cid);
-    }
-  }
-  if ( (0 == crm->retry_delay.rel_value_us) &&
-       (NULL != cid) )
-  {
-    struct CadetConnection *cc = GCC_lookup (cid);
-
-    if (NULL != cc)
-      crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
-    else
-      crm->retry_delay = ch->retry_time;
-  }
-  crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
-  crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
-                                               MIN_RTT_DELAY);
-  crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
-
-  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
-                                      cmp_crm_by_next_retry,
-                                      NULL,
-                                      ch->head_sent,
-                                      ch->tail_sent,
-                                      crm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Message %u sent, next transmission on %s in %s\n",
-       (unsigned int) ntohl (crm->data_message->mid.mid),
-       GCCH_2s (ch),
-       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
-                                               GNUNET_YES));
-  if (NULL == ch->head_sent->qe)
-  {
-    if (NULL != ch->retry_data_task)
-      GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task
-      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
-                                 &retry_transmission,
-                                 ch);
-  }
-}
-
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if
- * channel is reliable and send an ACK to the client if there is still
- * buffer space in the tunnel.
- *
- * @param ch Channel.
- * @param sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- *         #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
-                        const char *buf,
-                        size_t buf_len)
-{
-  struct CadetReliableMessage *crm;
-
-  if (ch->pending_messages > ch->max_pending_messages)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* we are going down, drop messages */
-    return GNUNET_OK;
-  }
-  ch->pending_messages++;
-
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    struct CadetChannelClient *receiver;
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_LocalData *ld;
-    int ack_to_owner;
-
-    env = GNUNET_MQ_msg_extra (ld,
-                               buf_len,
-                               GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-    if ( (NULL != ch->owner) &&
-         (sender_ccn.channel_of_client ==
-          ch->owner->ccn.channel_of_client) )
-    {
-      receiver = ch->dest;
-      ack_to_owner = GNUNET_YES;
-    }
-    else if ( (NULL != ch->dest) &&
-              (sender_ccn.channel_of_client ==
-               ch->dest->ccn.channel_of_client) )
-    {
-      receiver = ch->owner;
-      ack_to_owner = GNUNET_NO;
-    }
-    else
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
-    GNUNET_assert (NULL != receiver);
-    ld->ccn = receiver->ccn;
-    GNUNET_memcpy (&ld[1],
-                   buf,
-                   buf_len);
-    if (GNUNET_YES == receiver->client_ready)
-    {
-      ch->pending_messages--;
-      GSC_send_to_client (receiver->c,
-                          env);
-      send_ack_to_client (ch,
-                          ack_to_owner);
-    }
-    else
-    {
-      struct CadetOutOfOrderMessage *oom;
-
-      oom = GNUNET_new (struct CadetOutOfOrderMessage);
-      oom->env = env;
-      GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
-                                        receiver->tail_recv,
-                                        oom);
-      receiver->num_recv++;
-    }
-    return GNUNET_OK;
-  }
-
-  /* Everything is correct, send the message. */
-  crm = GNUNET_malloc (sizeof (*crm));
-  crm->ch = ch;
-  crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
-                                     + buf_len);
-  crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
-  crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
-  ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
-  crm->data_message->mid = ch->mid_send;
-  crm->data_message->ctn = ch->ctn;
-  GNUNET_memcpy (&crm->data_message[1],
-                 buf,
-                 buf_len);
-  GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
-                                    ch->tail_sent,
-                                    crm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message %u from local client to %s with %u bytes\n",
-       ntohl (crm->data_message->mid.mid),
-       GCCH_2s (ch),
-       buf_len);
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  crm->qe = GCT_send (ch->t,
-                      &crm->data_message->header,
-                      &data_sent_cb,
-                      crm);
-  GNUNET_assert (NULL == ch->retry_data_task);
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle ACK from client on local channel.  Means the client is ready
- * for more data, see if we have any for it.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
-                       struct GNUNET_CADET_ClientChannelNumber client_ccn)
-{
-  struct CadetChannelClient *ccc;
-  struct CadetOutOfOrderMessage *com;
-
-  if ( (NULL != ch->owner) &&
-       (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
-    ccc = ch->owner;
-  else if ( (NULL != ch->dest) &&
-            (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
-    ccc = ch->dest;
-  else
-    GNUNET_assert (0);
-  ccc->client_ready = GNUNET_YES;
-  com = ccc->head_recv;
-  if (NULL == com)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
-         GSC_2s (ccc->c),
-         ntohl (client_ccn.channel_of_client),
-         GCCH_2s (ch),
-         ntohl (ccc->ccn.channel_of_client),
-         ccc);
-    return; /* none pending */
-  }
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    int to_owner;
-
-    /* Messages are always in-order, just send */
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GSC_send_to_client (ccc->c,
-                        com->env);
-    /* Notify sender that we can receive more */
-    if ( (NULL != ch->owner) &&
-         (ccc->ccn.channel_of_client ==
-          ch->owner->ccn.channel_of_client) )
-    {
-      to_owner = GNUNET_NO;
-    }
-    else
-    {
-      GNUNET_assert ( (NULL != ch->dest) &&
-                      (ccc->ccn.channel_of_client ==
-                       ch->dest->ccn.channel_of_client) );
-      to_owner = GNUNET_YES;
-    }
-    send_ack_to_client (ch,
-                        to_owner);
-    GNUNET_free (com);
-    return;
-  }
-
-  if ( (com->mid.mid != ch->mid_recv.mid) &&
-       (GNUNET_NO == ch->out_of_order) &&
-       (GNUNET_YES == ch->reliable) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
-         GSC_2s (ccc->c),
-         ntohl (ccc->ccn.channel_of_client),
-         ntohl (com->mid.mid),
-         ntohl (ch->mid_recv.mid));
-    return; /* missing next one in-order */
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
-       ntohl (com->mid.mid),
-       GSC_2s (ccc->c),
-       ntohl (ccc->ccn.channel_of_client),
-       GCCH_2s (ch));
-
-  /* all good, pass next message to client */
-  GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                               ccc->tail_recv,
-                               com);
-  ccc->num_recv--;
-  /* FIXME: if unreliable, this is not aggressive
-     enough, as it would be OK to have lost some! */
-
-  ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
-  ch->mid_futures >>= 1; /* equivalent to division by 2 */
-  ccc->client_ready = GNUNET_NO;
-  GSC_send_to_client (ccc->c,
-                      com->env);
-  GNUNET_free (com);
-  send_channel_data_ack (ch);
-  if (NULL != ccc->head_recv)
-    return;
-  if (GNUNET_NO == ch->destroy)
-    return;
-  GCT_send_channel_destroy (ch->t,
-                            ch->ctn);
-  channel_destroy (ch);
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
-            enum GNUNET_ErrorType level)
-{
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-chn",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  if (NULL == ch)
-  {
-    LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
-    return;
-  }
-  LOG2 (level,
-        "CHN %s:%X (%p)\n",
-        GCT_2s (ch->t),
-        ch->ctn,
-        ch);
-  if (NULL != ch->owner)
-  {
-    LOG2 (level,
-          "CHN origin %s ready %s local-id: %u\n",
-          GSC_2s (ch->owner->c),
-          ch->owner->client_ready ? "YES" : "NO",
-          ntohl (ch->owner->ccn.channel_of_client));
-  }
-  if (NULL != ch->dest)
-  {
-    LOG2 (level,
-          "CHN destination %s ready %s local-id: %u\n",
-          GSC_2s (ch->dest->c),
-          ch->dest->client_ready ? "YES" : "NO",
-          ntohl (ch->dest->ccn.channel_of_client));
-  }
-  LOG2 (level,
-        "CHN  Message IDs recv: %d (%LLX), send: %d\n",
-        ntohl (ch->mid_recv.mid),
-        (unsigned long long) ch->mid_futures,
-        ntohl (ch->mid_send.mid));
-}
-
-
-
-/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h
deleted file mode 100644 (file)
index 5167305..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_channel.h
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
-#define GNUNET_SERVICE_CADET_CHANNEL_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * A channel is a bidirectional connection between two CADET
- * clients.  Communiation can be reliable, unreliable, in-order
- * or out-of-order.  One client is the "local" client, this
- * one initiated the connection.   The other client is the
- * "incoming" client, this one listened on a port to accept
- * the connection from the "local" client.
- */
-struct CadetChannel;
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch);
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
-            enum GNUNET_ErrorType level);
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch);
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param owner_id local chid of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
-                        struct GNUNET_CADET_ClientChannelNumber owner_id,
-                        struct CadetPeer *destination,
-                        const struct GNUNET_HashCode *port,
-                        uint32_t options);
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to.  Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
-           struct CadetClient *c);
-
-
-/**
- * Destroy locally created channel.  Called by the
- * local client, so no need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
-                            struct CadetClient *c,
-                            struct GNUNET_CADET_ClientChannelNumber ccn);
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message.  Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch);
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param chid identifier of this channel in the tunnel
- * @param origin peer to who initiated the channel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
-                           struct GNUNET_CADET_ChannelTunnelNumber chid,
-                           const struct GNUNET_HashCode *port,
-                           uint32_t options);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel.  If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-
-/**
- * We got payload data for a channel.  Pass it on to the client.
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
-                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg);
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
-                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack);
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *        NULL if the ACK was inferred because we got payload or are on loopback
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
-                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection.  Also needs to remove this channel from
- * the tunnel.
- *
- * FIXME: need to make it possible to defer destruction until we have
- * received all messages up to the destroy, and right now the destroy
- * message (and this API) fails to give is the information we need!
- *
- * FIXME: also need to know if the other peer got a destroy from
- * us before!
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *            NULL during shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if
- * channel is reliable and send an ACK to the client if there is still
- * buffer space in the tunnel.
- *
- * @param ch Channel.
- * @param sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- *         #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
-                        const char *buf,
-                        size_t buf_len);
-
-
-/**
- * Handle ACK from client on local channel.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
-                       struct GNUNET_CADET_ClientChannelNumber client_ccn);
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
deleted file mode 100644 (file)
index 6976e66..0000000
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.c
- * @brief management of CORE-level end-to-end connections; establishes
- *        end-to-end routes and transmits messages along the route
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#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"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetConnectionState
-{
-  /**
-   * Uninitialized status, we have not yet even gotten the message queue.
-   */
-  CADET_CONNECTION_NEW,
-
-  /**
-   * Connection create message in queue, awaiting transmission by CORE.
-   */
-  CADET_CONNECTION_SENDING_CREATE,
-
-  /**
-   * Connection create message sent, waiting for ACK.
-   */
-  CADET_CONNECTION_SENT,
-
-  /**
-   * We are an inbound connection, and received a CREATE. Need to
-   * send an CREATE_ACK back.
-   */
-  CADET_CONNECTION_CREATE_RECEIVED,
-
-  /**
-   * Connection confirmed, ready to carry traffic.
-   */
-  CADET_CONNECTION_READY
-
-};
-
-
-/**
- * Low-level connection to a destination.
- */
-struct CadetConnection
-{
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  /**
-   * To which peer does this connection go?
-   */
-  struct CadetPeer *destination;
-
-  /**
-   * Which tunnel is using this connection?
-   */
-  struct CadetTConnection *ct;
-
-  /**
-   * Path we are using to our destination.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Pending message, NULL if we are ready to transmit.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-  /**
-   * Handle for calling #GCP_request_mq_cancel() once we are finished.
-   */
-  struct GCP_MessageQueueManager *mq_man;
-
-  /**
-   * Task for connection maintenance.
-   */
-  struct GNUNET_SCHEDULER_Task *task;
-
-  /**
-   * Queue entry for keepalive messages.
-   */
-  struct CadetTunnelQueueEntry *keepalive_qe;
-
-  /**
-   * Function to call once we are ready to transmit.
-   */
-  GCC_ReadyCallback ready_cb;
-
-  /**
-   * Closure for @e ready_cb.
-   */
-  void *ready_cb_cls;
-
-  /**
-   * How long do we wait before we try again with a CREATE message?
-   */
-  struct GNUNET_TIME_Relative retry_delay;
-
-  /**
-   * Performance metrics for this connection.
-   */
-  struct CadetConnectionMetrics metrics;
-
-  /**
-   * State of the connection.
-   */
-  enum CadetConnectionState state;
-
-  /**
-   * Options for the route, control buffering.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-
-  /**
-   * How many latency observations did we make for this connection?
-   */
-  unsigned int latency_datapoints;
-
-  /**
-   * Offset of our @e destination in @e path.
-   */
-  unsigned int off;
-
-  /**
-   * Are we ready to transmit via @e mq_man right now?
-   */
-  int mqm_ready;
-
-};
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  return GNUNET_CONTAINER_multishortmap_get (connections,
-                                             &cid->connection_of_tunnel);
-}
-
-
-/**
- * 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
- */
-static void
-GCC_destroy (struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying %s\n",
-       GCC_2s (cc));
-  if (NULL != cc->mq_man)
-  {
-    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;
-  }
-  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,
-                                                        cc));
-  GNUNET_free (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.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc)
-{
-  return cc->ct;
-}
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc)
-{
-  return &cc->metrics;
-}
-
-
-/**
- * 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.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-keepalive_done (void *cls,
-                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  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);
-}
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetConnection *cc;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  cc->metrics.num_acked_transmissions++;
-}
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cti connection identifier where we got an ACK for a message
- *            that was originally sent via this connection (the ACK
- *            may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetConnection *cc;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  cc->metrics.num_successes++;
-}
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti.  (The same connection was taken
- * in both directions.)
- *
- * @param cid connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                      struct GNUNET_TIME_Relative latency)
-{
-  struct CadetConnection *cc;
-  double weight;
-  double result;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  GNUNET_STATISTICS_update (stats,
-                            "# latencies observed",
-                            1,
-                            GNUNET_NO);
-  cc->latency_datapoints++;
-  if (cc->latency_datapoints >= 7)
-    weight = 7.0;
-  else
-    weight = cc->latency_datapoints;
-  /* Compute weighted average, giving at MOST weight 7 to the
-     existing values, or less if that value is based on fewer than 7
-     measurements. */
-  result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
-  result /= (weight + 1.0);
-  cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
-}
-
-
-/**
- * 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.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
-       GCC_2s (cc),
-       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;
-  }
-  cc->metrics.age = GNUNET_TIME_absolute_get ();
-  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);
-}
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *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 (cc->ct,
-                 msg);
-}
-
-
-/**
- * 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.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  if (CADET_CONNECTION_SENT == cc->state)
-  {
-    /* 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 %s due to ENCRYPTED payload\n",
-         GCC_2s (cc));
-    GCC_handle_connection_create_ack (cc);
-  }
-  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
-  GCT_handle_encrypted (cc->ct,
-                        msg);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
- * first hop.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create (void *cls)
-{
-  struct CadetConnection *cc = cls;
-  struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
-  struct GNUNET_PeerIdentity *pids;
-  struct GNUNET_MQ_Envelope *env;
-  unsigned int path_length;
-
-  cc->task = NULL;
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  path_length = GCPP_get_length (cc->path);
-  env = GNUNET_MQ_msg_extra (create_msg,
-                             (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=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 CADET_CONNECTION_CREATE message for %s\n",
-       GCC_2s (cc));
-  cc->env = env;
-  update_state (cc,
-                CADET_CONNECTION_SENT,
-                GNUNET_NO);
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * Send a CREATE_ACK message towards the origin.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create_ack (void *cls)
-{
-  struct CadetConnection *cc = cls;
-  struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
-  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 %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;
-  update_state (cc,
-                CADET_CONNECTION_READY,
-                GNUNET_NO);
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have.  Either our ACK got lost
- * or something is fishy.  Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc)
-{
-  if (GNUNET_YES == cc->mqm_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "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. */
-    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);
-  }
-  else
-  {
-    /* We are currently sending something else back, which
-       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 %s. MQ is busy, not queueing another ACK\n",
-         GCC_2s (cc));
-  }
-}
-
-
-/**
- * There has been a change in the message queue existence for our
- * peer at the first hop.  Adjust accordingly.
- *
- * @param cls the `struct CadetConnection`
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-static void
-manage_first_hop_mq (void *cls,
-                     int available)
-{
-  struct CadetConnection *cc = cls;
-
-  if (GNUNET_YES != available)
-  {
-    /* Connection is down, for now... */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Core MQ for %s went down\n",
-         GCC_2s (cc));
-    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;
-    }
-    return;
-  }
-
-  update_state (cc,
-                cc->state,
-                GNUNET_YES);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Core MQ for %s became available in state %d\n",
-       GCC_2s (cc),
-       cc->state);
-  switch (cc->state)
-  {
-  case CADET_CONNECTION_NEW:
-    /* Transmit immediately */
-    cc->task = GNUNET_SCHEDULER_add_now (&send_create,
-                                         cc);
-    break;
-  case CADET_CONNECTION_SENDING_CREATE:
-    /* Should not be possible to be called in this state. */
-    GNUNET_assert (0);
-    break;
-  case CADET_CONNECTION_SENT:
-    /* Retry a bit later... */
-    cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
-    cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
-                                             &send_create,
-                                             cc);
-    break;
-  case CADET_CONNECTION_CREATE_RECEIVED:
-    /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
-    cc->metrics.age = GNUNET_TIME_absolute_get ();
-    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
-                                         cc);
-    break;
-  case CADET_CONNECTION_READY:
-    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;
-  }
-}
-
-
-/**
- * Create a connection to @a destination via @a path and notify @a cb
- * whenever we are ready for more data.  Shared logic independent of
- * who is initiating the connection.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a 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
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-static struct CadetConnection *
-connection_create (struct CadetPeer *destination,
-                   struct CadetPeerPath *path,
-                   unsigned int off,
-                   enum GNUNET_CADET_ChannelOption options,
-                   struct CadetTConnection *ct,
-                   const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                   enum CadetConnectionState init_state,
-                   GCC_ReadyCallback ready_cb,
-                   void *ready_cb_cls)
-{
-  struct CadetConnection *cc;
-  struct CadetPeer *first_hop;
-
-  cc = GNUNET_new (struct CadetConnection);
-  cc->options = options;
-  cc->state = init_state;
-  cc->ct = ct;
-  cc->cid = *cid;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (connections,
-                                                     &GCC_get_id (cc)->connection_of_tunnel,
-                                                     cc,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  cc->ready_cb = ready_cb;
-  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,
-                                                 i),
-                        cc);
-
-  first_hop = GCPP_get_peer_at_offset (path,
-                                       0);
-  cc->mq_man = GCP_request_mq (first_hop,
-                               &manage_first_hop_mq,
-                               cc);
-  return cc;
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.  This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @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, 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,
-                            off,
-                            options,
-                            ct,
-                            cid,
-                            CADET_CONNECTION_CREATE_RECEIVED,
-                            ready_cb,
-                            ready_cb_cls);
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a 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
- * @return handle to the connection
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
-            struct CadetPeerPath *path,
-            unsigned int off,
-            enum GNUNET_CADET_ChannelOption options,
-            struct CadetTConnection *ct,
-            GCC_ReadyCallback ready_cb,
-            void *ready_cb_cls)
-{
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
-                              &cid,
-                              sizeof (cid));
-  return connection_create (destination,
-                            path,
-                            off,
-                            options,
-                            ct,
-                            &cid,
-                            CADET_CONNECTION_NEW,
-                            ready_cb,
-                            ready_cb_cls);
-}
-
-
-/**
- * Transmit message @a msg via connection @a cc.  Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCC_transmit (struct CadetConnection *cc,
-              struct GNUNET_MQ_Envelope *env)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Scheduling message for transmission on %s\n",
-       GCC_2s (cc));
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  GNUNET_assert (CADET_CONNECTION_READY == cc->state);
-  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
-  cc->mqm_ready = GNUNET_NO;
-  if (NULL != cc->task)
-  {
-    GNUNET_SCHEDULER_cancel (cc->task);
-    cc->task = NULL;
-  }
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc)
-{
-  return cc->path;
-}
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc)
-{
-  return &cc->cid;
-}
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc)
-{
-  static char buf[128];
-
-  if (NULL == cc)
-    return "Connection(NULL)";
-
-  if (NULL != cc->ct)
-  {
-    GNUNET_snprintf (buf,
-                     sizeof (buf),
-                     "Connection %s (%s)",
-                     GNUNET_sh2s (&cc->cid.connection_of_tunnel),
-                     GCT_2s (cc->ct->t));
-    return buf;
-  }
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Connection %s",
-                   GNUNET_sh2s (&cc->cid.connection_of_tunnel));
-  return buf;
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
-           enum GNUNET_ErrorType level)
-{
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-con",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-  if (NULL == cc)
-  {
-    LOG2 (level,
-          "Connection (NULL)\n");
-    return;
-  }
-  LOG2 (level,
-        "%s to %s via path %s in state %d is %s\n",
-        GCC_2s (cc),
-        GCP_2s (cc->destination),
-        GCPP_2s (cc->path),
-        cc->state,
-        (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
-}
-
-/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h
deleted file mode 100644 (file)
index e48b208..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.h
- * @brief A connection is a live end-to-end messaging mechanism
- *       where the peers are identified by a path and know how
- *       to forward along the route using a connection identifier
- *       for routing the data.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
-#define GNUNET_SERVICE_CADET_CONNECTION_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * Function called to notify tunnel about change in our readyness.
- *
- * @param cls closure
- * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
- *                 #GNUNET_NO if the connection is no longer ready for transmission
- */
-typedef void
-(*GCC_ReadyCallback)(void *cls,
-                     int is_ready);
-
-
-/**
- * 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);
-
-
-/**
- * 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);
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a 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
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
-            struct CadetPeerPath *path,
-            unsigned int off,
-            enum GNUNET_CADET_ChannelOption options,
-            struct CadetTConnection *ct,
-            GCC_ReadyCallback ready_cb,
-            void *ready_cb_cls);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.  This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @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, 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);
-
-
-/**
- * Transmit message @a msg via connection @a cc.  Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit;
- *            the #GNUNET_MQ_notify_send() must not have yet been used
- *            for the envelope.  Also, the message better match the
- *            connection identifier of this connection...
- */
-void
-GCC_transmit (struct CadetConnection *cc,
-              struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * A CREATE_ACK was received for this connection, process it.
- *
- * @param cc the connection that got the ACK.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have.  Either our ACK got lost
- * or something is fishy.  Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc);
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * 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);
-
-
-/**
- * Performance metrics for a connection.
- */
-struct CadetConnectionMetrics
-{
-
-  /**
-   * Our current best estimate of the latency, based on a weighted
-   * average of at least @a latency_datapoints values.
-   */
-  struct GNUNET_TIME_Relative aged_latency;
-
-  /**
-   * When was this connection first established? (by us sending or
-   * receiving the CREATE_ACK for the first time)
-   */
-  struct GNUNET_TIME_Absolute age;
-
-  /**
-   * When was this connection last used? (by us sending or
-   * receiving a PAYLOAD message on it)
-   */
-  struct GNUNET_TIME_Absolute last_use;
-
-  /**
-   * How many packets that ought to generate an ACK did we send via
-   * this connection?
-   */
-  unsigned long long num_acked_transmissions;
-
-  /**
-   * Number of packets that were sent via this connection did actually
-   * receive an ACK?  (Note: ACKs may be transmitted and lost via
-   * other connections, so this value should only be interpreted
-   * relative to @e num_acked_transmissions and in relation to other
-   * connections.)
-   */
-  unsigned long long num_successes;
-
-};
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc);
-
-
-/**
- * Handle encrypted message.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we got an ACK for a message
- *            that was originally sent via this connection (the ACK
- *            may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti.  (The same connection was taken
- * in both directions.)
- *
- * @param cti connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                      struct GNUNET_TIME_Relative latency);
-
-
-/**
- * Return the tunnel associated with this connection.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc);
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc);
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc);
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc);
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
-           enum GNUNET_ErrorType level);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_core.c b/src/cadet/gnunet-service-cadet-new_core.c
deleted file mode 100644 (file)
index 3768c36..0000000
+++ /dev/null
@@ -1,1356 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_core.c
- * @brief cadet service; interaction with CORE service
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
- *
- * TODO:
- * - Optimization: given BROKEN messages, destroy paths (?)
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new_core.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
-
-/**
- * Information we keep per direction for a route.
- */
-struct RouteDirection;
-
-
-/**
- * Set of CadetRoutes that have exactly the same number of messages
- * in their buffer.  Used so we can efficiently find all of those
- * routes that have the current maximum of messages in the buffer (in
- * case we have to purge).
- */
-struct Rung
-{
-
-  /**
-   * Rung of RouteDirections with one more buffer entry each.
-   */
-  struct Rung *next;
-
-  /**
-   * Rung of RouteDirections with one less buffer entry each.
-   */
-  struct Rung *prev;
-
-  /**
-   * DLL of route directions with a number of buffer entries matching this rung.
-   */
-  struct RouteDirection *rd_head;
-
-  /**
-   * DLL of route directions with a number of buffer entries matching this rung.
-   */
-  struct RouteDirection *rd_tail;
-
-  /**
-   * Total number of route directions in this rung.
-   */
-  unsigned int num_routes;
-
-  /**
-   * Number of messages route directions at this rung have
-   * in their buffer.
-   */
-  unsigned int rung_off;
-};
-
-
-/**
- * Information we keep per direction for a route.
- */
-struct RouteDirection
-{
-
-  /**
-   * DLL of other route directions within the same `struct Rung`.
-   */
-  struct RouteDirection *prev;
-
-  /**
-   * DLL of other route directions within the same `struct Rung`.
-   */
-  struct RouteDirection *next;
-
-  /**
-   * Rung of this route direction (matches length of the buffer DLL).
-   */
-  struct Rung *rung;
-
-  /**
-   * Head of DLL of envelopes we have in the buffer for this direction.
-   */
-  struct GNUNET_MQ_Envelope *env_head;
-
-  /**
-   * Tail of DLL of envelopes we have in the buffer for this direction.
-   */
-  struct GNUNET_MQ_Envelope *env_tail;
-
-  /**
-   * Target peer.
-   */
-  struct CadetPeer *hop;
-
-  /**
-   * Route this direction is part of.
-   */
-  struct CadetRoute *my_route;
-
-  /**
-   * Message queue manager for @e hop.
-   */
-  struct GCP_MessageQueueManager *mqm;
-
-  /**
-   * Is @e mqm currently ready for transmission?
-   */
-  int is_ready;
-
-};
-
-
-/**
- * Description of a segment of a `struct CadetConnection` at the
- * intermediate peers.  Routes are basically entries in a peer's
- * routing table for forwarding traffic.  At both endpoints, the
- * routes are terminated by a `struct CadetConnection`, which knows
- * the complete `struct CadetPath` that is formed by the individual
- * routes.
- */
-struct CadetRoute
-{
-
-  /**
-   * Information about the next hop on this route.
-   */
-  struct RouteDirection next;
-
-  /**
-   * Information about the previous hop on this route.
-   */
-  struct RouteDirection prev;
-
-  /**
-   * Unique identifier for the connection that uses this route.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  /**
-   * When was this route last in use?
-   */
-  struct GNUNET_TIME_Absolute last_use;
-
-  /**
-   * Position of this route in the #route_heap.
-   */
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  /**
-   * Options for the route, control buffering.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-};
-
-
-/**
- * Handle to the CORE service.
- */
-static struct GNUNET_CORE_Handle *core;
-
-/**
- * Routes on which this peer is an intermediate.
- */
-static struct GNUNET_CONTAINER_MultiShortmap *routes;
-
-/**
- * Heap of routes, MIN-sorted by last activity.
- */
-static struct GNUNET_CONTAINER_Heap *route_heap;
-
-/**
- * Rung zero (always pointed to by #rung_head).
- */
-static struct Rung rung_zero;
-
-/**
- * DLL of rungs, with the head always point to a rung of
- * route directions with no messages in the queue.
- */
-static struct Rung *rung_head = &rung_zero;
-
-/**
- * Tail of the #rung_head DLL.
- */
-static struct Rung *rung_tail = &rung_zero;
-
-/**
- * Maximum number of concurrent routes this peer will support.
- */
-static unsigned long long max_routes;
-
-/**
- * Maximum number of envelopes we will buffer at this peer.
- */
-static unsigned long long max_buffers;
-
-/**
- * Current number of envelopes we have buffered at this peer.
- */
-static unsigned long long cur_buffers;
-
-/**
- * Task to timeout routes.
- */
-static struct GNUNET_SCHEDULER_Task *timeout_task;
-
-
-/**
- * Get the route corresponding to a hash.
- *
- * @param cid hash generated from the connection identifier
- */
-static struct CadetRoute *
-get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  return GNUNET_CONTAINER_multishortmap_get (routes,
-                                             &cid->connection_of_tunnel);
-}
-
-
-/**
- * Lower the rung in which @a dir is by 1.
- *
- * @param dir direction to lower in rung.
- */
-static void
-lower_rung (struct RouteDirection *dir)
-{
-  struct Rung *rung = dir->rung;
-  struct Rung *prev;
-
-  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
-                               rung->rd_tail,
-                               dir);
-  prev = rung->prev;
-  GNUNET_assert (NULL != prev);
-  if (prev->rung_off != rung->rung_off - 1)
-  {
-    prev = GNUNET_new (struct Rung);
-    prev->rung_off = rung->rung_off - 1;
-    GNUNET_CONTAINER_DLL_insert_after (rung_head,
-                                       rung_tail,
-                                       rung->prev,
-                                       prev);
-  }
-  GNUNET_assert (NULL != prev);
-  GNUNET_CONTAINER_DLL_insert (prev->rd_head,
-                               prev->rd_tail,
-                               dir);
-  dir->rung = prev;
-}
-
-
-/**
- * Discard the buffer @a env from the route direction @a dir and
- * move @a dir down a rung.
- *
- * @param dir direction that contains the @a env in the buffer
- * @param env envelope to discard
- */
-static void
-discard_buffer (struct RouteDirection *dir,
-                struct GNUNET_MQ_Envelope *env)
-{
-  GNUNET_MQ_dll_remove (&dir->env_head,
-                        &dir->env_tail,
-                        env);
-  cur_buffers--;
-  GNUNET_MQ_discard (env);
-  lower_rung (dir);
-  GNUNET_STATISTICS_set (stats,
-                         "# buffer use",
-                         cur_buffers,
-                         GNUNET_NO);
-}
-
-
-/**
- * Discard all messages from the highest rung, to make space.
- */
-static void
-discard_all_from_rung_tail ()
-{
-  struct Rung *tail = rung_tail;
-  struct RouteDirection *dir;
-
-  while (NULL != (dir = tail->rd_head))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Queue full due new message %s on connection %s, dropping old message\n",
-         GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
-    GNUNET_STATISTICS_update (stats,
-                              "# messages dropped due to full buffer",
-                              1,
-                              GNUNET_NO);
-    discard_buffer (dir,
-                    dir->env_head);
-  }
-  GNUNET_CONTAINER_DLL_remove (rung_head,
-                               rung_tail,
-                               tail);
-  GNUNET_free (tail);
-}
-
-
-/**
- * We message @a msg from @a prev.  Find its route by @a cid and
- * forward to the next hop.  Drop and signal broken route if we do not
- * have a route.
- *
- * @param prev previous hop (sender)
- * @param cid connection identifier, tells us which route to use
- * @param msg the message to forward
- */
-static void
-route_message (struct CadetPeer *prev,
-               const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-               const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetRoute *route;
-  struct RouteDirection *dir;
-  struct Rung *rung;
-  struct Rung *nxt;
-  struct GNUNET_MQ_Envelope *env;
-
-  route = get_route (cid);
-  if (NULL == route)
-  {
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to route message of type %u from %s on connection %s: no route\n",
-         ntohs (msg->type),
-         GCP_2s (prev),
-         GNUNET_sh2s (&cid->connection_of_tunnel));
-    switch (ntohs (msg->type))
-    {
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-      /* No need to respond to these! */
-      return;
-    }
-    env = GNUNET_MQ_msg (bm,
-                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-    bm->cid = *cid;
-    bm->peer1 = my_full_id;
-    GCP_send_ooo (prev,
-                  env);
-    return;
-  }
-  route->last_use = GNUNET_TIME_absolute_get ();
-  GNUNET_CONTAINER_heap_update_cost (route->hn,
-                                     route->last_use.abs_value_us);
-  dir = (prev == route->prev.hop) ? &route->next : &route->prev;
-  if (GNUNET_YES == dir->is_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Routing message of type %u from %s to %s on connection %s\n",
-         ntohs (msg->type),
-         GCP_2s (prev),
-         GNUNET_i2s (GCP_get_id (dir->hop)),
-         GNUNET_sh2s (&cid->connection_of_tunnel));
-    dir->is_ready = GNUNET_NO;
-    GCP_send (dir->mqm,
-              GNUNET_MQ_msg_copy (msg));
-    return;
-  }
-  /* Check if buffering is disallowed, and if so, make sure we only queue
-     one message per direction. */
-  if ( (0 != (route->options & GNUNET_CADET_OPTION_NOBUFFER)) &&
-       (NULL != dir->env_head) )
-    discard_buffer (dir,
-                    dir->env_head);
-  rung = dir->rung;
-  if (cur_buffers == max_buffers)
-  {
-    /* Need to make room. */
-    if (NULL != rung->next)
-    {
-      /* Easy case, drop messages from route directions in highest rung */
-      discard_all_from_rung_tail ();
-    }
-    else
-    {
-      /* We are in the highest rung, drop our own! */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Queue full due new message %s on connection %s, dropping old message\n",
-           GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
-      GNUNET_STATISTICS_update (stats,
-                                "# messages dropped due to full buffer",
-                                1,
-                                GNUNET_NO);
-      discard_buffer (dir,
-                      dir->env_head);
-      rung = dir->rung;
-    }
-  }
-  /* remove 'dir' from current rung */
-  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
-                               rung->rd_tail,
-                               dir);
-  /* make 'nxt' point to the next higher rung, creat if necessary */
-  nxt = rung->next;
-  if ( (NULL == nxt) ||
-       (rung->rung_off + 1 != nxt->rung_off) )
-  {
-    nxt = GNUNET_new (struct Rung);
-    nxt->rung_off = rung->rung_off + 1;
-    GNUNET_CONTAINER_DLL_insert_after (rung_head,
-                                       rung_tail,
-                                       rung,
-                                       nxt);
-  }
-  /* insert 'dir' into next higher rung */
-  GNUNET_CONTAINER_DLL_insert (nxt->rd_head,
-                               nxt->rd_tail,
-                               dir);
-  dir->rung = nxt;
-
-  /* add message into 'dir' buffer */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queueing new message of type %u from %s to %s on connection %s\n",
-       ntohs (msg->type),
-       GCP_2s (prev),
-       GNUNET_i2s (GCP_get_id (dir->hop)),
-       GNUNET_sh2s (&cid->connection_of_tunnel));
-  env = GNUNET_MQ_msg_copy (msg);
-  GNUNET_MQ_dll_insert_tail (&dir->env_head,
-                             &dir->env_tail,
-                             env);
-  cur_buffers++;
-  GNUNET_STATISTICS_set (stats,
-                         "# buffer use",
-                         cur_buffers,
-                         GNUNET_NO);
-  /* Clean up 'rung' if now empty (and not head) */
-  if ( (NULL == rung->rd_head) &&
-       (rung != rung_head) )
-  {
-    GNUNET_CONTAINER_DLL_remove (rung_head,
-                                 rung_tail,
-                                 rung);
-    GNUNET_free (rung);
-  }
-}
-
-
-/**
- * Check if the create_connection message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_connection_create (void *cls,
-                         const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
-
-  if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-
-
-/**
- * Free internal data of a route direction.
- *
- * @param dir direction to destroy (do NOT free memory of 'dir' itself)
- */
-static void
-destroy_direction (struct RouteDirection *dir)
-{
-  struct GNUNET_MQ_Envelope *env;
-
-  while (NULL != (env = dir->env_head))
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# messages dropped due to route destruction",
-                              1,
-                              GNUNET_NO);
-    discard_buffer (dir,
-                    env);
-  }
-  if (NULL != dir->mqm)
-  {
-    GCP_request_mq_cancel (dir->mqm,
-                           NULL);
-    dir->mqm = NULL;
-  }
-  GNUNET_CONTAINER_DLL_remove (rung_head->rd_head,
-                               rung_head->rd_tail,
-                               dir);
-}
-
-
-/**
- * Destroy our state for @a route.
- *
- * @param route route to destroy
- */
-static void
-destroy_route (struct CadetRoute *route)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying route from %s to %s of connection %s\n",
-       GNUNET_i2s  (GCP_get_id (route->prev.hop)),
-       GNUNET_i2s2 (GCP_get_id (route->next.hop)),
-       GNUNET_sh2s (&route->cid.connection_of_tunnel));
-  GNUNET_assert (route ==
-                 GNUNET_CONTAINER_heap_remove_node (route->hn));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_remove (routes,
-                                                        &route->cid.connection_of_tunnel,
-                                                        route));
-  GNUNET_STATISTICS_set (stats,
-                         "# routes",
-                         GNUNET_CONTAINER_multishortmap_size (routes),
-                         GNUNET_NO);
-  destroy_direction (&route->prev);
-  destroy_direction (&route->next);
-  GNUNET_free (route);
-}
-
-
-/**
- * Send message that a route is broken between @a peer1 and @a peer2.
- *
- * @param target where to send the message
- * @param cid connection identifier to use
- * @param peer1 one of the peers where a link is broken
- * @param peer2 another one of the peers where a link is broken
- */
-static void
-send_broken (struct RouteDirection *target,
-             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-             const struct GNUNET_PeerIdentity *peer1,
-             const struct GNUNET_PeerIdentity *peer2)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-  if (NULL == target->mqm)
-    return; /* Can't send notification, connection is down! */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Notifying %s about BROKEN route at %s-%s of connection %s\n",
-       GCP_2s (target->hop),
-       GNUNET_i2s (peer1),
-       GNUNET_i2s2 (peer2),
-       GNUNET_sh2s (&cid->connection_of_tunnel));
-
-  env = GNUNET_MQ_msg (bm,
-                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  bm->cid = *cid;
-  if (NULL != peer1)
-    bm->peer1 = *peer1;
-  if (NULL != peer2)
-    bm->peer2 = *peer2;
-  GCP_request_mq_cancel (target->mqm,
-                         env);
-  target->mqm = NULL;
-}
-
-
-/**
- * Function called to check if any routes have timed out, and if
- * so, to clean them up.  Finally, schedules itself again at the
- * earliest time where there might be more work.
- *
- * @param cls NULL
- */
-static void
-timeout_cb (void *cls)
-{
-  struct CadetRoute *r;
-  struct GNUNET_TIME_Relative linger;
-  struct GNUNET_TIME_Absolute exp;
-
-  timeout_task = NULL;
-  linger = GNUNET_TIME_relative_multiply (keepalive_period,
-                                          3);
-  while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
-  {
-    exp = GNUNET_TIME_absolute_add (r->last_use,
-                                    linger);
-    if (0 != GNUNET_TIME_absolute_get_duration (exp).rel_value_us)
-    {
-      /* Route not yet timed out, wait until it does. */
-      timeout_task = GNUNET_SCHEDULER_add_at (exp,
-                                              &timeout_cb,
-                                              NULL);
-      return;
-    }
-    send_broken (&r->prev,
-                 &r->cid,
-                 NULL,
-                 NULL);
-    send_broken (&r->next,
-                 &r->cid,
-                 NULL,
-                 NULL);
-    destroy_route (r);
-  }
-  /* No more routes left, so no need for a #timeout_task */
-}
-
-
-/**
- * Function called when the message queue to the previous hop
- * becomes available/unavailable.  We expect this function to
- * be called immediately when we register, and then again
- * later if the connection ever goes down.
- *
- * @param cls the `struct RouteDirection`
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-static void
-dir_ready_cb (void *cls,
-              int ready)
-{
-  struct RouteDirection *dir = cls;
-  struct CadetRoute *route = dir->my_route;
-  struct RouteDirection *odir;
-
-  if (GNUNET_YES == ready)
-  {
-    struct GNUNET_MQ_Envelope *env;
-
-    dir->is_ready = GNUNET_YES;
-    if (NULL != (env = dir->env_head))
-    {
-      GNUNET_MQ_dll_remove (&dir->env_head,
-                            &dir->env_tail,
-                            env);
-      cur_buffers--;
-      GNUNET_STATISTICS_set (stats,
-                             "# buffer use",
-                             cur_buffers,
-                             GNUNET_NO);
-      lower_rung (dir);
-      dir->is_ready = GNUNET_NO;
-      GCP_send (dir->mqm,
-                env);
-    }
-    return;
-  }
-  odir = (dir == &route->next) ? &route->prev : &route->next;
-  send_broken (&route->next,
-               &route->cid,
-               GCP_get_id (odir->hop),
-               &my_full_id);
-  destroy_route (route);
-}
-
-
-/**
- * Initialize one of the directions of a route.
- *
- * @param route route the direction belongs to
- * @param dir direction to initialize
- * @param hop next hop on in the @a dir
- */
-static void
-dir_init (struct RouteDirection *dir,
-          struct CadetRoute *route,
-          struct CadetPeer *hop)
-{
-  dir->hop = hop;
-  dir->my_route = route;
-  dir->mqm = GCP_request_mq (hop,
-                             &dir_ready_cb,
-                             dir);
-  GNUNET_CONTAINER_DLL_insert (rung_head->rd_head,
-                               rung_head->rd_tail,
-                               dir);
-  dir->rung = rung_head;
-  GNUNET_assert (GNUNET_YES == dir->is_ready);
-}
-
-
-/**
- * We could not create the desired route.  Send a
- * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- * message to @a target.
- *
- * @param target who should receive the message
- * @param cid identifier of the connection/route that failed
- * @param failure_at neighbour with which we failed to route,
- *        or NULL.
- */
-static void
-send_broken_without_mqm (struct CadetPeer *target,
-                         const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                         const struct GNUNET_PeerIdentity *failure_at)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-  env = GNUNET_MQ_msg (bm,
-                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  bm->cid = *cid;
-  bm->peer1 = my_full_id;
-  if (NULL != failure_at)
-    bm->peer2 = *failure_at;
-  GCP_send_ooo (target,
-                env);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_create (void *cls,
-                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-  struct CadetPeer *sender = cls;
-  struct CadetPeer *next;
-  const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
-  struct CadetRoute *route;
-  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
-  unsigned int path_length;
-  unsigned int off;
-  enum GNUNET_CADET_ChannelOption options;
-
-  options = (enum GNUNET_CADET_ChannelOption) ntohl (msg->options);
-  path_length = size / sizeof (struct GNUNET_PeerIdentity);
-  /* Initiator is at offset 0. */
-  for (off=1;off<path_length;off++)
-    if (0 == memcmp (&my_full_id,
-                     &pids[off],
-                     sizeof (struct GNUNET_PeerIdentity)))
-      break;
-  if (off == path_length)
-  {
-    /* We are not on the path, bogus request */
-    GNUNET_break_op (0);
-    return;
-  }
-  /* Check previous hop */
-  if (sender != GCP_get (&pids[off - 1],
-                         GNUNET_NO))
-  {
-    /* sender is not on the path, not allowed */
-    GNUNET_break_op (0);
-    return;
-  }
-  if (NULL !=
-      get_route (&msg->cid))
-  {
-    /* Duplicate CREATE, pass it on, previous one might have been lost! */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    route_message (sender,
-                   &msg->cid,
-                   &msg->header);
-    return;
-  }
-  if (off == path_length - 1)
-  {
-    /* We are the destination, create connection */
-    struct CadetConnection *cc;
-    struct CadetPeerPath *path;
-    struct CadetPeer *origin;
-
-    cc = GCC_lookup (&msg->cid);
-    if (NULL != cc)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
-           GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-      GCC_handle_duplicate_create (cc);
-      return;
-    }
-
-    origin = GCP_get (&pids[0],
-                      GNUNET_YES);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
-         GCP_2s (origin),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    path = GCPP_get_path_from_route (path_length - 1,
-                                     pids);
-    if (GNUNET_OK !=
-        GCT_add_inbound_connection (GCP_get_tunnel (origin,
-                                                    GNUNET_YES),
-                                    &msg->cid,
-                                    (enum GNUNET_CADET_ChannelOption) ntohl (msg->options),
-                                    path))
-    {
-      /* Send back BROKEN: duplicate connection on the same path,
-         we will use the other one. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
-           GCP_2s (sender),
-           GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-           GCPP_2s (path));
-      send_broken_without_mqm (sender,
-                               &msg->cid,
-                               NULL);
-      return;
-    }
-    return;
-  }
-  /* We are merely a hop on the way, check if we can support the route */
-  next = GCP_get (&pids[off + 1],
-                  GNUNET_NO);
-  if ( (NULL == next) ||
-       (GNUNET_NO == GCP_has_core_connection (next)) )
-  {
-    /* unworkable, send back BROKEN notification */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
-         GCP_2s (sender),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-         GNUNET_i2s (&pids[off + 1]),
-         off + 1);
-    send_broken_without_mqm (sender,
-                             &msg->cid,
-                             &pids[off + 1]);
-    return;
-  }
-  if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
-         GCP_2s (sender),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    send_broken_without_mqm (sender,
-                             &msg->cid,
-                             &pids[off - 1]);
-    return;
-  }
-
-  /* Workable route, create routing entry */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
-       GCP_2s (sender),
-       GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-       GNUNET_i2s (&pids[off + 1]),
-       off + 1);
-  route = GNUNET_new (struct CadetRoute);
-  route->options = options;
-  route->cid = msg->cid;
-  route->last_use = GNUNET_TIME_absolute_get ();
-  dir_init (&route->prev,
-            route,
-            sender);
-  dir_init (&route->next,
-            route,
-            next);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (routes,
-                                                     &route->cid.connection_of_tunnel,
-                                                     route,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  GNUNET_STATISTICS_set (stats,
-                         "# routes",
-                         GNUNET_CONTAINER_multishortmap_size (routes),
-                         GNUNET_NO);
-  route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
-                                            route,
-                                            route->last_use.abs_value_us);
-  if (NULL == timeout_task)
-    timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (keepalive_period,
-                                                                                3),
-                                                 &timeout_cb,
-                                                 NULL);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_create_ack (void *cls,
-                              const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if ACK belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify ACK came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received ACK from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_CREATE_ACK for connection %s.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    GCC_handle_connection_create_ack (cc);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- * @deprecated duplicate logic with #handle_destroy(); dedup!
- */
-static void
-handle_connection_broken (void *cls,
-                          const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-  struct CadetRoute *route;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    GCC_destroy_without_core (cc);
-
-    /* FIXME: also destroy the path up to the specified link! */
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-  route = get_route (&msg->cid);
-  if (NULL != route)
-    destroy_route (route);
-  /* FIXME: also destroy paths we MAY have up to the specified link! */
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_destroy (void *cls,
-                           const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-  struct CadetRoute *route;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-
-    GCC_destroy_without_core (cc);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
-       GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-  route = get_route (&msg->cid);
-  if (NULL != route)
-    destroy_route (route);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_kx (void *cls,
-                  const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_kx (cc,
-                   msg);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_kx_auth (void *cls,
-                       const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->kx.cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_kx_auth (cc,
-                        msg);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->kx.cid,
-                 &msg->kx.header);
-}
-
-
-/**
- * Check if the encrypted message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_tunnel_encrypted (void *cls,
-                        const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  return GNUNET_YES;
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_encrypted (void *cls,
-                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_encrypted (cc,
-                          msg);
-    return;
-  }
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Function called after #GNUNET_CORE_connect has succeeded (or failed
- * for good).  Note that the private key of the peer is intentionally
- * not exposed here; if you need it, your process should try to read
- * the private key file directly (which should work if you are
- * authorized...).  Implementations of this function must not call
- * #GNUNET_CORE_disconnect (other than by scheduling a new task to
- * do this later).
- *
- * @param cls closure
- * @param my_identity ID of this peer, NULL if we failed
- */
-static void
-core_init_cb (void *cls,
-              const struct GNUNET_PeerIdentity *my_identity)
-{
-  if (NULL == my_identity)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_break (0 ==
-                memcmp (my_identity,
-                        &my_full_id,
-                        sizeof (struct GNUNET_PeerIdentity)));
-}
-
-
-/**
- * Method called whenever a given peer connects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void *
-core_connect_cb (void *cls,
-                 const struct GNUNET_PeerIdentity *peer,
-                 struct GNUNET_MQ_Handle *mq)
-{
-  struct CadetPeer *cp;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "CORE connection to peer %s was established.\n",
-       GNUNET_i2s (peer));
-  cp = GCP_get (peer,
-                GNUNET_YES);
-  GCP_set_mq (cp,
-              mq);
-  return cp;
-}
-
-
-/**
- * Method called whenever a peer disconnects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void
-core_disconnect_cb (void *cls,
-                    const struct GNUNET_PeerIdentity *peer,
-                    void *peer_cls)
-{
-  struct CadetPeer *cp = peer_cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "CORE connection to peer %s went down.\n",
-       GNUNET_i2s (peer));
-  GCP_set_mq (cp,
-              NULL);
-}
-
-
-/**
- * Initialize the CORE subsystem.
- *
- * @param c Configuration.
- */
-void
-GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (connection_create,
-                           GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
-                           struct GNUNET_CADET_ConnectionCreateMessage,
-                           NULL),
-    GNUNET_MQ_hd_fixed_size (connection_create_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
-                             struct GNUNET_CADET_ConnectionCreateAckMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (connection_broken,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
-                             struct GNUNET_CADET_ConnectionBrokenMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (connection_destroy,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
-                             struct GNUNET_CADET_ConnectionDestroyMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (tunnel_kx,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
-                             struct GNUNET_CADET_TunnelKeyExchangeMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
-                             struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
-                             NULL),
-    GNUNET_MQ_hd_var_size (tunnel_encrypted,
-                           GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
-                           struct GNUNET_CADET_TunnelEncryptedMessage,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "MAX_ROUTES",
-                                             &max_routes))
-    max_routes = 5000;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "MAX_MSGS_QUEUE",
-                                             &max_buffers))
-    max_buffers = 10000;
-  routes = GNUNET_CONTAINER_multishortmap_create (1024,
-                                                  GNUNET_NO);
-  route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  core = GNUNET_CORE_connect (c,
-                              NULL,
-                              &core_init_cb,
-                              &core_connect_cb,
-                              &core_disconnect_cb,
-                              handlers);
-}
-
-
-/**
- * Shut down the CORE subsystem.
- */
-void
-GCO_shutdown ()
-{
-  if (NULL != core)
-  {
-    GNUNET_CORE_disconnect (core);
-    core = NULL;
-  }
-  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
-  GNUNET_CONTAINER_multishortmap_destroy (routes);
-  routes = NULL;
-  GNUNET_CONTAINER_heap_destroy (route_heap);
-  route_heap = NULL;
-  if (NULL != timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (timeout_task);
-    timeout_task = NULL;
-  }
-}
-
-/* end of gnunet-cadet-service_core.c */
diff --git a/src/cadet/gnunet-service-cadet-new_core.h b/src/cadet/gnunet-service-cadet-new_core.h
deleted file mode 100644 (file)
index 65b0a6b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_core.h
- * @brief cadet service; interaction with CORE service
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
- */
-
-#ifndef GNUNET_SERVICE_CADET_CORE_H
-#define GNUNET_SERVICE_CADET_CORE_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_util_lib.h"
-
-
-/**
- * Initialize the CORE subsystem.
- *
- * @param c Configuration.
- */
-void
-GCO_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the CORE subsystem.
- */
-void
-GCO_shutdown (void);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_CORE_H */
-#endif
-/* end of gnunet-cadet-service_core.h */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c
deleted file mode 100644 (file)
index 849562f..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_dht.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-/**
- * How long do we wait before first announcing our presence to the DHT.
- * Used to wait for our HELLO to be available.  Note that we also get
- * notifications when our HELLO is ready, so this is just the maximum
- * we wait for the first notification.
- */
-#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
-
-/**
- * How long do we wait after we get an updated HELLO before publishing?
- * Allows for the HELLO to be updated again quickly, for example in
- * case multiple addresses changed and we got a partial update.
- */
-#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
-
-
-/**
- * Handle for DHT searches.
- */
-struct GCD_search_handle
-{
-  /**
-   * DHT_GET handle.
-   */
-  struct GNUNET_DHT_GetHandle *dhtget;
-
-};
-
-
-/**
- * Handle to use DHT.
- */
-static struct GNUNET_DHT_Handle *dht_handle;
-
-/**
- * How often to PUT own ID in the DHT.
- */
-static struct GNUNET_TIME_Relative id_announce_time;
-
-/**
- * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
- */
-static unsigned long long dht_replication_level;
-
-/**
- * Task to periodically announce itself in the network.
- */
-static struct GNUNET_SCHEDULER_Task *announce_id_task;
-
-/**
- * Delay for the next ID announce.
- */
-static struct GNUNET_TIME_Relative announce_delay;
-
-
-/**
- * Function to process paths received for a new peer addition. The recorded
- * paths form the initial tunnel, which can be optimized later.
- * Called on each result obtained for the DHT search.
- *
- * @param cls closure
- * @param exp when will this value expire
- * @param key key of the result
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- * @param type type of the result
- * @param size number of bytes in data
- * @param data pointer to the result data
- */
-static void
-dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
-                    const struct GNUNET_HashCode *key,
-                    const struct GNUNET_PeerIdentity *get_path,
-                    unsigned int get_path_length,
-                    const struct GNUNET_PeerIdentity *put_path,
-                    unsigned int put_path_length,
-                    enum GNUNET_BLOCK_Type type,
-                    size_t size,
-                    const void *data)
-{
-  const struct GNUNET_HELLO_Message *hello = data;
-  struct CadetPeer *peer;
-
-  GCPP_try_path_from_dht (get_path,
-                          get_path_length,
-                          put_path,
-                          put_path_length);
-  if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
-       (ntohs (hello->header.size) == size) &&
-       (size == GNUNET_HELLO_size (hello)) )
-  {
-    peer = GCP_get (&put_path[0],
-                    GNUNET_YES);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got HELLO for %s\n",
-         GCP_2s (peer));
-    GCP_set_hello (peer,
-                   hello);
-  }
-}
-
-
-/**
- * Periodically announce self id in the DHT
- *
- * @param cls closure
- */
-static void
-announce_id (void *cls)
-{
-  struct GNUNET_HashCode phash;
-  const struct GNUNET_HELLO_Message *hello;
-  size_t size;
-  struct GNUNET_TIME_Absolute expiration;
-  struct GNUNET_TIME_Relative next_put;
-
-  hello = GCH_get_mine ();
-  size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
-  if (0 == size)
-  {
-    expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
-                                           announce_delay);
-    announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
-  }
-  else
-  {
-    expiration = GNUNET_HELLO_get_last_expiration (hello);
-    announce_delay = GNUNET_TIME_UNIT_SECONDS;
-  }
-
-  /* Call again in id_announce_time, unless HELLO expires first,
-   * but wait at least 1s. */
-  next_put
-    = GNUNET_TIME_absolute_get_remaining (expiration);
-  next_put
-    = GNUNET_TIME_relative_min (next_put,
-                                id_announce_time);
-  next_put
-    = GNUNET_TIME_relative_max (next_put,
-                                GNUNET_TIME_UNIT_SECONDS);
-  announce_id_task
-    = GNUNET_SCHEDULER_add_delayed (next_put,
-                                    &announce_id,
-                                    cls);
-  GNUNET_STATISTICS_update (stats,
-                            "# DHT announce",
-                            1,
-                            GNUNET_NO);
-  memset (&phash,
-          0,
-          sizeof (phash));
-  GNUNET_memcpy (&phash,
-                 &my_full_id,
-                 sizeof (my_full_id));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Announcing my HELLO (%u bytes) in the DHT\n",
-       size);
-  GNUNET_DHT_put (dht_handle,   /* DHT handle */
-                  &phash,       /* Key to use */
-                  dht_replication_level,     /* Replication level */
-                  GNUNET_DHT_RO_RECORD_ROUTE
-                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
-                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
-                  size,  /* Size of the data */
-                  (const char *) hello, /* Data itself */
-                  expiration,  /* Data expiration */
-                  NULL,         /* Continuation */
-                  NULL);        /* Continuation closure */
-}
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update ()
-{
-  if (NULL == announce_id_task)
-    return; /* too early */
-  GNUNET_SCHEDULER_cancel (announce_id_task);
-  announce_id_task
-    = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
-                                    &announce_id,
-                                    NULL);
-}
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "DHT_REPLICATION_LEVEL",
-                                             &dht_replication_level))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "DHT_REPLICATION_LEVEL",
-                               "USING DEFAULT");
-    dht_replication_level = 3;
-  }
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "ID_ANNOUNCE_TIME",
-                                           &id_announce_time))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-                               "CADET",
-                               "ID_ANNOUNCE_TIME",
-                               "MISSING");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-
-  dht_handle = GNUNET_DHT_connect (c,
-                                   64);
-  GNUNET_break (NULL != dht_handle);
-  announce_delay = GNUNET_TIME_UNIT_SECONDS;
-  announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
-                                                   &announce_id,
-                                                   NULL);
-}
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void)
-{
-  if (NULL != dht_handle)
-  {
-    GNUNET_DHT_disconnect (dht_handle);
-    dht_handle = NULL;
-  }
-  if (NULL != announce_id_task)
-  {
-    GNUNET_SCHEDULER_cancel (announce_id_task);
-    announce_id_task = NULL;
-  }
-}
-
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id)
-{
-  struct GNUNET_HashCode phash;
-  struct GCD_search_handle *h;
-
-  GNUNET_STATISTICS_update (stats,
-                            "# DHT search",
-                            1,
-                            GNUNET_NO);
-  memset (&phash,
-          0,
-          sizeof (phash));
-  GNUNET_memcpy (&phash,
-                 peer_id,
-                 sizeof (*peer_id));
-
-  h = GNUNET_new (struct GCD_search_handle);
-  h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
-                                    GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
-                                    &phash,     /* key to search */
-                                    dht_replication_level, /* replication level */
-                                    GNUNET_DHT_RO_RECORD_ROUTE |
-                                    GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
-                                    NULL,       /* xquery */
-                                    0,     /* xquery bits */
-                                    &dht_get_id_handler,
-                                   h);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Starting DHT GET for peer %s (%p)\n",
-       GNUNET_i2s (peer_id),
-       h);
-  return h;
-}
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Stopping DHT GET %p\n",
-       h);
-  GNUNET_DHT_get_stop (h->dhtget);
-  GNUNET_free (h);
-}
-
-/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h
deleted file mode 100644 (file)
index 5d7ab29..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_dht.h
- * @brief cadet service; dealing with DHT requests and results
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
- */
-#ifndef GNUNET_SERVICE_CADET_DHT_H
-#define GNUNET_SERVICE_CADET_DHT_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * Handle for DHT search operation.
- */
-struct GCD_search_handle;
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void);
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update (void);
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id);
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_DHT_H */
-#endif
-/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c
deleted file mode 100644 (file)
index a24325a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2014, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_hello.c
- * @brief spread knowledge about how to contact other peers from PEERINFO
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - is most of this necessary/helpful?
- * - should we not simply restrict this to OUR hello?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-#include "gnunet_peerinfo_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
-
-/**
- * Hello message of local peer.
- */
-static struct GNUNET_HELLO_Message *mine;
-
-/**
- * Handle to peerinfo service.
- */
-static struct GNUNET_PEERINFO_Handle *peerinfo;
-
-/**
- * Iterator context.
- */
-static struct GNUNET_PEERINFO_NotifyContext *nc;
-
-
-/**
- * Process each hello message received from peerinfo.
- *
- * @param cls Closure (unused).
- * @param peer Identity of the peer.
- * @param hello Hello of the peer.
- * @param err_msg Error message.
- */
-static void
-got_hello (void *cls,
-           const struct GNUNET_PeerIdentity *id,
-           const struct GNUNET_HELLO_Message *hello,
-           const char *err_msg)
-{
-  struct CadetPeer *peer;
-
-  if ( (NULL == id) ||
-       (NULL == hello) )
-    return;
-  if (0 == memcmp (id,
-                   &my_full_id,
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_free_non_null (mine);
-    mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
-    GCD_hello_update ();
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Hello for %s (%d bytes), expires on %s\n",
-       GNUNET_i2s (id),
-       GNUNET_HELLO_size (hello),
-       GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
-  peer = GCP_get (id,
-                  GNUNET_YES);
-  GCP_set_hello (peer,
-                 hello);
-}
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  GNUNET_assert (NULL == nc);
-  peerinfo = GNUNET_PEERINFO_connect (c);
-  nc = GNUNET_PEERINFO_notify (c,
-                               GNUNET_NO,
-                               &got_hello,
-                               NULL);
-}
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GCH_shutdown ()
-{
-  if (NULL != nc)
-  {
-    GNUNET_PEERINFO_notify_cancel (nc);
-    nc = NULL;
-  }
-  if (NULL != peerinfo)
-  {
-    GNUNET_PEERINFO_disconnect (peerinfo);
-    peerinfo = NULL;
-  }
-  if (NULL != mine)
-  {
-    GNUNET_free (mine);
-    mine = NULL;
-  }
-}
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_get_mine (void)
-{
-  return mine;
-}
-
-/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h
deleted file mode 100644 (file)
index 4291ae9..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2014, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_hello.h
- * @brief cadet service; dealing with hello messages
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
- */
-
-#ifndef GNUNET_SERVICE_CADET_HELLO_H
-#define GNUNET_SERVICE_CADET_HELLO_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GCH_shutdown (void);
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_get_mine (void);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
-#endif
-/* end of gnunet-cadet-service_hello.h */
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet-new_paths.c
deleted file mode 100644 (file)
index c6121a1..0000000
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_paths.c
- * @brief Information we track per path.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
-
-
-/**
- * Information regarding a possible path to reach a peer.
- */
-struct CadetPeerPath
-{
-
-  /**
-   * Array of all the peers on the path.  If @e hn is non-NULL, the
-   * last one is our owner.
-   */
-  struct CadetPeerPathEntry **entries;
-
-  /**
-   * Node of this path in the owner's heap.  Used to update our position
-   * in the heap whenever our @e desirability changes.
-   */
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  /**
-   * Desirability of the path. How unique is it for the various peers
-   * on it?
-   */
-  GNUNET_CONTAINER_HeapCostType desirability;
-
-  /**
-   * Length of the @e entries array.
-   */
-  unsigned int entries_length;
-
-};
-
-
-/**
- * Calculate the path's desirability score.
- *
- * @param path path to calculate the score for
- */
-static void
-recalculate_path_desirability (struct CadetPeerPath *path)
-{
-  double result = 0.0;
-
-  for (unsigned int i=0;i<path->entries_length;i++)
-  {
-    struct CadetPeer *cp = path->entries[i]->peer;
-
-    result += GCP_get_desirability_of_path (cp,
-                                            i);
-  }
-  path->desirability = (GNUNET_CONTAINER_HeapCostType) result;
-}
-
-
-/**
- * Return how much we like keeping the path.  This is an aggregate
- * score based on various factors, including the age of the path
- * (older == better), and the value of this path to all of its ajacent
- * peers.  For example, long paths that end at a peer that we have no
- * shorter way to reach are very desirable, while long paths that end
- * at a peer for which we have a shorter way as well are much less
- * desirable.  Higher values indicate more valuable paths.  The
- * returned value should be used to decide which paths to remember.
- *
- * @param path path to return the length for
- * @return desirability of the path, larger is more desirable
- */
-GNUNET_CONTAINER_HeapCostType
-GCPP_get_desirability (const struct CadetPeerPath *path)
-{
-  return path->desirability;
-}
-
-
-/**
- * Return connection to @a destination using @a path, or return
- * NULL if no such connection exists.
- *
- * @param path path to traverse
- * @param destination destination node to get to, must be on path
- * @param off offset of @a destination on @a path
- * @return NULL if we have no existing connection
- *         otherwise connection from us to @a destination via @a path
- */
-struct CadetConnection *
-GCPP_get_connection (struct CadetPeerPath *path,
-                     struct CadetPeer *destination,
-                     unsigned int off)
-{
-  struct CadetPeerPathEntry *entry;
-
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (entry->peer == destination);
-  return entry->cc;
-}
-
-
-/**
- * Notify @a path that it is used for connection @a cc
- * which ends at the path's offset @a off.
- *
- * @param path the path to remember the @a cc
- * @param off the offset where the @a cc ends
- * @param cc the connection to remember
- */
-void
-GCPP_add_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc)
-{
-  struct CadetPeerPathEntry *entry;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding connection %s to path %s at offset %u\n",
-       GCC_2s (cc),
-       GCPP_2s (path),
-       off);
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (NULL == entry->cc);
-  GNUNET_assert (NULL != cc);
-  entry->cc = cc;
-}
-
-
-
-/**
- * Notify @a path that it is no longer used for connection @a cc which
- * ended at the path's offset @a off.
- *
- * @param path the path to forget the @a cc
- * @param off the offset where the @a cc ended
- * @param cc the connection to forget
- */
-void
-GCPP_del_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc)
-{
-  struct CadetPeerPathEntry *entry;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing connection %s to path %s at offset %u\n",
-       GCC_2s (cc),
-       GCPP_2s (path),
-       off);
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (cc == entry->cc);
-  entry->cc = NULL;
-}
-
-
-/**
- * This path is no longer needed, free resources.
- *
- * @param path path resources to free
- */
-static void
-path_destroy (struct CadetPeerPath *path)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying path %s\n",
-       GCPP_2s (path));
-  for (unsigned int i=0;i<path->entries_length;i++)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    if (NULL != entry->cc)
-    {
-      struct CadetTConnection *ct;
-
-      ct = GCC_get_ct (entry->cc);
-      if (NULL != ct)
-        GCT_connection_lost (ct);
-      GCC_destroy_without_tunnel (entry->cc);
-    }
-    GNUNET_free (entry);
-  }
-  GNUNET_free (path->entries);
-  GNUNET_free (path);
-}
-
-
-/**
- * The owning peer of this path is no longer interested in maintaining
- * it, so the path should be discarded or shortened (in case a
- * previous peer on the path finds the path desirable).
- *
- * @param path the path that is being released
- */
-void
-GCPP_release (struct CadetPeerPath *path)
-{
-  struct CadetPeerPathEntry *entry;
-  int force;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Owner releases path %s\n",
-       GCPP_2s (path));
-  path->hn = NULL;
-  entry = path->entries[path->entries_length - 1];
-  GNUNET_assert (path == entry->path);
-  while (1)
-  {
-    /* cut 'off' end of path */
-    GNUNET_assert (NULL == entry->cc);
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           path->entries_length - 1);
-    path->entries_length--; /* We don't bother shrinking the 'entries' array,
-                               as it's probably not worth it. */
-    GNUNET_free (entry);
-    if (0 == path->entries_length)
-      break; /* the end */
-
-    /* see if new peer at the end likes this path any better */
-    entry = path->entries[path->entries_length - 1];
-    GNUNET_assert (path == entry->path);
-    force = (NULL == entry->cc) ? GNUNET_NO : GNUNET_YES;
-    path->hn = GCP_attach_path (entry->peer,
-                                path,
-                                path->entries_length - 1,
-                                force);
-    if (NULL != path->hn)
-      return; /* yep, got attached, we are done. */
-    GNUNET_assert (GNUNET_NO == force);
-  }
-
-  /* nobody wants us, discard the path */
-  path_destroy (path);
-}
-
-
-/**
- * Updates the score for an entry on the path based
- * on our experiences with using @a path.
- *
- * @param path the path to update
- * @param off offset of the entry to update
- * @param delta change in the score to apply
- */
-void
-GCPP_update_score (struct CadetPeerPath *path,
-                   unsigned int off,
-                   int delta)
-{
-  struct CadetPeerPathEntry *entry;
-
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-
-  /* Add delta, with checks for overflows */
-  if (delta >= 0)
-  {
-    if (delta + entry->score < entry->score)
-      entry->score = INT_MAX;
-    else
-      entry->score += delta;
-  }
-  else
-  {
-    if (delta + entry->score > entry->score)
-      entry->score = INT_MIN;
-    else
-      entry->score += delta;
-  }
-  recalculate_path_desirability (path);
-}
-
-
-/**
- * Closure for #find_peer_at() and #check_match().
- */
-struct CheckMatchContext
-{
-
-  /**
-   * Set to a matching path, if any.
-   */
-  struct CadetPeerPath *match;
-
-  /**
-   * Array the combined paths.
-   */
-  struct CadetPeer **cpath;
-
-  /**
-   * How long is the @e cpath array?
-   */
-  unsigned int cpath_length;
-
-};
-
-
-/**
- * Check if the given path is identical on all of the
- * hops until @a off, and not longer than @a off.  If the
- * @a path matches, store it in `match`.
- *
- * @param cls the `struct CheckMatchContext` to check against
- * @param path the path to check
- * @param off offset to check at
- * @return #GNUNET_YES (continue to iterate), or if found #GNUNET_NO
- */
-static int
-check_match (void *cls,
-             struct CadetPeerPath *path,
-             unsigned int off)
-{
-  struct CheckMatchContext *cm_ctx = cls;
-
-  GNUNET_assert (path->entries_length > off);
-  if ( (path->entries_length != off + 1) &&
-       (off + 1 != cm_ctx->cpath_length) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "check_match missmatch because path %s is too long (%u vs. %u vs. %u)\n",
-         GCPP_2s (path),
-         path->entries_length,
-         off + 1,
-         cm_ctx->cpath_length);
-    return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
-  }
-  for (unsigned int i=0;i<off;i++)
-    if (cm_ctx->cpath[i] !=
-        GCPP_get_peer_at_offset (path,
-                                 i))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "check_match path %s missmatches at offset %u\n",
-           GCPP_2s (path),
-           i);
-      return GNUNET_YES; /* missmatch, ignore */
-    }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "check_match found match with path %s\n",
-       GCPP_2s (path));
-  cm_ctx->match = path;
-  return GNUNET_NO; /* match, we are done! */
-}
-
-
-/**
- * Extend path @a path by the @a num_peers from the @a peers
- * array, assuming the owners past the current owner want it.
- *
- * @param path path to extend
- * @param peers list of peers beyond the end of @a path
- * @param num_peers length of the @a peers array
- * @param force force attachment, even if we have other
- *        paths already
- */
-static void
-extend_path (struct CadetPeerPath *path,
-             struct CadetPeer **peers,
-             unsigned int num_peers,
-             int force)
-{
-  unsigned int old_len = path->entries_length;
-  int i;
-
-  /* Expand path */
-  GNUNET_array_grow (path->entries,
-                     path->entries_length,
-                     old_len + num_peers);
-  for (i=num_peers-1;i >= 0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[old_len + i] = entry;
-    entry->peer = peers[i];
-    entry->path = path;
-  }
-  for (i=num_peers-1;i >= 0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        old_len + i);
-  }
-
-  /* If we extend an existing path, detach it from the
-     old owner and re-attach to the new one */
-  GCP_detach_path (path->entries[old_len-1]->peer,
-                   path,
-                   path->hn);
-  path->hn = NULL;
-  for (i=num_peers-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
-
-    path->entries_length = old_len + i + 1;
-    recalculate_path_desirability (path);
-    path->hn = GCP_attach_path (peers[i],
-                                path,
-                                old_len + (unsigned int) i,
-                                force);
-    if (NULL != path->hn)
-      break;
-    GNUNET_assert (NULL == entry->cc);
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           old_len + i);
-    GNUNET_free (entry);
-    path->entries[old_len + i] = NULL;
-  }
-  if (NULL == path->hn)
-  {
-    /* none of the peers is interested in this path;
-       shrink path back and re-attach. */
-    GNUNET_array_grow (path->entries,
-                       path->entries_length,
-                       old_len);
-    path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
-                                path,
-                                old_len - 1,
-                                GNUNET_YES);
-    GNUNET_assert (NULL != path->hn);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Extended path %s\n",
-       GCPP_2s (path));
-}
-
-
-/**
- * Create a peer path based on the result of a DHT lookup.  If we
- * already know this path, or one that is longer, simply return NULL.
- * Otherwise, we try to extend an existing path, or create a new one
- * if applicable.
- *
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- * @return a path through the network
- */
-void
-GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
-                        unsigned int get_path_length,
-                        const struct GNUNET_PeerIdentity *put_path,
-                        unsigned int put_path_length)
-{
-  struct CadetPeer *cpath[get_path_length + put_path_length];
-  struct CheckMatchContext cm_ctx;
-  struct CadetPeerPath *path;
-  struct GNUNET_CONTAINER_HeapNode *hn;
-  int i;
-  unsigned int skip;
-  unsigned int total_len;
-
-  /* precompute 'cpath' so we can avoid doing the lookups lots of times */
-  skip = 0;
-  memset (cpath,
-          0,
-          sizeof (cpath)); /* Just to trigger harder errors later. */
-  total_len = get_path_length + put_path_length;
-  for (unsigned int off=0;off<total_len;off++)
-  {
-    const struct GNUNET_PeerIdentity *pid;
-
-    pid = (off < get_path_length)
-      ? &get_path[get_path_length - off]
-      : &put_path[get_path_length + put_path_length - off];
-    cpath[off - skip] = GCP_get (pid,
-                                 GNUNET_YES);
-    /* Check that no peer is twice on the path */
-    for (unsigned int i=0;i<off - skip;i++)
-    {
-     if (cpath[i] == cpath[off - skip])
-      {
-        skip = off - i;
-        break;
-      }
-    }
-  }
-  total_len -= skip;
-
-  /* First figure out if this path is a subset of an existing path, an
-     extension of an existing path, or a new path. */
-  cm_ctx.cpath_length = total_len;
-  cm_ctx.cpath = cpath;
-  cm_ctx.match = NULL;
-  for (i=total_len-1;i>=0;i--)
-  {
-    GCP_iterate_paths_at (cpath[i],
-                          (unsigned int) i,
-                          &check_match,
-                          &cm_ctx);
-    if (NULL != cm_ctx.match)
-    {
-      if (i == total_len - 1)
-      {
-        /* Existing path includes this one, nothing to do! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Path discovered from DHT is already known\n");
-        return;
-      }
-      if (cm_ctx.match->entries_length == i + 1)
-      {
-        /* Existing path ends in the middle of new path, extend it! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Trying to extend existing path %s by additional links discovered from DHT\n",
-             GCPP_2s (cm_ctx.match));
-        extend_path (cm_ctx.match,
-                     &cpath[i + 1],
-                     total_len - i - 1,
-                     GNUNET_NO);
-        return;
-      }
-    }
-  }
-
-  /* No match at all, create completely new path */
-  path = GNUNET_new (struct CadetPeerPath);
-  path->entries_length = total_len;
-  path->entries = GNUNET_new_array (path->entries_length,
-                                    struct CadetPeerPathEntry *);
-  for (i=path->entries_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[i] = entry;
-    entry->peer = cpath[i];
-    entry->path = path;
-  }
-  for (i=path->entries_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        i);
-  }
-
-  /* Finally, try to attach it */
-  hn = NULL;
-  for (i=total_len-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    path->entries_length = i + 1;
-    recalculate_path_desirability (path);
-    hn = GCP_attach_path (cpath[i],
-                          path,
-                          (unsigned int) i,
-                          GNUNET_NO);
-    if (NULL != hn)
-      break;
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           i);
-    GNUNET_free (entry);
-    path->entries[i] = NULL;
-  }
-  if (NULL == hn)
-  {
-    /* None of the peers on the path care about it. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Path discovered from DHT is not interesting to us\n");
-    GNUNET_free (path->entries);
-    GNUNET_free (path);
-    return;
-  }
-  path->hn = hn;
-  /* Shrink path to actual useful length */
-  GNUNET_array_grow (path->entries,
-                     path->entries_length,
-                     i + 1);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created new path %s based on information from DHT\n",
-       GCPP_2s (path));
-}
-
-
-/**
- * We got an incoming connection, obtain the corresponding path.
- *
- * @param path_length number of segments on the @a path
- * @param pids path through the network, in reverse order (we are at the end at index @a path_length)
- * @return corresponding path object
- */
-struct CadetPeerPath *
-GCPP_get_path_from_route (unsigned int path_length,
-                          const struct GNUNET_PeerIdentity *pids)
-{
-  struct CheckMatchContext cm_ctx;
-  struct CadetPeer *cpath[path_length];
-  struct CadetPeerPath *path;
-
-  /* precompute inverted 'cpath' so we can avoid doing the lookups and
-     have the correct order */
-  for (unsigned int off=0;off<path_length;off++)
-    cpath[off] = GCP_get (&pids[path_length - 1 - off],
-                          GNUNET_YES);
-
-  /* First figure out if this path is a subset of an existing path, an
-     extension of an existing path, or a new path. */
-  cm_ctx.cpath = cpath;
-  cm_ctx.cpath_length = path_length;
-  cm_ctx.match = NULL;
-  for (int i=path_length-1;i>=0;i--)
-  {
-    GCP_iterate_paths_at (cpath[i],
-                          (unsigned int) i,
-                          &check_match,
-                          &cm_ctx);
-    if (NULL != cm_ctx.match)
-    {
-      if (i == path_length - 1)
-      {
-        /* Existing path includes this one, return the match! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Returning existing path %s as inverse for incoming connection\n",
-             GCPP_2s (cm_ctx.match));
-        return cm_ctx.match;
-      }
-      if (cm_ctx.match->entries_length == i + 1)
-      {
-        /* Existing path ends in the middle of new path, extend it! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Extending existing path %s to create inverse for incoming connection\n",
-             GCPP_2s (cm_ctx.match));
-        extend_path (cm_ctx.match,
-                     &cpath[i + 1],
-                     path_length - i - 1,
-                     GNUNET_YES);
-        /* Check that extension was successful */
-        GNUNET_assert (cm_ctx.match->entries_length == path_length);
-        return cm_ctx.match;
-      }
-      /* Eh, we found a match but couldn't use it? Something is wrong. */
-      GNUNET_break (0);
-    }
-  }
-
-  /* No match at all, create completely new path */
-  path = GNUNET_new (struct CadetPeerPath);
-  path->entries_length = path_length;
-  path->entries = GNUNET_new_array (path->entries_length,
-                                    struct CadetPeerPathEntry *);
-  for (int i=path_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[i] = entry;
-    entry->peer = cpath[i];
-    entry->path = path;
-  }
-  for (int i=path_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        i);
-  }
-  recalculate_path_desirability (path);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created new path %s to create inverse for incoming connection\n",
-       GCPP_2s (path));
-  path->hn = GCP_attach_path (cpath[path_length - 1],
-                              path,
-                              path_length - 1,
-                              GNUNET_YES);
-  return path;
-}
-
-
-/**
- * Return the length of the path.  Excludes one end of the
- * path, so the loopback path has length 0.
- *
- * @param path path to return the length for
- * @return number of peers on the path
- */
-unsigned int
-GCPP_get_length (struct CadetPeerPath *path)
-{
-  return path->entries_length;
-}
-
-
-/**
- * Find peer's offset on path.
- *
- * @param path path to search
- * @param cp peer to look for
- * @return offset of @a cp on @a path, or UINT_MAX if not found
- */
-unsigned int
-GCPP_find_peer (struct CadetPeerPath *path,
-                struct CadetPeer *cp)
-{
-  for (unsigned int off = 0;
-       off < path->entries_length;
-       off++)
-    if (cp == GCPP_get_peer_at_offset (path,
-                                       off))
-      return off;
-  return UINT_MAX;
-}
-
-
-/**
- * Obtain the peer at offset @a off in @a path.
- *
- * @param path peer path to inspect
- * @param off offset to return, must be smaller than path length
- * @return the peer at offset @a off
- */
-struct CadetPeer *
-GCPP_get_peer_at_offset (struct CadetPeerPath *path,
-                         unsigned int off)
-{
-  GNUNET_assert (off < path->entries_length);
-  return path->entries[off]->peer;
-}
-
-
-/**
- * Convert a path to a human-readable string.
- *
- * @param path path to convert
- * @return string, to be freed by caller (unlike other *_2s APIs!)
- */
-const char *
-GCPP_2s (struct CadetPeerPath *path)
-{
-  static char buf[2048];
-  size_t off;
-  const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
-
-  off = 0;
-  for (unsigned int i = 0;
-       i < path->entries_length;
-       i++)
-  {
-    if ( (path->entries_length > max_plen) &&
-         (i == max_plen / 2) )
-      off += GNUNET_snprintf (&buf[off],
-                              sizeof (buf) - off,
-                              "...-");
-    if ( (path->entries_length > max_plen) &&
-         (i > max_plen / 2) &&
-         (i < path->entries_length - max_plen / 2) )
-      continue;
-    off += GNUNET_snprintf (&buf[off],
-                            sizeof (buf) - off,
-                            "%s%s",
-                            GNUNET_i2s (GCP_get_id (GCPP_get_peer_at_offset (path,
-                                                                             i))),
-                            (i == path->entries_length -1) ? "" : "-");
-  }
-  GNUNET_snprintf (&buf[off],
-                   sizeof (buf) - off,
-                   "(%p)",
-                   path);
-  return buf;
-}
-
-
-/* end of gnunet-service-cadet-new_paths.c */
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet-new_paths.h
deleted file mode 100644 (file)
index 7310d75..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_paths.h
- * @brief Information we track per path.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_PATHS_H
-#define GNUNET_SERVICE_CADET_PATHS_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
-
-/**
- * Create a peer path based on the result of a DHT lookup.  If we
- * already know this path, or one that is longer, simply return NULL.
- * Otherwise, we try to extend an existing path, or create a new one
- * if applicable.
- *
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- */
-void
-GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
-                        unsigned int get_path_length,
-                        const struct GNUNET_PeerIdentity *put_path,
-                        unsigned int put_path_length);
-
-
-/**
- * We got an incoming connection, obtain the corresponding path.
- *
- * @param path_length number of segments on the @a path
- * @param path through the network, in reverse order (we are at the end!)
- * @return corresponding path object
- */
-struct CadetPeerPath *
-GCPP_get_path_from_route (unsigned int path_length,
-                          const struct GNUNET_PeerIdentity *pids);
-
-
-/**
- * Return the length of the path.  Excludes one end of the
- * path, so the loopback path has length 0.
- *
- * @param path path to return the length for
- * @return number of peers on the path
- */
-unsigned int
-GCPP_get_length (struct CadetPeerPath *path);
-
-
-/**
- * Return connection to @a destination using @a path, or return
- * NULL if no such connection exists.
- *
- * @param path path to traverse
- * @param destination destination node to get to, must be on path
- * @param off offset of @a destination on @a path
- * @return NULL if we have no existing connection
- *         otherwise connection from us to @a destination via @a path
- */
-struct CadetConnection *
-GCPP_get_connection (struct CadetPeerPath *path,
-                     struct CadetPeer *destination,
-                     unsigned int off);
-
-
-/**
- * Notify @a path that it is used for connection @a cc
- * which ends at the path's offset @a off.
- *
- * @param path the path to remember the @a cc
- * @param off the offset where the @a cc ends
- * @param cc the connection to remember
- */
-void
-GCPP_add_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc);
-
-
-/**
- * Notify @a path that it is no longer used for connection @a cc which
- * ended at the path's offset @a off.
- *
- * @param path the path to forget the @a cc
- * @param off the offset where the @a cc ended
- * @param cc the connection to forget
- */
-void
-GCPP_del_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc);
-
-
-/**
- * Find peer's offset on path.
- *
- * @param path path to search
- * @param cp peer to look for
- * @return offset of @a cp on @a path, or UINT_MAX if not found
- */
-unsigned int
-GCPP_find_peer (struct CadetPeerPath *path,
-                struct CadetPeer *cp);
-
-
-/**
- * Return how much we like keeping the path.  This is an aggregate
- * score based on various factors, including the age of the path
- * (older == better), and the value of this path to all of its ajacent
- * peers.  For example, long paths that end at a peer that we have no
- * shorter way to reach are very desirable, while long paths that end
- * at a peer for which we have a shorter way as well are much less
- * desirable.  Higher values indicate more valuable paths.  The
- * returned value should be used to decide which paths to remember.
- *
- * @param path path to return the length for
- * @return desirability of the path, larger is more desirable
- */
-GNUNET_CONTAINER_HeapCostType
-GCPP_get_desirability (const struct CadetPeerPath *path);
-
-
-/**
- * The given peer @a cp used to own this @a path.  However, it is no
- * longer interested in maintaining it, so the path should be
- * discarded or shortened (in case a previous peer on the path finds
- * the path desirable).
- *
- * @param path the path that is being released
- */
-void
-GCPP_release (struct CadetPeerPath *path);
-
-
-/**
- * Obtain the peer at offset @a off in @a path.
- *
- * @param path peer path to inspect
- * @param off offset to return, must be smaller than path length
- * @return peer at offset @a off
- */
-struct CadetPeer *
-GCPP_get_peer_at_offset (struct CadetPeerPath *path,
-                         unsigned int off);
-
-
-/**
- * Convert a path to a human-readable string.
- *
- * @param path path to convert
- * @return string, statically allocated
- */
-const char *
-GCPP_2s (struct CadetPeerPath *p);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c
deleted file mode 100644 (file)
index 29aef68..0000000
+++ /dev/null
@@ -1,1478 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - optimize stopping/restarting DHT search to situations
- *   where we actually need it (i.e. not if we have a direct connection,
- *   or if we already have plenty of good short ones, or maybe even
- *   to take a break if we have some connections and have searched a lot (?))
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-#include "gnunet_signatures.h"
-#include "gnunet_transport_service.h"
-#include "gnunet_ats_service.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
-
-
-/**
- * How long do we wait until tearing down an idle peer?
- */
-#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
-
-/**
- * How long do we keep paths around if we no longer care about the peer?
- */
-#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
-
-
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * to our message queue.
- */
-struct GCP_MessageQueueManager
-{
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GCP_MessageQueueManager *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GCP_MessageQueueManager *prev;
-
-  /**
-   * Function to call with updated message queue object.
-   */
-  GCP_MessageQueueNotificationCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * The peer this is for.
-   */
-  struct CadetPeer *cp;
-
-  /**
-   * Envelope this manager would like to transmit once it is its turn.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer
-{
-  /**
-   * ID of the peer
-   */
-  struct GNUNET_PeerIdentity pid;
-
-  /**
-   * Last time we heard from this peer (currently not used!)
-   */
-  struct GNUNET_TIME_Absolute last_contactXXX;
-
-  /**
-   * Array of DLLs of paths traversing the peer, organized by the
-   * offset of the peer on the larger path.
-   */
-  struct CadetPeerPathEntry **path_heads;
-
-  /**
-   * Array of DLL of paths traversing the peer, organized by the
-   * offset of the peer on the larger path.
-   */
-  struct CadetPeerPathEntry **path_tails;
-
-  /**
-   * Notifications to call when @e core_mq changes.
-   */
-  struct GCP_MessageQueueManager *mqm_head;
-
-  /**
-   * Notifications to call when @e core_mq changes.
-   */
-  struct GCP_MessageQueueManager *mqm_tail;
-
-  /**
-   * Pointer to first "ready" entry in @e mqm_head.
-   */
-  struct GCP_MessageQueueManager *mqm_ready_ptr;
-
-  /**
-   * MIN-heap of paths owned by this peer (they also end at this
-   * peer).  Ordered by desirability.
-   */
-  struct GNUNET_CONTAINER_Heap *path_heap;
-
-  /**
-   * Handle to stop the DHT search for paths to this peer
-   */
-  struct GCD_search_handle *search_h;
-
-  /**
-   * Task to clean up @e path_heap asynchronously.
-   */
-  struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
-
-  /**
-   * Task to destroy this entry.
-   */
-  struct GNUNET_SCHEDULER_Task *destroy_task;
-
-  /**
-   * Tunnel to this peer, if any.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Connections that go through this peer; indexed by tid.
-   */
-  struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-  /**
-   * Handle for core transmissions.
-   */
-  struct GNUNET_MQ_Handle *core_mq;
-
-  /**
-   * Hello message of the peer.
-   */
-  struct GNUNET_HELLO_Message *hello;
-
-  /**
-   * Handle to us offering the HELLO to the transport.
-   */
-  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
-
-  /**
-   * Handle to our ATS request asking ATS to suggest an address
-   * to TRANSPORT for this peer (to establish a direct link).
-   */
-  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
-
-  /**
-   * How many messages are in the queue to this peer.
-   */
-  unsigned int queue_n;
-
-  /**
-   * How many paths do we have to this peer (in all @e path_heads DLLs combined).
-   */
-  unsigned int num_paths;
-
-  /**
-   * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
-   * Used to speed-up @GCP_get_desirability_of_path() calculation.
-   */
-  unsigned int off_sum;
-
-  /**
-   * Number of message queue managers of this peer that have a message in waiting.
-   *
-   * Used to quickly see if we need to bother scanning the @e msm_head DLL.
-   * TODO: could be replaced by another DLL that would then allow us to avoid
-   * the O(n)-scan of the DLL for ready entries!
-   */
-  unsigned int mqm_ready_counter;
-
-  /**
-   * Current length of the @e path_heads and @path_tails arrays.
-   * The arrays should be grown as needed.
-   */
-  unsigned int path_dll_length;
-
-};
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param cp Peer.
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *cp)
-{
-  static char buf[32];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "P(%s)",
-                   GNUNET_i2s (&cp->pid));
-  return buf;
-}
-
-
-/**
- * Calculate how desirable a path is for @a cp if @a cp
- * is at offset @a off.
- *
- * The 'desirability_table.c' program can be used to compute a list of
- * sample outputs for different scenarios.  Basically, we score paths
- * lower if there are many alternatives, and higher if they are
- * shorter than average, and very high if they are much shorter than
- * average and without many alternatives.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in the path
- * @return score how useful a path is to reach @a cp,
- *         positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
-                              unsigned int off)
-{
-  unsigned int num_alts = cp->num_paths;
-  unsigned int off_sum;
-  double avg_sum;
-  double path_delta;
-  double weight_alts;
-
-  GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
-  GNUNET_assert (0 != cp->path_dll_length);
-
-  /* We maintain 'off_sum' in 'peer' and thereby
-     avoid the SLOW recalculation each time. Kept here
-     just to document what is going on. */
-#if SLOW
-  off_sum = 0;
-  for (unsigned int j=0;j<cp->path_dll_length;j++)
-    for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
-         NULL != pe;
-         pe = pe->next)
-      off_sum += j;
-  GNUNET_assert (off_sum == cp->off_sum);
-#else
-  off_sum = cp->off_sum;
-#endif
-  avg_sum = off_sum * 1.0 / cp->path_dll_length;
-  path_delta = off - avg_sum;
-  /* path_delta positiv: path off of peer above average (bad path for peer),
-     path_delta negativ: path off of peer below average (good path for peer) */
-  if (path_delta <= - 1.0)
-    weight_alts = - num_alts / path_delta; /* discount alternative paths */
-  else if (path_delta >= 1.0)
-    weight_alts = num_alts * path_delta; /* overcount alternative paths */
-  else
-    weight_alts = num_alts; /* count alternative paths normally */
-
-
-  /* off+1: long paths are generally harder to find and thus count
-     a bit more as they get longer.  However, above-average paths
-     still need to count less, hence the squaring of that factor. */
-  return (off + 1.0) / (weight_alts * weight_alts);
-}
-
-
-/**
- * This peer is no longer be needed, clean it up now.
- *
- * @param cls peer to clean up
- */
-static void
-destroy_peer (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying state about peer %s\n",
-       GCP_2s (cp));
-  cp->destroy_task = NULL;
-  GNUNET_assert (NULL == cp->t);
-  GNUNET_assert (NULL == cp->core_mq);
-  GNUNET_assert (0 == cp->num_paths);
-  for (unsigned int i=0;i<cp->path_dll_length;i++)
-    GNUNET_assert (NULL == cp->path_heads[i]);
-  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_remove (peers,
-                                                       &cp->pid,
-                                                       cp));
-  GNUNET_free_non_null (cp->path_heads);
-  GNUNET_free_non_null (cp->path_tails);
-  cp->path_dll_length = 0;
-  if (NULL != cp->search_h)
-  {
-    GCD_search_stop (cp->search_h);
-    cp->search_h = NULL;
-  }
-  /* FIXME: clean up search_delayedXXX! */
-
-  if (NULL != cp->hello_offer)
-  {
-    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
-    cp->hello_offer = NULL;
-  }
-  if (NULL != cp->connectivity_suggestion)
-  {
-    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-    cp->connectivity_suggestion = NULL;
-  }
-  GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
-  if (NULL != cp->path_heap)
-  {
-    GNUNET_CONTAINER_heap_destroy (cp->path_heap);
-    cp->path_heap = NULL;
-  }
-  if (NULL != cp->heap_cleanup_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
-    cp->heap_cleanup_task = NULL;
-  }
-  GNUNET_free_non_null (cp->hello);
-  /* Peer should not be freed if paths exist; if there are no paths,
-     there ought to be no connections, and without connections, no
-     notifications. Thus we can assert that mqm_head is empty at this
-     point. */
-  GNUNET_assert (NULL == cp->mqm_head);
-  GNUNET_assert (NULL == cp->mqm_ready_ptr);
-  GNUNET_free (cp);
-}
-
-
-/**
- * This peer is now on more "active" duty, activate processes related to it.
- *
- * @param cp the more-active peer
- */
-static void
-consider_peer_activate (struct CadetPeer *cp)
-{
-  uint32_t strength;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Updating peer %s activation state (%u connections)%s%s\n",
-       GCP_2s (cp),
-       GNUNET_CONTAINER_multishortmap_size (cp->connections),
-       (NULL == cp->t) ? "" : " with tunnel",
-       (NULL == cp->core_mq) ? "" : " with CORE link");
-  if (NULL != cp->destroy_task)
-  {
-    /* It's active, do not destory! */
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
-       (NULL == cp->t) )
-  {
-    /* We're just on a path or directly connected; don't bother too much */
-    if (NULL != cp->connectivity_suggestion)
-    {
-      GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-      cp->connectivity_suggestion = NULL;
-    }
-    if (NULL != cp->search_h)
-    {
-      GCD_search_stop (cp->search_h);
-      cp->search_h = NULL;
-    }
-    return;
-  }
-  if (NULL == cp->core_mq)
-  {
-    /* Lacks direct connection, try to create one by querying the DHT */
-    if ( (NULL == cp->search_h) &&
-         (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
-      cp->search_h
-        = GCD_search (&cp->pid);
-  }
-  else
-  {
-    /* Have direct connection, stop DHT search if active */
-    if (NULL != cp->search_h)
-    {
-      GCD_search_stop (cp->search_h);
-      cp->search_h = NULL;
-    }
-  }
-
-  /* If we have a tunnel, our urge for connections is much bigger */
-  strength = (NULL != cp->t) ? 32 : 1;
-  if (NULL != cp->connectivity_suggestion)
-    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-  cp->connectivity_suggestion
-    = GNUNET_ATS_connectivity_suggest (ats_ch,
-                                       &cp->pid,
-                                       strength);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp);
-
-
-/**
- * We really no longere care about a peer, stop hogging memory with paths to it.
- * Afterwards, see if there is more to be cleaned up about this peer.
- *
- * @param cls a `struct CadetPeer`.
- */
-static void
-drop_paths (void *cls)
-{
-  struct CadetPeer *cp = cls;
-  struct CadetPeerPath *path;
-
-  cp->destroy_task = NULL;
-  while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
-    GCPP_release (path);
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp)
-{
-  struct GNUNET_TIME_Relative exp;
-
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  if (NULL != cp->t)
-    return; /* still relevant! */
-  if (NULL != cp->core_mq)
-    return; /* still relevant! */
-  if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
-    return; /* still relevant! */
-  if ( (NULL != cp->path_heap) &&
-       (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
-  {
-    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
-                                                     &drop_paths,
-                                                     cp);
-    return;
-  }
-  if (0 != cp->num_paths)
-    return; /* still relevant! */
-  if (NULL != cp->hello)
-  {
-    /* relevant only until HELLO expires */
-    exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
-    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
-                                                     &destroy_peer,
-                                                     cp);
-    return;
-  }
-  cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
-                                                   &destroy_peer,
-                                                   cp);
-}
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
-            struct GNUNET_MQ_Handle *mq)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Message queue for peer %s is now %p\n",
-       GCP_2s (cp),
-       mq);
-  cp->core_mq = mq;
-  for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
-       NULL != mqm;
-       mqm = next)
-  {
-    /* Save next pointer in case mqm gets freed by the callback */
-    next = mqm->next;
-    if (NULL == mq)
-    {
-      if (NULL != mqm->env)
-      {
-        GNUNET_MQ_discard (mqm->env);
-        mqm->env = NULL;
-        mqm->cb (mqm->cb_cls,
-                 GNUNET_SYSERR);
-      }
-      else
-      {
-        mqm->cb (mqm->cb_cls,
-                 GNUNET_NO);
-      }
-    }
-    else
-    {
-      GNUNET_assert (NULL == mqm->env);
-      mqm->cb (mqm->cb_cls,
-               GNUNET_YES);
-    }
-  }
-  if ( (NULL != mq) ||
-       (NULL != cp->t) )
-    consider_peer_activate (cp);
-  else
-    consider_peer_destroy (cp);
-
-  if ( (NULL != mq) &&
-       (NULL != cp->t) )
-  {
-    /* have a new, direct path to the target, notify tunnel */
-    struct CadetPeerPath *path;
-
-    path = GCPP_get_path_from_route (1,
-                                     &cp->pid);
-    GCT_consider_path (cp->t,
-                       path,
-                       0);
-  }
-}
-
-
-/**
- * Debug function should NEVER return true in production code, useful to
- * simulate losses for testcases.
- *
- * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
- */
-static int
-should_I_drop (void)
-{
-  if (0 == drop_percent)
-    return GNUNET_NO;
-  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                101) < drop_percent)
-    return GNUNET_YES;
-  return GNUNET_NO;
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls);
-
-
-/**
- * Transmit current envelope from this @a mqm.
- *
- * @param mqm mqm to transmit message for now
- */
-static void
-mqm_execute (struct GCP_MessageQueueManager *mqm)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  /* Move ready pointer to the next entry that might be ready. */
-  if ( (mqm == cp->mqm_ready_ptr) &&
-       (NULL != mqm->next) )
-    cp->mqm_ready_ptr = mqm->next;
-  /* Move entry to the end of the DLL, to be fair. */
-  if (mqm != cp->mqm_tail)
-  {
-    GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
-                                 cp->mqm_tail,
-                                 mqm);
-    GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
-                                      cp->mqm_tail,
-                                      mqm);
-  }
-  cp->mqm_ready_counter--;
-  if (GNUNET_YES == should_I_drop ())
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "DROPPING message to peer %s from MQM %p\n",
-         GCP_2s (cp),
-         mqm);
-    GNUNET_MQ_discard (mqm->env);
-    mqm->env = NULL;
-    mqm_send_done (cp);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Sending to peer %s from MQM %p\n",
-         GCP_2s (cp),
-         mqm);
-    GNUNET_MQ_send (cp->core_mq,
-                    mqm->env);
-    mqm->env = NULL;
-  }
-  mqm->cb (mqm->cb_cls,
-           GNUNET_YES);
-}
-
-
-/**
- * Find the next ready message in the queue (starting
- * the search from the `cp->mqm_ready_ptr`) and if possible
- * execute the transmission.
- *
- * @param cp peer to try to send the next ready message to
- */
-static void
-send_next_ready (struct CadetPeer *cp)
-{
-  struct GCP_MessageQueueManager *mqm;
-
-  if (0 == cp->mqm_ready_counter)
-    return;
-  while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
-          (NULL == mqm->env) )
-    cp->mqm_ready_ptr = mqm->next;
-  if (NULL == mqm)
-    return; /* nothing to do */
-  mqm_execute (mqm);
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending to peer %s completed\n",
-       GCP_2s (cp));
-  send_next_ready (cp);
-}
-
-
-/**
- * Send the message in @a env to @a cp.
- *
- * @param mqm the message queue manager to use for transmission
- * @param env envelope with the message to send; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
-          struct GNUNET_MQ_Envelope *env)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  GNUNET_assert (NULL != env);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queueing message to peer %s in MQM %p\n",
-       GCP_2s (cp),
-       mqm);
-  GNUNET_assert (NULL != cp->core_mq);
-  GNUNET_assert (NULL == mqm->env);
-  GNUNET_MQ_notify_sent (env,
-                         &mqm_send_done,
-                         cp);
-  mqm->env = env;
-  cp->mqm_ready_counter++;
-  if (mqm != cp->mqm_ready_ptr)
-    cp->mqm_ready_ptr = cp->mqm_head;
-  if (1 == cp->mqm_ready_counter)
-    cp->mqm_ready_ptr = mqm;
-  if (0 != GNUNET_MQ_get_length (cp->core_mq))
-    return;
-  send_next_ready (cp);
-}
-
-
-/**
- * Function called to destroy a peer now.
- *
- * @param cls NULL
- * @param pid identity of the peer (unused)
- * @param value the `struct CadetPeer` to clean up
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_iterator_cb (void *cls,
-                     const struct GNUNET_PeerIdentity *pid,
-                     void *value)
-{
-  struct CadetPeer *cp = value;
-
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  destroy_peer (cp);
-  return GNUNET_OK;
-}
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers ()
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying all peers now\n");
-  GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                         &destroy_iterator_cb,
-                                         NULL);
-}
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp)
-{
-  struct CadetPeerPath *path;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying all paths to %s\n",
-       GCP_2s (cp));
-  while (NULL != (path =
-                  GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
-    GCPP_release (path);
-  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
-  cp->path_heap = NULL;
-}
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
-                    struct CadetPeerPathEntry *entry,
-                    unsigned int off)
-{
-  GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
-                                                off));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Discovered that peer %s is on path %s at offset %u\n",
-       GCP_2s (cp),
-       GCPP_2s (entry->path),
-       off);
-  if (off >= cp->path_dll_length)
-  {
-    unsigned int len = cp->path_dll_length;
-
-    GNUNET_array_grow (cp->path_heads,
-                       len,
-                       off + 4);
-    GNUNET_array_grow (cp->path_tails,
-                       cp->path_dll_length,
-                       off + 4);
-  }
-  GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
-                               cp->path_tails[off],
-                               entry);
-  cp->off_sum += off;
-  cp->num_paths++;
-
-  /* If we have a tunnel to this peer, tell the tunnel that there is a
-     new path available. */
-  if (NULL != cp->t)
-    GCT_consider_path (cp->t,
-                       entry->path,
-                       off);
-
-  if ( (NULL != cp->search_h) &&
-       (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
-  {
-    /* Now I have enough paths, stop search */
-    GCD_search_stop (cp->search_h);
-    cp->search_h = NULL;
-  }
-  if (NULL != cp->destroy_task)
-  {
-    /* paths changed, this resets the destroy timeout counter
-       and aborts a destroy task that may no longer be valid
-       to have (as we now have more paths via this peer). */
-    consider_peer_destroy (cp);
-  }
-}
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
-                       struct CadetPeerPathEntry *entry,
-                       unsigned int off)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing knowledge about peer %s beging on path %s at offset %u\n",
-       GCP_2s (cp),
-       GCPP_2s (entry->path),
-       off);
-  GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
-                               cp->path_tails[off],
-                               entry);
-  GNUNET_assert (0 < cp->num_paths);
-  cp->off_sum -= off;
-  cp->num_paths--;
-  if ( (NULL == cp->core_mq) &&
-       (NULL != cp->t) &&
-       (NULL == cp->search_h) &&
-       (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
-    cp->search_h
-      = GCD_search (&cp->pid);
-  if (NULL == cp->destroy_task)
-  {
-    /* paths changed, we might now be ready for destruction, check again */
-    consider_peer_destroy (cp);
-  }
-}
-
-
-/**
- * Prune down the number of paths to this peer, we seem to
- * have way too many.
- *
- * @param cls the `struct CadetPeer` to maintain the path heap for
- */
-static void
-path_heap_cleanup (void *cls)
-{
-  struct CadetPeer *cp = cls;
-  struct CadetPeerPath *root;
-
-  cp->heap_cleanup_task = NULL;
-  while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
-         2 * DESIRED_CONNECTIONS_PER_TUNNEL)
-  {
-    /* Now we have way too many, drop least desirable UNLESS it is in use!
-       (Note that this intentionally keeps highly desireable, but currently
-       unused paths around in the hope that we might be able to switch, even
-       if the number of paths exceeds the threshold.) */
-    root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
-    GNUNET_assert (NULL != root);
-    if (NULL !=
-        GCPP_get_connection (root,
-                             cp,
-                             GCPP_get_length (root) - 1))
-      break; /* can't fix */
-    /* Got plenty of paths to this destination, and this is a low-quality
-       one that we don't care about. Allow it to die. */
-    GNUNET_assert (root ==
-                   GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
-    GCPP_release (root);
-  }
-}
-
-
-/**
- * Try adding a @a path to this @a peer.  If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force force attaching the path
- * @return NULL if this peer does not care to become a new owner,
- *         otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 unsigned int off,
-                 int force)
-{
-  GNUNET_CONTAINER_HeapCostType desirability;
-  struct CadetPeerPath *root;
-  GNUNET_CONTAINER_HeapCostType root_desirability;
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  GNUNET_assert (off == GCPP_get_length (path) - 1);
-  GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
-                                                off));
-  if (NULL == cp->path_heap)
-  {
-    /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
-    GNUNET_assert (GNUNET_NO == force);
-    return NULL;
-  }
-  desirability = GCPP_get_desirability (path);
-  if (GNUNET_NO == force)
-  {
-    /* FIXME: desirability is not yet initialized; tricky! */
-    if (GNUNET_NO ==
-        GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
-                                     (void **) &root,
-                                     &root_desirability))
-    {
-      root = NULL;
-      root_desirability = 0;
-    }
-
-    if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
-         (desirability < root_desirability) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Decided to not attach path %p to peer %s due to undesirability\n",
-           GCPP_2s (path),
-           GCP_2s (cp));
-      return NULL;
-    }
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Attaching path %s to peer %s (%s)\n",
-       GCPP_2s (path),
-       GCP_2s (cp),
-       (GNUNET_NO == force) ? "desirable" : "forced");
-
-  /* Yes, we'd like to add this path, add to our heap */
-  hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
-                                     path,
-                                     desirability);
-
-  /* Consider maybe dropping other paths because of the new one */
-  if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
-        2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (NULL != cp->heap_cleanup_task) )
-    cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
-                                                      cp);
-  return hn;
-}
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 struct GNUNET_CONTAINER_HeapNode *hn)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Detatching path %s from peer %s\n",
-       GCPP_2s (path),
-       GCP_2s (cp));
-  GNUNET_assert (path ==
-                 GNUNET_CONTAINER_heap_remove_node (hn));
-}
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
-                    struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding connection %s to peer %s\n",
-       GCC_2s (cc),
-       GCP_2s (cp));
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (cp->connections,
-                                                     &GCC_get_id (cc)->connection_of_tunnel,
-                                                     cc,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-}
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
-                       struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing connection %s from peer %s\n",
-       GCC_2s (cc),
-       GCP_2s (cp));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
-                                                        &GCC_get_id (cc)->connection_of_tunnel,
-                                                        cc));
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
-         int create)
-{
-  struct CadetPeer *cp;
-
-  cp = GNUNET_CONTAINER_multipeermap_get (peers,
-                                          peer_id);
-  if (NULL != cp)
-    return cp;
-  if (GNUNET_NO == create)
-    return NULL;
-  cp = GNUNET_new (struct CadetPeer);
-  cp->pid = *peer_id;
-  cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
-                                                           GNUNET_YES);
-  cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_put (peers,
-                                                    &cp->pid,
-                                                    cp,
-                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating peer %s\n",
-       GCP_2s (cp));
-  return cp;
-}
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp)
-{
-  return &cp->pid;
-}
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls)
-{
-  GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                         iter,
-                                         cls);
-}
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp)
-{
-  return cp->num_paths;
-}
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
-                   GCP_PathIterator callback,
-                   void *callback_cls)
-{
-  unsigned int ret = 0;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Iterating over paths to peer %s%s\n",
-       GCP_2s (cp),
-       (NULL == cp->core_mq) ? "" : " including direct link");
-  if (NULL != cp->core_mq)
-  {
-    struct CadetPeerPath *path;
-
-    path = GCPP_get_path_from_route (1,
-                                     &cp->pid);
-    ret++;
-    if (GNUNET_NO ==
-        callback (callback_cls,
-                  path,
-                  0))
-      return ret;
-  }
-  for (unsigned int i=0;i<cp->path_dll_length;i++)
-  {
-    for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
-         NULL != pe;
-         pe = pe->next)
-    {
-      ret++;
-      if (GNUNET_NO ==
-          callback (callback_cls,
-                    pe->path,
-                    i))
-        return ret;
-    }
-  }
-  return ret;
-}
-
-
-/**
- * Iterate over the paths to @a cp where
- * @a cp is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a cp to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
-                      unsigned int dist,
-                      GCP_PathIterator callback,
-                      void *callback_cls)
-{
-  unsigned int ret = 0;
-
-  if (dist >= cp->path_dll_length)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Asked to look for paths at distance %u, but maximum for me is < %u\n",
-         dist,
-         cp->path_dll_length);
-    return 0;
-  }
-  for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
-       NULL != pe;
-       pe = pe->next)
-  {
-    if (GNUNET_NO ==
-        callback (callback_cls,
-                  pe->path,
-                  dist))
-      return ret;
-    ret++;
-  }
-  return ret;
-}
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
-                int create)
-{
-  if (NULL == cp)
-    return NULL;
-  if ( (NULL != cp->t) ||
-       (GNUNET_NO == create) )
-    return cp->t;
-  cp->t = GCT_create_tunnel (cp);
-  consider_peer_activate (cp);
-  return cp->t;
-}
-
-
-/**
- * Hello offer was passed to the transport service. Mark it
- * as done.
- *
- * @param cls the `struct CadetPeer` where the offer completed
- */
-static void
-hello_offer_done (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  cp->hello_offer = NULL;
-}
-
-
-/**
- * We got a HELLO for a @a peer, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
-               const struct GNUNET_HELLO_Message *hello)
-{
-  struct GNUNET_HELLO_Message *mrg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got %u byte HELLO for peer %s\n",
-       (unsigned int) GNUNET_HELLO_size (hello),
-       GCP_2s (cp));
-  if (NULL != cp->hello_offer)
-  {
-    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
-    cp->hello_offer = NULL;
-  }
-  if (NULL != cp->hello)
-  {
-    mrg = GNUNET_HELLO_merge (hello,
-                              cp->hello);
-    GNUNET_free (cp->hello);
-    cp->hello = mrg;
-  }
-  else
-  {
-    cp->hello = GNUNET_memdup (hello,
-                               GNUNET_HELLO_size (hello));
-  }
-  cp->hello_offer
-    = GNUNET_TRANSPORT_offer_hello (cfg,
-                                    GNUNET_HELLO_get_header (cp->hello) ,
-                                    &hello_offer_done,
-                                    cp);
-  /* New HELLO means cp's destruction time may change... */
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
-                 struct CadetTunnel *t)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Dropping tunnel %s to peer %s\n",
-       GCT_2s (t),
-       GCP_2s (cp));
-  GNUNET_assert (cp->t == t);
-  cp->t = NULL;
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp)
-{
-  return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Start message queue change notifications.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
-                GCP_MessageQueueNotificationCallback cb,
-                void *cb_cls)
-{
-  struct GCP_MessageQueueManager *mqm;
-
-  mqm = GNUNET_new (struct GCP_MessageQueueManager);
-  mqm->cb = cb;
-  mqm->cb_cls = cb_cls;
-  mqm->cp = cp;
-  GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
-                               cp->mqm_tail,
-                               mqm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating MQM %p for peer %s\n",
-       mqm,
-       GCP_2s (cp));
-  if (NULL != cp->core_mq)
-    cb (cb_cls,
-        GNUNET_YES);
-  return mqm;
-}
-
-
-/**
- * Stops message queue change notifications.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
-                       struct GNUNET_MQ_Envelope *last_env)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying MQM %p for peer %s%s\n",
-       mqm,
-       GCP_2s (cp),
-       (NULL == last_env) ? "" : " with last ditch transmission");
-  if (NULL != mqm->env)
-    GNUNET_MQ_discard (mqm->env);
-  if (NULL != last_env)
-  {
-    if (NULL != cp->core_mq)
-    {
-      GNUNET_MQ_notify_sent (last_env,
-                             &mqm_send_done,
-                             cp);
-      GNUNET_MQ_send (cp->core_mq,
-                      last_env);
-    }
-    else
-    {
-      GNUNET_MQ_discard (last_env);
-    }
-  }
-  if (cp->mqm_ready_ptr == mqm)
-    cp->mqm_ready_ptr = mqm->next;
-  GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
-                               cp->mqm_tail,
-                               mqm);
-  GNUNET_free (mqm);
-}
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP.  Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
-              struct GNUNET_MQ_Envelope *env)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message to %s out of management\n",
-       GCP_2s (cp));
-  if (NULL == cp->core_mq)
-  {
-    GNUNET_MQ_discard (env);
-    return;
-  }
-  GNUNET_MQ_notify_sent (env,
-                         &mqm_send_done,
-                         cp);
-  GNUNET_MQ_send (cp->core_mq,
-                  env);
-}
-
-
-
-
-/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h
deleted file mode 100644 (file)
index e1d6fc3..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.h
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_PEER_H
-#define GNUNET_SERVICE_CADET_PEER_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *peer);
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
-         int create);
-
-
-/**
- * Calculate how desirable a path is for @a cp if
- * @a cp is at offset @a off in the path.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in a path
- * @return score how useful a path is to reach @a cp,
- *         positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
-                              unsigned int off);
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp);
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls);
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp);
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp);
-
-
-/**
- * Peer path iterator.
- *
- * @param cls Closure.
- * @param path Path itself
- * @param off offset of the target peer in @a path
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-typedef int
-(*GCP_PathIterator) (void *cls,
-                     struct CadetPeerPath *path,
-                     unsigned int off);
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
-                   GCP_PathIterator callback,
-                   void *callback_cls);
-
-
-/**
- * Iterate over the paths to @a peer where
- * @a peer is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a peer to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
-                      unsigned int dist,
-                      GCP_PathIterator callback,
-                      void *callback_cls);
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
-                       struct CadetPeerPathEntry *entry,
-                       unsigned int off);
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
-                    struct CadetPeerPathEntry *entry,
-                    unsigned int off);
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
-                int create);
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
-                 struct CadetTunnel *t);
-
-
-/**
- * Try adding a @a path to this @a cp.  If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force for attaching the path
- * @return NULL if this peer does not care to become a new owner,
- *         otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 unsigned int off,
-                 int force);
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 struct GNUNET_CONTAINER_HeapNode *hn);
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
-                    struct CadetConnection *cc);
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
-                       struct CadetConnection *cc);
-
-
-/**
- * We got a HELLO for a @a cp, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
-               const struct GNUNET_HELLO_Message *hello);
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers (void);
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * in our ability to transmit to a given peer.
- *
- * All queue managers will be given equal chance for sending messages
- * to @a cp.  This construct this guarantees fairness for access to @a
- * cp among the different message queues.  Each connection or route
- * will have its respective message queue managers for each direction.
- */
-struct GCP_MessageQueueManager;
-
-
-/**
- * Function to call with updated message queue object.
- *
- * @param cls closure
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-typedef void
-(*GCP_MessageQueueNotificationCallback)(void *cls,
-                                        int available);
-
-
-/**
- * Start message queue change notifications.  Will create a new slot
- * to manage the message queue to the given @a cp.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
-                GCP_MessageQueueNotificationCallback cb,
-                void *cb_cls);
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp);
-
-
-/**
- * Send the message in @a env via a @a mqm.  Must only be called at
- * most once after the respective
- * #GCP_MessageQueueNotificationCallback was called with `available`
- * set to #GNUNET_YES, and not after the callback was called with
- * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
- *
- * @param mqm message queue manager for the transmission
- * @param env envelope with the message to send; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
-          struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP.  Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
-              struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Stops message queue change notifications and sends a last message.
- * In practice, this is implemented by sending that @a last_env
- * message immediately (if any), ignoring queue order.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
-                       struct GNUNET_MQ_Envelope *last_env);
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
-            struct GNUNET_MQ_Handle *mq);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c
deleted file mode 100644 (file)
index d508606..0000000
+++ /dev/null
@@ -1,3441 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_tunnels.c
- * @brief Information we track per tunnel.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * FIXME:
- * - proper connection evaluation during connection management:
- *   + consider quality (or quality spread?) of current connection set
- *     when deciding how often to do maintenance
- *   + interact with PEER to drive DHT GET/PUT operations based
- *     on how much we like our connections
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet_signatures.h"
-#include "gnunet-service-cadet-new.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
-
-/**
- * How often do we try to decrypt payload with unverified key
- * material?  Used to limit CPU increase upon receiving bogus
- * KX.
- */
-#define MAX_UNVERIFIED_ATTEMPTS 16
-
-/**
- * How long do we wait until tearing down an idle tunnel?
- */
-#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
-
-/**
- * How long do we wait initially before retransmitting the KX?
- * TODO: replace by 2 RTT if/once we have connection-level RTT data!
- */
-#define INITIAL_KX_RETRY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-/**
- * Maximum number of skipped keys we keep in memory per tunnel.
- */
-#define MAX_SKIPPED_KEYS 64
-
-/**
- * Maximum number of keys (and thus ratchet steps) we are willing to
- * skip before we decide this is either a bogus packet or a DoS-attempt.
- */
-#define MAX_KEY_GAP 256
-
-
-/**
- * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
- */
-struct CadetTunnelSkippedKey
-{
-  /**
-   * DLL next.
-   */
-  struct CadetTunnelSkippedKey *next;
-
-  /**
-   * DLL prev.
-   */
-  struct CadetTunnelSkippedKey *prev;
-
-  /**
-   * When was this key stored (for timeout).
-   */
-  struct GNUNET_TIME_Absolute timestamp;
-
-  /**
-   * Header key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-
-  /**
-   * Message key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-
-  /**
-   * Key number for a given HK.
-   */
-  unsigned int Kn;
-};
-
-
-/**
- * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
- */
-struct CadetTunnelAxolotl
-{
-  /**
-   * A (double linked) list of stored message keys and associated header keys
-   * for "skipped" messages, i.e. messages that have not been
-   * received despite the reception of more recent messages, (head).
-   */
-  struct CadetTunnelSkippedKey *skipped_head;
-
-  /**
-   * Skipped messages' keys DLL, tail.
-   */
-  struct CadetTunnelSkippedKey *skipped_tail;
-
-  /**
-   * 32-byte root key which gets updated by DH ratchet.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey RK;
-
-  /**
-   * 32-byte header key (currently used for sending).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
-
-  /**
-   * 32-byte header key (currently used for receiving)
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
-
-  /**
-   * 32-byte next header key (for sending), used once the
-   * ratchet advances.  We are sure that the sender has this
-   * key as well only after @e ratchet_allowed is #GNUNET_YES.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
-
-  /**
-   * 32-byte next header key (for receiving).  To be tried
-   * when decrypting with @e HKr fails and thus the sender
-   * may have advanced the ratchet.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy) for
-   * sending messages. Updated for every message.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy) for
-   * receiving messages. Updated for every message. If
-   * messages are skipped, the respective derived MKs
-   * (and the current @HKr) are kept in the @e skipped_head DLL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
-
-  /**
-   * ECDH for key exchange (A0 / B0).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
-
-  /**
-   * ECDH Ratchet key (our private key in the current DH).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
-
-  /**
-   * ECDH Ratchet key (other peer's public key in the current DH).
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
-
-  /**
-   * Time when the current ratchet expires and a new one is triggered
-   * (if @e ratchet_allowed is #GNUNET_YES).
-   */
-  struct GNUNET_TIME_Absolute ratchet_expiration;
-
-  /**
-   * Number of elements in @a skipped_head <-> @a skipped_tail.
-   */
-  unsigned int skipped;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to send).
-   */
-  uint32_t Ns;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to recv).
-   */
-  uint32_t Nr;
-
-  /**
-   * Previous message numbers (# of msgs sent under prev ratchet)
-   */
-  uint32_t PNs;
-
-  /**
-   * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
-   */
-  int ratchet_flag;
-
-  /**
-   * True (#GNUNET_YES) if we have received a message from the
-   * other peer that uses the keys from our last ratchet step.
-   * This implies that we are again allowed to advance the ratchet,
-   * otherwise we have to wait until the other peer sees our current
-   * ephemeral key and advances first.
-   *
-   * #GNUNET_NO if we have advanced the ratched but lack any evidence
-   * that the other peer has noticed this.
-   */
-  int ratchet_allowed;
-
-  /**
-   * Number of messages recieved since our last ratchet advance.
-   *
-   * If this counter = 0, we cannot send a new ratchet key in the next
-   * message.
-   *
-   * If this counter > 0, we could (but don't have to) send a new key.
-   *
-   * Once the @e ratchet_counter is larger than
-   * #ratchet_messages (or @e ratchet_expiration time has past), and
-   * @e ratchet_allowed is #GNUNET_YES, we advance the ratchet.
-   */
-  unsigned int ratchet_counter;
-
-};
-
-
-/**
- * Struct used to save messages in a non-ready tunnel to send once connected.
- */
-struct CadetTunnelQueueEntry
-{
-  /**
-   * We are entries in a DLL
-   */
-  struct CadetTunnelQueueEntry *next;
-
-  /**
-   * We are entries in a DLL
-   */
-  struct CadetTunnelQueueEntry *prev;
-
-  /**
-   * Tunnel these messages belong in.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Continuation to call once sent (on the channel layer).
-   */
-  GCT_SendContinuation cont;
-
-  /**
-   * Closure for @c cont.
-   */
-  void *cont_cls;
-
-  /**
-   * Envelope of message to send follows.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-  /**
-   * Where to put the connection identifier into the payload
-   * of the message in @e env once we have it?
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
-};
-
-
-/**
- * Struct containing all information regarding a tunnel to a peer.
- */
-struct CadetTunnel
-{
-  /**
-   * Destination of the tunnel.
-   */
-  struct CadetPeer *destination;
-
-  /**
-   * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
-   * ephemeral key changes.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
-
-  /**
-   * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
-
-  /**
-   * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
-
-  /**
-   * Axolotl info.
-   */
-  struct CadetTunnelAxolotl ax;
-
-  /**
-   * Unverified Axolotl info, used only if we got a fresh KX (not a
-   * KX_AUTH) while our end of the tunnel was still up.  In this case,
-   * we keep the fresh KX around but do not put it into action until
-   * we got encrypted payload that assures us of the authenticity of
-   * the KX.
-   */
-  struct CadetTunnelAxolotl *unverified_ax;
-
-  /**
-   * Task scheduled if there are no more channels using the tunnel.
-   */
-  struct GNUNET_SCHEDULER_Task *destroy_task;
-
-  /**
-   * Task to trim connections if too many are present.
-   */
-  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
-
-  /**
-   * Task to send messages from queue (if possible).
-   */
-  struct GNUNET_SCHEDULER_Task *send_task;
-
-  /**
-   * Task to trigger KX.
-   */
-  struct GNUNET_SCHEDULER_Task *kx_task;
-
-  /**
-   * Tokenizer for decrypted messages.
-   */
-  struct GNUNET_MessageStreamTokenizer *mst;
-
-  /**
-   * Dispatcher for decrypted messages only (do NOT use for sending!).
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * DLL of ready connections that are actively used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_ready_head;
-
-  /**
-   * DLL of ready connections that are actively used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_ready_tail;
-
-  /**
-   * DLL of connections that we maintain that might be used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_busy_head;
-
-  /**
-   * DLL of connections that we maintain that might be used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_busy_tail;
-
-  /**
-   * Channels inside this tunnel. Maps
-   * `struct GNUNET_CADET_ChannelTunnelNumber` to a `struct CadetChannel`.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
-  /**
-   * Channel ID for the next created channel in this tunnel.
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
-
-  /**
-   * Queued messages, to transmit once tunnel gets connected.
-   */
-  struct CadetTunnelQueueEntry *tq_head;
-
-  /**
-   * Queued messages, to transmit once tunnel gets connected.
-   */
-  struct CadetTunnelQueueEntry *tq_tail;
-
-  /**
-   * Identification of the connection from which we are currently processing
-   * a message. Only valid (non-NULL) during #handle_decrypted() and the
-   * handle-*()-functions called from our @e mq during that function.
-   */
-  struct CadetTConnection *current_ct;
-
-  /**
-   * How long do we wait until we retry the KX?
-   */
-  struct GNUNET_TIME_Relative kx_retry_delay;
-
-  /**
-   * When do we try the next KX?
-   */
-  struct GNUNET_TIME_Absolute next_kx_attempt;
-
-  /**
-   * Number of connections in the @e connection_ready_head DLL.
-   */
-  unsigned int num_ready_connections;
-
-  /**
-   * Number of connections in the @e connection_busy_head DLL.
-   */
-  unsigned int num_busy_connections;
-
-  /**
-   * How often have we tried and failed to decrypt a message using
-   * the unverified KX material from @e unverified_ax?  Used to
-   * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
-   */
-  unsigned int unverified_attempts;
-
-  /**
-   * Number of entries in the @e tq_head DLL.
-   */
-  unsigned int tq_len;
-
-  /**
-   * State of the tunnel encryption.
-   */
-  enum CadetTunnelEState estate;
-
-  /**
-   * Force triggering KX_AUTH independent of @e estate.
-   */
-  int kx_auth_requested;
-
-};
-
-
-/**
- * Connection @a ct is now unready, clear it's ready flag
- * and move it from the ready DLL to the busy DLL.
- *
- * @param ct connection to move to unready status
- */
-static void
-mark_connection_unready (struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = ct->t;
-
-  GNUNET_assert (GNUNET_YES == ct->is_ready);
-  GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
-                               t->connection_ready_tail,
-                               ct);
-  GNUNET_assert (0 < t->num_ready_connections);
-  t->num_ready_connections--;
-  ct->is_ready = GNUNET_NO;
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-}
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t)
-{
-  static char buf[64];
-
-  if (NULL == t)
-    return "Tunnel(NULL)";
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Tunnel %s",
-                   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_AX_RECV:
-    return "CADET_TUNNEL_KEY_AX_RECV";
-  case CADET_TUNNEL_KEY_AX_SENT:
-    return "CADET_TUNNEL_KEY_AX_SENT";
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    return "CADET_TUNNEL_KEY_AX_SENT_AND_RECV";
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
-  case CADET_TUNNEL_KEY_OK:
-    return "CADET_TUNNEL_KEY_OK";
-  default:
-    GNUNET_snprintf (buf,
-                     sizeof (buf),
-                     "%u (UNKNOWN STATE)",
-                     es);
-    return buf;
-  }
-}
-
-
-/**
- * Return the peer to which this tunnel goes.
- *
- * @param t a tunnel
- * @return the destination of the tunnel
- */
-struct CadetPeer *
-GCT_get_destination (struct CadetTunnel *t)
-{
-  return t->destination;
-}
-
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t)
-{
-  return GNUNET_CONTAINER_multihashmap32_size (t->channels);
-}
-
-
-/**
- * Lookup a channel by its @a ctn.
- *
- * @param t tunnel to look in
- * @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 ctn)
-{
-  return GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              ntohl (ctn.cn));
-}
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (const struct CadetTunnel *t)
-{
-  return t->num_ready_connections + t->num_busy_connections;
-}
-
-
-/**
- * Find first connection that is ready in the list of
- * our connections.  Picks ready connections round-robin.
- *
- * @param t tunnel to search
- * @return NULL if we have no connection that is ready
- */
-static struct CadetTConnection *
-get_ready_connection (struct CadetTunnel *t)
-{
-  struct CadetTConnection *hd = t->connection_ready_head;
-
-  GNUNET_assert ( (NULL == hd) ||
-                  (GNUNET_YES == hd->is_ready) );
-  return hd;
-}
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t)
-{
-  return t->estate;
-}
-
-
-/**
- * Called when either we have a new connection, or a new message in the
- * queue, or some existing connection has transmission capacity.  Looks
- * at our message queue and if there is a message, picks a connection
- * to send it on.
- *
- * @param cls the `struct CadetTunnel` to process messages on
- */
-static void
-trigger_transmissions (void *cls);
-
-
-/* ************************************** start core crypto ***************************** */
-
-
-/**
- * Create a new Axolotl ephemeral (ratchet) key.
- *
- * @param ax key material to update
- */
-static void
-new_ephemeral (struct CadetTunnelAxolotl *ax)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating new ephemeral ratchet key (DHRs)\n");
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
-}
-
-
-/**
- * Calculate HMAC.
- *
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param key Key to use.
- * @param hmac[out] Destination to store the HMAC.
- */
-static void
-t_hmac (const void *plaintext,
-        size_t size,
-        uint32_t iv,
-        const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-        struct GNUNET_ShortHashCode *hmac)
-{
-  static const char ctx[] = "cadet authentication key";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-  struct GNUNET_HashCode hash;
-
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
-                                 key,
-                                 &iv, sizeof (iv),
-                                 key, sizeof (*key),
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  /* Two step: GNUNET_ShortHash is only 256 bits,
-     GNUNET_HashCode is 512, so we truncate. */
-  GNUNET_CRYPTO_hmac (&auth_key,
-                      plaintext,
-                      size,
-                      &hash);
-  GNUNET_memcpy (hmac,
-                 &hash,
-                 sizeof (*hmac));
-}
-
-
-/**
- * Perform a HMAC.
- *
- * @param key Key to use.
- * @param[out] hash Resulting HMAC.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_ax_hmac_hash (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                struct GNUNET_HashCode *hash,
-                const void *source,
-                unsigned int len)
-{
-  static const char ctx[] = "axolotl HMAC-HASH";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
-                                 key,
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  GNUNET_CRYPTO_hmac (&auth_key,
-                      source,
-                      len,
-                      hash);
-}
-
-
-/**
- * Derive a symmetric encryption key from an HMAC-HASH.
- *
- * @param key Key to use for the HMAC.
- * @param[out] out Key to generate.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
-                   const void *source,
-                   unsigned int len)
-{
-  static const char ctx[] = "axolotl derive key";
-  struct GNUNET_HashCode h;
-
-  t_ax_hmac_hash (key,
-                  &h,
-                  source,
-                  len);
-  GNUNET_CRYPTO_kdf (out, sizeof (*out),
-                     ctx, sizeof (ctx),
-                     &h, sizeof (h),
-                     NULL);
-}
-
-
-/**
- * Encrypt data with the axolotl tunnel key.
- *
- * @param ax key material to use.
- * @param dst Destination with @a size bytes for the encrypted data.
- * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
- * @param size Size of the buffers at @a src and @a dst
- */
-static void
-t_ax_encrypt (struct CadetTunnelAxolotl *ax,
-              void *dst,
-              const void *src,
-              size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  ax->ratchet_counter++;
-  if ( (GNUNET_YES == ax->ratchet_allowed) &&
-       ( (ratchet_messages <= ax->ratchet_counter) ||
-         (0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) )
-  {
-    ax->ratchet_flag = GNUNET_YES;
-  }
-  if (GNUNET_YES == ax->ratchet_flag)
-  {
-    /* Advance ratchet */
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
-    struct GNUNET_HashCode dh;
-    struct GNUNET_HashCode hmac;
-    static const char ctx[] = "axolotl ratchet";
-
-    new_ephemeral (ax);
-    ax->HKs = ax->NHKs;
-
-    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
-    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
-                            &ax->DHRr,
-                            &dh);
-    t_ax_hmac_hash (&ax->RK,
-                    &hmac,
-                    &dh,
-                    sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                       ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac),
-                       NULL);
-    ax->RK = keys[0];
-    ax->NHKs = keys[1];
-    ax->CKs = keys[2];
-
-    ax->PNs = ax->Ns;
-    ax->Ns = 0;
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_allowed = GNUNET_NO;
-    ax->ratchet_counter = 0;
-    ax->ratchet_expiration
-      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
-                                  ratchet_time);
-  }
-
-  t_hmac_derive_key (&ax->CKs,
-                     &MK,
-                     "0",
-                     1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &MK,
-                                     NULL, 0,
-                                     NULL);
-
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (src,
-                                              size,
-                                              &MK,
-                                              &iv,
-                                              dst);
-  GNUNET_assert (size == out_size);
-  t_hmac_derive_key (&ax->CKs,
-                     &ax->CKs,
-                     "1",
-                     1);
-}
-
-
-/**
- * Decrypt data with the axolotl tunnel key.
- *
- * @param ax key material to use.
- * @param dst Destination for the decrypted data, must contain @a size bytes.
- * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes.
- * @param size Size of the @a src and @a dst buffers
- */
-static void
-t_ax_decrypt (struct CadetTunnelAxolotl *ax,
-              void *dst,
-              const void *src,
-              size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  t_hmac_derive_key (&ax->CKr,
-                     &MK,
-                     "0",
-                     1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &MK,
-                                     NULL, 0,
-                                     NULL);
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (src,
-                                              size,
-                                              &MK,
-                                              &iv,
-                                              dst);
-  GNUNET_assert (out_size == size);
-  t_hmac_derive_key (&ax->CKr,
-                     &ax->CKr,
-                     "1",
-                     1);
-}
-
-
-/**
- * Encrypt header with the axolotl header key.
- *
- * @param ax key material to use.
- * @param[in|out] msg Message whose header to encrypt.
- */
-static void
-t_h_encrypt (struct CadetTunnelAxolotl *ax,
-             struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &ax->HKs,
-                                     NULL, 0,
-                                     NULL);
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->ax_header,
-                                              sizeof (struct GNUNET_CADET_AxHeader),
-                                              &ax->HKs,
-                                              &iv,
-                                              &msg->ax_header);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
-}
-
-
-/**
- * Decrypt header with the current axolotl header key.
- *
- * @param ax key material to use.
- * @param src Message whose header to decrypt.
- * @param dst Where to decrypt header to.
- */
-static void
-t_h_decrypt (struct CadetTunnelAxolotl *ax,
-             const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &ax->HKr,
-                                     NULL, 0,
-                                     NULL);
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
-                                              sizeof (struct GNUNET_CADET_AxHeader),
-                                              &ax->HKr,
-                                              &iv,
-                                              &dst->ax_header.Ns);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param ax key material to delete @a key from.
- * @param key Key to delete.
- */
-static void
-delete_skipped_key (struct CadetTunnelAxolotl *ax,
-                    struct CadetTunnelSkippedKey *key)
-{
-  GNUNET_CONTAINER_DLL_remove (ax->skipped_head,
-                               ax->skipped_tail,
-                               key);
-  GNUNET_free (key);
-  ax->skipped--;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param ax key material to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static ssize_t
-try_old_ax_keys (struct CadetTunnelAxolotl *ax,
-                 void *dst,
-                 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-                 size_t size)
-{
-  struct CadetTunnelSkippedKey *key;
-  struct GNUNET_ShortHashCode *hmac;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
-  size_t esize;
-  size_t res;
-  size_t len;
-  unsigned int N;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Trying skipped keys\n");
-  hmac = &plaintext_header.hmac;
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
-  /* Find a correct Header Key */
-  valid_HK = NULL;
-  for (key = ax->skipped_head; NULL != key; key = key->next)
-  {
-    t_hmac (&src->ax_header,
-            sizeof (struct GNUNET_CADET_AxHeader) + esize,
-            0,
-            &key->HK,
-            hmac);
-    if (0 == memcmp (hmac,
-                     &src->hmac,
-                     sizeof (*hmac)))
-    {
-      valid_HK = &key->HK;
-      break;
-    }
-  }
-  if (NULL == key)
-    return -1;
-
-  /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
-  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
-  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-  GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
-
-  /* Decrypt header */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &key->HK,
-                                     NULL, 0,
-                                     NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
-                                         sizeof (struct GNUNET_CADET_AxHeader),
-                                         &key->HK,
-                                         &iv,
-                                         &plaintext_header.ax_header.Ns);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == res);
-
-  /* Find the correct message key */
-  N = ntohl (plaintext_header.ax_header.Ns);
-  while ( (NULL != key) &&
-          (N != key->Kn) )
-    key = key->next;
-  if ( (NULL == key) ||
-       (0 != memcmp (&key->HK,
-                     valid_HK,
-                     sizeof (*valid_HK))) )
-    return -1;
-
-  /* Decrypt payload */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &key->MK,
-                                     NULL,
-                                     0,
-                                     NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src[1],
-                                         len,
-                                         &key->MK,
-                                         &iv,
-                                         dst);
-  delete_skipped_key (ax,
-                      key);
-  return res;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param ax key material to delete from.
- * @param HKr Header Key to use.
- */
-static void
-store_skipped_key (struct CadetTunnelAxolotl *ax,
-                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
-{
-  struct CadetTunnelSkippedKey *key;
-
-  key = GNUNET_new (struct CadetTunnelSkippedKey);
-  key->timestamp = GNUNET_TIME_absolute_get ();
-  key->Kn = ax->Nr;
-  key->HK = ax->HKr;
-  t_hmac_derive_key (&ax->CKr,
-                     &key->MK,
-                     "0",
-                     1);
-  t_hmac_derive_key (&ax->CKr,
-                     &ax->CKr,
-                     "1",
-                     1);
-  GNUNET_CONTAINER_DLL_insert (ax->skipped_head,
-                               ax->skipped_tail,
-                               key);
-  ax->skipped++;
-  ax->Nr++;
-}
-
-
-/**
- * Stage skipped AX keys and calculate the message key.
- * Stores each HK and MK for skipped messages.
- *
- * @param ax key material to use
- * @param HKr Header key.
- * @param Np Received meesage number.
- * @return #GNUNET_OK if keys were stored.
- *         #GNUNET_SYSERR if an error ocurred (@a Np not expected).
- */
-static int
-store_ax_keys (struct CadetTunnelAxolotl *ax,
-               const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
-               uint32_t Np)
-{
-  int gap;
-
-  gap = Np - ax->Nr;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Storing skipped keys [%u, %u)\n",
-       ax->Nr,
-       Np);
-  if (MAX_KEY_GAP < gap)
-  {
-    /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */
-    /* TODO: start new key exchange on return */
-    GNUNET_break_op (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Got message %u, expected %u+\n",
-         Np,
-         ax->Nr);
-    return GNUNET_SYSERR;
-  }
-  if (0 > gap)
-  {
-    /* Delayed message: don't store keys, flag to try old keys. */
-    return GNUNET_SYSERR;
-  }
-
-  while (ax->Nr < Np)
-    store_skipped_key (ax,
-                       HKr);
-
-  while (ax->skipped > MAX_SKIPPED_KEYS)
-    delete_skipped_key (ax,
-                        ax->skipped_tail);
-  return GNUNET_OK;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param ax key material to use
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static ssize_t
-t_ax_decrypt_and_validate (struct CadetTunnelAxolotl *ax,
-                           void *dst,
-                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-                           size_t size)
-{
-  struct GNUNET_ShortHashCode msg_hmac;
-  struct GNUNET_HashCode hmac;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  uint32_t Np;
-  uint32_t PNp;
-  size_t esize; /* Size of encryped payload */
-
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
-  /* Try current HK */
-  t_hmac (&src->ax_header,
-          sizeof (struct GNUNET_CADET_AxHeader) + esize,
-          0, &ax->HKr,
-          &msg_hmac);
-  if (0 != memcmp (&msg_hmac,
-                   &src->hmac,
-                   sizeof (msg_hmac)))
-  {
-    static const char ctx[] = "axolotl ratchet";
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
-    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-    struct GNUNET_HashCode dh;
-    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
-
-    /* Try Next HK */
-    t_hmac (&src->ax_header,
-            sizeof (struct GNUNET_CADET_AxHeader) + esize,
-            0,
-            &ax->NHKr,
-            &msg_hmac);
-    if (0 != memcmp (&msg_hmac,
-                     &src->hmac,
-                     sizeof (msg_hmac)))
-    {
-      /* Try the skipped keys, if that fails, we're out of luck. */
-      return try_old_ax_keys (ax,
-                              dst,
-                              src,
-                              size);
-    }
-    HK = ax->HKr;
-    ax->HKr = ax->NHKr;
-    t_h_decrypt (ax,
-                 src,
-                 &plaintext_header);
-    Np = ntohl (plaintext_header.ax_header.Ns);
-    PNp = ntohl (plaintext_header.ax_header.PNs);
-    DHRp = &plaintext_header.ax_header.DHRs;
-    store_ax_keys (ax,
-                   &HK,
-                   PNp);
-
-    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
-    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
-                            DHRp,
-                            &dh);
-    t_ax_hmac_hash (&ax->RK,
-                    &hmac,
-                    &dh, sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                       ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac),
-                       NULL);
-
-    /* Commit "purported" keys */
-    ax->RK = keys[0];
-    ax->NHKr = keys[1];
-    ax->CKr = keys[2];
-    ax->DHRr = *DHRp;
-    ax->Nr = 0;
-    ax->ratchet_allowed = GNUNET_YES;
-  }
-  else
-  {
-    t_h_decrypt (ax,
-                 src,
-                 &plaintext_header);
-    Np = ntohl (plaintext_header.ax_header.Ns);
-    PNp = ntohl (plaintext_header.ax_header.PNs);
-  }
-  if ( (Np != ax->Nr) &&
-       (GNUNET_OK != store_ax_keys (ax,
-                                    &ax->HKr,
-                                    Np)) )
-  {
-    /* Try the skipped keys, if that fails, we're out of luck. */
-    return try_old_ax_keys (ax,
-                            dst,
-                            src,
-                            size);
-  }
-
-  t_ax_decrypt (ax,
-                dst,
-                &src[1],
-                esize);
-  ax->Nr = Np + 1;
-  return esize;
-}
-
-
-/**
- * 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.
- *
- * @param t Tunnel whose encryption state to change, or NULL.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel *t,
-                   enum CadetTunnelEState state)
-{
-  enum CadetTunnelEState old = t->estate;
-
-  t->estate = state;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s estate changed from %s to %s\n",
-       GCT_2s (t),
-       estate2s (old),
-       estate2s (state));
-
-  if ( (CADET_TUNNEL_KEY_OK != old) &&
-       (CADET_TUNNEL_KEY_OK == t->estate) )
-  {
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    /* notify all channels that have been waiting */
-    GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                             &notify_tunnel_up_cb,
-                                             t);
-    if (NULL != t->send_task)
-      GNUNET_SCHEDULER_cancel (t->send_task);
-    t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                             t);
-  }
-}
-
-
-/**
- * Send a KX message.
- *
- * @param t tunnel on which to send the KX_AUTH
- * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
- *           we are to find one that is ready.
- * @param ax axolotl key context to use
- */
-static void
-send_kx (struct CadetTunnel *t,
-         struct CadetTConnection *ct,
-         struct CadetTunnelAxolotl *ax)
-{
-  struct CadetConnection *cc;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
-  enum GNUNET_CADET_KX_Flags flags;
-
-  if ( (NULL == ct) ||
-       (GNUNET_NO == ct->is_ready) )
-    ct = get_ready_connection (t);
-  if (NULL == ct)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Wanted to send %s in state %s, but no connection is ready, deferring\n",
-         GCT_2s (t),
-         estate2s (t->estate));
-    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
-    return;
-  }
-  cc = ct->cc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending KX on %s via %s in state %s\n",
-       GCT_2s (t),
-       GCC_2s (cc),
-       estate2s (t->estate));
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
-  flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
-  msg->flags = htonl (flags);
-  msg->cid = *GCC_get_id (cc);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
-                                      &msg->ephemeral_key);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
-                                      &msg->ratchet_key);
-  mark_connection_unready (ct);
-  t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
-  t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
-  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT);
-  else if (CADET_TUNNEL_KEY_AX_RECV == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
-  GCC_transmit (cc,
-                env);
-}
-
-
-/**
- * Send a KX_AUTH message.
- *
- * @param t tunnel on which to send the KX_AUTH
- * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
- *           we are to find one that is ready.
- * @param ax axolotl key context to use
- * @param force_reply Force the other peer to reply with a KX_AUTH message
- *         (set if we would like to transmit right now, but cannot)
- */
-static void
-send_kx_auth (struct CadetTunnel *t,
-              struct CadetTConnection *ct,
-              struct CadetTunnelAxolotl *ax,
-              int force_reply)
-{
-  struct CadetConnection *cc;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg;
-  enum GNUNET_CADET_KX_Flags flags;
-
-  if ( (NULL == ct) ||
-       (GNUNET_NO == ct->is_ready) )
-    ct = get_ready_connection (t);
-  if (NULL == ct)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Wanted to send KX_AUTH on %s, but no connection is ready, deferring\n",
-         GCT_2s (t));
-    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
-    t->kx_auth_requested = GNUNET_YES; /* queue KX_AUTH independent of estate */
-    return;
-  }
-  t->kx_auth_requested = GNUNET_NO; /* clear flag */
-  cc = ct->cc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending KX_AUTH on %s using %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
-  flags = GNUNET_CADET_KX_FLAG_NONE;
-  if (GNUNET_YES == force_reply)
-    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
-  msg->kx.flags = htonl (flags);
-  msg->kx.cid = *GCC_get_id (cc);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
-                                      &msg->kx.ephemeral_key);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
-                                      &msg->kx.ratchet_key);
-  /* Compute authenticator (this is the main difference to #send_kx()) */
-  GNUNET_CRYPTO_hash (&ax->RK,
-                      sizeof (ax->RK),
-                      &msg->auth);
-
-  /* Compute when to be triggered again; actual job will
-     be scheduled via #connection_ready_cb() */
-  t->kx_retry_delay
-    = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
-  t->next_kx_attempt
-    = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
-
-  /* Send via cc, mark it as unready */
-  mark_connection_unready (ct);
-
-  /* Update state machine, unless we are already OK */
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_AUTH_SENT);
-
-  GCC_transmit (cc,
-                env);
-}
-
-
-/**
- * Cleanup state used by @a ax.
- *
- * @param ax state to free, but not memory of @a ax itself
- */
-static void
-cleanup_ax (struct CadetTunnelAxolotl *ax)
-{
-  while (NULL != ax->skipped_head)
-    delete_skipped_key (ax,
-                        ax->skipped_head);
-  GNUNET_assert (0 == ax->skipped);
-  GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
-  GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
-}
-
-
-/**
- * Update our Axolotl key state based on the KX data we received.
- * Computes the new chain keys, and root keys, etc, and also checks
- * wether this is a replay of the current chain.
- *
- * @param[in|out] axolotl chain key state to recompute
- * @param pid peer identity of the other peer
- * @param ephemeral_key ephemeral public key of the other peer
- * @param ratchet_key senders next ephemeral public key
- * @return #GNUNET_OK on success, #GNUNET_NO if the resulting
- *       root key is already in @a ax and thus the KX is useless;
- *       #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id)
- */
-static int
-update_ax_by_kx (struct CadetTunnelAxolotl *ax,
-                 const struct GNUNET_PeerIdentity *pid,
-                 const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
-                 const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key)
-{
-  struct GNUNET_HashCode key_material[3];
-  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
-  const char salt[] = "CADET Axolotl salt";
-  int am_I_alice;
-
-  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                           pid))
-    am_I_alice = GNUNET_YES;
-  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                                pid))
-    am_I_alice = GNUNET_NO;
-  else
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-
-  if (0 == memcmp (&ax->DHRr,
-                   ratchet_key,
-                   sizeof (*ratchet_key)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ratchet key already known. Ignoring KX.\n");
-    return GNUNET_NO;
-  }
-
-  ax->DHRr = *ratchet_key;
-
-  /* ECDH A B0 */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
-                              ephemeral_key, /* B0 */
-                              &key_material[0]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* B0 */
-                              &pid->public_key,    /* A */
-                              &key_material[0]);
-  }
-
-  /* ECDH A0 B */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* A0 */
-                              &pid->public_key,    /* B */
-                              &key_material[1]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
-                              ephemeral_key, /* B0 */
-                              &key_material[1]);
-
-
-  }
-
-  /* ECDH A0 B0 */
-  /* (This is the triple-DH, we could probably safely skip this,
-     as A0/B0 are already in the key material.) */
-  GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0,             /* A0 or B0 */
-                          ephemeral_key,  /* B0 or A0 */
-                          &key_material[2]);
-
-  /* KDF */
-  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                     salt, sizeof (salt),
-                     &key_material, sizeof (key_material),
-                     NULL);
-
-  if (0 == memcmp (&ax->RK,
-                   &keys[0],
-                   sizeof (ax->RK)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Root key of handshake already known. Ignoring KX.\n");
-    return GNUNET_NO;
-  }
-
-  ax->RK = keys[0];
-  if (GNUNET_YES == am_I_alice)
-  {
-    ax->HKr = keys[1];
-    ax->NHKs = keys[2];
-    ax->NHKr = keys[3];
-    ax->CKr = keys[4];
-    ax->ratchet_flag = GNUNET_YES;
-  }
-  else
-  {
-    ax->HKs = keys[1];
-    ax->NHKr = keys[2];
-    ax->NHKs = keys[3];
-    ax->CKs = keys[4];
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_expiration
-      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
-                                  ratchet_time);
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Try to redo the KX or KX_AUTH handshake, if we can.
- *
- * @param cls the `struct CadetTunnel` to do KX for.
- */
-static void
-retry_kx (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTunnelAxolotl *ax;
-
-  t->kx_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Trying to make KX progress on %s in state %s\n",
-       GCT_2s (t),
-       estate2s (t->estate));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
-  case CADET_TUNNEL_KEY_AX_SENT:       /* trying again */
-    send_kx (t,
-             NULL,
-             &t->ax);
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* We are responding, so only require reply
-       if WE have a channel waiting. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Send AX_AUTH so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* How can this be? */
-      GNUNET_break (0);
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  (0 == GCT_count_channels (t))
-                  ? GNUNET_NO
-                  : GNUNET_YES);
-    break;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* We are responding, so only require reply
-       if WE have a channel waiting. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Send AX_AUTH so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* How can this be? */
-      GNUNET_break (0);
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  (0 == GCT_count_channels (t))
-                  ? GNUNET_NO
-                  : GNUNET_YES);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* Must have been the *other* peer asking us to
-       respond with a KX_AUTH. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Sending AX_AUTH in response to AX so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* Sending AX_AUTH in response to AX_AUTH */
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  GNUNET_NO);
-    break;
-  }
-}
-
-
-/**
- * Handle KX message that lacks authentication (and which will thus
- * only be considered authenticated after we respond with our own
- * KX_AUTH and finally successfully decrypt payload).
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx (struct CadetTConnection *ct,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  struct CadetTunnelAxolotl *ax;
-  int ret;
-
-  if (0 ==
-      memcmp (&t->ax.DHRr,
-              &msg->ratchet_key,
-              sizeof (msg->ratchet_key)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate KX. Firing back KX_AUTH.\n");
-    send_kx_auth (t,
-                  ct,
-                  &t->ax,
-                  GNUNET_NO);
-    return;
-  }
-
-  /* We only keep ONE unverified KX around, so if there is an existing one,
-     clean it up. */
-  if (NULL != t->unverified_ax)
-  {
-    if (0 ==
-        memcmp (&t->unverified_ax->DHRr,
-                &msg->ratchet_key,
-                sizeof (msg->ratchet_key)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
-           GCT_2s (t));
-      send_kx_auth (t,
-                    ct,
-                    t->unverified_ax,
-                    GNUNET_NO);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Dropping old unverified KX state. Got a fresh KX for %s.\n",
-         GCT_2s (t));
-    memset (t->unverified_ax,
-            0,
-            sizeof (struct CadetTunnelAxolotl));
-    t->unverified_ax->DHRs = t->ax.DHRs;
-    t->unverified_ax->kx_0 = t->ax.kx_0;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Creating fresh unverified KX for %s.\n",
-         GCT_2s (t));
-    t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
-    t->unverified_ax->DHRs = t->ax.DHRs;
-    t->unverified_ax->kx_0 = t->ax.kx_0;
-  }
-  /* Set as the 'current' RK/DHRr the one we are currently using,
-     so that the duplicate-detection logic of
-     #update_ax_by_kx can work. */
-  t->unverified_ax->RK = t->ax.RK;
-  t->unverified_ax->DHRr = t->ax.DHRr;
-  t->unverified_attempts = 0;
-  ax = t->unverified_ax;
-
-  /* Update 'ax' by the new key material */
-  ret = update_ax_by_kx (ax,
-                         GCP_get_id (t->destination),
-                         &msg->ephemeral_key,
-                         &msg->ratchet_key);
-  GNUNET_break (GNUNET_SYSERR != ret);
-  if (GNUNET_OK != ret)
-    return; /* duplicate KX, nothing to do */
-
-  /* move ahead in our state machine */
-  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_RECV);
-  else if (CADET_TUNNEL_KEY_AX_SENT == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
-
-  /* KX is still not done, try again our end. */
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-  {
-    if (NULL != t->kx_task)
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-    t->kx_task
-      = GNUNET_SCHEDULER_add_now (&retry_kx,
-                                  t);
-  }
-}
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx_auth (struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  struct CadetTunnelAxolotl ax_tmp;
-  struct GNUNET_HashCode kx_auth;
-  int ret;
-
-  if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
-       (CADET_TUNNEL_KEY_AX_RECV == t->estate) )
-  {
-    /* Confusing, we got a KX_AUTH before we even send our own
-       KX. This should not happen. We'll send our own KX ASAP anyway,
-       so let's ignore this here. */
-    GNUNET_break_op (0);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Handling KX_AUTH message for %s\n",
-       GCT_2s (t));
-
-  /* We do everything in ax_tmp until we've checked the authentication
-     so we don't clobber anything we care about by accident. */
-  ax_tmp = t->ax;
-
-  /* Update 'ax' by the new key material */
-  ret = update_ax_by_kx (&ax_tmp,
-                         GCP_get_id (t->destination),
-                         &msg->kx.ephemeral_key,
-                         &msg->kx.ratchet_key);
-  if (GNUNET_OK != ret)
-  {
-    if (GNUNET_NO == ret)
-      GNUNET_STATISTICS_update (stats,
-                                "# redundant KX_AUTH received",
-                                1,
-                                GNUNET_NO);
-    else
-      GNUNET_break (0); /* connect to self!? */
-    return;
-  }
-  GNUNET_CRYPTO_hash (&ax_tmp.RK,
-                      sizeof (ax_tmp.RK),
-                      &kx_auth);
-  if (0 != memcmp (&kx_auth,
-                   &msg->auth,
-                   sizeof (kx_auth)))
-  {
-    /* This KX_AUTH is not using the latest KX/KX_AUTH data
-       we transmitted to the sender, refuse it, try KX again. */
-    GNUNET_STATISTICS_update (stats,
-                              "# KX_AUTH not using our last KX received (auth failure)",
-                              1,
-                              GNUNET_NO);
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  }
-  /* Yep, we're good. */
-  t->ax = ax_tmp;
-  if (NULL != t->unverified_ax)
-  {
-    /* We got some "stale" KX before, drop that. */
-    cleanup_ax (t->unverified_ax);
-    GNUNET_free (t->unverified_ax);
-    t->unverified_ax = NULL;
-  }
-
-  /* move ahead in our state machine */
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-  case CADET_TUNNEL_KEY_AX_RECV:
-    /* Checked above, this is impossible. */
-    GNUNET_assert (0);
-    break;
-  case CADET_TUNNEL_KEY_AX_SENT:      /* This is the normal case */
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV: /* both peers started KX */
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT: /* both peers now did KX_AUTH */
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_OK);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* Did not expect another KX_AUTH, but so what, still acceptable.
-       Nothing to do here. */
-    break;
-  }
-}
-
-
-
-/* ************************************** end core crypto ***************************** */
-
-
-/**
- * Compute the next free channel tunnel number for this tunnel.
- *
- * @param t the tunnel
- * @return unused number that can uniquely identify a channel in the tunnel
- */
-static struct GNUNET_CADET_ChannelTunnelNumber
-get_next_free_ctn (struct CadetTunnel *t)
-{
-#define HIGH_BIT 0x8000000
-  struct GNUNET_CADET_ChannelTunnelNumber ret;
-  uint32_t ctn;
-  int cmp;
-  uint32_t highbit;
-
-  cmp = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                         GCP_get_id (GCT_get_destination (t)));
-  if (0 < cmp)
-    highbit = HIGH_BIT;
-  else if (0 > cmp)
-    highbit = 0;
-  else
-    GNUNET_assert (0); // loopback must never go here!
-  ctn = ntohl (t->next_ctn.cn);
-  while (NULL !=
-         GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              ctn | highbit))
-  {
-    ctn = ((ctn + 1) & (~ HIGH_BIT));
-  }
-  t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
-  ret.cn = htonl (ctn | highbit);
-  return ret;
-}
-
-
-/**
- * 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
- * @return unique number identifying @a ch within @a t
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  ctn = get_next_free_ctn (t);
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (ctn.cn),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding %s to %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-    /* waiting for connection to start KX */
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* we're currently waiting for KX to complete */
-    break;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* waiting for OTHER peer to send us data,
-       we might need to prompt more aggressively! */
-    if (NULL == t->kx_task)
-      t->kx_task
-        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
-                                   &retry_kx,
-                                   t);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* We are ready. Tell the new channel that we are up. */
-    GCCH_tunnel_up (ch);
-    break;
-  }
-  return ctn;
-}
-
-
-/**
- * We lost a connection, remove it from our list and clean up
- * the connection object itself.
- *
- * @param ct binding of connection to tunnel of the connection that was lost.
- */
-void
-GCT_connection_lost (struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = ct->t;
-
-  if (GNUNET_YES == ct->is_ready)
-  {
-    GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
-                                 t->connection_ready_tail,
-                                 ct);
-    t->num_ready_connections--;
-  }
-  else
-  {
-    GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
-                                 t->connection_busy_tail,
-                                 ct);
-    t->num_busy_connections--;
-  }
-  GNUNET_free (ct);
-}
-
-
-/**
- * Clean up connection @a ct of a tunnel.
- *
- * @param cls the `struct CadetTunnel`
- * @param ct connection to clean up
- */
-static void
-destroy_t_connection (void *cls,
-                      struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetConnection *cc = ct->cc;
-
-  GNUNET_assert (ct->t == t);
-  GCT_connection_lost (ct);
-  GCC_destroy_without_tunnel (cc);
-}
-
-
-/**
- * This tunnel is no longer used, destroy it.
- *
- * @param cls the idle tunnel
- */
-static void
-destroy_tunnel (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTunnelQueueEntry *tq;
-
-  t->destroy_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying idle %s\n",
-       GCT_2s (t));
-  GNUNET_assert (0 == GCT_count_channels (t));
-  GCT_iterate_connections (t,
-                           &destroy_t_connection,
-                           t);
-  GNUNET_assert (NULL == t->connection_ready_head);
-  GNUNET_assert (NULL == t->connection_busy_head);
-  while (NULL != (tq = t->tq_head))
-  {
-    if (NULL != tq->cont)
-      tq->cont (tq->cont_cls,
-                NULL);
-    GCT_send_cancel (tq);
-  }
-  GCP_drop_tunnel (t->destination,
-                   t);
-  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
-  if (NULL != t->maintain_connections_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
-    t->maintain_connections_task = NULL;
-  }
-  if (NULL != t->send_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->send_task);
-    t->send_task = NULL;
-  }
-  if (NULL != t->kx_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->kx_task);
-    t->kx_task = NULL;
-  }
-  GNUNET_MST_destroy (t->mst);
-  GNUNET_MQ_destroy (t->mq);
-  if (NULL != t->unverified_ax)
-  {
-    cleanup_ax (t->unverified_ax);
-    GNUNET_free (t->unverified_ax);
-  }
-  cleanup_ax (&t->ax);
-  GNUNET_assert (NULL == t->destroy_task);
-  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)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
-                                                         ntohl (ctn.cn),
-                                                         ch));
-  if ( (0 ==
-        GCT_count_channels (t)) &&
-       (NULL == t->destroy_task) )
-  {
-    t->destroy_task
-      = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
-                                      &destroy_tunnel,
-                                      t);
-  }
-}
-
-
-/**
- * Destroy remaining channels during shutdown.
- *
- * @param cls the `struct CadetTunnel` of the channel
- * @param key key of the channel
- * @param value the `struct CadetChannel`
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_remaining_channels (void *cls,
-                            uint32_t key,
-                            void *value)
-{
-  struct CadetChannel *ch = value;
-
-  GCCH_handle_remote_destroy (ch,
-                              NULL);
-  return GNUNET_OK;
-}
-
-
-/**
- * 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 (GNUNET_YES == shutting_down);
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &destroy_remaining_channels,
-                                           t);
-  GNUNET_assert (0 ==
-                 GCT_count_channels (t));
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  destroy_tunnel (t);
-}
-
-
-/**
- * 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 */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Not sending payload of %s on ready %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);
-  mark_connection_unready (ct);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending payload of %s on %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-  GCC_transmit (ct->cc,
-                tq->env);
-  if (NULL != tq->cont)
-    tq->cont (tq->cont_cls,
-              GCC_get_id (ct->cc));
-  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.
- *
- * @param cls the `struct CadetTConnection` that is @a is_ready
- * @param is_ready #GNUNET_YES if connection are now ready,
- *                 #GNUNET_NO if connection are no longer ready
- */
-static void
-connection_ready_cb (void *cls,
-                     int is_ready)
-{
-  struct CadetTConnection *ct = cls;
-  struct CadetTunnel *t = ct->t;
-
-  if (GNUNET_NO == is_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s no longer ready for %s\n",
-         GCC_2s (ct->cc),
-         GCT_2s (t));
-    mark_connection_unready (ct);
-    return;
-  }
-  GNUNET_assert (GNUNET_NO == ct->is_ready);
-  GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  GNUNET_assert (0 < t->num_busy_connections);
-  t->num_busy_connections--;
-  ct->is_ready = GNUNET_YES;
-  GNUNET_CONTAINER_DLL_insert_tail (t->connection_ready_head,
-                                    t->connection_ready_tail,
-                                    ct);
-  t->num_ready_connections++;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s now ready for %s in state %s\n",
-       GCC_2s (ct->cc),
-       GCT_2s (t),
-       estate2s (t->estate));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-    /* Do not begin KX if WE have no channels waiting! */
-    if (0 == GCT_count_channels (t))
-      return;
-    /* We are uninitialized, just transmit immediately,
-       without undue delay. */
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* we're currently waiting for KX to complete, schedule job */
-    if (NULL == t->kx_task)
-      t->kx_task
-        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
-                                   &retry_kx,
-                                   t);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    if (GNUNET_YES == t->kx_auth_requested)
-    {
-      if (NULL != t->kx_task)
-      {
-        GNUNET_SCHEDULER_cancel (t->kx_task);
-        t->kx_task = NULL;
-      }
-      send_kx_auth (t,
-                    ct,
-                    &t->ax,
-                    GNUNET_NO);
-      return;
-    }
-    try_send_normal_payload (t,
-                             ct);
-    break;
-  }
-}
-
-
-/**
- * Called when either we have a new connection, or a new message in the
- * queue, or some existing connection has transmission capacity.  Looks
- * at our message queue and if there is a message, picks a connection
- * to send it on.
- *
- * @param cls the `struct CadetTunnel` to process messages on
- */
-static void
-trigger_transmissions (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTConnection *ct;
-
-  t->send_task = NULL;
-  if (NULL == t->tq_head)
-    return; /* no messages pending right now */
-  ct = get_ready_connection (t);
-  if (NULL == ct)
-    return; /* no connections ready */
-  try_send_normal_payload (t,
-                           ct);
-}
-
-
-/**
- * Closure for #evaluate_connection. Used to assemble summary information
- * about the existing connections so we can evaluate a new path.
- */
-struct EvaluationSummary
-{
-
-  /**
-   * Minimum length of any of our connections, `UINT_MAX` if we have none.
-   */
-  unsigned int min_length;
-
-  /**
-   * Maximum length of any of our connections, 0 if we have none.
-   */
-  unsigned int max_length;
-
-  /**
-   * Minimum desirability of any of our connections, UINT64_MAX if we have none.
-   */
-  GNUNET_CONTAINER_HeapCostType min_desire;
-
-  /**
-   * Maximum desirability of any of our connections, 0 if we have none.
-   */
-  GNUNET_CONTAINER_HeapCostType max_desire;
-
-  /**
-   * Path we are comparing against for #evaluate_connection, can be NULL.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Connection deemed the "worst" so far encountered by #evaluate_connection,
-   * NULL if we did not yet encounter any connections.
-   */
-  struct CadetTConnection *worst;
-
-  /**
-   * Numeric score of @e worst, only set if @e worst is non-NULL.
-   */
-  double worst_score;
-
-  /**
-   * Set to #GNUNET_YES if we have a connection over @e path already.
-   */
-  int duplicate;
-
-};
-
-
-/**
- * Evaluate a connection, updating our summary information in @a cls about
- * what kinds of connections we have.
- *
- * @param cls the `struct EvaluationSummary *` to update
- * @param ct a connection to include in the summary
- */
-static void
-evaluate_connection (void *cls,
-                     struct CadetTConnection *ct)
-{
-  struct EvaluationSummary *es = cls;
-  struct CadetConnection *cc = ct->cc;
-  struct CadetPeerPath *ps = GCC_get_path (cc);
-  const struct CadetConnectionMetrics *metrics;
-  GNUNET_CONTAINER_HeapCostType ct_desirability;
-  struct GNUNET_TIME_Relative uptime;
-  struct GNUNET_TIME_Relative last_use;
-  uint32_t ct_length;
-  double score;
-  double success_rate;
-
-  if (ps == es->path)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate path %s.\n",
-         GCPP_2s (es->path));
-    es->duplicate = GNUNET_YES;
-    return;
-  }
-  ct_desirability = GCPP_get_desirability (ps);
-  ct_length = GCPP_get_length (ps);
-  metrics = GCC_get_metrics (cc);
-  uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
-  last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
-  /* We add 1.0 here to avoid division by zero. */
-  success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
-  score
-    = ct_desirability
-    + 100.0 / (1.0 + ct_length) /* longer paths = better */
-    + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
-    - last_use.rel_value_us / 1000L;          /* longer idle = worse */
-  score *= success_rate;        /* weigh overall by success rate */
-
-  if ( (NULL == es->worst) ||
-       (score < es->worst_score) )
-  {
-    es->worst = ct;
-    es->worst_score = score;
-  }
-  es->min_length = GNUNET_MIN (es->min_length,
-                               ct_length);
-  es->max_length = GNUNET_MAX (es->max_length,
-                               ct_length);
-  es->min_desire = GNUNET_MIN (es->min_desire,
-                               ct_desirability);
-  es->max_desire = GNUNET_MAX (es->max_desire,
-                               ct_desirability);
-}
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- * @return #GNUNET_YES (should keep iterating)
- */
-static int
-consider_path_cb (void *cls,
-                  struct CadetPeerPath *path,
-                  unsigned int off)
-{
-  struct CadetTunnel *t = cls;
-  struct EvaluationSummary es;
-  struct CadetTConnection *ct;
-
-  GNUNET_assert (off < GCPP_get_length (path));
-  es.min_length = UINT_MAX;
-  es.max_length = 0;
-  es.max_desire = 0;
-  es.min_desire = UINT64_MAX;
-  es.path = path;
-  es.duplicate = GNUNET_NO;
-  es.worst = NULL;
-
-  /* Compute evaluation summary over existing connections. */
-  GCT_iterate_connections (t,
-                           &evaluate_connection,
-                           &es);
-  if (GNUNET_YES == es.duplicate)
-    return GNUNET_YES;
-
-  /* FIXME: not sure we should really just count
-     'num_connections' here, as they may all have
-     consistently failed to connect. */
-
-  /* We iterate by increasing path length; if we have enough paths and
-     this one is more than twice as long than what we are currently
-     using, then ignore all of these super-long ones! */
-  if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (es.min_length * 2 < off) &&
-       (es.max_length < off) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring paths of length %u, they are way too long.\n",
-         es.min_length * 2);
-    return GNUNET_NO;
-  }
-  /* If we have enough paths and this one looks no better, ignore it. */
-  if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (es.min_length < GCPP_get_length (path)) &&
-       (es.min_desire > GCPP_get_desirability (path)) &&
-       (es.max_length < off) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring path (%u/%llu) to %s, got something better already.\n",
-         GCPP_get_length (path),
-         (unsigned long long) GCPP_get_desirability (path),
-         GCP_2s (t->destination));
-    return GNUNET_YES;
-  }
-
-  /* Path is interesting (better by some metric, or we don't have
-     enough paths yet). */
-  ct = GNUNET_new (struct CadetTConnection);
-  ct->created = GNUNET_TIME_absolute_get ();
-  ct->t = t;
-  ct->cc = GCC_create (t->destination,
-                       path,
-                       off,
-                       GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
-                       ct,
-                       &connection_ready_cb,
-                       ct);
-
-  /* FIXME: schedule job to kill connection (and path?)  if it takes
-     too long to get ready! (And track performance data on how long
-     other connections took with the tunnel!)
-     => Note: to be done within 'connection'-logic! */
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Found interesting path %s for %s, created %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;
-  struct GNUNET_TIME_Relative delay;
-  struct EvaluationSummary es;
-
-  t->maintain_connections_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Performing connection maintenance for %s.\n",
-       GCT_2s (t));
-
-  es.min_length = UINT_MAX;
-  es.max_length = 0;
-  es.max_desire = 0;
-  es.min_desire = UINT64_MAX;
-  es.path = NULL;
-  es.worst = NULL;
-  es.duplicate = GNUNET_NO;
-  GCT_iterate_connections (t,
-                           &evaluate_connection,
-                           &es);
-  if ( (NULL != es.worst) &&
-       (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
-  {
-    /* Clear out worst-performing connection 'es.worst'. */
-    destroy_t_connection (t,
-                          es.worst);
-  }
-
-  /* Consider additional paths */
-  (void) GCP_iterate_paths (t->destination,
-                            &consider_path_cb,
-                            t);
-
-  /* FIXME: calculate when to try again based on how well we are doing;
-     in particular, if we have to few connections, we might be able
-     to do without this (as PATHS should tell us whenever a new path
-     is available instantly; however, need to make sure this job is
-     restarted after that happens).
-     Furthermore, if the paths we do know are in a reasonably narrow
-     quality band and are plentyful, we might also consider us stabilized
-     and then reduce the frequency accordingly.  */
-  delay = GNUNET_TIME_UNIT_MINUTES;
-  t->maintain_connections_task
-    = GNUNET_SCHEDULER_add_delayed (delay,
-                                    &maintain_connections_cb,
-                                    t);
-}
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- */
-void
-GCT_consider_path (struct CadetTunnel *t,
-                   struct CadetPeerPath *p,
-                   unsigned int off)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Considering %s for %s\n",
-       GCPP_2s (p),
-       GCT_2s (t));
-  (void) consider_path_cb (t,
-                           p,
-                           off);
-}
-
-
-/**
- * We got a keepalive. Track in statistics.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg  the message we received on the tunnel
- */
-static void
-handle_plaintext_keepalive (void *cls,
-                            const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetTunnel *t = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received KEEPALIVE on %s\n",
-       GCT_2s (t));
-  GNUNET_STATISTICS_update (stats,
-                            "# keepalives received",
-                            1,
-                            GNUNET_NO);
-}
-
-
-/**
- * Check that @a msg is well-formed.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg  the message we received on the tunnel
- * @return #GNUNET_OK (any variable-size payload goes)
- */
-static int
-check_plaintext_data (void *cls,
-                      const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  return GNUNET_OK;
-}
-
-
-/**
- * We received payload data for a channel.  Locate the channel
- * and process the data, or return an error if the channel is unknown.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg the message we received on the tunnel
- */
-static void
-handle_plaintext_data (void *cls,
-                       const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       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,
-         "Received %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->ctn);
-    return;
-  }
-  GCCH_handle_channel_plaintext_data (ch,
-                                      GCC_get_id (t->current_ct->cc),
-                                      msg);
-}
-
-
-/**
- * We received an acknowledgement for data we sent on a channel.
- * Locate the channel and process it, or return an error if the
- * channel is unknown.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param ack the message we received on the tunnel
- */
-static void
-handle_plaintext_data_ack (void *cls,
-                           const struct GNUNET_CADET_ChannelDataAckMessage *ack)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       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,
-         "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
-         ntohl (ack->ctn.cn));
-    GCT_send_channel_destroy (t,
-                              ack->ctn);
-    return;
-  }
-  GCCH_handle_channel_plaintext_data_ack (ch,
-                                          GCC_get_id (t->current_ct->cc),
-                                          ack);
-}
-
-
-/**
- * We have received a request to open a channel to a port from
- * another peer.  Creates the incoming channel.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param copen the message we received on the tunnel
- */
-static void
-handle_plaintext_channel_open (void *cls,
-                               const struct GNUNET_CADET_ChannelOpenMessage *copen)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                            ntohl (copen->ctn.cn));
-  if (NULL != ch)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
-         GNUNET_h2s (&copen->port),
-         GCT_2s (t),
-         GCCH_2s (ch));
-    GCCH_handle_duplicate_open (ch,
-                                GCC_get_id (t->current_ct->cc));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CHANNEL_OPEN on port %s from %s\n",
-       GNUNET_h2s (&copen->port),
-       GCT_2s (t));
-  ch = GCCH_channel_incoming_new (t,
-                                  copen->ctn,
-                                  &copen->port,
-                                  ntohl (copen->opt));
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (copen->ctn.cn),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-}
-
-
-/**
- * Send a DESTROY message via the tunnel.
- *
- * @param t the tunnel to transmit over
- * @param ctn ID of the channel to destroy
- */
-void
-GCT_send_channel_destroy (struct CadetTunnel *t,
-                          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.ctn = ctn;
-  GCT_send (t,
-            &msg.header,
-            NULL,
-            NULL);
-}
-
-
-/**
- * We have received confirmation from the target peer that the
- * given channel could be established (the port is open).
- * Tell the client.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param cm the message we received on the tunnel
- */
-static void
-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->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 %u, sending DESTROY\n",
-         ntohl (cm->ctn.cn));
-    GCT_send_channel_destroy (t,
-                              cm->ctn);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received channel OPEN_ACK on channel %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GCCH_handle_channel_open_ack (ch,
-                                GCC_get_id (t->current_ct->cc));
-}
-
-
-/**
- * We received a message saying that a channel should be destroyed.
- * Pass it on to the correct channel.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param cm the message we received on the tunnel
- */
-static void
-handle_plaintext_channel_destroy (void *cls,
-                                  const struct GNUNET_CADET_ChannelManageMessage *cm)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  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 %u. Ignoring.\n",
-         ntohl (cm->ctn.cn));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received channel DESTROY on %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GCCH_handle_remote_destroy (ch,
-                              GCC_get_id (t->current_ct->cc));
-}
-
-
-/**
- * Handles a message we decrypted, by injecting it into
- * our message queue (which will do the dispatching).
- *
- * @param cls the `struct CadetTunnel` that got the message
- * @param msg the message
- * @return #GNUNET_OK (continue to process)
- */
-static int
-handle_decrypted (void *cls,
-                  const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetTunnel *t = cls;
-
-  GNUNET_assert (NULL != t->current_ct);
-  GNUNET_MQ_inject_message (t->mq,
-                            msg);
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called if we had an error processing
- * an incoming decrypted message.
- *
- * @param cls the `struct CadetTunnel`
- * @param error error code
- */
-static void
-decrypted_error_cb (void *cls,
-                    enum GNUNET_MQ_Error error)
-{
-  GNUNET_break_op (0);
-}
-
-
-/**
- * Create a tunnel to @a destionation.  Must only be called
- * from within #GCP_get_tunnel().
- *
- * @param destination where to create the tunnel to
- * @return new tunnel to @a destination
- */
-struct CadetTunnel *
-GCT_create_tunnel (struct CadetPeer *destination)
-{
-  struct CadetTunnel *t = GNUNET_new (struct CadetTunnel);
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_fixed_size (plaintext_keepalive,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE,
-                             struct GNUNET_MessageHeader,
-                             t),
-    GNUNET_MQ_hd_var_size (plaintext_data,
-                           GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA,
-                           struct GNUNET_CADET_ChannelAppDataMessage,
-                           t),
-    GNUNET_MQ_hd_fixed_size (plaintext_data_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
-                             struct GNUNET_CADET_ChannelDataAckMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
-                             struct GNUNET_CADET_ChannelOpenMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
-                             struct GNUNET_CADET_ChannelManageMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
-                             struct GNUNET_CADET_ChannelManageMessage,
-                             t),
-    GNUNET_MQ_handler_end ()
-  };
-
-  t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
-  new_ephemeral (&t->ax);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
-  t->destination = destination;
-  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-  t->maintain_connections_task
-    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
-                                t);
-  t->mq = GNUNET_MQ_queue_for_callbacks (NULL,
-                                         NULL,
-                                         NULL,
-                                         NULL,
-                                         handlers,
-                                         &decrypted_error_cb,
-                                         t);
-  t->mst = GNUNET_MST_create (&handle_decrypted,
-                              t);
-  return t;
-}
-
-
-/**
- * Add a @a connection to the @a tunnel.
- *
- * @param t a tunnel
- * @param cid connection identifer to use for the connection
- * @param options options for the connection
- * @param path path to use for the connection
- * @return #GNUNET_OK on success,
- *         #GNUNET_SYSERR on failure (duplicate connection)
- */
-int
-GCT_add_inbound_connection (struct CadetTunnel *t,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                            enum GNUNET_CADET_ChannelOption options,
-                            struct CadetPeerPath *path)
-{
-  struct CadetTConnection *ct;
-
-  ct = GNUNET_new (struct CadetTConnection);
-  ct->created = GNUNET_TIME_absolute_get ();
-  ct->t = t;
-  ct->cc = GCC_create_inbound (t->destination,
-                               path,
-                               options,
-                               ct,
-                               cid,
-                               &connection_ready_cb,
-                               ct);
-  if (NULL == ct->cc)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s refused inbound %s (duplicate)\n",
-         GCT_2s (t),
-         GCC_2s (ct->cc));
-    GNUNET_free (ct);
-    return GNUNET_SYSERR;
-  }
-  /* FIXME: schedule job to kill connection (and path?)  if it takes
-     too long to get ready! (And track performance data on how long
-     other connections took with the tunnel!)
-     => Note: to be done within 'connection'-logic! */
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s has new %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle encrypted message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCT_handle_encrypted (struct CadetTConnection *ct,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  uint16_t size = ntohs (msg->header.size);
-  char cbuf [size] GNUNET_ALIGN;
-  ssize_t decrypted_size;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%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:
-  case CADET_TUNNEL_KEY_AX_RECV:
-    /* We did not even SEND our KX, how can the other peer
-       send us encrypted data? Must have been that we went
-       down and the other peer still things we are up.
-       Let's send it KX back. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without any KX",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* We send KX, and other peer send KX to us at the same time.
-       Neither KX is AUTH'ed, so let's try KX_AUTH this time. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without KX_AUTH",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx_auth (t,
-                  ct,
-                  &t->ax,
-                  GNUNET_YES);
-    return;
-  case CADET_TUNNEL_KEY_AX_SENT:
-    /* We did not get the KX of the other peer, but that
-       might have been lost.  Send our KX again immediately. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without KX",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* Great, first payload, we might graduate to OK! */
-  case CADET_TUNNEL_KEY_OK:
-    /* We are up and running, all good. */
-    break;
-  }
-
-  decrypted_size = -1;
-  if (CADET_TUNNEL_KEY_OK == t->estate)
-  {
-    /* We have well-established key material available,
-       try that. (This is the common case.) */
-    decrypted_size = t_ax_decrypt_and_validate (&t->ax,
-                                                cbuf,
-                                                msg,
-                                                size);
-  }
-
-  if ( (-1 == decrypted_size) &&
-       (NULL != t->unverified_ax) )
-  {
-    /* We have un-authenticated KX material available. We should try
-       this as a back-up option, in case the sender crashed and
-       switched keys. */
-    decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
-                                                cbuf,
-                                                msg,
-                                                size);
-    if (-1 != decrypted_size)
-    {
-      /* It worked! Treat this as authentication of the AX data! */
-      cleanup_ax (&t->ax);
-      t->ax = *t->unverified_ax;
-      GNUNET_free (t->unverified_ax);
-      t->unverified_ax = NULL;
-    }
-    if (CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate)
-    {
-      /* First time it worked, move tunnel into production! */
-      GCT_change_estate (t,
-                         CADET_TUNNEL_KEY_OK);
-      if (NULL != t->send_task)
-        GNUNET_SCHEDULER_cancel (t->send_task);
-      t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                               t);
-    }
-  }
-  if (NULL != t->unverified_ax)
-  {
-    /* We had unverified KX material that was useless; so increment
-       counter and eventually move to ignore it.  Note that we even do
-       this increment if we successfully decrypted with the old KX
-       material and thus didn't even both with the new one.  This is
-       the ideal case, as a malicious injection of bogus KX data
-       basically only causes us to increment a counter a few times. */
-    t->unverified_attempts++;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to decrypt message with unverified KX data %u times\n",
-         t->unverified_attempts);
-    if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
-    {
-      cleanup_ax (t->unverified_ax);
-      GNUNET_free (t->unverified_ax);
-      t->unverified_ax = NULL;
-    }
-  }
-
-  if (-1 == decrypted_size)
-  {
-    /* Decryption failed for good, complain. */
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "%s failed to decrypt and validate encrypted data, retrying KX\n",
-         GCT_2s (t));
-    GNUNET_STATISTICS_update (stats,
-                              "# unable to decrypt",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  }
-  GNUNET_STATISTICS_update (stats,
-                            "# decrypted bytes",
-                            decrypted_size,
-                            GNUNET_NO);
-
-  /* The MST will ultimately call #handle_decrypted() on each message. */
-  t->current_ct = ct;
-  GNUNET_break_op (GNUNET_OK ==
-                   GNUNET_MST_from_buffer (t->mst,
-                                           cbuf,
-                                           decrypted_size,
-                                           GNUNET_YES,
-                                           GNUNET_NO));
-  t->current_ct = NULL;
-}
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection if not provided.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message
- */
-struct CadetTunnelQueueEntry *
-GCT_send (struct CadetTunnel *t,
-          const struct GNUNET_MessageHeader *message,
-          GCT_SendContinuation cont,
-          void *cont_cls)
-{
-  struct CadetTunnelQueueEntry *tq;
-  uint16_t payload_size;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
-
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  payload_size = ntohs (message->size);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Encrypting %u bytes for %s\n",
-       (unsigned int) payload_size,
-       GCT_2s (t));
-  env = GNUNET_MQ_msg_extra (ax_msg,
-                             payload_size,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
-  t_ax_encrypt (&t->ax,
-                &ax_msg[1],
-                message,
-                payload_size);
-  GNUNET_STATISTICS_update (stats,
-                            "# encrypted bytes",
-                            payload_size,
-                            GNUNET_NO);
-  ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
-  ax_msg->ax_header.PNs = htonl (t->ax.PNs);
-  /* FIXME: we should do this once, not once per message;
-     this is a point multiplication, and DHRs does not
-     change all the time. */
-  GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
-                                      &ax_msg->ax_header.DHRs);
-  t_h_encrypt (&t->ax,
-               ax_msg);
-  t_hmac (&ax_msg->ax_header,
-          sizeof (struct GNUNET_CADET_AxHeader) + payload_size,
-          0,
-          &t->ax.HKs,
-          &ax_msg->hmac);
-
-  tq = GNUNET_malloc (sizeof (*tq));
-  tq->t = t;
-  tq->env = env;
-  tq->cid = &ax_msg->cid; /* will initialize 'ax_msg->cid' once we know the connection */
-  tq->cont = cont;
-  tq->cont_cls = cont_cls;
-  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
-                                    t->tq_tail,
-                                    tq);
-  if (NULL != t->send_task)
-    GNUNET_SCHEDULER_cancel (t->send_task);
-  t->send_task
-    = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                t);
-  return tq;
-}
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send
- * function is called. Once the continuation is called, the message is
- * no longer in the queue!
- *
- * @param tq Handle to the queue entry to cancel.
- */
-void
-GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
-{
-  struct CadetTunnel *t = tq->t;
-
-  GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                               t->tq_tail,
-                               tq);
-  GNUNET_MQ_discard (tq->env);
-  GNUNET_free (tq);
-}
-
-
-/**
- * Iterate over all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t,
-                         GCT_ConnectionIterator iter,
-                         void *iter_cls)
-{
-  struct CadetTConnection *n;
-  for (struct CadetTConnection *ct = t->connection_ready_head;
-       NULL != ct;
-       ct = n)
-  {
-    n = ct->next;
-    iter (iter_cls,
-          ct);
-  }
-  for (struct CadetTConnection *ct = t->connection_busy_head;
-       NULL != ct;
-       ct = n)
-  {
-    n = ct->next;
-    iter (iter_cls,
-          ct);
-  }
-}
-
-
-/**
- * Closure for #iterate_channels_cb.
- */
-struct ChanIterCls
-{
-  /**
-   * Function to call.
-   */
-  GCT_ChannelIterator iter;
-
-  /**
-   * Closure for @e iter.
-   */
-  void *iter_cls;
-};
-
-
-/**
- * Helper function for #GCT_iterate_channels.
- *
- * @param cls the `struct ChanIterCls`
- * @param key unused
- * @param value a `struct CadetChannel`
- * @return #GNUNET_OK
- */
-static int
-iterate_channels_cb (void *cls,
-                     uint32_t key,
-                     void *value)
-{
-  struct ChanIterCls *ctx = cls;
-  struct CadetChannel *ch = value;
-
-  ctx->iter (ctx->iter_cls,
-             ch);
-  return GNUNET_OK;
-}
-
-
-/**
- * Iterate over all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t,
-                      GCT_ChannelIterator iter,
-                      void *iter_cls)
-{
-  struct ChanIterCls ctx;
-
-  ctx.iter = iter;
-  ctx.iter_cls = iter_cls;
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &iterate_channels_cb,
-                                           &ctx);
-
-}
-
-
-/**
- * Call #GCCH_debug() on a channel.
- *
- * @param cls points to the log level to use
- * @param key unused
- * @param value the `struct CadetChannel` to dump
- * @return #GNUNET_OK (continue iteration)
- */
-static int
-debug_channel (void *cls,
-               uint32_t key,
-               void *value)
-{
-  const enum GNUNET_ErrorType *level = cls;
-  struct CadetChannel *ch = value;
-
-  GCCH_debug (ch, *level);
-  return GNUNET_OK;
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t,
-           enum GNUNET_ErrorType level)
-{
-  struct CadetTConnection *iter_c;
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-tun",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  LOG2 (level,
-        "TTT TUNNEL TOWARDS %s in estate %s tq_len: %u #cons: %u\n",
-        GCT_2s (t),
-        estate2s (t->estate),
-        t->tq_len,
-        GCT_count_any_connections (t));
-  LOG2 (level,
-        "TTT channels:\n");
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &debug_channel,
-                                           &level);
-  LOG2 (level,
-        "TTT connections:\n");
-  for (iter_c = t->connection_ready_head; NULL != iter_c; iter_c = iter_c->next)
-    GCC_debug (iter_c->cc,
-               level);
-  for (iter_c = t->connection_busy_head; NULL != iter_c; iter_c = iter_c->next)
-    GCC_debug (iter_c->cc,
-               level);
-
-  LOG2 (level,
-        "TTT TUNNEL END\n");
-}
-
-
-/* end of gnunet-service-cadet-new_tunnels.c */
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet-new_tunnels.h
deleted file mode 100644 (file)
index a81bc23..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_tunnels.h
- * @brief Information we track per tunnel.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
-#define GNUNET_SERVICE_CADET_TUNNELS_H
-
-#include "gnunet-service-cadet-new.h"
-#include "cadet_protocol.h"
-
-
-/**
- * How many connections would we like to have per tunnel?
- */
-#define DESIRED_CONNECTIONS_PER_TUNNEL 3
-
-
-/**
- * All the encryption states a tunnel can be in.
- */
-enum CadetTunnelEState
-{
-  /**
-   * Uninitialized status, we need to send KX.  We will stay
-   * in this state until the first connection is up.
-   */
-  CADET_TUNNEL_KEY_UNINITIALIZED,
-
-  /**
-   * KX message sent, waiting for other peer's KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_SENT,
-
-  /**
-   * KX message received, trying to send back KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_RECV,
-
-  /**
-   * KX message sent and received, trying to send back KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_SENT_AND_RECV,
-
-  /**
-   * KX received and we sent KX_AUTH back, but we got no traffic yet,
-   * so we're waiting for either KX_AUTH or ENCRYPED traffic from
-   * the other peer.
-   *
-   * We will not yet send traffic, as this might have been a replay.
-   * The other (initiating) peer should send a CHANNEL_OPEN next
-   * anyway, and then we are in business!
-   */
-  CADET_TUNNEL_KEY_AX_AUTH_SENT,
-
-  /**
-   * Handshake completed: session key available.
-   */
-  CADET_TUNNEL_KEY_OK
-
-};
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t);
-
-
-/**
- * Create a tunnel to @a destionation.  Must only be called
- * from within #GCP_get_tunnel().
- *
- * @param destination where to create the tunnel to
- * @return new tunnel to @a destination
- */
-struct CadetTunnel *
-GCT_create_tunnel (struct CadetPeer *destination);
-
-
-/**
- * Destroys the tunnel @a t now, without delay. Used during shutdown.
- *
- * @param t tunnel to destroy
- */
-void
-GCT_destroy_tunnel_now (struct CadetTunnel *t);
-
-
-/**
- * Add a @a connection to the @a tunnel.
- *
- * @param t a tunnel
- * @param cid connection identifer to use for the connection
- * @param options options for the connection
- * @param path path to use for the connection
- * @return #GNUNET_OK on success,
- *         #GNUNET_SYSERR on failure (duplicate connection)
- */
-int
-GCT_add_inbound_connection (struct CadetTunnel *t,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                            enum GNUNET_CADET_ChannelOption options,
-                            struct CadetPeerPath *path);
-
-
-/**
- * We lost a connection, remove it from our list and clean up
- * the connection object itself.
- *
- * @param ct binding of connection to tunnel of the connection that was lost.
- */
-void
-GCT_connection_lost (struct CadetTConnection *ct);
-
-
-/**
- * Return the peer to which this tunnel goes.
- *
- * @param t a tunnel
- * @return the destination of the tunnel
- */
-struct CadetPeer *
-GCT_get_destination (struct CadetTunnel *t);
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- */
-void
-GCT_consider_path (struct CadetTunnel *t,
-                   struct CadetPeerPath *p,
-                   unsigned int off);
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel
- * @return unique number identifying @a ch within @a t
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch);
-
-
-/**
- * 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);
-
-
-/**
- * Send a DESTROY message via the tunnel.
- *
- * @param t the tunnel to transmit over
- * @param ctn ID of the channel to destroy
- */
-void
-GCT_send_channel_destroy (struct CadetTunnel *t,
-                          struct GNUNET_CADET_ChannelTunnelNumber ctn);
-
-
-/**
- * Function called when a transmission requested using #GCT_send is done.
- *
- * @param cls closure
- * @param ctn identifier of the connection used for transmission, NULL if
- *            the transmission failed (to be used to match ACKs to the
- *            respective connection for connection performance evaluation)
- */
-typedef void
-(*GCT_SendContinuation)(void *cls,
-                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection if not provided.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message.
- */
-struct CadetTunnelQueueEntry *
-GCT_send (struct CadetTunnel *t,
-          const struct GNUNET_MessageHeader *message,
-          GCT_SendContinuation cont,
-          void *cont_cls);
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send
- * 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.
- */
-void
-GCT_send_cancel (struct CadetTunnelQueueEntry *q);
-
-
-/**
- * Return the number of channels using a tunnel.
- *
- * @param t tunnel to count obtain the number of channels for
- * @return number of channels using the tunnel
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t);
-
-
-/**
- * Return the number of connections available for a tunnel.
- *
- * @param t tunnel to count obtain the number of connections for
- * @return number of connections available for the tunnel
- */
-unsigned int
-GCT_count_any_connections (const struct CadetTunnel *t);
-
-
-/**
- * Iterator over connections.
- *
- * @param cls closure
- * @param ct one of the connections
- */
-typedef void
-(*GCT_ConnectionIterator) (void *cls,
-                           struct CadetTConnection *ct);
-
-
-/**
- * Iterate over all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t,
-                         GCT_ConnectionIterator iter,
-                         void *iter_cls);
-
-
-/**
- * Iterator over channels.
- *
- * @param cls closure
- * @param ch one of the channels
- */
-typedef void
-(*GCT_ChannelIterator) (void *cls,
-                        struct CadetChannel *ch);
-
-
-/**
- * Iterate over all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t,
-                      GCT_ChannelIterator iter,
-                      void *iter_cls);
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t);
-
-
-/**
- * Handle KX message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx (struct CadetTConnection *ct,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx_auth (struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
-
-
-/**
- * Handle encrypted message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCT_handle_encrypted (struct CadetTConnection *ct,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t,
-           enum GNUNET_ErrorType level);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c
new file mode 100644 (file)
index 0000000..a7e1fca
--- /dev/null
@@ -0,0 +1,1496 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2013, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet.c
+ * @brief GNUnet CADET service with encryption
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * Dictionary:
+ * - peer: other cadet instance. If there is direct connection it's a neighbor.
+ * - path: series of directly connected peer from one peer to another.
+ * - connection: path which is being used in a tunnel.
+ * - tunnel: encrypted connection to a peer, neighbor or not.
+ * - channel: logical link between two clients, on the same or different peers.
+ *            have properties like reliability.
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_core.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
+
+
+/**
+ * Struct containing information about a client of the service
+ */
+struct CadetClient
+{
+  /**
+   * Linked list next
+   */
+  struct CadetClient *next;
+
+  /**
+   * Linked list prev
+   */
+  struct CadetClient *prev;
+
+  /**
+   * Tunnels that belong to this client, indexed by local id,
+   * value is a `struct CadetChannel`.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+  /**
+   * Handle to communicate with the client
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Client handle.
+   */
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * Ports that this client has declared interest in.
+   * Indexed by port, contains *Client.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *ports;
+
+  /**
+   * Channel ID to use for the next incoming channel for this client.
+   * Wraps around (in theory).
+   */
+  struct GNUNET_CADET_ClientChannelNumber next_ccn;
+
+  /**
+   * ID of the client, mainly for debug messages. Purely internal to this file.
+   */
+  unsigned int id;
+};
+
+/******************************************************************************/
+/***********************      GLOBAL VARIABLES     ****************************/
+/******************************************************************************/
+
+/****************************** Global variables ******************************/
+
+/**
+ * Handle to our configuration.
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to the statistics service.
+ */
+struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to communicate with ATS.
+ */
+struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
+/**
+ * Local peer own ID.
+ */
+struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Own private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * Signal that shutdown is happening: prevent recovery measures.
+ */
+int shutting_down;
+
+/**
+ * DLL with all the clients, head.
+ */
+static struct CadetClient *clients_head;
+
+/**
+ * DLL with all the clients, tail.
+ */
+static struct CadetClient *clients_tail;
+
+/**
+ * Next ID to assign to a client.
+ */
+static unsigned int next_client_id;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
+ * hash codes to `struct CadetConnection` objects.
+ */
+struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+/**
+ * How many messages are needed to trigger an AXOLOTL ratchet advance.
+ */
+unsigned long long ratchet_messages;
+
+/**
+ * How long until we trigger a ratched advance due to time.
+ */
+struct GNUNET_TIME_Relative ratchet_time;
+
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+unsigned long long drop_percent;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+                    struct GNUNET_MQ_Envelope *env)
+{
+  GNUNET_MQ_send (c->mq,
+                  env);
+}
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c)
+{
+  static char buf[32];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Client(%u)",
+                   c->id);
+  return buf;
+}
+
+
+/**
+ * Lookup channel of client @a c by @a ccn.
+ *
+ * @param c client to look in
+ * @param ccn channel ID to look up
+ * @return NULL if no such channel exists
+ */
+static struct CadetChannel *
+lookup_channel (struct CadetClient *c,
+                struct GNUNET_CADET_ClientChannelNumber ccn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (c->channels,
+                                              ntohl (ccn.channel_of_client));
+}
+
+
+/**
+ * Obtain the next LID to use for incoming connections to
+ * the given client.
+ *
+ * @param c client handle
+ */
+static struct GNUNET_CADET_ClientChannelNumber
+client_get_next_ccn (struct CadetClient *c)
+{
+  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
+
+  /* increment until we have a free one... */
+  while (NULL !=
+         lookup_channel (c,
+                         ccn))
+  {
+    ccn.channel_of_client
+      = htonl (1 + (ntohl (ccn.channel_of_client)));
+    if (ntohl (ccn.channel_of_client) >=
+        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+      ccn.channel_of_client = htonl (0);
+  }
+  c->next_ccn.channel_of_client
+    = htonl (1 + (ntohl (ccn.channel_of_client)));
+  return ccn;
+}
+
+
+/**
+ * Bind incoming channel to this client, and notify client about
+ * incoming connection.  Caller is responsible for notifying the other
+ * peer about our acceptance of the channel.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+          struct CadetChannel *ch,
+          struct CadetPeer *dest,
+          const struct GNUNET_HashCode *port,
+          uint32_t options)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalChannelCreateMessage *cm;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+
+  ccn = client_get_next_ccn (c);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (ccn.channel_of_client),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
+       GCCH_2s (ch),
+       GCP_2s (dest),
+       GNUNET_h2s (port),
+       (uint32_t) ntohl (options),
+       (uint32_t) ntohl (ccn.channel_of_client));
+  /* notify local client about incoming connection! */
+  env = GNUNET_MQ_msg (cm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
+  cm->ccn = ccn;
+  cm->port = *port;
+  cm->opt = htonl (options);
+  cm->peer = *GCP_get_id (dest);
+  GSC_send_to_client (c,
+                      env);
+  return ccn;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_tunnels_now (void *cls,
+                     const struct GNUNET_PeerIdentity *pid,
+                     void *value)
+{
+  struct CadetPeer *cp = value;
+  struct CadetTunnel *t = GCP_get_tunnel (cp,
+                                          GNUNET_NO);
+
+  if (NULL != t)
+    GCT_destroy_tunnel_now (t);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_paths_now (void *cls,
+                   const struct GNUNET_PeerIdentity *pid,
+                   void *value)
+{
+  struct CadetPeer *cp = value;
+
+  GCP_drop_owned_paths (cp);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown everything once the clients have disconnected.
+ */
+static void
+shutdown_rest ()
+{
+  if (NULL != stats)
+  {
+    GNUNET_STATISTICS_destroy (stats,
+                               GNUNET_NO);
+    stats = NULL;
+  }
+  if (NULL != open_ports)
+  {
+    GNUNET_CONTAINER_multihashmap_destroy (open_ports);
+    open_ports = NULL;
+  }
+  if (NULL != loose_channels)
+  {
+    GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
+    loose_channels = NULL;
+  }
+  /* Destroy tunnels.  Note that all channels must be destroyed first! */
+  GCP_iterate_all (&destroy_tunnels_now,
+                   NULL);
+  /* All tunnels, channels, connections and CORE must be down before this point. */
+  GCP_iterate_all (&destroy_paths_now,
+                   NULL);
+  /* All paths, tunnels, channels, connections and CORE must be down before this point. */
+  GCP_destroy_all_peers ();
+  if (NULL != peers)
+  {
+    GNUNET_CONTAINER_multipeermap_destroy (peers);
+    peers = NULL;
+  }
+  if (NULL != connections)
+  {
+    GNUNET_CONTAINER_multishortmap_destroy (connections);
+    connections = NULL;
+  }
+  if (NULL != ats_ch)
+  {
+    GNUNET_ATS_connectivity_done (ats_ch);
+    ats_ch = NULL;
+  }
+  GCD_shutdown ();
+  GCH_shutdown ();
+  GNUNET_free_non_null (my_private_key);
+  my_private_key = NULL;
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ */
+static void
+shutdown_task (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Shutting down\n");
+  shutting_down = GNUNET_YES;
+  GCO_shutdown ();
+  if (NULL == clients_head)
+    shutdown_rest ();
+}
+
+
+/**
+ * We had a remote connection @a value to port @a port before
+ * client @a cls opened port @a port.  Bind them now.
+ *
+ * @param cls the `struct CadetClient`
+ * @param port the port
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_YES (iterate over all such channels)
+ */
+static int
+bind_loose_channel (void *cls,
+                    const struct GNUNET_HashCode *port,
+                    void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch = value;
+
+  GCCH_bind (ch,
+             c);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+                                                       port,
+                                                       value));
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handle port open request.  Creates a mapping from the
+ * port to the respective client and checks whether we have
+ * loose channels trying to bind to the port.  If so, those
+ * are bound.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_open (void *cls,
+                  const struct GNUNET_CADET_PortMessage *pmsg)
+{
+  struct CadetClient *c = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Open port %s requested by %s\n",
+       GNUNET_h2s (&pmsg->port),
+       GSC_2s (c));
+  if (NULL == c->ports)
+    c->ports = GNUNET_CONTAINER_multihashmap_create (4,
+                                                      GNUNET_NO);
+  if (GNUNET_OK !=
+      GNUNET_CONTAINER_multihashmap_put (c->ports,
+                                         &pmsg->port,
+                                         c,
+                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
+                                            &pmsg->port,
+                                            c,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
+                                              &pmsg->port,
+                                              &bind_loose_channel,
+                                              c);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for port close requests.  Marks this port as closed
+ * (unless of course we have another client with the same port
+ * open).  Note that existing channels accepted on the port are
+ * not affected.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_close (void *cls,
+                   const struct GNUNET_CADET_PortMessage *pmsg)
+{
+  struct CadetClient *c = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing port %s as requested by %s\n",
+       GNUNET_h2s (&pmsg->port),
+       GSC_2s (c));
+  if (GNUNET_YES !=
+      GNUNET_CONTAINER_multihashmap_remove (c->ports,
+                                            &pmsg->port,
+                                            c))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
+                                                       &pmsg->port,
+                                                       c));
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for requests for us creating a new channel to another peer and port.
+ *
+ * @param cls Identification of the client.
+ * @param tcm The actual message.
+ */
+static void
+handle_channel_create (void *cls,
+                       const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+
+  if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+  {
+    /* Channel ID not in allowed range. */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  ch = lookup_channel (c,
+                       tcm->ccn);
+  if (NULL != ch)
+  {
+    /* Channel ID already in use. Not allowed. */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "New channel to %s at port %s requested by %s\n",
+       GNUNET_i2s (&tcm->peer),
+       GNUNET_h2s (&tcm->port),
+       GSC_2s (c));
+
+  /* Create channel */
+  ch = GCCH_channel_local_new (c,
+                               tcm->ccn,
+                               GCP_get (&tcm->peer,
+                                        GNUNET_YES),
+                               &tcm->port,
+                               ntohl (tcm->opt));
+  if (NULL == ch)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (tcm->ccn.channel_of_client),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for requests of destroying an existing channel.
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+                        const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Client attempted to destroy unknown channel.
+       Can happen if the other side went down at the same time.*/
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s tried to destroy unknown channel %X\n",
+         GSC_2s(c),
+         (uint32_t) ntohl (msg->ccn.channel_of_client));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s is destroying %s\n",
+       GSC_2s(c),
+       GCCH_2s (ch));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (msg->ccn.channel_of_client),
+                                                         ch));
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              msg->ccn);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Check for client traffic data message is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
+ */
+static int
+check_local_data (void *cls,
+                  const struct GNUNET_CADET_LocalData *msg)
+{
+  size_t payload_size;
+  size_t payload_claimed_size;
+  const char *buf;
+  struct GNUNET_MessageHeader pa;
+
+  /* FIXME: what is the format we shall allow for @a msg?
+     ONE payload item or multiple? Seems current cadet_api
+     at least in theory allows more than one. Next-gen
+     cadet_api will likely no more, so we could then
+     simplify this mess again. */
+  /* Sanity check for message size */
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  buf = (const char *) &msg[1];
+  while (payload_size >= sizeof (struct GNUNET_MessageHeader))
+  {
+    /* need to memcpy() for alignment */
+    GNUNET_memcpy (&pa,
+                   buf,
+                   sizeof (pa));
+    payload_claimed_size = ntohs (pa.size);
+    if ( (payload_size < payload_claimed_size) ||
+         (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
+         (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
+    {
+      GNUNET_break (0);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Local data of %u total size had sub-message %u at %u with %u bytes\n",
+           ntohs (msg->header.size),
+           ntohs (pa.type),
+           (unsigned int) (buf - (const char *) &msg[1]),
+           (unsigned int) payload_claimed_size);
+      return GNUNET_SYSERR;
+    }
+    payload_size -= payload_claimed_size;
+    buf += payload_claimed_size;
+  }
+  if (0 != payload_size)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client payload traffic to be send on a channel to
+ * another peer.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_local_data (void *cls,
+                   const struct GNUNET_CADET_LocalData *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+  size_t payload_size;
+  const char *buf;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Channel does not exist (anymore) */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+         (unsigned int) ntohl (msg->ccn.channel_of_client));
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  GNUNET_STATISTICS_update (stats,
+                            "# payload received from clients",
+                            payload_size,
+                            GNUNET_NO);
+  buf = (const char *) &msg[1];
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received %u bytes payload from %s for %s\n",
+       (unsigned int) payload_size,
+       GSC_2s (c),
+       GCCH_2s (ch));
+  if (GNUNET_OK !=
+      GCCH_handle_local_data (ch,
+                              msg->ccn,
+                              buf,
+                              payload_size))
+  {
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_local_ack (void *cls,
+                  const struct GNUNET_CADET_LocalAck *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Channel does not exist (anymore) */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+         (unsigned int) ntohl (msg->ccn.channel_of_client));
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got a local ACK from %s for %s\n",
+       GSC_2s(c),
+       GCCH_2s (ch));
+  GCCH_handle_local_ack (ch,
+                         msg->ccn);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to send a monitoring client info about each peer.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_peers_iterator (void *cls,
+                        const struct GNUNET_PeerIdentity *peer,
+                        void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p = value;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoPeer *msg;
+
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+  msg->destination = *peer;
+  msg->paths = htons (GCP_count_paths (p));
+  msg->tunnel = htons (NULL != GCP_get_tunnel (p,
+                                               GNUNET_NO));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls,
+                  const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *reply;
+
+  GCP_iterate_all (&get_all_peers_iterator,
+                   c);
+  env = GNUNET_MQ_msg (reply,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all paths of a peer to build an InfoPeer message.
+ * Message contains blocks of peers, first not included.
+ *
+ * @param cls message queue for transmission
+ * @param path Path itself
+ * @param off offset of the peer on @a path
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
+ */
+static int
+path_info_iterator (void *cls,
+                    struct CadetPeerPath *path,
+                    unsigned int off)
+{
+  struct GNUNET_MQ_Handle *mq = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *resp;
+  struct GNUNET_PeerIdentity *id;
+  uint16_t path_size;
+  unsigned int i;
+  unsigned int path_length;
+
+  path_length = GCPP_get_length (path);
+  path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
+  if (sizeof (*resp) + path_size > UINT16_MAX)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Path of %u entries is too long for info message\n",
+         path_length);
+    return GNUNET_YES;
+  }
+  env = GNUNET_MQ_msg_extra (resp,
+                             path_size,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+  id = (struct GNUNET_PeerIdentity *) &resp[1];
+
+  /* Don't copy first peer.  First peer is always the local one.  Last
+   * peer is always the destination (leave as 0, EOL).
+   */
+  for (i = 0; i < off; i++)
+    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
+                                                  i + 1));
+  GNUNET_MQ_send (mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's SHOW_PEER request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_peer (void *cls,
+                  const struct GNUNET_CADET_LocalInfo *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *resp;
+
+  p = GCP_get (&msg->peer,
+               GNUNET_NO);
+  if (NULL != p)
+    GCP_iterate_paths (p,
+                       &path_info_iterator,
+                       c->mq);
+  /* Send message with 0/0 to indicate the end */
+  env = GNUNET_MQ_msg (resp,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all tunnels to send a monitoring client info about each tunnel.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value a `struct CadetPeer`
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+                          const struct GNUNET_PeerIdentity *peer,
+                          void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p = value;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoTunnel *msg;
+  struct CadetTunnel *t;
+
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL == t)
+    return GNUNET_YES;
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+  msg->destination = *peer;
+  msg->channels = htonl (GCT_count_channels (t));
+  msg->connections = htonl (GCT_count_any_connections (t));
+  msg->cstate = htons (0);
+  msg->estate = htons ((uint16_t) GCT_get_estate (t));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_tunnels (void *cls,
+                     const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *reply;
+
+  GCP_iterate_all (&get_all_tunnels_iterator,
+                   c);
+  env = GNUNET_MQ_msg (reply,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Update the message with information about the connection.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ct a connection about which we should store information in @a cls
+ */
+static void
+iter_connection (void *cls,
+                 struct CadetTConnection *ct)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct CadetConnection *cc = ct->cc;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
+
+  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  h[msg->connections++] = *(GCC_get_id (cc));
+}
+
+
+/**
+ * Update the message with information about the channel.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ch a channel about which we should store information in @a cls
+ */
+static void
+iter_channel (void *cls,
+              struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  struct GNUNET_CADET_ChannelTunnelNumber *chn
+    = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
+
+  chn[msg->channels++] = GCCH_get_id (ch);
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_info_tunnel (void *cls,
+                    const struct GNUNET_CADET_LocalInfo *msg)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoTunnel *resp;
+  struct CadetTunnel *t;
+  struct CadetPeer *p;
+  unsigned int ch_n;
+  unsigned int c_n;
+
+  p = GCP_get (&msg->peer,
+               GNUNET_NO);
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL == t)
+  {
+    /* We don't know the tunnel */
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_LocalInfoTunnel *warn;
+
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Tunnel to %s unknown\n",
+         GNUNET_i2s_full (&msg->peer));
+    env = GNUNET_MQ_msg (warn,
+                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+    warn->destination = msg->peer;
+    GNUNET_MQ_send (c->mq,
+                    env);
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+
+  /* Initialize context */
+  ch_n = GCT_count_channels (t);
+  c_n = GCT_count_any_connections (t);
+  env = GNUNET_MQ_msg_extra (resp,
+                             c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
+                             ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+  resp->destination = msg->peer;
+  /* Do not reorder! #iter_channel needs counters in HBO! */
+  GCT_iterate_connections (t,
+                           &iter_connection,
+                           resp);
+  GCT_iterate_channels (t,
+                        &iter_channel,
+                        resp);
+  resp->connections = htonl (resp->connections);
+  resp->channels = htonl (resp->channels);
+  resp->cstate = htons (0);
+  resp->estate = htons (GCT_get_estate (t));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to dump info for each peer.
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+show_peer_iterator (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
+                    void *value)
+{
+  struct CadetPeer *p = value;
+  struct CadetTunnel *t;
+
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL != t)
+    GCT_debug (t,
+               GNUNET_ERROR_TYPE_ERROR);
+  LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO_DUMP request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_dump (void *cls,
+                  const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Received dump info request from client %u\n",
+       c->id);
+
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       "*************************** DUMP START ***************************\n");
+  for (struct CadetClient *ci = clients_head;
+       NULL != ci;
+       ci = ci->next)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
+         ci->id,
+         ci,
+         ci->client,
+         (NULL != c->ports)
+         ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
+         : 0,
+         GNUNET_CONTAINER_multihashmap32_size (ci->channels));
+  }
+  LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
+  GCP_iterate_all (&show_peer_iterator,
+                   NULL);
+
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       "**************************** DUMP END ****************************\n");
+
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param client the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
+ */
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *client,
+                  struct GNUNET_MQ_Handle *mq)
+{
+  struct CadetClient *c;
+
+  c = GNUNET_new (struct CadetClient);
+  c->client = client;
+  c->mq = mq;
+  c->id = next_client_id++; /* overflow not important: just for debug */
+  c->channels
+    = GNUNET_CONTAINER_multihashmap32_create (32);
+  GNUNET_CONTAINER_DLL_insert (clients_head,
+                               clients_tail,
+                               c);
+  GNUNET_STATISTICS_update (stats,
+                            "# clients",
+                            +1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s connected\n",
+       GSC_2s (c));
+  return c;
+}
+
+
+/**
+ * A channel was destroyed by the other peer. Tell our client.
+ *
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
+ */
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+                                   struct GNUNET_CADET_ClientChannelNumber ccn,
+                                   struct CadetChannel *ch)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
+
+  env = GNUNET_MQ_msg (tdm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
+  tdm->ccn = ccn;
+  GSC_send_to_client (c,
+                      env);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (ccn.channel_of_client),
+                                                         ch));
+}
+
+
+/**
+ * A client that created a loose channel that was not bound to a port
+ * disconnected, drop it from the #loose_channels list.
+ *
+ * @param port the port the channel was trying to bind to
+ * @param ch the channel that was lost
+ */
+void
+GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+                        struct CadetChannel *ch)
+{
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+                                                       port,
+                                                       ch));
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id in host byte order
+ * @param value The value stored at the key (channel to destroy).
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+channel_destroy_iterator (void *cls,
+                          uint32_t key,
+                          void *value)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+  struct CadetChannel *ch = value;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying %s, due to %s disconnecting.\n",
+       GCCH_2s (ch),
+       GSC_2s (c));
+  ccn.channel_of_client = htonl (key);
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              ccn);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         key,
+                                                         ch));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key the port.
+ * @param value the `struct CadetClient` to remove
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+client_release_ports (void *cls,
+                      const struct GNUNET_HashCode *key,
+                      void *value)
+{
+  struct CadetClient *c = value;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing port %s due to %s disconnect.\n",
+       GNUNET_h2s (key),
+       GSC_2s (c));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
+                                                       key,
+                                                       value));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (c->ports,
+                                                       key,
+                                                       value));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param client the client that disconnected
+ * @param internal_cls should be equal to @a c
+ */
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *client,
+                     void *internal_cls)
+{
+  struct CadetClient *c = internal_cls;
+
+  GNUNET_assert (c->client == client);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s is disconnecting.\n",
+       GSC_2s (c));
+  if (NULL != c->channels)
+  {
+    GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
+                                             &channel_destroy_iterator,
+                                             c);
+    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
+    GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
+  }
+  if (NULL != c->ports)
+  {
+    GNUNET_CONTAINER_multihashmap_iterate (c->ports,
+                                           &client_release_ports,
+                                           c);
+    GNUNET_CONTAINER_multihashmap_destroy (c->ports);
+  }
+  GNUNET_CONTAINER_DLL_remove (clients_head,
+                               clients_tail,
+                               c);
+  GNUNET_STATISTICS_update (stats,
+                            "# clients",
+                            -1,
+                            GNUNET_NO);
+  GNUNET_free (c);
+  if ( (NULL == clients_head) &&
+       (GNUNET_YES == shutting_down) )
+    shutdown_rest ();
+}
+
+
+/**
+ * Setup CADET internals.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *service)
+{
+  cfg = c;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "RATCHET_MESSAGES",
+                                             &ratchet_messages))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "RATCHET_MESSAGES",
+                               "needs to be a number");
+    ratchet_messages = 64;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "RATCHET_TIME",
+                                           &ratchet_time))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "RATCHET_TIME",
+                               "need delay value");
+    ratchet_time = GNUNET_TIME_UNIT_HOURS;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "REFRESH_CONNECTION_TIME",
+                                           &keepalive_period))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "REFRESH_CONNECTION_TIME",
+                               "need delay value");
+    keepalive_period = GNUNET_TIME_UNIT_MINUTES;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "DROP_PERCENT",
+                                             &drop_percent))
+  {
+    drop_percent = 0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+  }
+  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
+  if (NULL == my_private_key)
+  {
+    GNUNET_break (0);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
+                                      &my_full_id.public_key);
+  stats = GNUNET_STATISTICS_create ("cadet",
+                                    c);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                NULL);
+  ats_ch = GNUNET_ATS_connectivity_init (c);
+  /* FIXME: optimize code to allow GNUNET_YES here! */
+  open_ports = GNUNET_CONTAINER_multihashmap_create (16,
+                                                     GNUNET_NO);
+  loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
+                                                         GNUNET_NO);
+  peers = GNUNET_CONTAINER_multipeermap_create (16,
+                                                GNUNET_YES);
+  connections = GNUNET_CONTAINER_multishortmap_create (256,
+                                                       GNUNET_YES);
+  GCH_init (c);
+  GCD_init (c);
+  GCO_init (c);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "CADET started for peer %s\n",
+              GNUNET_i2s (&my_full_id));
+
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("cadet",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (port_open,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
+                          struct GNUNET_CADET_PortMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (port_close,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
+                          struct GNUNET_CADET_PortMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (channel_create,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
+                          struct GNUNET_CADET_LocalChannelCreateMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (channel_destroy,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
+                          struct GNUNET_CADET_LocalChannelDestroyMessage,
+                          NULL),
+ GNUNET_MQ_hd_var_size (local_data,
+                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
+                        struct GNUNET_CADET_LocalData,
+                        NULL),
+ GNUNET_MQ_hd_fixed_size (local_ack,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
+                          struct GNUNET_CADET_LocalAck,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (get_peers,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (show_peer,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
+                          struct GNUNET_CADET_LocalInfo,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnels,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnel,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
+                          struct GNUNET_CADET_LocalInfo,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_dump,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_handler_end ());
+
+/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet.h b/src/cadet/gnunet-service-cadet.h
new file mode 100644 (file)
index 0000000..2f2d7ba
--- /dev/null
@@ -0,0 +1,308 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet.h
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_H
+#define GNUNET_SERVICE_CADET_H
+
+#include "gnunet_util_lib.h"
+#define NEW_CADET 1
+#include "cadet_protocol.h"
+
+/**
+ * A client to the CADET service.  Each client gets a unique handle.
+ */
+struct CadetClient;
+
+/**
+ * A peer in the GNUnet network.  Each peer we care about must have one globally
+ * unique such handle within this process.
+ */
+struct CadetPeer;
+
+/**
+ * Tunnel from us to another peer.  There can only be at most one
+ * tunnel per peer.
+ */
+struct CadetTunnel;
+
+/**
+ * Entry in the message queue of a `struct CadetTunnel`.
+ */
+struct CadetTunnelQueueEntry;
+
+/**
+ * A path of peer in the GNUnet network.  There must only be at most
+ * once such path.  Paths may share disjoint prefixes, but must all
+ * end at a unique suffix.  Paths must also not be proper subsets of
+ * other existing paths.
+ */
+struct CadetPeerPath;
+
+/**
+ * Entry in a peer path.
+ */
+struct CadetPeerPathEntry
+{
+  /**
+   * DLL of paths where the same @e peer is at the same offset.
+   */
+  struct CadetPeerPathEntry *next;
+
+  /**
+   * DLL of paths where the same @e peer is at the same offset.
+   */
+  struct CadetPeerPathEntry *prev;
+
+  /**
+   * The peer at this offset of the path.
+   */
+  struct CadetPeer *peer;
+
+  /**
+   * Path this entry belongs to.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Connection using this path, or NULL for none.
+   */
+  struct CadetConnection *cc;
+
+  /**
+   * Path's historic score up to this point.  Basically, how often did
+   * we succeed or fail to use the path up to this entry in a
+   * connection.  Positive values indicate good experiences, negative
+   * values bad experiences.  Code updating the score must guard
+   * against overflows.
+   */
+  int score;
+
+};
+
+/**
+ * Entry in list of connections used by tunnel, with metadata.
+ */
+struct CadetTConnection
+{
+  /**
+   * Next in DLL.
+   */
+  struct CadetTConnection *next;
+
+  /**
+   * Prev in DLL.
+   */
+  struct CadetTConnection *prev;
+
+  /**
+   * Connection handle.
+   */
+  struct CadetConnection *cc;
+
+  /**
+   * Tunnel this connection belongs to.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Creation time, to keep oldest connection alive.
+   */
+  struct GNUNET_TIME_Absolute created;
+
+  /**
+   * Connection throughput, to keep fastest connection alive.
+   */
+  uint32_t throughput;
+
+  /**
+   * Is the connection currently ready for transmission?
+   */
+  int is_ready;
+};
+
+
+/**
+ * Active path through the network (used by a tunnel).  There may
+ * be at most one connection per path.
+ */
+struct CadetConnection;
+
+/**
+ * Description of a segment of a `struct CadetConnection` at the
+ * intermediate peers.  Routes are basically entries in a peer's
+ * routing table for forwarding traffic.  At both endpoints, the
+ * routes are terminated by a `struct CadetConnection`, which knows
+ * the complete `struct CadetPath` that is formed by the individual
+ * routes.
+ */
+struct CadetRoute;
+
+/**
+ * Logical end-to-end conenction between clients.  There can be
+ * any number of channels between clients.
+ */
+struct CadetChannel;
+
+/**
+ * Handle to our configuration.
+ */
+extern const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to communicate with ATS.
+ */
+extern struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
+/**
+ * Local peer own ID.
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Own private key.
+ */
+extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
+ * hash codes to `struct CadetConnection` objects.
+ */
+extern struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+extern struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * How many messages are needed to trigger an AXOLOTL ratchet advance.
+ */
+extern unsigned long long ratchet_messages;
+
+/**
+ * How long until we trigger a ratched advance due to time.
+ */
+extern struct GNUNET_TIME_Relative ratchet_time;
+
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+extern struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Signal that shutdown is happening: prevent recovery measures.
+ */
+extern int shutting_down;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+extern unsigned long long drop_percent;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+                    struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * A channel was destroyed by the other peer. Tell our client.
+ *
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
+ */
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+                                   struct GNUNET_CADET_ClientChannelNumber ccn,
+                                   struct CadetChannel *ch);
+
+/**
+ * A client that created a loose channel that was not bound to a port
+ * disconnected, drop it from the #loose_channels list.
+ *
+ * @param port the port the channel was trying to bind to
+ * @param ch the channel that was lost
+ */
+void
+GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+                        struct CadetChannel *ch);
+
+
+/**
+ * Bind incoming channel to this client, and notify client
+ * about incoming connection.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+          struct CadetChannel *ch,
+          struct CadetPeer *dest,
+          const struct GNUNET_HashCode *port,
+          uint32_t options);
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c
new file mode 100644 (file)
index 0000000..68e29b6
--- /dev/null
@@ -0,0 +1,2037 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_channel.c
+ * @brief logical links between CADET clients
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - Congestion/flow control:
+ *   + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
+ *     (and figure out how/where to use this!)
+ *   + figure out flow control without ACKs (unreliable traffic!)
+ * - revisit handling of 'unbuffered' traffic!
+ *   (need to push down through tunnel into connection selection)
+ * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
+ *   reserve more bits in 'options' to allow for buffer size control?
+ */
+#include "platform.h"
+#include "cadet.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_paths.h"
+
+#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
+
+/**
+ * How long do we initially wait before retransmitting?
+ */
+#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
+
+/**
+ * How long do we wait before dropping state about incoming
+ * connection to closed port?
+ */
+#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * How long do we wait at least before retransmitting ever?
+ */
+#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
+
+/**
+ * Maximum message ID into the future we accept for out-of-order messages.
+ * If the message is more than this into the future, we drop it.  This is
+ * important both to detect values that are actually in the past, as well
+ * as to limit adversarially triggerable memory consumption.
+ *
+ * Note that right now we have "max_pending_messages = 4" hard-coded in
+ * the logic below, so a value of 4 would suffice here. But we plan to
+ * allow larger windows in the future...
+ */
+#define MAX_OUT_OF_ORDER_DISTANCE 1024
+
+
+/**
+ * All the states a channel can be in.
+ */
+enum CadetChannelState
+{
+  /**
+   * Uninitialized status, should never appear in operation.
+   */
+  CADET_CHANNEL_NEW,
+
+  /**
+   * Channel is to a port that is not open, we're waiting for the
+   * port to be opened.
+   */
+  CADET_CHANNEL_LOOSE,
+
+  /**
+   * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
+   */
+  CADET_CHANNEL_OPEN_SENT,
+
+  /**
+   * Connection confirmed, ready to carry traffic.
+   */
+  CADET_CHANNEL_READY
+};
+
+
+/**
+ * Info needed to retry a message in case it gets lost.
+ * Note that we DO use this structure also for unreliable
+ * messages.
+ */
+struct CadetReliableMessage
+{
+  /**
+   * Double linked list, FIFO style
+   */
+  struct CadetReliableMessage *next;
+
+  /**
+   * Double linked list, FIFO style
+   */
+  struct CadetReliableMessage *prev;
+
+  /**
+   * Which channel is this message in?
+   */
+  struct CadetChannel *ch;
+
+  /**
+   * Entry in the tunnels queue for this message, NULL if it has left
+   * the tunnel.  Used to cancel transmission in case we receive an
+   * ACK in time.
+   */
+  struct CadetTunnelQueueEntry *qe;
+
+  /**
+   * Data message we are trying to send.
+   */
+  struct GNUNET_CADET_ChannelAppDataMessage *data_message;
+
+  /**
+   * How soon should we retry if we fail to get an ACK?
+   * Messages in the queue are sorted by this value.
+   */
+  struct GNUNET_TIME_Absolute next_retry;
+
+  /**
+   * How long do we wait for an ACK after transmission?
+   * Use for the back-off calculation.
+   */
+  struct GNUNET_TIME_Relative retry_delay;
+
+  /**
+   * Time when we first successfully transmitted the message
+   * (that is, set @e num_transmissions to 1).
+   */
+  struct GNUNET_TIME_Absolute first_transmission_time;
+
+  /**
+   * Identifier of the connection that this message took when it
+   * was first transmitted.  Only useful if @e num_transmissions is 1.
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
+
+  /**
+   * How often was this message transmitted?  #GNUNET_SYSERR if there
+   * was an error transmitting the message, #GNUNET_NO if it was not
+   * yet transmitted ever, otherwise the number of (re) transmissions.
+   */
+  int num_transmissions;
+
+};
+
+
+/**
+ * List of received out-of-order data messages.
+ */
+struct CadetOutOfOrderMessage
+{
+  /**
+   * Double linked list, FIFO style
+   */
+  struct CadetOutOfOrderMessage *next;
+
+  /**
+   * Double linked list, FIFO style
+   */
+  struct CadetOutOfOrderMessage *prev;
+
+  /**
+   * ID of the message (messages up to this point needed
+   * before we give this one to the client).
+   */
+  struct ChannelMessageIdentifier mid;
+
+  /**
+   * The envelope with the payload of the out-of-order message
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+};
+
+
+/**
+ * Client endpoint of a `struct CadetChannel`.  A channel may be a
+ * loopback channel, in which case it has two of these endpoints.
+ * Note that flow control also is required in both directions.
+ */
+struct CadetChannelClient
+{
+  /**
+   * Client handle.  Not by itself sufficient to designate
+   * the client endpoint, as the same client handle may
+   * be used for both the owner and the destination, and
+   * we thus also need the channel ID to identify the client.
+   */
+  struct CadetClient *c;
+
+  /**
+   * Head of DLL of messages received out of order or while client was unready.
+   */
+  struct CadetOutOfOrderMessage *head_recv;
+
+  /**
+   * Tail DLL of messages received out of order or while client was unready.
+   */
+  struct CadetOutOfOrderMessage *tail_recv;
+
+  /**
+   * Local tunnel number for this client.
+   * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
+   *  otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+   */
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+
+  /**
+   * Number of entries currently in @a head_recv DLL.
+   */
+  unsigned int num_recv;
+
+  /**
+   * Can we send data to the client?
+   */
+  int client_ready;
+
+};
+
+
+/**
+ * Struct containing all information regarding a channel to a remote client.
+ */
+struct CadetChannel
+{
+  /**
+   * Tunnel this channel is in.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Client owner of the tunnel, if any.
+   * (Used if this channel represends the initiating end of the tunnel.)
+   */
+  struct CadetChannelClient *owner;
+
+  /**
+   * Client destination of the tunnel, if any.
+   * (Used if this channel represents the listening end of the tunnel.)
+   */
+  struct CadetChannelClient *dest;
+
+  /**
+   * Last entry in the tunnel's queue relating to control messages
+   * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
+   * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK).  Used to cancel
+   * transmission in case we receive updated information.
+   */
+  struct CadetTunnelQueueEntry *last_control_qe;
+
+  /**
+   * Head of DLL of messages sent and not yet ACK'd.
+   */
+  struct CadetReliableMessage *head_sent;
+
+  /**
+   * Tail of DLL of messages sent and not yet ACK'd.
+   */
+  struct CadetReliableMessage *tail_sent;
+
+  /**
+   * Task to resend/poll in case no ACK is received.
+   */
+  struct GNUNET_SCHEDULER_Task *retry_control_task;
+
+  /**
+   * Task to resend/poll in case no ACK is received.
+   */
+  struct GNUNET_SCHEDULER_Task *retry_data_task;
+
+  /**
+   * Last time the channel was used
+   */
+  struct GNUNET_TIME_Absolute timestamp;
+
+  /**
+   * Destination port of the channel.
+   */
+  struct GNUNET_HashCode port;
+
+  /**
+   * Counter for exponential backoff.
+   */
+  struct GNUNET_TIME_Relative retry_time;
+
+  /**
+   * Bitfield of already-received messages past @e mid_recv.
+   */
+  uint64_t mid_futures;
+
+  /**
+   * Next MID expected for incoming traffic.
+   */
+  struct ChannelMessageIdentifier mid_recv;
+
+  /**
+   * Next MID to use for outgoing traffic.
+   */
+  struct ChannelMessageIdentifier mid_send;
+
+  /**
+   * Total (reliable) messages pending ACK for this channel.
+   */
+  unsigned int pending_messages;
+
+  /**
+   * Maximum (reliable) messages pending ACK for this channel
+   * before we throttle the client.
+   */
+  unsigned int max_pending_messages;
+
+  /**
+   * Number identifying this channel in its tunnel.
+   */
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+  /**
+   * Channel state.
+   */
+  enum CadetChannelState state;
+
+  /**
+   * Count how many ACKs we skipped, used to prevent long
+   * sequences of ACK skipping.
+   */
+  unsigned int skip_ack_series;
+
+  /**
+   * Is the tunnel bufferless (minimum latency)?
+   */
+  int nobuffer;
+
+  /**
+   * Is the tunnel reliable?
+   */
+  int reliable;
+
+  /**
+   * Is the tunnel out-of-order?
+   */
+  int out_of_order;
+
+  /**
+   * Is this channel a loopback channel, where the destination is us again?
+   */
+  int is_loopback;
+
+  /**
+   * Flag to signal the destruction of the channel.  If this is set to
+   * #GNUNET_YES the channel will be destroyed once the queue is
+   * empty.
+   */
+  int destroy;
+
+};
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GCCH_2s (const struct CadetChannel *ch)
+{
+  static char buf[128];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Channel %s:%s ctn:%X(%X/%X)",
+                   (GNUNET_YES == ch->is_loopback)
+                   ? "loopback"
+                   : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
+                   GNUNET_h2s (&ch->port),
+                   ch->ctn,
+                   (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
+                   (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
+  return buf;
+}
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch)
+{
+  return ch->ctn;
+}
+
+
+/**
+ * Release memory associated with @a ccc
+ *
+ * @param ccc data structure to clean up
+ */
+static void
+free_channel_client (struct CadetChannelClient *ccc)
+{
+  struct CadetOutOfOrderMessage *com;
+
+  while (NULL != (com = ccc->head_recv))
+  {
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GNUNET_MQ_discard (com->env);
+    GNUNET_free (com);
+  }
+  GNUNET_free (ccc);
+}
+
+
+/**
+ * Destroy the given channel.
+ *
+ * @param ch channel to destroy
+ */
+static void
+channel_destroy (struct CadetChannel *ch)
+{
+  struct CadetReliableMessage *crm;
+
+  while (NULL != (crm = ch->head_sent))
+  {
+    GNUNET_assert (ch == crm->ch);
+    if (NULL != crm->qe)
+    {
+      GCT_send_cancel (crm->qe);
+      crm->qe = NULL;
+    }
+    GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                                 ch->tail_sent,
+                                 crm);
+    GNUNET_free (crm->data_message);
+    GNUNET_free (crm);
+  }
+  if (NULL != ch->owner)
+  {
+    free_channel_client (ch->owner);
+    ch->owner = NULL;
+  }
+  if (NULL != ch->dest)
+  {
+    free_channel_client (ch->dest);
+    ch->dest = NULL;
+  }
+  if (NULL != ch->last_control_qe)
+  {
+    GCT_send_cancel (ch->last_control_qe);
+    ch->last_control_qe = NULL;
+  }
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
+  }
+  if (NULL != ch->retry_control_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task = NULL;
+  }
+  if (GNUNET_NO == ch->is_loopback)
+  {
+    GCT_remove_channel (ch->t,
+                        ch,
+                        ch->ctn);
+    ch->t = NULL;
+  }
+  GNUNET_free (ch);
+}
+
+
+/**
+ * Send a channel create message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_channel_open (void *cls);
+
+
+/**
+ * Function called once the tunnel confirms that we sent the
+ * create message.  Delays for a bit until we retry.
+ *
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+channel_open_sent_cb (void *cls,
+                      const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  struct CadetChannel *ch = cls;
+
+  GNUNET_assert (NULL != ch->last_control_qe);
+  ch->last_control_qe = NULL;
+  ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
+       GCCH_2s (ch),
+       GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
+                                               GNUNET_YES));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
+                                    &send_channel_open,
+                                    ch);
+}
+
+
+/**
+ * Send a channel open message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_channel_open (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct GNUNET_CADET_ChannelOpenMessage msgcc;
+  uint32_t options;
+
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CHANNEL_OPEN message for %s\n",
+       GCCH_2s (ch));
+  options = 0;
+  if (ch->nobuffer)
+    options |= GNUNET_CADET_OPTION_NOBUFFER;
+  if (ch->reliable)
+    options |= GNUNET_CADET_OPTION_RELIABLE;
+  if (ch->out_of_order)
+    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+  msgcc.header.size = htons (sizeof (msgcc));
+  msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
+  msgcc.opt = htonl (options);
+  msgcc.port = ch->port;
+  msgcc.ctn = ch->ctn;
+  ch->state = CADET_CHANNEL_OPEN_SENT;
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msgcc.header,
+                                  &channel_open_sent_cb,
+                                  ch);
+  GNUNET_assert (NULL == ch->retry_control_task);
+}
+
+
+/**
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
+ */
+void
+GCCH_tunnel_up (struct CadetChannel *ch)
+{
+  GNUNET_assert (NULL == ch->retry_control_task);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel up, sending CHANNEL_OPEN on %s now\n",
+       GCCH_2s (ch));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_now (&send_channel_open,
+                                ch);
+}
+
+
+/**
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param ccn local number of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+                        struct GNUNET_CADET_ClientChannelNumber ccn,
+                        struct CadetPeer *destination,
+                        const struct GNUNET_HashCode *port,
+                        uint32_t options)
+{
+  struct CadetChannel *ch;
+  struct CadetChannelClient *ccco;
+
+  ccco = GNUNET_new (struct CadetChannelClient);
+  ccco->c = owner;
+  ccco->ccn = ccn;
+  ccco->client_ready = GNUNET_YES;
+
+  ch = GNUNET_new (struct CadetChannel);
+  ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
+  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+  ch->owner = ccco;
+  ch->port = *port;
+  if (0 == memcmp (&my_full_id,
+                   GCP_get_id (destination),
+                   sizeof (struct GNUNET_PeerIdentity)))
+  {
+    struct CadetClient *c;
+
+    ch->is_loopback = GNUNET_YES;
+    c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+                                           port);
+    if (NULL == c)
+    {
+      /* port closed, wait for it to possibly open */
+      ch->state = CADET_CHANNEL_LOOSE;
+      (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+                                                port,
+                                                ch,
+                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Created loose incoming loopback channel to port %s\n",
+           GNUNET_h2s (&ch->port));
+    }
+    else
+    {
+      GCCH_bind (ch,
+                 c);
+    }
+  }
+  else
+  {
+    ch->t = GCP_get_tunnel (destination,
+                            GNUNET_YES);
+    ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+    ch->ctn = GCT_add_channel (ch->t,
+                               ch);
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created channel to port %s at peer %s for %s using %s\n",
+       GNUNET_h2s (port),
+       GCP_2s (destination),
+       GSC_2s (owner),
+       (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
+  return ch;
+}
+
+
+/**
+ * We had an incoming channel to a port that is closed.
+ * It has not been opened for a while, drop it.
+ *
+ * @param cls the channel to drop
+ */
+static void
+timeout_closed_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing incoming channel to port %s from peer %s due to timeout\n",
+       GNUNET_h2s (&ch->port),
+       GCP_2s (GCT_get_destination (ch->t)));
+  channel_destroy (ch);
+}
+
+
+/**
+ * Create a new channel based on a request coming in over the network.
+ *
+ * @param t tunnel to the remote peer
+ * @param ctn identifier of this channel in the tunnel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+                           struct GNUNET_CADET_ChannelTunnelNumber ctn,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options)
+{
+  struct CadetChannel *ch;
+  struct CadetClient *c;
+
+  ch = GNUNET_new (struct CadetChannel);
+  ch->port = *port;
+  ch->t = t;
+  ch->ctn = ctn;
+  ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+
+  c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+                                         port);
+  if (NULL == c)
+  {
+    /* port closed, wait for it to possibly open */
+    ch->state = CADET_CHANNEL_LOOSE;
+    (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+                                              port,
+                                              ch,
+                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+    GNUNET_assert (NULL == ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
+                                      &timeout_closed_cb,
+                                      ch);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Created loose incoming channel to port %s from peer %s\n",
+         GNUNET_h2s (&ch->port),
+         GCP_2s (GCT_get_destination (ch->t)));
+  }
+  else
+  {
+    GCCH_bind (ch,
+               c);
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+  return ch;
+}
+
+
+/**
+ * Function called once the tunnel confirms that we sent the
+ * ACK message.  Just remembers it was sent, we do not expect
+ * ACKs for ACKs ;-).
+ *
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+send_ack_cb (void *cls,
+             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  struct CadetChannel *ch = cls;
+
+  GNUNET_assert (NULL != ch->last_control_qe);
+  ch->last_control_qe = NULL;
+}
+
+
+/**
+ * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
+ *
+ * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
+ */
+static void
+send_channel_data_ack (struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_ChannelDataAckMessage msg;
+
+  if (GNUNET_NO == ch->reliable)
+    return; /* no ACKs */
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
+  msg.header.size = htons (sizeof (msg));
+  msg.ctn = ch->ctn;
+  msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
+  msg.futures = GNUNET_htonll (ch->mid_futures);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending DATA_ACK %u:%llX via %s\n",
+       (unsigned int) ntohl (msg.mid.mid),
+       (unsigned long long) ch->mid_futures,
+       GCCH_2s (ch));
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msg.header,
+                                  &send_ack_cb,
+                                  ch);
+}
+
+
+/**
+ * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
+ * connection is up.
+ *
+ * @param cls the `struct CadetChannel`
+ */
+static void
+send_open_ack (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct GNUNET_CADET_ChannelManageMessage msg;
+
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CHANNEL_OPEN_ACK on %s\n",
+       GCCH_2s (ch));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
+  msg.header.size = htons (sizeof (msg));
+  msg.reserved = htonl (0);
+  msg.ctn = ch->ctn;
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msg.header,
+                                  &send_ack_cb,
+                                  ch);
+}
+
+
+/**
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel.  If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
+ *
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
+ */
+void
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
+{
+  if (NULL == ch->dest)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
+         GCCH_2s (ch));
+    return;
+  }
+  if (NULL != ch->retry_control_task)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
+         GCCH_2s (ch));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Retransmitting CHANNEL_OPEN_ACK on %s\n",
+       GCCH_2s (ch));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_now (&send_open_ack,
+                                ch);
+}
+
+
+/**
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
+ *
+ * @param ch channel the ack is for
+ * @param to_owner #GNUNET_YES to send to owner,
+ *                 #GNUNET_NO to send to dest
+ */
+static void
+send_ack_to_client (struct CadetChannel *ch,
+                    int to_owner)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalAck *ack;
+  struct CadetChannelClient *ccc;
+
+  ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
+  if (NULL == ccc)
+  {
+    /* This can happen if we are just getting ACKs after
+       our local client already disconnected. */
+    GNUNET_assert (GNUNET_YES == ch->destroy);
+    return;
+  }
+  env = GNUNET_MQ_msg (ack,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+  ack->ccn = ccc->ccn;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
+       GSC_2s (ccc->c),
+       (GNUNET_YES == to_owner) ? "owner" : "dest",
+       ntohl (ack->ccn.channel_of_client),
+       ch->pending_messages,
+       ch->max_pending_messages);
+  GSC_send_to_client (ccc->c,
+                      env);
+}
+
+
+/**
+ * A client is bound to the port that we have a channel
+ * open to.  Send the acknowledgement for the connection
+ * request and establish the link with the client.
+ *
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
+ */
+void
+GCCH_bind (struct CadetChannel *ch,
+           struct CadetClient *c)
+{
+  uint32_t options;
+  struct CadetChannelClient *cccd;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Binding %s from %s to port %s of %s\n",
+       GCCH_2s (ch),
+       GCT_2s (ch->t),
+       GNUNET_h2s (&ch->port),
+       GSC_2s (c));
+  if (NULL != ch->retry_control_task)
+  {
+    /* there might be a timeout task here */
+    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task = NULL;
+  }
+  options = 0;
+  if (ch->nobuffer)
+    options |= GNUNET_CADET_OPTION_NOBUFFER;
+  if (ch->reliable)
+    options |= GNUNET_CADET_OPTION_RELIABLE;
+  if (ch->out_of_order)
+    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+  cccd = GNUNET_new (struct CadetChannelClient);
+  GNUNET_assert (NULL == ch->dest);
+  ch->dest = cccd;
+  cccd->c = c;
+  cccd->client_ready = GNUNET_YES;
+  cccd->ccn = GSC_bind (c,
+                        ch,
+                        (GNUNET_YES == ch->is_loopback)
+                        ? GCP_get (&my_full_id,
+                                   GNUNET_YES)
+                        : GCT_get_destination (ch->t),
+                        &ch->port,
+                        options);
+  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+  ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
+  if (GNUNET_YES == ch->is_loopback)
+  {
+    ch->state = CADET_CHANNEL_OPEN_SENT;
+    GCCH_handle_channel_open_ack (ch,
+                                  NULL);
+  }
+  else
+  {
+    /* notify other peer that we accepted the connection */
+    ch->state = CADET_CHANNEL_READY;
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&send_open_ack,
+                                  ch);
+  }
+  /* give client it's initial supply of ACKs */
+  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+  for (unsigned int i=0;i<ch->max_pending_messages;i++)
+    send_ack_to_client (ch,
+                        GNUNET_NO);
+}
+
+
+/**
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
+ *
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
+ */
+static void
+signal_remote_destroy_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct CadetChannelClient *ccc;
+
+  /* Find which end is left... */
+  ch->retry_control_task = NULL;
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  GSC_handle_remote_channel_destroy (ccc->c,
+                                     ccc->ccn,
+                                     ch);
+  channel_destroy (ch);
+}
+
+
+/**
+ * Destroy locally created channel.  Called by the local client, so no
+ * need to tell the client.
+ *
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+                            struct CadetClient *c,
+                            struct GNUNET_CADET_ClientChannelNumber ccn)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s asks for destruction of %s\n",
+       GSC_2s (c),
+       GCCH_2s (ch));
+  GNUNET_assert (NULL != c);
+  if ( (NULL != ch->owner) &&
+       (c == ch->owner->c) &&
+       (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
+  {
+    free_channel_client (ch->owner);
+    ch->owner = NULL;
+  }
+  else if ( (NULL != ch->dest) &&
+            (c == ch->dest->c) &&
+            (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
+  {
+    free_channel_client (ch->dest);
+    ch->dest = NULL;
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
+
+  if (GNUNET_YES == ch->destroy)
+  {
+    /* other end already destroyed, with the local client gone, no need
+       to finish transmissions, just destroy immediately. */
+    channel_destroy (ch);
+    return;
+  }
+  if ( (NULL != ch->head_sent) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
+  {
+    /* Wait for other end to destroy us as well,
+       and otherwise allow send queue to be transmitted first */
+    ch->destroy = GNUNET_YES;
+    return;
+  }
+  if ( (GNUNET_YES == ch->is_loopback) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
+  {
+    if (NULL != ch->retry_control_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+                                  ch);
+    return;
+  }
+  if (GNUNET_NO == ch->is_loopback)
+  {
+    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+    switch (ch->state)
+    {
+    case CADET_CHANNEL_NEW:
+      /* We gave up on a channel that we created as a client to a remote
+         target, but that never went anywhere. Nothing to do here. */
+      break;
+    case CADET_CHANNEL_LOOSE:
+      GSC_drop_loose_channel (&ch->port,
+                              ch);
+      break;
+    default:
+      GCT_send_channel_destroy (ch->t,
+                                ch->ctn);
+    }
+  }
+  /* Nothing left to do, just finish destruction */
+  channel_destroy (ch);
+}
+
+
+/**
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
+ *
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message
+ */
+void
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
+{
+  switch (ch->state)
+  {
+  case CADET_CHANNEL_NEW:
+    /* this should be impossible */
+    GNUNET_break (0);
+    break;
+  case CADET_CHANNEL_LOOSE:
+    /* This makes no sense. */
+    GNUNET_break_op (0);
+    break;
+  case CADET_CHANNEL_OPEN_SENT:
+    if (NULL == ch->owner)
+    {
+      /* We're not the owner, wrong direction! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
+         GCCH_2s (ch));
+    if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
+    {
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+      ch->retry_control_task = NULL;
+    }
+    ch->state = CADET_CHANNEL_READY;
+    /* On first connect, send client as many ACKs as we allow messages
+       to be buffered! */
+    for (unsigned int i=0;i<ch->max_pending_messages;i++)
+      send_ack_to_client (ch,
+                          GNUNET_YES);
+    break;
+  case CADET_CHANNEL_READY:
+    /* duplicate ACK, maybe we retried the CREATE. Ignore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received duplicate channel OPEN_ACK for %s\n",
+         GCCH_2s (ch));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate CREATE_ACKs",
+                              1,
+                              GNUNET_NO);
+    break;
+  }
+}
+
+
+/**
+ * Test if element @a e1 comes before element @a e2.
+ *
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param m1 a message of to sort
+ * @param m2 another message to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
+ */
+static int
+is_before (void *cls,
+           struct CadetOutOfOrderMessage *m1,
+           struct CadetOutOfOrderMessage *m2)
+{
+  int *duplicate = cls;
+  uint32_t v1 = ntohl (m1->mid.mid);
+  uint32_t v2 = ntohl (m2->mid.mid);
+  uint32_t delta;
+
+  delta = v2 - v1;
+  if (0 == delta)
+    *duplicate = GNUNET_YES;
+  if (delta > (uint32_t) INT_MAX)
+  {
+    /* in overflow range, we can safely assume we wrapped around */
+    return GNUNET_NO;
+  }
+  else
+  {
+    /* result is small, thus v2 > v1, thus m1 < m2 */
+    return GNUNET_YES;
+  }
+}
+
+
+/**
+ * We got payload data for a channel.  Pass it on to the client
+ * and send an ACK to the other end (once flow control allows it!)
+ *
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
+ */
+void
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalData *ld;
+  struct CadetChannelClient *ccc;
+  size_t payload_size;
+  struct CadetOutOfOrderMessage *com;
+  int duplicate;
+  uint32_t mid_min;
+  uint32_t mid_max;
+  uint32_t mid_msg;
+  uint32_t delta;
+
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  if ( (GNUNET_YES == ch->destroy) &&
+       (NULL == ch->owner) &&
+       (NULL == ch->dest) )
+  {
+    /* This client is gone, but we still have messages to send to
+       the other end (which is why @a ch is not yet dead).  However,
+       we cannot pass messages to our client anymore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping incoming payload on %s as this end is already closed\n",
+         GCCH_2s (ch));
+    /* send back DESTROY notification to stop further retransmissions! */
+    GCT_send_channel_destroy (ch->t,
+                              ch->ctn);
+    return;
+  }
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  env = GNUNET_MQ_msg_extra (ld,
+                             payload_size,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+  ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
+  GNUNET_memcpy (&ld[1],
+                 &msg[1],
+                 payload_size);
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  if ( (GNUNET_YES == ccc->client_ready) &&
+       ( (GNUNET_YES == ch->out_of_order) ||
+         (msg->mid.mid == ch->mid_recv.mid) ) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Giving %u bytes of payload with MID %u from %s to client %s\n",
+         (unsigned int) payload_size,
+         ntohl (msg->mid.mid),
+         GCCH_2s (ch),
+         GSC_2s (ccc->c));
+    ccc->client_ready = GNUNET_NO;
+    GSC_send_to_client (ccc->c,
+                        env);
+    ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
+    ch->mid_futures >>= 1;
+    send_channel_data_ack (ch);
+    return;
+  }
+
+  if (GNUNET_YES == ch->reliable)
+  {
+    /* check if message ought to be dropped because it is ancient/too distant/duplicate */
+    mid_min = ntohl (ch->mid_recv.mid);
+    mid_max = mid_min + ch->max_pending_messages;
+    mid_msg = ntohl (msg->mid.mid);
+    if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
+         ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "%s at %u drops ancient or far-future message %u\n",
+           GCCH_2s (ch),
+           (unsigned int) mid_min,
+           ntohl (msg->mid.mid));
+
+      GNUNET_STATISTICS_update (stats,
+                                "# duplicate DATA (ancient or future)",
+                                1,
+                                GNUNET_NO);
+      GNUNET_MQ_discard (env);
+      send_channel_data_ack (ch);
+      return;
+    }
+    /* mark bit for future ACKs */
+    delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
+    if (delta < 64)
+    {
+      if (0 != (ch->mid_futures & (1LLU << delta)))
+      {
+        /* Duplicate within the queue, drop also */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+             (unsigned int) payload_size,
+             GCCH_2s (ch),
+             ntohl (msg->mid.mid));
+        GNUNET_STATISTICS_update (stats,
+                                  "# duplicate DATA",
+                                  1,
+                                  GNUNET_NO);
+        GNUNET_MQ_discard (env);
+        send_channel_data_ack (ch);
+        return;
+      }
+      ch->mid_futures |= (1LLU << delta);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Marked bit %llX for mid %u (base: %u); now: %llX\n",
+           (1LLU << delta),
+           mid_msg,
+           mid_min,
+           ch->mid_futures);
+    }
+  }
+  else /* ! ch->reliable */
+  {
+    /* Channel is unreliable, so we do not ACK. But we also cannot
+       allow buffering everything, so check if we have space... */
+    if (ccc->num_recv >= ch->max_pending_messages)
+    {
+      struct CadetOutOfOrderMessage *drop;
+
+      /* Yep, need to drop. Drop the oldest message in
+         the buffer. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Queue full due slow client on %s, dropping oldest message\n",
+           GCCH_2s (ch));
+      GNUNET_STATISTICS_update (stats,
+                                "# messages dropped due to slow client",
+                                1,
+                                GNUNET_NO);
+      drop = ccc->head_recv;
+      GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                   ccc->tail_recv,
+                                   drop);
+      ccc->num_recv--;
+      GNUNET_MQ_discard (drop->env);
+      GNUNET_free (drop);
+    }
+  }
+
+  /* Insert message into sorted out-of-order queue */
+  com = GNUNET_new (struct CadetOutOfOrderMessage);
+  com->mid = msg->mid;
+  com->env = env;
+  duplicate = GNUNET_NO;
+  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
+                                      is_before,
+                                      &duplicate,
+                                      ccc->head_recv,
+                                      ccc->tail_recv,
+                                      com);
+  ccc->num_recv++;
+  if (GNUNET_YES == duplicate)
+  {
+    /* Duplicate within the queue, drop also (this is not covered by
+       the case above if "delta" >= 64, which could be the case if
+       max_pending_messages is also >= 64 or if our client is unready
+       and we are seeing retransmissions of the message our client is
+       blocked on. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+         (unsigned int) payload_size,
+         GCCH_2s (ch),
+         ntohl (msg->mid.mid));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate DATA",
+                              1,
+                              GNUNET_NO);
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GNUNET_MQ_discard (com->env);
+    GNUNET_free (com);
+    send_channel_data_ack (ch);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
+       (GNUNET_YES == ccc->client_ready)
+       ? "out-of-order"
+       : "client-not-ready",
+       (unsigned int) payload_size,
+       GCCH_2s (ch),
+       ntohl (ccc->ccn.channel_of_client),
+       ccc,
+       ntohl (msg->mid.mid),
+       ntohl (ch->mid_recv.mid));
+  /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
+     the sender may already be transmitting the previous one.  Needs
+     experimental evaluation to see if/when this ACK helps or
+     hurts. (We might even want another option.) */
+  send_channel_data_ack (ch);
+}
+
+
+/**
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+data_sent_cb (void *cls,
+              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * We need to retry a transmission, the last one took too long to
+ * be acknowledged.
+ *
+ * @param cls the `struct CadetChannel` where we need to retransmit
+ */
+static void
+retry_transmission (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct CadetReliableMessage *crm = ch->head_sent;
+
+  ch->retry_data_task = NULL;
+  GNUNET_assert (NULL == crm->qe);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Retrying transmission on %s of message %u\n",
+       GCCH_2s (ch),
+       (unsigned int) ntohl (crm->data_message->mid.mid));
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message->header,
+                      &data_sent_cb,
+                      crm);
+  GNUNET_assert (NULL == ch->retry_data_task);
+}
+
+
+/**
+ * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
+ * the queue and tell our client that it can send more.
+ *
+ * @param ch the channel that got the PLAINTEXT_DATA_ACK
+ * @param cti identifier of the connection that delivered the message
+ * @param crm the message that got acknowledged
+ */
+static void
+handle_matching_ack (struct CadetChannel *ch,
+                     const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                     struct CadetReliableMessage *crm)
+{
+  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
+  ch->pending_messages--;
+  GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
+       GCCH_2s (ch),
+       (unsigned int) ntohl (crm->data_message->mid.mid),
+       ch->pending_messages);
+  if (NULL != crm->qe)
+  {
+    GCT_send_cancel (crm->qe);
+    crm->qe = NULL;
+  }
+  if ( (1 == crm->num_transmissions) &&
+       (NULL != cti) )
+  {
+    GCC_ack_observed (cti);
+    if (0 == memcmp (cti,
+                     &crm->connection_taken,
+                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
+    {
+      GCC_latency_observed (cti,
+                            GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
+    }
+  }
+  GNUNET_free (crm->data_message);
+  GNUNET_free (crm);
+  send_ack_to_client (ch,
+                      (NULL == ch->owner)
+                      ? GNUNET_NO
+                      : GNUNET_YES);
+}
+
+
+/**
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
+ *
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
+ */
+void
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack)
+{
+  struct CadetReliableMessage *crm;
+  struct CadetReliableMessage *crmn;
+  int found;
+  uint32_t mid_base;
+  uint64_t mid_mask;
+  unsigned int delta;
+
+  GNUNET_break (GNUNET_NO == ch->is_loopback);
+  if (GNUNET_NO == ch->reliable)
+  {
+    /* not expecting ACKs on unreliable channel, odd */
+    GNUNET_break_op (0);
+    return;
+  }
+  /* mid_base is the MID of the next message that the
+     other peer expects (i.e. that is missing!), everything
+     LOWER (but excluding mid_base itself) was received. */
+  mid_base = ntohl (ack->mid.mid);
+  mid_mask = GNUNET_htonll (ack->futures);
+  found = GNUNET_NO;
+  for (crm = ch->head_sent;
+        NULL != crm;
+       crm = crmn)
+  {
+    crmn = crm->next;
+    delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
+    if (delta >= UINT_MAX - ch->max_pending_messages)
+    {
+      /* overflow, means crm was a bit in the past, so this ACK counts for it. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with base %u satisfying past message %u on %s\n",
+           (unsigned int) mid_base,
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
+      handle_matching_ack (ch,
+                           cti,
+                           crm);
+      found = GNUNET_YES;
+      continue;
+    }
+    delta--;
+    if (delta >= 64)
+      continue;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Testing bit %llX for mid %u (base: %u)\n",
+         (1LLU << delta),
+         ntohl (crm->data_message->mid.mid),
+         mid_base);
+    if (0 != (mid_mask & (1LLU << delta)))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with mask for %u on %s\n",
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
+      handle_matching_ack (ch,
+                           cti,
+                           crm);
+      found = GNUNET_YES;
+    }
+  }
+  if (GNUNET_NO == found)
+  {
+    /* ACK for message we already dropped, might have been a
+       duplicate ACK? Ignore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Duplicate DATA_ACK on %s, ignoring\n",
+         GCCH_2s (ch));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate DATA_ACKs",
+                              1,
+                              GNUNET_NO);
+    return;
+  }
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
+  }
+  if ( (NULL != ch->head_sent) &&
+       (NULL == ch->head_sent->qe) )
+    ch->retry_data_task
+      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+                                 &retry_transmission,
+                                 ch);
+}
+
+
+/**
+ * Destroy channel, based on the other peer closing the
+ * connection.  Also needs to remove this channel from
+ * the tunnel.
+ *
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *            NULL if we are simulating receiving a destroy due to shutdown
+ */
+void
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
+{
+  struct CadetChannelClient *ccc;
+
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received remote channel DESTROY for %s\n",
+       GCCH_2s (ch));
+  if (GNUNET_YES == ch->destroy)
+  {
+    /* Local client already gone, this is instant-death. */
+    channel_destroy (ch);
+    return;
+  }
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  if ( (NULL != ccc) &&
+       (NULL != ccc->head_recv) )
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Lost end of transmission due to remote shutdown on %s\n",
+         GCCH_2s (ch));
+    /* FIXME: change API to notify client about truncated transmission! */
+  }
+  ch->destroy = GNUNET_YES;
+  if (NULL != ccc)
+    GSC_handle_remote_channel_destroy (ccc->c,
+                                       ccc->ccn,
+                                       ch);
+  channel_destroy (ch);
+}
+
+
+/**
+ * Test if element @a e1 comes before element @a e2.
+ *
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param crm1 an element of to sort
+ * @param crm2 another element to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
+ */
+static int
+cmp_crm_by_next_retry (void *cls,
+                       struct CadetReliableMessage *crm1,
+                       struct CadetReliableMessage *crm2)
+{
+  if (crm1->next_retry.abs_value_us <
+      crm2->next_retry.abs_value_us)
+    return GNUNET_YES;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+data_sent_cb (void *cls,
+              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  struct CadetReliableMessage *crm = cls;
+  struct CadetChannel *ch = crm->ch;
+
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  GNUNET_assert (NULL != crm->qe);
+  crm->qe = NULL;
+  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
+  if (GNUNET_NO == ch->reliable)
+  {
+    GNUNET_free (crm->data_message);
+    GNUNET_free (crm);
+    ch->pending_messages--;
+    send_ack_to_client (ch,
+                        (NULL == ch->owner)
+                        ? GNUNET_NO
+                        : GNUNET_YES);
+    return;
+  }
+  if (NULL == cid)
+  {
+    /* There was an error sending. */
+    crm->num_transmissions = GNUNET_SYSERR;
+  }
+  else if (GNUNET_SYSERR != crm->num_transmissions)
+  {
+    /* Increment transmission counter, and possibly store @a cid
+       if this was the first transmission. */
+    crm->num_transmissions++;
+    if (1 == crm->num_transmissions)
+    {
+      crm->first_transmission_time = GNUNET_TIME_absolute_get ();
+      crm->connection_taken = *cid;
+      GCC_ack_expected (cid);
+    }
+  }
+  if ( (0 == crm->retry_delay.rel_value_us) &&
+       (NULL != cid) )
+  {
+    struct CadetConnection *cc = GCC_lookup (cid);
+
+    if (NULL != cc)
+      crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
+    else
+      crm->retry_delay = ch->retry_time;
+  }
+  crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
+  crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
+                                               MIN_RTT_DELAY);
+  crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
+
+  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
+                                      cmp_crm_by_next_retry,
+                                      NULL,
+                                      ch->head_sent,
+                                      ch->tail_sent,
+                                      crm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message %u sent, next transmission on %s in %s\n",
+       (unsigned int) ntohl (crm->data_message->mid.mid),
+       GCCH_2s (ch),
+       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
+                                               GNUNET_YES));
+  if (NULL == ch->head_sent->qe)
+  {
+    if (NULL != ch->retry_data_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task
+      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+                                 &retry_transmission,
+                                 ch);
+  }
+}
+
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if
+ * channel is reliable and send an ACK to the client if there is still
+ * buffer space in the tunnel.
+ *
+ * @param ch Channel.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+                        const char *buf,
+                        size_t buf_len)
+{
+  struct CadetReliableMessage *crm;
+
+  if (ch->pending_messages > ch->max_pending_messages)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_YES == ch->destroy)
+  {
+    /* we are going down, drop messages */
+    return GNUNET_OK;
+  }
+  ch->pending_messages++;
+
+  if (GNUNET_YES == ch->is_loopback)
+  {
+    struct CadetChannelClient *receiver;
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_LocalData *ld;
+    int ack_to_owner;
+
+    env = GNUNET_MQ_msg_extra (ld,
+                               buf_len,
+                               GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+    if ( (NULL != ch->owner) &&
+         (sender_ccn.channel_of_client ==
+          ch->owner->ccn.channel_of_client) )
+    {
+      receiver = ch->dest;
+      ack_to_owner = GNUNET_YES;
+    }
+    else if ( (NULL != ch->dest) &&
+              (sender_ccn.channel_of_client ==
+               ch->dest->ccn.channel_of_client) )
+    {
+      receiver = ch->owner;
+      ack_to_owner = GNUNET_NO;
+    }
+    else
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_assert (NULL != receiver);
+    ld->ccn = receiver->ccn;
+    GNUNET_memcpy (&ld[1],
+                   buf,
+                   buf_len);
+    if (GNUNET_YES == receiver->client_ready)
+    {
+      ch->pending_messages--;
+      GSC_send_to_client (receiver->c,
+                          env);
+      send_ack_to_client (ch,
+                          ack_to_owner);
+    }
+    else
+    {
+      struct CadetOutOfOrderMessage *oom;
+
+      oom = GNUNET_new (struct CadetOutOfOrderMessage);
+      oom->env = env;
+      GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
+                                        receiver->tail_recv,
+                                        oom);
+      receiver->num_recv++;
+    }
+    return GNUNET_OK;
+  }
+
+  /* Everything is correct, send the message. */
+  crm = GNUNET_malloc (sizeof (*crm));
+  crm->ch = ch;
+  crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
+                                     + buf_len);
+  crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
+  crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
+  ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
+  crm->data_message->mid = ch->mid_send;
+  crm->data_message->ctn = ch->ctn;
+  GNUNET_memcpy (&crm->data_message[1],
+                 buf,
+                 buf_len);
+  GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
+                                    ch->tail_sent,
+                                    crm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message %u from local client to %s with %u bytes\n",
+       ntohl (crm->data_message->mid.mid),
+       GCCH_2s (ch),
+       buf_len);
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
+  }
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message->header,
+                      &data_sent_cb,
+                      crm);
+  GNUNET_assert (NULL == ch->retry_data_task);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle ACK from client on local channel.  Means the client is ready
+ * for more data, see if we have any for it.
+ *
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch,
+                       struct GNUNET_CADET_ClientChannelNumber client_ccn)
+{
+  struct CadetChannelClient *ccc;
+  struct CadetOutOfOrderMessage *com;
+
+  if ( (NULL != ch->owner) &&
+       (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
+    ccc = ch->owner;
+  else if ( (NULL != ch->dest) &&
+            (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
+    ccc = ch->dest;
+  else
+    GNUNET_assert (0);
+  ccc->client_ready = GNUNET_YES;
+  com = ccc->head_recv;
+  if (NULL == com)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
+         GSC_2s (ccc->c),
+         ntohl (client_ccn.channel_of_client),
+         GCCH_2s (ch),
+         ntohl (ccc->ccn.channel_of_client),
+         ccc);
+    return; /* none pending */
+  }
+  if (GNUNET_YES == ch->is_loopback)
+  {
+    int to_owner;
+
+    /* Messages are always in-order, just send */
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GSC_send_to_client (ccc->c,
+                        com->env);
+    /* Notify sender that we can receive more */
+    if ( (NULL != ch->owner) &&
+         (ccc->ccn.channel_of_client ==
+          ch->owner->ccn.channel_of_client) )
+    {
+      to_owner = GNUNET_NO;
+    }
+    else
+    {
+      GNUNET_assert ( (NULL != ch->dest) &&
+                      (ccc->ccn.channel_of_client ==
+                       ch->dest->ccn.channel_of_client) );
+      to_owner = GNUNET_YES;
+    }
+    send_ack_to_client (ch,
+                        to_owner);
+    GNUNET_free (com);
+    return;
+  }
+
+  if ( (com->mid.mid != ch->mid_recv.mid) &&
+       (GNUNET_NO == ch->out_of_order) &&
+       (GNUNET_YES == ch->reliable) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
+         GSC_2s (ccc->c),
+         ntohl (ccc->ccn.channel_of_client),
+         ntohl (com->mid.mid),
+         ntohl (ch->mid_recv.mid));
+    return; /* missing next one in-order */
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
+       ntohl (com->mid.mid),
+       GSC_2s (ccc->c),
+       ntohl (ccc->ccn.channel_of_client),
+       GCCH_2s (ch));
+
+  /* all good, pass next message to client */
+  GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                               ccc->tail_recv,
+                               com);
+  ccc->num_recv--;
+  /* FIXME: if unreliable, this is not aggressive
+     enough, as it would be OK to have lost some! */
+
+  ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
+  ch->mid_futures >>= 1; /* equivalent to division by 2 */
+  ccc->client_ready = GNUNET_NO;
+  GSC_send_to_client (ccc->c,
+                      com->env);
+  GNUNET_free (com);
+  send_channel_data_ack (ch);
+  if (NULL != ccc->head_recv)
+    return;
+  if (GNUNET_NO == ch->destroy)
+    return;
+  GCT_send_channel_destroy (ch->t,
+                            ch->ctn);
+  channel_destroy (ch);
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
+
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ * @param level Debug level to use.
+ */
+void
+GCCH_debug (struct CadetChannel *ch,
+            enum GNUNET_ErrorType level)
+{
+  int do_log;
+
+  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+                                       "cadet-chn",
+                                       __FILE__, __FUNCTION__, __LINE__);
+  if (0 == do_log)
+    return;
+
+  if (NULL == ch)
+  {
+    LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
+    return;
+  }
+  LOG2 (level,
+        "CHN %s:%X (%p)\n",
+        GCT_2s (ch->t),
+        ch->ctn,
+        ch);
+  if (NULL != ch->owner)
+  {
+    LOG2 (level,
+          "CHN origin %s ready %s local-id: %u\n",
+          GSC_2s (ch->owner->c),
+          ch->owner->client_ready ? "YES" : "NO",
+          ntohl (ch->owner->ccn.channel_of_client));
+  }
+  if (NULL != ch->dest)
+  {
+    LOG2 (level,
+          "CHN destination %s ready %s local-id: %u\n",
+          GSC_2s (ch->dest->c),
+          ch->dest->client_ready ? "YES" : "NO",
+          ntohl (ch->dest->ccn.channel_of_client));
+  }
+  LOG2 (level,
+        "CHN  Message IDs recv: %d (%LLX), send: %d\n",
+        ntohl (ch->mid_recv.mid),
+        (unsigned long long) ch->mid_futures,
+        ntohl (ch->mid_send.mid));
+}
+
+
+
+/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h
new file mode 100644 (file)
index 0000000..a3ef9a0
--- /dev/null
@@ -0,0 +1,262 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_channel.h
+ * @brief GNUnet CADET service with encryption
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
+#define GNUNET_SERVICE_CADET_CHANNEL_H
+
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_peer.h"
+#include "cadet_protocol.h"
+
+
+/**
+ * A channel is a bidirectional connection between two CADET
+ * clients.  Communiation can be reliable, unreliable, in-order
+ * or out-of-order.  One client is the "local" client, this
+ * one initiated the connection.   The other client is the
+ * "incoming" client, this one listened on a port to accept
+ * the connection from the "local" client.
+ */
+struct CadetChannel;
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GCCH_2s (const struct CadetChannel *ch);
+
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ * @param level Debug level to use.
+ */
+void
+GCCH_debug (struct CadetChannel *ch,
+            enum GNUNET_ErrorType level);
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch);
+
+
+/**
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param owner_id local chid of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+                        struct GNUNET_CADET_ClientChannelNumber owner_id,
+                        struct CadetPeer *destination,
+                        const struct GNUNET_HashCode *port,
+                        uint32_t options);
+
+
+/**
+ * A client is bound to the port that we have a channel
+ * open to.  Send the acknowledgement for the connection
+ * request and establish the link with the client.
+ *
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
+ */
+void
+GCCH_bind (struct CadetChannel *ch,
+           struct CadetClient *c);
+
+
+/**
+ * Destroy locally created channel.  Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+                            struct CadetClient *c,
+                            struct GNUNET_CADET_ClientChannelNumber ccn);
+
+
+/**
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
+ */
+void
+GCCH_tunnel_up (struct CadetChannel *ch);
+
+
+/**
+ * Create a new channel based on a request coming in over the network.
+ *
+ * @param t tunnel to the remote peer
+ * @param chid identifier of this channel in the tunnel
+ * @param origin peer to who initiated the channel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+                           struct GNUNET_CADET_ChannelTunnelNumber chid,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options);
+
+
+/**
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel.  If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
+ *
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
+ */
+void
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
+
+
+
+/**
+ * We got payload data for a channel.  Pass it on to the client.
+ *
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
+ */
+void
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg);
+
+
+/**
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
+ *
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
+ */
+void
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack);
+
+
+/**
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
+ *
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *        NULL if the ACK was inferred because we got payload or are on loopback
+ */
+void
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
+
+
+/**
+ * Destroy channel, based on the other peer closing the
+ * connection.  Also needs to remove this channel from
+ * the tunnel.
+ *
+ * FIXME: need to make it possible to defer destruction until we have
+ * received all messages up to the destroy, and right now the destroy
+ * message (and this API) fails to give is the information we need!
+ *
+ * FIXME: also need to know if the other peer got a destroy from
+ * us before!
+ *
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *            NULL during shutdown
+ */
+void
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
+
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if
+ * channel is reliable and send an ACK to the client if there is still
+ * buffer space in the tunnel.
+ *
+ * @param ch Channel.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+                        const char *buf,
+                        size_t buf_len);
+
+
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch,
+                       struct GNUNET_CADET_ClientChannelNumber client_ccn);
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c
new file mode 100644 (file)
index 0000000..7b66f61
--- /dev/null
@@ -0,0 +1,1091 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_connection.c
+ * @brief management of CORE-level end-to-end connections; establishes
+ *        end-to-end routes and transmits messages along the route
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
+#include "cadet_protocol.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
+
+
+/**
+ * All the states a connection can be in.
+ */
+enum CadetConnectionState
+{
+  /**
+   * Uninitialized status, we have not yet even gotten the message queue.
+   */
+  CADET_CONNECTION_NEW,
+
+  /**
+   * Connection create message in queue, awaiting transmission by CORE.
+   */
+  CADET_CONNECTION_SENDING_CREATE,
+
+  /**
+   * Connection create message sent, waiting for ACK.
+   */
+  CADET_CONNECTION_SENT,
+
+  /**
+   * We are an inbound connection, and received a CREATE. Need to
+   * send an CREATE_ACK back.
+   */
+  CADET_CONNECTION_CREATE_RECEIVED,
+
+  /**
+   * Connection confirmed, ready to carry traffic.
+   */
+  CADET_CONNECTION_READY
+
+};
+
+
+/**
+ * Low-level connection to a destination.
+ */
+struct CadetConnection
+{
+
+  /**
+   * ID of the connection.
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
+
+  /**
+   * To which peer does this connection go?
+   */
+  struct CadetPeer *destination;
+
+  /**
+   * Which tunnel is using this connection?
+   */
+  struct CadetTConnection *ct;
+
+  /**
+   * Path we are using to our destination.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Pending message, NULL if we are ready to transmit.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+  /**
+   * Handle for calling #GCP_request_mq_cancel() once we are finished.
+   */
+  struct GCP_MessageQueueManager *mq_man;
+
+  /**
+   * Task for connection maintenance.
+   */
+  struct GNUNET_SCHEDULER_Task *task;
+
+  /**
+   * Queue entry for keepalive messages.
+   */
+  struct CadetTunnelQueueEntry *keepalive_qe;
+
+  /**
+   * Function to call once we are ready to transmit.
+   */
+  GCC_ReadyCallback ready_cb;
+
+  /**
+   * Closure for @e ready_cb.
+   */
+  void *ready_cb_cls;
+
+  /**
+   * How long do we wait before we try again with a CREATE message?
+   */
+  struct GNUNET_TIME_Relative retry_delay;
+
+  /**
+   * Performance metrics for this connection.
+   */
+  struct CadetConnectionMetrics metrics;
+
+  /**
+   * State of the connection.
+   */
+  enum CadetConnectionState state;
+
+  /**
+   * Options for the route, control buffering.
+   */
+  enum GNUNET_CADET_ChannelOption options;
+
+  /**
+   * How many latency observations did we make for this connection?
+   */
+  unsigned int latency_datapoints;
+
+  /**
+   * Offset of our @e destination in @e path.
+   */
+  unsigned int off;
+
+  /**
+   * Are we ready to transmit via @e mq_man right now?
+   */
+  int mqm_ready;
+
+};
+
+
+/**
+ * Lookup a connection by its identifier.
+ *
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
+ */
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  return GNUNET_CONTAINER_multishortmap_get (connections,
+                                             &cid->connection_of_tunnel);
+}
+
+
+/**
+ * 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
+ */
+static void
+GCC_destroy (struct CadetConnection *cc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying %s\n",
+       GCC_2s (cc));
+  if (NULL != cc->mq_man)
+  {
+    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;
+  }
+  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,
+                                                        cc));
+  GNUNET_free (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.
+ *
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
+ */
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc)
+{
+  return cc->ct;
+}
+
+
+/**
+ * Obtain performance @a metrics from @a cc.
+ *
+ * @param cc connection to query
+ * @return the metrics
+ */
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc)
+{
+  return &cc->metrics;
+}
+
+
+/**
+ * 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.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+keepalive_done (void *cls,
+                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  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);
+}
+
+
+/**
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
+ *
+ * @param cid connection identifier where we expect an ACK
+ */
+void
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  struct CadetConnection *cc;
+
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  cc->metrics.num_acked_transmissions++;
+}
+
+
+/**
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
+ *
+ * @param cti connection identifier where we got an ACK for a message
+ *            that was originally sent via this connection (the ACK
+ *            may have gotten back to us via a different connection).
+ */
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  struct CadetConnection *cc;
+
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  cc->metrics.num_successes++;
+}
+
+
+/**
+ * We observed some the given @a latency on the connection
+ * identified by @a cti.  (The same connection was taken
+ * in both directions.)
+ *
+ * @param cid connection identifier where we measured latency
+ * @param latency the observed latency
+ */
+void
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                      struct GNUNET_TIME_Relative latency)
+{
+  struct CadetConnection *cc;
+  double weight;
+  double result;
+
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  GNUNET_STATISTICS_update (stats,
+                            "# latencies observed",
+                            1,
+                            GNUNET_NO);
+  cc->latency_datapoints++;
+  if (cc->latency_datapoints >= 7)
+    weight = 7.0;
+  else
+    weight = cc->latency_datapoints;
+  /* Compute weighted average, giving at MOST weight 7 to the
+     existing values, or less if that value is based on fewer than 7
+     measurements. */
+  result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
+  result /= (weight + 1.0);
+  cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
+}
+
+
+/**
+ * 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.
+ */
+void
+GCC_handle_connection_create_ack (struct CadetConnection *cc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
+       GCC_2s (cc),
+       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;
+  }
+  cc->metrics.age = GNUNET_TIME_absolute_get ();
+  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);
+}
+
+
+/**
+ * Handle KX message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCC_handle_kx (struct CadetConnection *cc,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *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 (cc->ct,
+                 msg);
+}
+
+
+/**
+ * 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.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCC_handle_encrypted (struct CadetConnection *cc,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  if (CADET_CONNECTION_SENT == cc->state)
+  {
+    /* 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 %s due to ENCRYPTED payload\n",
+         GCC_2s (cc));
+    GCC_handle_connection_create_ack (cc);
+  }
+  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+  GCT_handle_encrypted (cc->ct,
+                        msg);
+}
+
+
+/**
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
+ * first hop.
+ *
+ * @param cls the `struct CadetConnection` to initiate
+ */
+static void
+send_create (void *cls)
+{
+  struct CadetConnection *cc = cls;
+  struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
+  struct GNUNET_PeerIdentity *pids;
+  struct GNUNET_MQ_Envelope *env;
+  unsigned int path_length;
+
+  cc->task = NULL;
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  path_length = GCPP_get_length (cc->path);
+  env = GNUNET_MQ_msg_extra (create_msg,
+                             (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=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 CADET_CONNECTION_CREATE message for %s\n",
+       GCC_2s (cc));
+  cc->env = env;
+  update_state (cc,
+                CADET_CONNECTION_SENT,
+                GNUNET_NO);
+  GCP_send (cc->mq_man,
+            env);
+}
+
+
+/**
+ * Send a CREATE_ACK message towards the origin.
+ *
+ * @param cls the `struct CadetConnection` to initiate
+ */
+static void
+send_create_ack (void *cls)
+{
+  struct CadetConnection *cc = cls;
+  struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
+  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 %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;
+  update_state (cc,
+                CADET_CONNECTION_READY,
+                GNUNET_NO);
+  GCP_send (cc->mq_man,
+            env);
+}
+
+
+/**
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have.  Either our ACK got lost
+ * or something is fishy.  Consider retransmitting the ACK.
+ *
+ * @param cc connection that got the duplicate CREATE
+ */
+void
+GCC_handle_duplicate_create (struct CadetConnection *cc)
+{
+  if (GNUNET_YES == cc->mqm_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "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. */
+    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);
+  }
+  else
+  {
+    /* We are currently sending something else back, which
+       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 %s. MQ is busy, not queueing another ACK\n",
+         GCC_2s (cc));
+  }
+}
+
+
+/**
+ * There has been a change in the message queue existence for our
+ * peer at the first hop.  Adjust accordingly.
+ *
+ * @param cls the `struct CadetConnection`
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
+ */
+static void
+manage_first_hop_mq (void *cls,
+                     int available)
+{
+  struct CadetConnection *cc = cls;
+
+  if (GNUNET_YES != available)
+  {
+    /* Connection is down, for now... */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Core MQ for %s went down\n",
+         GCC_2s (cc));
+    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;
+    }
+    return;
+  }
+
+  update_state (cc,
+                cc->state,
+                GNUNET_YES);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Core MQ for %s became available in state %d\n",
+       GCC_2s (cc),
+       cc->state);
+  switch (cc->state)
+  {
+  case CADET_CONNECTION_NEW:
+    /* Transmit immediately */
+    cc->task = GNUNET_SCHEDULER_add_now (&send_create,
+                                         cc);
+    break;
+  case CADET_CONNECTION_SENDING_CREATE:
+    /* Should not be possible to be called in this state. */
+    GNUNET_assert (0);
+    break;
+  case CADET_CONNECTION_SENT:
+    /* Retry a bit later... */
+    cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
+    cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
+                                             &send_create,
+                                             cc);
+    break;
+  case CADET_CONNECTION_CREATE_RECEIVED:
+    /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
+    cc->metrics.age = GNUNET_TIME_absolute_get ();
+    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
+                                         cc);
+    break;
+  case CADET_CONNECTION_READY:
+    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;
+  }
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and notify @a cb
+ * whenever we are ready for more data.  Shared logic independent of
+ * who is initiating the connection.
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a 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
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
+ */
+static struct CadetConnection *
+connection_create (struct CadetPeer *destination,
+                   struct CadetPeerPath *path,
+                   unsigned int off,
+                   enum GNUNET_CADET_ChannelOption options,
+                   struct CadetTConnection *ct,
+                   const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                   enum CadetConnectionState init_state,
+                   GCC_ReadyCallback ready_cb,
+                   void *ready_cb_cls)
+{
+  struct CadetConnection *cc;
+  struct CadetPeer *first_hop;
+
+  cc = GNUNET_new (struct CadetConnection);
+  cc->options = options;
+  cc->state = init_state;
+  cc->ct = ct;
+  cc->cid = *cid;
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (connections,
+                                                     &GCC_get_id (cc)->connection_of_tunnel,
+                                                     cc,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  cc->ready_cb = ready_cb;
+  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,
+                                                 i),
+                        cc);
+
+  first_hop = GCPP_get_peer_at_offset (path,
+                                       0);
+  cc->mq_man = GCP_request_mq (first_hop,
+                               &manage_first_hop_mq,
+                               cc);
+  return cc;
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.  This
+ * is an inbound tunnel, so we must use the existing @a cid
+ *
+ * @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, 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,
+                            off,
+                            options,
+                            ct,
+                            cid,
+                            CADET_CONNECTION_CREATE_RECEIVED,
+                            ready_cb,
+                            ready_cb_cls);
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a 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
+ * @return handle to the connection
+ */
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            unsigned int off,
+            enum GNUNET_CADET_ChannelOption options,
+            struct CadetTConnection *ct,
+            GCC_ReadyCallback ready_cb,
+            void *ready_cb_cls)
+{
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
+
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                              &cid,
+                              sizeof (cid));
+  return connection_create (destination,
+                            path,
+                            off,
+                            options,
+                            ct,
+                            &cid,
+                            CADET_CONNECTION_NEW,
+                            ready_cb,
+                            ready_cb_cls);
+}
+
+
+/**
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
+ *
+ * @param cc connection identification
+ * @param env envelope with message to transmit; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
+ */
+void
+GCC_transmit (struct CadetConnection *cc,
+              struct GNUNET_MQ_Envelope *env)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Scheduling message for transmission on %s\n",
+       GCC_2s (cc));
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  GNUNET_assert (CADET_CONNECTION_READY == cc->state);
+  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+  cc->mqm_ready = GNUNET_NO;
+  if (NULL != cc->task)
+  {
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
+  }
+  GCP_send (cc->mq_man,
+            env);
+}
+
+
+/**
+ * Obtain the path used by this connection.
+ *
+ * @param cc connection
+ * @return path to @a cc
+ */
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc)
+{
+  return cc->path;
+}
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
+{
+  return &cc->cid;
+}
+
+
+/**
+ * Get a (static) string for a connection.
+ *
+ * @param cc Connection.
+ */
+const char *
+GCC_2s (const struct CadetConnection *cc)
+{
+  static char buf[128];
+
+  if (NULL == cc)
+    return "Connection(NULL)";
+
+  if (NULL != cc->ct)
+  {
+    GNUNET_snprintf (buf,
+                     sizeof (buf),
+                     "Connection %s (%s)",
+                     GNUNET_sh2s (&cc->cid.connection_of_tunnel),
+                     GCT_2s (cc->ct->t));
+    return buf;
+  }
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Connection %s",
+                   GNUNET_sh2s (&cc->cid.connection_of_tunnel));
+  return buf;
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level)
+{
+  int do_log;
+
+  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+                                       "cadet-con",
+                                       __FILE__, __FUNCTION__, __LINE__);
+  if (0 == do_log)
+    return;
+  if (NULL == cc)
+  {
+    LOG2 (level,
+          "Connection (NULL)\n");
+    return;
+  }
+  LOG2 (level,
+        "%s to %s via path %s in state %d is %s\n",
+        GCC_2s (cc),
+        GCP_2s (cc->destination),
+        GCPP_2s (cc->path),
+        cc->state,
+        (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
+}
+
+/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h
new file mode 100644 (file)
index 0000000..fdb1843
--- /dev/null
@@ -0,0 +1,339 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_connection.h
+ * @brief A connection is a live end-to-end messaging mechanism
+ *       where the peers are identified by a path and know how
+ *       to forward along the route using a connection identifier
+ *       for routing the data.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
+#define GNUNET_SERVICE_CADET_CONNECTION_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_peer.h"
+#include "cadet_protocol.h"
+
+
+/**
+ * Function called to notify tunnel about change in our readyness.
+ *
+ * @param cls closure
+ * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
+ *                 #GNUNET_NO if the connection is no longer ready for transmission
+ */
+typedef void
+(*GCC_ReadyCallback)(void *cls,
+                     int is_ready);
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+
+/**
+ * Lookup a connection by its identifier.
+ *
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
+ */
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a 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
+ */
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            unsigned int off,
+            enum GNUNET_CADET_ChannelOption options,
+            struct CadetTConnection *ct,
+            GCC_ReadyCallback ready_cb,
+            void *ready_cb_cls);
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.  This
+ * is an inbound tunnel, so we must use the existing @a cid
+ *
+ * @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, 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);
+
+
+/**
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
+ *
+ * @param cc connection identification
+ * @param env envelope with message to transmit;
+ *            the #GNUNET_MQ_notify_send() must not have yet been used
+ *            for the envelope.  Also, the message better match the
+ *            connection identifier of this connection...
+ */
+void
+GCC_transmit (struct CadetConnection *cc,
+              struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * A CREATE_ACK was received for this connection, process it.
+ *
+ * @param cc the connection that got the ACK.
+ */
+void
+GCC_handle_connection_create_ack (struct CadetConnection *cc);
+
+
+/**
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have.  Either our ACK got lost
+ * or something is fishy.  Consider retransmitting the ACK.
+ *
+ * @param cc connection that got the duplicate CREATE
+ */
+void
+GCC_handle_duplicate_create (struct CadetConnection *cc);
+
+
+/**
+ * Handle KX message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCC_handle_kx (struct CadetConnection *cc,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
+
+
+/**
+ * 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);
+
+
+/**
+ * Performance metrics for a connection.
+ */
+struct CadetConnectionMetrics
+{
+
+  /**
+   * Our current best estimate of the latency, based on a weighted
+   * average of at least @a latency_datapoints values.
+   */
+  struct GNUNET_TIME_Relative aged_latency;
+
+  /**
+   * When was this connection first established? (by us sending or
+   * receiving the CREATE_ACK for the first time)
+   */
+  struct GNUNET_TIME_Absolute age;
+
+  /**
+   * When was this connection last used? (by us sending or
+   * receiving a PAYLOAD message on it)
+   */
+  struct GNUNET_TIME_Absolute last_use;
+
+  /**
+   * How many packets that ought to generate an ACK did we send via
+   * this connection?
+   */
+  unsigned long long num_acked_transmissions;
+
+  /**
+   * Number of packets that were sent via this connection did actually
+   * receive an ACK?  (Note: ACKs may be transmitted and lost via
+   * other connections, so this value should only be interpreted
+   * relative to @e num_acked_transmissions and in relation to other
+   * connections.)
+   */
+  unsigned long long num_successes;
+
+};
+
+
+/**
+ * Obtain performance @a metrics from @a cc.
+ *
+ * @param cc connection to query
+ * @return the metrics
+ */
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc);
+
+
+/**
+ * Handle encrypted message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCC_handle_encrypted (struct CadetConnection *cc,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
+
+
+/**
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
+ *
+ * @param cid connection identifier where we expect an ACK
+ */
+void
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
+ *
+ * @param cid connection identifier where we got an ACK for a message
+ *            that was originally sent via this connection (the ACK
+ *            may have gotten back to us via a different connection).
+ */
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * We observed some the given @a latency on the connection
+ * identified by @a cti.  (The same connection was taken
+ * in both directions.)
+ *
+ * @param cti connection identifier where we measured latency
+ * @param latency the observed latency
+ */
+void
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                      struct GNUNET_TIME_Relative latency);
+
+
+/**
+ * Return the tunnel associated with this connection.
+ *
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
+ */
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc);
+
+
+/**
+ * Obtain the path used by this connection.
+ *
+ * @param cc connection
+ * @return path to @a cc
+ */
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc);
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
+
+
+/**
+ * Get a (static) string for a connection.
+ *
+ * @param cc Connection.
+ */
+const char *
+GCC_2s (const struct CadetConnection *cc);
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet_core.c b/src/cadet/gnunet-service-cadet_core.c
new file mode 100644 (file)
index 0000000..ae03b4f
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_core.c
+ * @brief cadet service; interaction with CORE service
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
+ *
+ * TODO:
+ * - Optimization: given BROKEN messages, destroy paths (?)
+ */
+#include "platform.h"
+#include "gnunet-service-cadet_core.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "cadet_protocol.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
+
+/**
+ * Information we keep per direction for a route.
+ */
+struct RouteDirection;
+
+
+/**
+ * Set of CadetRoutes that have exactly the same number of messages
+ * in their buffer.  Used so we can efficiently find all of those
+ * routes that have the current maximum of messages in the buffer (in
+ * case we have to purge).
+ */
+struct Rung
+{
+
+  /**
+   * Rung of RouteDirections with one more buffer entry each.
+   */
+  struct Rung *next;
+
+  /**
+   * Rung of RouteDirections with one less buffer entry each.
+   */
+  struct Rung *prev;
+
+  /**
+   * DLL of route directions with a number of buffer entries matching this rung.
+   */
+  struct RouteDirection *rd_head;
+
+  /**
+   * DLL of route directions with a number of buffer entries matching this rung.
+   */
+  struct RouteDirection *rd_tail;
+
+  /**
+   * Total number of route directions in this rung.
+   */
+  unsigned int num_routes;
+
+  /**
+   * Number of messages route directions at this rung have
+   * in their buffer.
+   */
+  unsigned int rung_off;
+};
+
+
+/**
+ * Information we keep per direction for a route.
+ */
+struct RouteDirection
+{
+
+  /**
+   * DLL of other route directions within the same `struct Rung`.
+   */
+  struct RouteDirection *prev;
+
+  /**
+   * DLL of other route directions within the same `struct Rung`.
+   */
+  struct RouteDirection *next;
+
+  /**
+   * Rung of this route direction (matches length of the buffer DLL).
+   */
+  struct Rung *rung;
+
+  /**
+   * Head of DLL of envelopes we have in the buffer for this direction.
+   */
+  struct GNUNET_MQ_Envelope *env_head;
+
+  /**
+   * Tail of DLL of envelopes we have in the buffer for this direction.
+   */
+  struct GNUNET_MQ_Envelope *env_tail;
+
+  /**
+   * Target peer.
+   */
+  struct CadetPeer *hop;
+
+  /**
+   * Route this direction is part of.
+   */
+  struct CadetRoute *my_route;
+
+  /**
+   * Message queue manager for @e hop.
+   */
+  struct GCP_MessageQueueManager *mqm;
+
+  /**
+   * Is @e mqm currently ready for transmission?
+   */
+  int is_ready;
+
+};
+
+
+/**
+ * Description of a segment of a `struct CadetConnection` at the
+ * intermediate peers.  Routes are basically entries in a peer's
+ * routing table for forwarding traffic.  At both endpoints, the
+ * routes are terminated by a `struct CadetConnection`, which knows
+ * the complete `struct CadetPath` that is formed by the individual
+ * routes.
+ */
+struct CadetRoute
+{
+
+  /**
+   * Information about the next hop on this route.
+   */
+  struct RouteDirection next;
+
+  /**
+   * Information about the previous hop on this route.
+   */
+  struct RouteDirection prev;
+
+  /**
+   * Unique identifier for the connection that uses this route.
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
+
+  /**
+   * When was this route last in use?
+   */
+  struct GNUNET_TIME_Absolute last_use;
+
+  /**
+   * Position of this route in the #route_heap.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  /**
+   * Options for the route, control buffering.
+   */
+  enum GNUNET_CADET_ChannelOption options;
+};
+
+
+/**
+ * Handle to the CORE service.
+ */
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Routes on which this peer is an intermediate.
+ */
+static struct GNUNET_CONTAINER_MultiShortmap *routes;
+
+/**
+ * Heap of routes, MIN-sorted by last activity.
+ */
+static struct GNUNET_CONTAINER_Heap *route_heap;
+
+/**
+ * Rung zero (always pointed to by #rung_head).
+ */
+static struct Rung rung_zero;
+
+/**
+ * DLL of rungs, with the head always point to a rung of
+ * route directions with no messages in the queue.
+ */
+static struct Rung *rung_head = &rung_zero;
+
+/**
+ * Tail of the #rung_head DLL.
+ */
+static struct Rung *rung_tail = &rung_zero;
+
+/**
+ * Maximum number of concurrent routes this peer will support.
+ */
+static unsigned long long max_routes;
+
+/**
+ * Maximum number of envelopes we will buffer at this peer.
+ */
+static unsigned long long max_buffers;
+
+/**
+ * Current number of envelopes we have buffered at this peer.
+ */
+static unsigned long long cur_buffers;
+
+/**
+ * Task to timeout routes.
+ */
+static struct GNUNET_SCHEDULER_Task *timeout_task;
+
+
+/**
+ * Get the route corresponding to a hash.
+ *
+ * @param cid hash generated from the connection identifier
+ */
+static struct CadetRoute *
+get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  return GNUNET_CONTAINER_multishortmap_get (routes,
+                                             &cid->connection_of_tunnel);
+}
+
+
+/**
+ * Lower the rung in which @a dir is by 1.
+ *
+ * @param dir direction to lower in rung.
+ */
+static void
+lower_rung (struct RouteDirection *dir)
+{
+  struct Rung *rung = dir->rung;
+  struct Rung *prev;
+
+  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
+                               rung->rd_tail,
+                               dir);
+  prev = rung->prev;
+  GNUNET_assert (NULL != prev);
+  if (prev->rung_off != rung->rung_off - 1)
+  {
+    prev = GNUNET_new (struct Rung);
+    prev->rung_off = rung->rung_off - 1;
+    GNUNET_CONTAINER_DLL_insert_after (rung_head,
+                                       rung_tail,
+                                       rung->prev,
+                                       prev);
+  }
+  GNUNET_assert (NULL != prev);
+  GNUNET_CONTAINER_DLL_insert (prev->rd_head,
+                               prev->rd_tail,
+                               dir);
+  dir->rung = prev;
+}
+
+
+/**
+ * Discard the buffer @a env from the route direction @a dir and
+ * move @a dir down a rung.
+ *
+ * @param dir direction that contains the @a env in the buffer
+ * @param env envelope to discard
+ */
+static void
+discard_buffer (struct RouteDirection *dir,
+                struct GNUNET_MQ_Envelope *env)
+{
+  GNUNET_MQ_dll_remove (&dir->env_head,
+                        &dir->env_tail,
+                        env);
+  cur_buffers--;
+  GNUNET_MQ_discard (env);
+  lower_rung (dir);
+  GNUNET_STATISTICS_set (stats,
+                         "# buffer use",
+                         cur_buffers,
+                         GNUNET_NO);
+}
+
+
+/**
+ * Discard all messages from the highest rung, to make space.
+ */
+static void
+discard_all_from_rung_tail ()
+{
+  struct Rung *tail = rung_tail;
+  struct RouteDirection *dir;
+
+  while (NULL != (dir = tail->rd_head))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Queue full due new message %s on connection %s, dropping old message\n",
+         GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
+    GNUNET_STATISTICS_update (stats,
+                              "# messages dropped due to full buffer",
+                              1,
+                              GNUNET_NO);
+    discard_buffer (dir,
+                    dir->env_head);
+  }
+  GNUNET_CONTAINER_DLL_remove (rung_head,
+                               rung_tail,
+                               tail);
+  GNUNET_free (tail);
+}
+
+
+/**
+ * We message @a msg from @a prev.  Find its route by @a cid and
+ * forward to the next hop.  Drop and signal broken route if we do not
+ * have a route.
+ *
+ * @param prev previous hop (sender)
+ * @param cid connection identifier, tells us which route to use
+ * @param msg the message to forward
+ */
+static void
+route_message (struct CadetPeer *prev,
+               const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+               const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetRoute *route;
+  struct RouteDirection *dir;
+  struct Rung *rung;
+  struct Rung *nxt;
+  struct GNUNET_MQ_Envelope *env;
+
+  route = get_route (cid);
+  if (NULL == route)
+  {
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to route message of type %u from %s on connection %s: no route\n",
+         ntohs (msg->type),
+         GCP_2s (prev),
+         GNUNET_sh2s (&cid->connection_of_tunnel));
+    switch (ntohs (msg->type))
+    {
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+      /* No need to respond to these! */
+      return;
+    }
+    env = GNUNET_MQ_msg (bm,
+                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+    bm->cid = *cid;
+    bm->peer1 = my_full_id;
+    GCP_send_ooo (prev,
+                  env);
+    return;
+  }
+  route->last_use = GNUNET_TIME_absolute_get ();
+  GNUNET_CONTAINER_heap_update_cost (route->hn,
+                                     route->last_use.abs_value_us);
+  dir = (prev == route->prev.hop) ? &route->next : &route->prev;
+  if (GNUNET_YES == dir->is_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Routing message of type %u from %s to %s on connection %s\n",
+         ntohs (msg->type),
+         GCP_2s (prev),
+         GNUNET_i2s (GCP_get_id (dir->hop)),
+         GNUNET_sh2s (&cid->connection_of_tunnel));
+    dir->is_ready = GNUNET_NO;
+    GCP_send (dir->mqm,
+              GNUNET_MQ_msg_copy (msg));
+    return;
+  }
+  /* Check if buffering is disallowed, and if so, make sure we only queue
+     one message per direction. */
+  if ( (0 != (route->options & GNUNET_CADET_OPTION_NOBUFFER)) &&
+       (NULL != dir->env_head) )
+    discard_buffer (dir,
+                    dir->env_head);
+  rung = dir->rung;
+  if (cur_buffers == max_buffers)
+  {
+    /* Need to make room. */
+    if (NULL != rung->next)
+    {
+      /* Easy case, drop messages from route directions in highest rung */
+      discard_all_from_rung_tail ();
+    }
+    else
+    {
+      /* We are in the highest rung, drop our own! */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Queue full due new message %s on connection %s, dropping old message\n",
+           GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
+      GNUNET_STATISTICS_update (stats,
+                                "# messages dropped due to full buffer",
+                                1,
+                                GNUNET_NO);
+      discard_buffer (dir,
+                      dir->env_head);
+      rung = dir->rung;
+    }
+  }
+  /* remove 'dir' from current rung */
+  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
+                               rung->rd_tail,
+                               dir);
+  /* make 'nxt' point to the next higher rung, creat if necessary */
+  nxt = rung->next;
+  if ( (NULL == nxt) ||
+       (rung->rung_off + 1 != nxt->rung_off) )
+  {
+    nxt = GNUNET_new (struct Rung);
+    nxt->rung_off = rung->rung_off + 1;
+    GNUNET_CONTAINER_DLL_insert_after (rung_head,
+                                       rung_tail,
+                                       rung,
+                                       nxt);
+  }
+  /* insert 'dir' into next higher rung */
+  GNUNET_CONTAINER_DLL_insert (nxt->rd_head,
+                               nxt->rd_tail,
+                               dir);
+  dir->rung = nxt;
+
+  /* add message into 'dir' buffer */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queueing new message of type %u from %s to %s on connection %s\n",
+       ntohs (msg->type),
+       GCP_2s (prev),
+       GNUNET_i2s (GCP_get_id (dir->hop)),
+       GNUNET_sh2s (&cid->connection_of_tunnel));
+  env = GNUNET_MQ_msg_copy (msg);
+  GNUNET_MQ_dll_insert_tail (&dir->env_head,
+                             &dir->env_tail,
+                             env);
+  cur_buffers++;
+  GNUNET_STATISTICS_set (stats,
+                         "# buffer use",
+                         cur_buffers,
+                         GNUNET_NO);
+  /* Clean up 'rung' if now empty (and not head) */
+  if ( (NULL == rung->rd_head) &&
+       (rung != rung_head) )
+  {
+    GNUNET_CONTAINER_DLL_remove (rung_head,
+                                 rung_tail,
+                                 rung);
+    GNUNET_free (rung);
+  }
+}
+
+
+/**
+ * Check if the create_connection message has the appropriate size.
+ *
+ * @param cls Closure (unused).
+ * @param msg Message to check.
+ *
+ * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ */
+static int
+check_connection_create (void *cls,
+                         const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+{
+  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
+
+  if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  return GNUNET_YES;
+}
+
+
+/**
+ * Free internal data of a route direction.
+ *
+ * @param dir direction to destroy (do NOT free memory of 'dir' itself)
+ */
+static void
+destroy_direction (struct RouteDirection *dir)
+{
+  struct GNUNET_MQ_Envelope *env;
+
+  while (NULL != (env = dir->env_head))
+  {
+    GNUNET_STATISTICS_update (stats,
+                              "# messages dropped due to route destruction",
+                              1,
+                              GNUNET_NO);
+    discard_buffer (dir,
+                    env);
+  }
+  if (NULL != dir->mqm)
+  {
+    GCP_request_mq_cancel (dir->mqm,
+                           NULL);
+    dir->mqm = NULL;
+  }
+  GNUNET_CONTAINER_DLL_remove (rung_head->rd_head,
+                               rung_head->rd_tail,
+                               dir);
+}
+
+
+/**
+ * Destroy our state for @a route.
+ *
+ * @param route route to destroy
+ */
+static void
+destroy_route (struct CadetRoute *route)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying route from %s to %s of connection %s\n",
+       GNUNET_i2s  (GCP_get_id (route->prev.hop)),
+       GNUNET_i2s2 (GCP_get_id (route->next.hop)),
+       GNUNET_sh2s (&route->cid.connection_of_tunnel));
+  GNUNET_assert (route ==
+                 GNUNET_CONTAINER_heap_remove_node (route->hn));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multishortmap_remove (routes,
+                                                        &route->cid.connection_of_tunnel,
+                                                        route));
+  GNUNET_STATISTICS_set (stats,
+                         "# routes",
+                         GNUNET_CONTAINER_multishortmap_size (routes),
+                         GNUNET_NO);
+  destroy_direction (&route->prev);
+  destroy_direction (&route->next);
+  GNUNET_free (route);
+}
+
+
+/**
+ * Send message that a route is broken between @a peer1 and @a peer2.
+ *
+ * @param target where to send the message
+ * @param cid connection identifier to use
+ * @param peer1 one of the peers where a link is broken
+ * @param peer2 another one of the peers where a link is broken
+ */
+static void
+send_broken (struct RouteDirection *target,
+             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+             const struct GNUNET_PeerIdentity *peer1,
+             const struct GNUNET_PeerIdentity *peer2)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+  if (NULL == target->mqm)
+    return; /* Can't send notification, connection is down! */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Notifying %s about BROKEN route at %s-%s of connection %s\n",
+       GCP_2s (target->hop),
+       GNUNET_i2s (peer1),
+       GNUNET_i2s2 (peer2),
+       GNUNET_sh2s (&cid->connection_of_tunnel));
+
+  env = GNUNET_MQ_msg (bm,
+                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+  bm->cid = *cid;
+  if (NULL != peer1)
+    bm->peer1 = *peer1;
+  if (NULL != peer2)
+    bm->peer2 = *peer2;
+  GCP_request_mq_cancel (target->mqm,
+                         env);
+  target->mqm = NULL;
+}
+
+
+/**
+ * Function called to check if any routes have timed out, and if
+ * so, to clean them up.  Finally, schedules itself again at the
+ * earliest time where there might be more work.
+ *
+ * @param cls NULL
+ */
+static void
+timeout_cb (void *cls)
+{
+  struct CadetRoute *r;
+  struct GNUNET_TIME_Relative linger;
+  struct GNUNET_TIME_Absolute exp;
+
+  timeout_task = NULL;
+  linger = GNUNET_TIME_relative_multiply (keepalive_period,
+                                          3);
+  while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
+  {
+    exp = GNUNET_TIME_absolute_add (r->last_use,
+                                    linger);
+    if (0 != GNUNET_TIME_absolute_get_duration (exp).rel_value_us)
+    {
+      /* Route not yet timed out, wait until it does. */
+      timeout_task = GNUNET_SCHEDULER_add_at (exp,
+                                              &timeout_cb,
+                                              NULL);
+      return;
+    }
+    send_broken (&r->prev,
+                 &r->cid,
+                 NULL,
+                 NULL);
+    send_broken (&r->next,
+                 &r->cid,
+                 NULL,
+                 NULL);
+    destroy_route (r);
+  }
+  /* No more routes left, so no need for a #timeout_task */
+}
+
+
+/**
+ * Function called when the message queue to the previous hop
+ * becomes available/unavailable.  We expect this function to
+ * be called immediately when we register, and then again
+ * later if the connection ever goes down.
+ *
+ * @param cls the `struct RouteDirection`
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
+ */
+static void
+dir_ready_cb (void *cls,
+              int ready)
+{
+  struct RouteDirection *dir = cls;
+  struct CadetRoute *route = dir->my_route;
+  struct RouteDirection *odir;
+
+  if (GNUNET_YES == ready)
+  {
+    struct GNUNET_MQ_Envelope *env;
+
+    dir->is_ready = GNUNET_YES;
+    if (NULL != (env = dir->env_head))
+    {
+      GNUNET_MQ_dll_remove (&dir->env_head,
+                            &dir->env_tail,
+                            env);
+      cur_buffers--;
+      GNUNET_STATISTICS_set (stats,
+                             "# buffer use",
+                             cur_buffers,
+                             GNUNET_NO);
+      lower_rung (dir);
+      dir->is_ready = GNUNET_NO;
+      GCP_send (dir->mqm,
+                env);
+    }
+    return;
+  }
+  odir = (dir == &route->next) ? &route->prev : &route->next;
+  send_broken (&route->next,
+               &route->cid,
+               GCP_get_id (odir->hop),
+               &my_full_id);
+  destroy_route (route);
+}
+
+
+/**
+ * Initialize one of the directions of a route.
+ *
+ * @param route route the direction belongs to
+ * @param dir direction to initialize
+ * @param hop next hop on in the @a dir
+ */
+static void
+dir_init (struct RouteDirection *dir,
+          struct CadetRoute *route,
+          struct CadetPeer *hop)
+{
+  dir->hop = hop;
+  dir->my_route = route;
+  dir->mqm = GCP_request_mq (hop,
+                             &dir_ready_cb,
+                             dir);
+  GNUNET_CONTAINER_DLL_insert (rung_head->rd_head,
+                               rung_head->rd_tail,
+                               dir);
+  dir->rung = rung_head;
+  GNUNET_assert (GNUNET_YES == dir->is_ready);
+}
+
+
+/**
+ * We could not create the desired route.  Send a
+ * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ * message to @a target.
+ *
+ * @param target who should receive the message
+ * @param cid identifier of the connection/route that failed
+ * @param failure_at neighbour with which we failed to route,
+ *        or NULL.
+ */
+static void
+send_broken_without_mqm (struct CadetPeer *target,
+                         const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                         const struct GNUNET_PeerIdentity *failure_at)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+  env = GNUNET_MQ_msg (bm,
+                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+  bm->cid = *cid;
+  bm->peer1 = my_full_id;
+  if (NULL != failure_at)
+    bm->peer2 = *failure_at;
+  GCP_send_ooo (target,
+                env);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_create (void *cls,
+                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+{
+  struct CadetPeer *sender = cls;
+  struct CadetPeer *next;
+  const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
+  struct CadetRoute *route;
+  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
+  unsigned int path_length;
+  unsigned int off;
+  enum GNUNET_CADET_ChannelOption options;
+
+  options = (enum GNUNET_CADET_ChannelOption) ntohl (msg->options);
+  path_length = size / sizeof (struct GNUNET_PeerIdentity);
+  /* Initiator is at offset 0. */
+  for (off=1;off<path_length;off++)
+    if (0 == memcmp (&my_full_id,
+                     &pids[off],
+                     sizeof (struct GNUNET_PeerIdentity)))
+      break;
+  if (off == path_length)
+  {
+    /* We are not on the path, bogus request */
+    GNUNET_break_op (0);
+    return;
+  }
+  /* Check previous hop */
+  if (sender != GCP_get (&pids[off - 1],
+                         GNUNET_NO))
+  {
+    /* sender is not on the path, not allowed */
+    GNUNET_break_op (0);
+    return;
+  }
+  if (NULL !=
+      get_route (&msg->cid))
+  {
+    /* Duplicate CREATE, pass it on, previous one might have been lost! */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    route_message (sender,
+                   &msg->cid,
+                   &msg->header);
+    return;
+  }
+  if (off == path_length - 1)
+  {
+    /* We are the destination, create connection */
+    struct CadetConnection *cc;
+    struct CadetPeerPath *path;
+    struct CadetPeer *origin;
+
+    cc = GCC_lookup (&msg->cid);
+    if (NULL != cc)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
+           GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+      GCC_handle_duplicate_create (cc);
+      return;
+    }
+
+    origin = GCP_get (&pids[0],
+                      GNUNET_YES);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
+         GCP_2s (origin),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    path = GCPP_get_path_from_route (path_length - 1,
+                                     pids);
+    if (GNUNET_OK !=
+        GCT_add_inbound_connection (GCP_get_tunnel (origin,
+                                                    GNUNET_YES),
+                                    &msg->cid,
+                                    (enum GNUNET_CADET_ChannelOption) ntohl (msg->options),
+                                    path))
+    {
+      /* Send back BROKEN: duplicate connection on the same path,
+         we will use the other one. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
+           GCP_2s (sender),
+           GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+           GCPP_2s (path));
+      send_broken_without_mqm (sender,
+                               &msg->cid,
+                               NULL);
+      return;
+    }
+    return;
+  }
+  /* We are merely a hop on the way, check if we can support the route */
+  next = GCP_get (&pids[off + 1],
+                  GNUNET_NO);
+  if ( (NULL == next) ||
+       (GNUNET_NO == GCP_has_core_connection (next)) )
+  {
+    /* unworkable, send back BROKEN notification */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
+         GCP_2s (sender),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+         GNUNET_i2s (&pids[off + 1]),
+         off + 1);
+    send_broken_without_mqm (sender,
+                             &msg->cid,
+                             &pids[off + 1]);
+    return;
+  }
+  if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
+         GCP_2s (sender),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    send_broken_without_mqm (sender,
+                             &msg->cid,
+                             &pids[off - 1]);
+    return;
+  }
+
+  /* Workable route, create routing entry */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
+       GCP_2s (sender),
+       GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+       GNUNET_i2s (&pids[off + 1]),
+       off + 1);
+  route = GNUNET_new (struct CadetRoute);
+  route->options = options;
+  route->cid = msg->cid;
+  route->last_use = GNUNET_TIME_absolute_get ();
+  dir_init (&route->prev,
+            route,
+            sender);
+  dir_init (&route->next,
+            route,
+            next);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (routes,
+                                                     &route->cid.connection_of_tunnel,
+                                                     route,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  GNUNET_STATISTICS_set (stats,
+                         "# routes",
+                         GNUNET_CONTAINER_multishortmap_size (routes),
+                         GNUNET_NO);
+  route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
+                                            route,
+                                            route->last_use.abs_value_us);
+  if (NULL == timeout_task)
+    timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (keepalive_period,
+                                                                                3),
+                                                 &timeout_cb,
+                                                 NULL);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_create_ack (void *cls,
+                              const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if ACK belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify ACK came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received ACK from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_CREATE_ACK for connection %s.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    GCC_handle_connection_create_ack (cc);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ * @deprecated duplicate logic with #handle_destroy(); dedup!
+ */
+static void
+handle_connection_broken (void *cls,
+                          const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+  struct CadetRoute *route;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    GCC_destroy_without_core (cc);
+
+    /* FIXME: also destroy the path up to the specified link! */
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+  route = get_route (&msg->cid);
+  if (NULL != route)
+    destroy_route (route);
+  /* FIXME: also destroy paths we MAY have up to the specified link! */
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_destroy (void *cls,
+                           const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+  struct CadetRoute *route;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+
+    GCC_destroy_without_core (cc);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
+       GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+  route = get_route (&msg->cid);
+  if (NULL != route)
+    destroy_route (route);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_kx (void *cls,
+                  const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_kx (cc,
+                   msg);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_kx_auth (void *cls,
+                       const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->kx.cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_kx_auth (cc,
+                        msg);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->kx.cid,
+                 &msg->kx.header);
+}
+
+
+/**
+ * Check if the encrypted message has the appropriate size.
+ *
+ * @param cls Closure (unused).
+ * @param msg Message to check.
+ *
+ * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ */
+static int
+check_tunnel_encrypted (void *cls,
+                        const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_encrypted (void *cls,
+                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_encrypted (cc,
+                          msg);
+    return;
+  }
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Function called after #GNUNET_CORE_connect has succeeded (or failed
+ * for good).  Note that the private key of the peer is intentionally
+ * not exposed here; if you need it, your process should try to read
+ * the private key file directly (which should work if you are
+ * authorized...).  Implementations of this function must not call
+ * #GNUNET_CORE_disconnect (other than by scheduling a new task to
+ * do this later).
+ *
+ * @param cls closure
+ * @param my_identity ID of this peer, NULL if we failed
+ */
+static void
+core_init_cb (void *cls,
+              const struct GNUNET_PeerIdentity *my_identity)
+{
+  if (NULL == my_identity)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_break (0 ==
+                memcmp (my_identity,
+                        &my_full_id,
+                        sizeof (struct GNUNET_PeerIdentity)));
+}
+
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void *
+core_connect_cb (void *cls,
+                 const struct GNUNET_PeerIdentity *peer,
+                 struct GNUNET_MQ_Handle *mq)
+{
+  struct CadetPeer *cp;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "CORE connection to peer %s was established.\n",
+       GNUNET_i2s (peer));
+  cp = GCP_get (peer,
+                GNUNET_YES);
+  GCP_set_mq (cp,
+              mq);
+  return cp;
+}
+
+
+/**
+ * Method called whenever a peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_disconnect_cb (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
+                    void *peer_cls)
+{
+  struct CadetPeer *cp = peer_cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "CORE connection to peer %s went down.\n",
+       GNUNET_i2s (peer));
+  GCP_set_mq (cp,
+              NULL);
+}
+
+
+/**
+ * Initialize the CORE subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (connection_create,
+                           GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
+                           struct GNUNET_CADET_ConnectionCreateMessage,
+                           NULL),
+    GNUNET_MQ_hd_fixed_size (connection_create_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
+                             struct GNUNET_CADET_ConnectionCreateAckMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (connection_broken,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
+                             struct GNUNET_CADET_ConnectionBrokenMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (connection_destroy,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
+                             struct GNUNET_CADET_ConnectionDestroyMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (tunnel_kx,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
+                             struct GNUNET_CADET_TunnelKeyExchangeMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
+                             struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
+                             NULL),
+    GNUNET_MQ_hd_var_size (tunnel_encrypted,
+                           GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
+                           struct GNUNET_CADET_TunnelEncryptedMessage,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "MAX_ROUTES",
+                                             &max_routes))
+    max_routes = 5000;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "MAX_MSGS_QUEUE",
+                                             &max_buffers))
+    max_buffers = 10000;
+  routes = GNUNET_CONTAINER_multishortmap_create (1024,
+                                                  GNUNET_NO);
+  route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  core = GNUNET_CORE_connect (c,
+                              NULL,
+                              &core_init_cb,
+                              &core_connect_cb,
+                              &core_disconnect_cb,
+                              handlers);
+}
+
+
+/**
+ * Shut down the CORE subsystem.
+ */
+void
+GCO_shutdown ()
+{
+  if (NULL != core)
+  {
+    GNUNET_CORE_disconnect (core);
+    core = NULL;
+  }
+  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
+  GNUNET_CONTAINER_multishortmap_destroy (routes);
+  routes = NULL;
+  GNUNET_CONTAINER_heap_destroy (route_heap);
+  route_heap = NULL;
+  if (NULL != timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (timeout_task);
+    timeout_task = NULL;
+  }
+}
+
+/* end of gnunet-cadet-service_core.c */
diff --git a/src/cadet/gnunet-service-cadet_core.h b/src/cadet/gnunet-service-cadet_core.h
new file mode 100644 (file)
index 0000000..65b0a6b
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_core.h
+ * @brief cadet service; interaction with CORE service
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
+ */
+
+#ifndef GNUNET_SERVICE_CADET_CORE_H
+#define GNUNET_SERVICE_CADET_CORE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Initialize the CORE subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCO_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the CORE subsystem.
+ */
+void
+GCO_shutdown (void);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_CORE_H */
+#endif
+/* end of gnunet-cadet-service_core.h */
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c
new file mode 100644 (file)
index 0000000..f00c0ca
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2013, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_dht.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+/**
+ * How long do we wait before first announcing our presence to the DHT.
+ * Used to wait for our HELLO to be available.  Note that we also get
+ * notifications when our HELLO is ready, so this is just the maximum
+ * we wait for the first notification.
+ */
+#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
+
+/**
+ * How long do we wait after we get an updated HELLO before publishing?
+ * Allows for the HELLO to be updated again quickly, for example in
+ * case multiple addresses changed and we got a partial update.
+ */
+#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
+
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
+
+
+/**
+ * Handle for DHT searches.
+ */
+struct GCD_search_handle
+{
+  /**
+   * DHT_GET handle.
+   */
+  struct GNUNET_DHT_GetHandle *dhtget;
+
+};
+
+
+/**
+ * Handle to use DHT.
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
+
+/**
+ * How often to PUT own ID in the DHT.
+ */
+static struct GNUNET_TIME_Relative id_announce_time;
+
+/**
+ * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
+ */
+static unsigned long long dht_replication_level;
+
+/**
+ * Task to periodically announce itself in the network.
+ */
+static struct GNUNET_SCHEDULER_Task *announce_id_task;
+
+/**
+ * Delay for the next ID announce.
+ */
+static struct GNUNET_TIME_Relative announce_delay;
+
+
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+static void
+dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
+                    const struct GNUNET_HashCode *key,
+                    const struct GNUNET_PeerIdentity *get_path,
+                    unsigned int get_path_length,
+                    const struct GNUNET_PeerIdentity *put_path,
+                    unsigned int put_path_length,
+                    enum GNUNET_BLOCK_Type type,
+                    size_t size,
+                    const void *data)
+{
+  const struct GNUNET_HELLO_Message *hello = data;
+  struct CadetPeer *peer;
+
+  GCPP_try_path_from_dht (get_path,
+                          get_path_length,
+                          put_path,
+                          put_path_length);
+  if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
+       (ntohs (hello->header.size) == size) &&
+       (size == GNUNET_HELLO_size (hello)) )
+  {
+    peer = GCP_get (&put_path[0],
+                    GNUNET_YES);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got HELLO for %s\n",
+         GCP_2s (peer));
+    GCP_set_hello (peer,
+                   hello);
+  }
+}
+
+
+/**
+ * Periodically announce self id in the DHT
+ *
+ * @param cls closure
+ */
+static void
+announce_id (void *cls)
+{
+  struct GNUNET_HashCode phash;
+  const struct GNUNET_HELLO_Message *hello;
+  size_t size;
+  struct GNUNET_TIME_Absolute expiration;
+  struct GNUNET_TIME_Relative next_put;
+
+  hello = GCH_get_mine ();
+  size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
+  if (0 == size)
+  {
+    expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+                                           announce_delay);
+    announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
+  }
+  else
+  {
+    expiration = GNUNET_HELLO_get_last_expiration (hello);
+    announce_delay = GNUNET_TIME_UNIT_SECONDS;
+  }
+
+  /* Call again in id_announce_time, unless HELLO expires first,
+   * but wait at least 1s. */
+  next_put
+    = GNUNET_TIME_absolute_get_remaining (expiration);
+  next_put
+    = GNUNET_TIME_relative_min (next_put,
+                                id_announce_time);
+  next_put
+    = GNUNET_TIME_relative_max (next_put,
+                                GNUNET_TIME_UNIT_SECONDS);
+  announce_id_task
+    = GNUNET_SCHEDULER_add_delayed (next_put,
+                                    &announce_id,
+                                    cls);
+  GNUNET_STATISTICS_update (stats,
+                            "# DHT announce",
+                            1,
+                            GNUNET_NO);
+  memset (&phash,
+          0,
+          sizeof (phash));
+  GNUNET_memcpy (&phash,
+                 &my_full_id,
+                 sizeof (my_full_id));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Announcing my HELLO (%u bytes) in the DHT\n",
+       size);
+  GNUNET_DHT_put (dht_handle,   /* DHT handle */
+                  &phash,       /* Key to use */
+                  dht_replication_level,     /* Replication level */
+                  GNUNET_DHT_RO_RECORD_ROUTE
+                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
+                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
+                  size,  /* Size of the data */
+                  (const char *) hello, /* Data itself */
+                  expiration,  /* Data expiration */
+                  NULL,         /* Continuation */
+                  NULL);        /* Continuation closure */
+}
+
+
+/**
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
+ */
+void
+GCD_hello_update ()
+{
+  if (NULL == announce_id_task)
+    return; /* too early */
+  GNUNET_SCHEDULER_cancel (announce_id_task);
+  announce_id_task
+    = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
+                                    &announce_id,
+                                    NULL);
+}
+
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "DHT_REPLICATION_LEVEL",
+                                             &dht_replication_level))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "DHT_REPLICATION_LEVEL",
+                               "USING DEFAULT");
+    dht_replication_level = 3;
+  }
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "ID_ANNOUNCE_TIME",
+                                           &id_announce_time))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "CADET",
+                               "ID_ANNOUNCE_TIME",
+                               "MISSING");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
+  dht_handle = GNUNET_DHT_connect (c,
+                                   64);
+  GNUNET_break (NULL != dht_handle);
+  announce_delay = GNUNET_TIME_UNIT_SECONDS;
+  announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
+                                                   &announce_id,
+                                                   NULL);
+}
+
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GCD_shutdown (void)
+{
+  if (NULL != dht_handle)
+  {
+    GNUNET_DHT_disconnect (dht_handle);
+    dht_handle = NULL;
+  }
+  if (NULL != announce_id_task)
+  {
+    GNUNET_SCHEDULER_cancel (announce_id_task);
+    announce_id_task = NULL;
+  }
+}
+
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id)
+{
+  struct GNUNET_HashCode phash;
+  struct GCD_search_handle *h;
+
+  GNUNET_STATISTICS_update (stats,
+                            "# DHT search",
+                            1,
+                            GNUNET_NO);
+  memset (&phash,
+          0,
+          sizeof (phash));
+  GNUNET_memcpy (&phash,
+                 peer_id,
+                 sizeof (*peer_id));
+
+  h = GNUNET_new (struct GCD_search_handle);
+  h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
+                                    GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
+                                    &phash,     /* key to search */
+                                    dht_replication_level, /* replication level */
+                                    GNUNET_DHT_RO_RECORD_ROUTE |
+                                    GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+                                    NULL,       /* xquery */
+                                    0,     /* xquery bits */
+                                    &dht_get_id_handler,
+                                   h);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting DHT GET for peer %s (%p)\n",
+       GNUNET_i2s (peer_id),
+       h);
+  return h;
+}
+
+
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
+void
+GCD_search_stop (struct GCD_search_handle *h)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Stopping DHT GET %p\n",
+       h);
+  GNUNET_DHT_get_stop (h->dhtget);
+  GNUNET_free (h);
+}
+
+/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h
new file mode 100644 (file)
index 0000000..5d7ab29
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2013, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_dht.h
+ * @brief cadet service; dealing with DHT requests and results
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
+ */
+#ifndef GNUNET_SERVICE_CADET_DHT_H
+#define GNUNET_SERVICE_CADET_DHT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Handle for DHT search operation.
+ */
+struct GCD_search_handle;
+
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GCD_shutdown (void);
+
+
+/**
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
+ */
+void
+GCD_hello_update (void);
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id);
+
+
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
+void
+GCD_search_stop (struct GCD_search_handle *h);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
+#endif
+/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c
new file mode 100644 (file)
index 0000000..6d85de3
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2014, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_hello.c
+ * @brief spread knowledge about how to contact other peers from PEERINFO
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - is most of this necessary/helpful?
+ * - should we not simply restrict this to OUR hello?
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "cadet_protocol.h"
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
+
+/**
+ * Hello message of local peer.
+ */
+static struct GNUNET_HELLO_Message *mine;
+
+/**
+ * Handle to peerinfo service.
+ */
+static struct GNUNET_PEERINFO_Handle *peerinfo;
+
+/**
+ * Iterator context.
+ */
+static struct GNUNET_PEERINFO_NotifyContext *nc;
+
+
+/**
+ * Process each hello message received from peerinfo.
+ *
+ * @param cls Closure (unused).
+ * @param peer Identity of the peer.
+ * @param hello Hello of the peer.
+ * @param err_msg Error message.
+ */
+static void
+got_hello (void *cls,
+           const struct GNUNET_PeerIdentity *id,
+           const struct GNUNET_HELLO_Message *hello,
+           const char *err_msg)
+{
+  struct CadetPeer *peer;
+
+  if ( (NULL == id) ||
+       (NULL == hello) )
+    return;
+  if (0 == memcmp (id,
+                   &my_full_id,
+                   sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_free_non_null (mine);
+    mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
+    GCD_hello_update ();
+    return;
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Hello for %s (%d bytes), expires on %s\n",
+       GNUNET_i2s (id),
+       GNUNET_HELLO_size (hello),
+       GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
+  peer = GCP_get (id,
+                  GNUNET_YES);
+  GCP_set_hello (peer,
+                 hello);
+}
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  GNUNET_assert (NULL == nc);
+  peerinfo = GNUNET_PEERINFO_connect (c);
+  nc = GNUNET_PEERINFO_notify (c,
+                               GNUNET_NO,
+                               &got_hello,
+                               NULL);
+}
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GCH_shutdown ()
+{
+  if (NULL != nc)
+  {
+    GNUNET_PEERINFO_notify_cancel (nc);
+    nc = NULL;
+  }
+  if (NULL != peerinfo)
+  {
+    GNUNET_PEERINFO_disconnect (peerinfo);
+    peerinfo = NULL;
+  }
+  if (NULL != mine)
+  {
+    GNUNET_free (mine);
+    mine = NULL;
+  }
+}
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GCH_get_mine (void)
+{
+  return mine;
+}
+
+/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h
new file mode 100644 (file)
index 0000000..4291ae9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2014, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_hello.h
+ * @brief cadet service; dealing with hello messages
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_HELLO_H
+#define GNUNET_SERVICE_CADET_HELLO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GCH_shutdown (void);
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GCH_get_mine (void);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
+#endif
+/* end of gnunet-cadet-service_hello.h */
diff --git a/src/cadet/gnunet-service-cadet_paths.c b/src/cadet/gnunet-service-cadet_paths.c
new file mode 100644 (file)
index 0000000..1375264
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_paths.c
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
+
+
+/**
+ * Information regarding a possible path to reach a peer.
+ */
+struct CadetPeerPath
+{
+
+  /**
+   * Array of all the peers on the path.  If @e hn is non-NULL, the
+   * last one is our owner.
+   */
+  struct CadetPeerPathEntry **entries;
+
+  /**
+   * Node of this path in the owner's heap.  Used to update our position
+   * in the heap whenever our @e desirability changes.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  /**
+   * Desirability of the path. How unique is it for the various peers
+   * on it?
+   */
+  GNUNET_CONTAINER_HeapCostType desirability;
+
+  /**
+   * Length of the @e entries array.
+   */
+  unsigned int entries_length;
+
+};
+
+
+/**
+ * Calculate the path's desirability score.
+ *
+ * @param path path to calculate the score for
+ */
+static void
+recalculate_path_desirability (struct CadetPeerPath *path)
+{
+  double result = 0.0;
+
+  for (unsigned int i=0;i<path->entries_length;i++)
+  {
+    struct CadetPeer *cp = path->entries[i]->peer;
+
+    result += GCP_get_desirability_of_path (cp,
+                                            i);
+  }
+  path->desirability = (GNUNET_CONTAINER_HeapCostType) result;
+}
+
+
+/**
+ * Return how much we like keeping the path.  This is an aggregate
+ * score based on various factors, including the age of the path
+ * (older == better), and the value of this path to all of its ajacent
+ * peers.  For example, long paths that end at a peer that we have no
+ * shorter way to reach are very desirable, while long paths that end
+ * at a peer for which we have a shorter way as well are much less
+ * desirable.  Higher values indicate more valuable paths.  The
+ * returned value should be used to decide which paths to remember.
+ *
+ * @param path path to return the length for
+ * @return desirability of the path, larger is more desirable
+ */
+GNUNET_CONTAINER_HeapCostType
+GCPP_get_desirability (const struct CadetPeerPath *path)
+{
+  return path->desirability;
+}
+
+
+/**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (entry->peer == destination);
+  return entry->cc;
+}
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding connection %s to path %s at offset %u\n",
+       GCC_2s (cc),
+       GCPP_2s (path),
+       off);
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (NULL == entry->cc);
+  GNUNET_assert (NULL != cc);
+  entry->cc = cc;
+}
+
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing connection %s to path %s at offset %u\n",
+       GCC_2s (cc),
+       GCPP_2s (path),
+       off);
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (cc == entry->cc);
+  entry->cc = NULL;
+}
+
+
+/**
+ * This path is no longer needed, free resources.
+ *
+ * @param path path resources to free
+ */
+static void
+path_destroy (struct CadetPeerPath *path)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying path %s\n",
+       GCPP_2s (path));
+  for (unsigned int i=0;i<path->entries_length;i++)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    if (NULL != entry->cc)
+    {
+      struct CadetTConnection *ct;
+
+      ct = GCC_get_ct (entry->cc);
+      if (NULL != ct)
+        GCT_connection_lost (ct);
+      GCC_destroy_without_tunnel (entry->cc);
+    }
+    GNUNET_free (entry);
+  }
+  GNUNET_free (path->entries);
+  GNUNET_free (path);
+}
+
+
+/**
+ * The owning peer of this path is no longer interested in maintaining
+ * it, so the path should be discarded or shortened (in case a
+ * previous peer on the path finds the path desirable).
+ *
+ * @param path the path that is being released
+ */
+void
+GCPP_release (struct CadetPeerPath *path)
+{
+  struct CadetPeerPathEntry *entry;
+  int force;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Owner releases path %s\n",
+       GCPP_2s (path));
+  path->hn = NULL;
+  entry = path->entries[path->entries_length - 1];
+  GNUNET_assert (path == entry->path);
+  while (1)
+  {
+    /* cut 'off' end of path */
+    GNUNET_assert (NULL == entry->cc);
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           path->entries_length - 1);
+    path->entries_length--; /* We don't bother shrinking the 'entries' array,
+                               as it's probably not worth it. */
+    GNUNET_free (entry);
+    if (0 == path->entries_length)
+      break; /* the end */
+
+    /* see if new peer at the end likes this path any better */
+    entry = path->entries[path->entries_length - 1];
+    GNUNET_assert (path == entry->path);
+    force = (NULL == entry->cc) ? GNUNET_NO : GNUNET_YES;
+    path->hn = GCP_attach_path (entry->peer,
+                                path,
+                                path->entries_length - 1,
+                                force);
+    if (NULL != path->hn)
+      return; /* yep, got attached, we are done. */
+    GNUNET_assert (GNUNET_NO == force);
+  }
+
+  /* nobody wants us, discard the path */
+  path_destroy (path);
+}
+
+
+/**
+ * Updates the score for an entry on the path based
+ * on our experiences with using @a path.
+ *
+ * @param path the path to update
+ * @param off offset of the entry to update
+ * @param delta change in the score to apply
+ */
+void
+GCPP_update_score (struct CadetPeerPath *path,
+                   unsigned int off,
+                   int delta)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+
+  /* Add delta, with checks for overflows */
+  if (delta >= 0)
+  {
+    if (delta + entry->score < entry->score)
+      entry->score = INT_MAX;
+    else
+      entry->score += delta;
+  }
+  else
+  {
+    if (delta + entry->score > entry->score)
+      entry->score = INT_MIN;
+    else
+      entry->score += delta;
+  }
+  recalculate_path_desirability (path);
+}
+
+
+/**
+ * Closure for #find_peer_at() and #check_match().
+ */
+struct CheckMatchContext
+{
+
+  /**
+   * Set to a matching path, if any.
+   */
+  struct CadetPeerPath *match;
+
+  /**
+   * Array the combined paths.
+   */
+  struct CadetPeer **cpath;
+
+  /**
+   * How long is the @e cpath array?
+   */
+  unsigned int cpath_length;
+
+};
+
+
+/**
+ * Check if the given path is identical on all of the
+ * hops until @a off, and not longer than @a off.  If the
+ * @a path matches, store it in `match`.
+ *
+ * @param cls the `struct CheckMatchContext` to check against
+ * @param path the path to check
+ * @param off offset to check at
+ * @return #GNUNET_YES (continue to iterate), or if found #GNUNET_NO
+ */
+static int
+check_match (void *cls,
+             struct CadetPeerPath *path,
+             unsigned int off)
+{
+  struct CheckMatchContext *cm_ctx = cls;
+
+  GNUNET_assert (path->entries_length > off);
+  if ( (path->entries_length != off + 1) &&
+       (off + 1 != cm_ctx->cpath_length) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "check_match missmatch because path %s is too long (%u vs. %u vs. %u)\n",
+         GCPP_2s (path),
+         path->entries_length,
+         off + 1,
+         cm_ctx->cpath_length);
+    return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
+  }
+  for (unsigned int i=0;i<off;i++)
+    if (cm_ctx->cpath[i] !=
+        GCPP_get_peer_at_offset (path,
+                                 i))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "check_match path %s missmatches at offset %u\n",
+           GCPP_2s (path),
+           i);
+      return GNUNET_YES; /* missmatch, ignore */
+    }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "check_match found match with path %s\n",
+       GCPP_2s (path));
+  cm_ctx->match = path;
+  return GNUNET_NO; /* match, we are done! */
+}
+
+
+/**
+ * Extend path @a path by the @a num_peers from the @a peers
+ * array, assuming the owners past the current owner want it.
+ *
+ * @param path path to extend
+ * @param peers list of peers beyond the end of @a path
+ * @param num_peers length of the @a peers array
+ * @param force force attachment, even if we have other
+ *        paths already
+ */
+static void
+extend_path (struct CadetPeerPath *path,
+             struct CadetPeer **peers,
+             unsigned int num_peers,
+             int force)
+{
+  unsigned int old_len = path->entries_length;
+  int i;
+
+  /* Expand path */
+  GNUNET_array_grow (path->entries,
+                     path->entries_length,
+                     old_len + num_peers);
+  for (i=num_peers-1;i >= 0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[old_len + i] = entry;
+    entry->peer = peers[i];
+    entry->path = path;
+  }
+  for (i=num_peers-1;i >= 0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        old_len + i);
+  }
+
+  /* If we extend an existing path, detach it from the
+     old owner and re-attach to the new one */
+  GCP_detach_path (path->entries[old_len-1]->peer,
+                   path,
+                   path->hn);
+  path->hn = NULL;
+  for (i=num_peers-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
+
+    path->entries_length = old_len + i + 1;
+    recalculate_path_desirability (path);
+    path->hn = GCP_attach_path (peers[i],
+                                path,
+                                old_len + (unsigned int) i,
+                                force);
+    if (NULL != path->hn)
+      break;
+    GNUNET_assert (NULL == entry->cc);
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           old_len + i);
+    GNUNET_free (entry);
+    path->entries[old_len + i] = NULL;
+  }
+  if (NULL == path->hn)
+  {
+    /* none of the peers is interested in this path;
+       shrink path back and re-attach. */
+    GNUNET_array_grow (path->entries,
+                       path->entries_length,
+                       old_len);
+    path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
+                                path,
+                                old_len - 1,
+                                GNUNET_YES);
+    GNUNET_assert (NULL != path->hn);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Extended path %s\n",
+       GCPP_2s (path));
+}
+
+
+/**
+ * Create a peer path based on the result of a DHT lookup.  If we
+ * already know this path, or one that is longer, simply return NULL.
+ * Otherwise, we try to extend an existing path, or create a new one
+ * if applicable.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @return a path through the network
+ */
+void
+GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+                        unsigned int get_path_length,
+                        const struct GNUNET_PeerIdentity *put_path,
+                        unsigned int put_path_length)
+{
+  struct CadetPeer *cpath[get_path_length + put_path_length];
+  struct CheckMatchContext cm_ctx;
+  struct CadetPeerPath *path;
+  struct GNUNET_CONTAINER_HeapNode *hn;
+  int i;
+  unsigned int skip;
+  unsigned int total_len;
+
+  /* precompute 'cpath' so we can avoid doing the lookups lots of times */
+  skip = 0;
+  memset (cpath,
+          0,
+          sizeof (cpath)); /* Just to trigger harder errors later. */
+  total_len = get_path_length + put_path_length;
+  for (unsigned int off=0;off<total_len;off++)
+  {
+    const struct GNUNET_PeerIdentity *pid;
+
+    pid = (off < get_path_length)
+      ? &get_path[get_path_length - off]
+      : &put_path[get_path_length + put_path_length - off];
+    cpath[off - skip] = GCP_get (pid,
+                                 GNUNET_YES);
+    /* Check that no peer is twice on the path */
+    for (unsigned int i=0;i<off - skip;i++)
+    {
+     if (cpath[i] == cpath[off - skip])
+      {
+        skip = off - i;
+        break;
+      }
+    }
+  }
+  total_len -= skip;
+
+  /* First figure out if this path is a subset of an existing path, an
+     extension of an existing path, or a new path. */
+  cm_ctx.cpath_length = total_len;
+  cm_ctx.cpath = cpath;
+  cm_ctx.match = NULL;
+  for (i=total_len-1;i>=0;i--)
+  {
+    GCP_iterate_paths_at (cpath[i],
+                          (unsigned int) i,
+                          &check_match,
+                          &cm_ctx);
+    if (NULL != cm_ctx.match)
+    {
+      if (i == total_len - 1)
+      {
+        /* Existing path includes this one, nothing to do! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Path discovered from DHT is already known\n");
+        return;
+      }
+      if (cm_ctx.match->entries_length == i + 1)
+      {
+        /* Existing path ends in the middle of new path, extend it! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Trying to extend existing path %s by additional links discovered from DHT\n",
+             GCPP_2s (cm_ctx.match));
+        extend_path (cm_ctx.match,
+                     &cpath[i + 1],
+                     total_len - i - 1,
+                     GNUNET_NO);
+        return;
+      }
+    }
+  }
+
+  /* No match at all, create completely new path */
+  path = GNUNET_new (struct CadetPeerPath);
+  path->entries_length = total_len;
+  path->entries = GNUNET_new_array (path->entries_length,
+                                    struct CadetPeerPathEntry *);
+  for (i=path->entries_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[i] = entry;
+    entry->peer = cpath[i];
+    entry->path = path;
+  }
+  for (i=path->entries_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        i);
+  }
+
+  /* Finally, try to attach it */
+  hn = NULL;
+  for (i=total_len-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    path->entries_length = i + 1;
+    recalculate_path_desirability (path);
+    hn = GCP_attach_path (cpath[i],
+                          path,
+                          (unsigned int) i,
+                          GNUNET_NO);
+    if (NULL != hn)
+      break;
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           i);
+    GNUNET_free (entry);
+    path->entries[i] = NULL;
+  }
+  if (NULL == hn)
+  {
+    /* None of the peers on the path care about it. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Path discovered from DHT is not interesting to us\n");
+    GNUNET_free (path->entries);
+    GNUNET_free (path);
+    return;
+  }
+  path->hn = hn;
+  /* Shrink path to actual useful length */
+  GNUNET_array_grow (path->entries,
+                     path->entries_length,
+                     i + 1);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created new path %s based on information from DHT\n",
+       GCPP_2s (path));
+}
+
+
+/**
+ * We got an incoming connection, obtain the corresponding path.
+ *
+ * @param path_length number of segments on the @a path
+ * @param pids path through the network, in reverse order (we are at the end at index @a path_length)
+ * @return corresponding path object
+ */
+struct CadetPeerPath *
+GCPP_get_path_from_route (unsigned int path_length,
+                          const struct GNUNET_PeerIdentity *pids)
+{
+  struct CheckMatchContext cm_ctx;
+  struct CadetPeer *cpath[path_length];
+  struct CadetPeerPath *path;
+
+  /* precompute inverted 'cpath' so we can avoid doing the lookups and
+     have the correct order */
+  for (unsigned int off=0;off<path_length;off++)
+    cpath[off] = GCP_get (&pids[path_length - 1 - off],
+                          GNUNET_YES);
+
+  /* First figure out if this path is a subset of an existing path, an
+     extension of an existing path, or a new path. */
+  cm_ctx.cpath = cpath;
+  cm_ctx.cpath_length = path_length;
+  cm_ctx.match = NULL;
+  for (int i=path_length-1;i>=0;i--)
+  {
+    GCP_iterate_paths_at (cpath[i],
+                          (unsigned int) i,
+                          &check_match,
+                          &cm_ctx);
+    if (NULL != cm_ctx.match)
+    {
+      if (i == path_length - 1)
+      {
+        /* Existing path includes this one, return the match! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Returning existing path %s as inverse for incoming connection\n",
+             GCPP_2s (cm_ctx.match));
+        return cm_ctx.match;
+      }
+      if (cm_ctx.match->entries_length == i + 1)
+      {
+        /* Existing path ends in the middle of new path, extend it! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Extending existing path %s to create inverse for incoming connection\n",
+             GCPP_2s (cm_ctx.match));
+        extend_path (cm_ctx.match,
+                     &cpath[i + 1],
+                     path_length - i - 1,
+                     GNUNET_YES);
+        /* Check that extension was successful */
+        GNUNET_assert (cm_ctx.match->entries_length == path_length);
+        return cm_ctx.match;
+      }
+      /* Eh, we found a match but couldn't use it? Something is wrong. */
+      GNUNET_break (0);
+    }
+  }
+
+  /* No match at all, create completely new path */
+  path = GNUNET_new (struct CadetPeerPath);
+  path->entries_length = path_length;
+  path->entries = GNUNET_new_array (path->entries_length,
+                                    struct CadetPeerPathEntry *);
+  for (int i=path_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[i] = entry;
+    entry->peer = cpath[i];
+    entry->path = path;
+  }
+  for (int i=path_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        i);
+  }
+  recalculate_path_desirability (path);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created new path %s to create inverse for incoming connection\n",
+       GCPP_2s (path));
+  path->hn = GCP_attach_path (cpath[path_length - 1],
+                              path,
+                              path_length - 1,
+                              GNUNET_YES);
+  return path;
+}
+
+
+/**
+ * Return the length of the path.  Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path)
+{
+  return path->entries_length;
+}
+
+
+/**
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp)
+{
+  for (unsigned int off = 0;
+       off < path->entries_length;
+       off++)
+    if (cp == GCPP_get_peer_at_offset (path,
+                                       off))
+      return off;
+  return UINT_MAX;
+}
+
+
+/**
+ * Obtain the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @return the peer at offset @a off
+ */
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off)
+{
+  GNUNET_assert (off < path->entries_length);
+  return path->entries[off]->peer;
+}
+
+
+/**
+ * Convert a path to a human-readable string.
+ *
+ * @param path path to convert
+ * @return string, to be freed by caller (unlike other *_2s APIs!)
+ */
+const char *
+GCPP_2s (struct CadetPeerPath *path)
+{
+  static char buf[2048];
+  size_t off;
+  const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
+
+  off = 0;
+  for (unsigned int i = 0;
+       i < path->entries_length;
+       i++)
+  {
+    if ( (path->entries_length > max_plen) &&
+         (i == max_plen / 2) )
+      off += GNUNET_snprintf (&buf[off],
+                              sizeof (buf) - off,
+                              "...-");
+    if ( (path->entries_length > max_plen) &&
+         (i > max_plen / 2) &&
+         (i < path->entries_length - max_plen / 2) )
+      continue;
+    off += GNUNET_snprintf (&buf[off],
+                            sizeof (buf) - off,
+                            "%s%s",
+                            GNUNET_i2s (GCP_get_id (GCPP_get_peer_at_offset (path,
+                                                                             i))),
+                            (i == path->entries_length -1) ? "" : "-");
+  }
+  GNUNET_snprintf (&buf[off],
+                   sizeof (buf) - off,
+                   "(%p)",
+                   path);
+  return buf;
+}
+
+
+/* end of gnunet-service-cadet-new_paths.c */
diff --git a/src/cadet/gnunet-service-cadet_paths.h b/src/cadet/gnunet-service-cadet_paths.h
new file mode 100644 (file)
index 0000000..6b7bef6
--- /dev/null
@@ -0,0 +1,182 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_paths.h
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_PATHS_H
+#define GNUNET_SERVICE_CADET_PATHS_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet.h"
+
+/**
+ * Create a peer path based on the result of a DHT lookup.  If we
+ * already know this path, or one that is longer, simply return NULL.
+ * Otherwise, we try to extend an existing path, or create a new one
+ * if applicable.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ */
+void
+GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+                        unsigned int get_path_length,
+                        const struct GNUNET_PeerIdentity *put_path,
+                        unsigned int put_path_length);
+
+
+/**
+ * We got an incoming connection, obtain the corresponding path.
+ *
+ * @param path_length number of segments on the @a path
+ * @param path through the network, in reverse order (we are at the end!)
+ * @return corresponding path object
+ */
+struct CadetPeerPath *
+GCPP_get_path_from_route (unsigned int path_length,
+                          const struct GNUNET_PeerIdentity *pids);
+
+
+/**
+ * Return the length of the path.  Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path);
+
+
+/**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off);
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp);
+
+
+/**
+ * Return how much we like keeping the path.  This is an aggregate
+ * score based on various factors, including the age of the path
+ * (older == better), and the value of this path to all of its ajacent
+ * peers.  For example, long paths that end at a peer that we have no
+ * shorter way to reach are very desirable, while long paths that end
+ * at a peer for which we have a shorter way as well are much less
+ * desirable.  Higher values indicate more valuable paths.  The
+ * returned value should be used to decide which paths to remember.
+ *
+ * @param path path to return the length for
+ * @return desirability of the path, larger is more desirable
+ */
+GNUNET_CONTAINER_HeapCostType
+GCPP_get_desirability (const struct CadetPeerPath *path);
+
+
+/**
+ * The given peer @a cp used to own this @a path.  However, it is no
+ * longer interested in maintaining it, so the path should be
+ * discarded or shortened (in case a previous peer on the path finds
+ * the path desirable).
+ *
+ * @param path the path that is being released
+ */
+void
+GCPP_release (struct CadetPeerPath *path);
+
+
+/**
+ * Obtain the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @return peer at offset @a off
+ */
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off);
+
+
+/**
+ * Convert a path to a human-readable string.
+ *
+ * @param path path to convert
+ * @return string, statically allocated
+ */
+const char *
+GCPP_2s (struct CadetPeerPath *p);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c
new file mode 100644 (file)
index 0000000..71c7c67
--- /dev/null
@@ -0,0 +1,1477 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_peer.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - optimize stopping/restarting DHT search to situations
+ *   where we actually need it (i.e. not if we have a direct connection,
+ *   or if we already have plenty of good short ones, or maybe even
+ *   to take a break if we have some connections and have searched a lot (?))
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_ats_service.h"
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "cadet_protocol.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
+
+
+/**
+ * How long do we wait until tearing down an idle peer?
+ */
+#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
+
+/**
+ * How long do we keep paths around if we no longer care about the peer?
+ */
+#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
+
+
+
+
+/**
+ * Data structure used to track whom we have to notify about changes
+ * to our message queue.
+ */
+struct GCP_MessageQueueManager
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct GCP_MessageQueueManager *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct GCP_MessageQueueManager *prev;
+
+  /**
+   * Function to call with updated message queue object.
+   */
+  GCP_MessageQueueNotificationCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * The peer this is for.
+   */
+  struct CadetPeer *cp;
+
+  /**
+   * Envelope this manager would like to transmit once it is its turn.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+};
+
+
+/**
+ * Struct containing all information regarding a given peer
+ */
+struct CadetPeer
+{
+  /**
+   * ID of the peer
+   */
+  struct GNUNET_PeerIdentity pid;
+
+  /**
+   * Last time we heard from this peer (currently not used!)
+   */
+  struct GNUNET_TIME_Absolute last_contactXXX;
+
+  /**
+   * Array of DLLs of paths traversing the peer, organized by the
+   * offset of the peer on the larger path.
+   */
+  struct CadetPeerPathEntry **path_heads;
+
+  /**
+   * Array of DLL of paths traversing the peer, organized by the
+   * offset of the peer on the larger path.
+   */
+  struct CadetPeerPathEntry **path_tails;
+
+  /**
+   * Notifications to call when @e core_mq changes.
+   */
+  struct GCP_MessageQueueManager *mqm_head;
+
+  /**
+   * Notifications to call when @e core_mq changes.
+   */
+  struct GCP_MessageQueueManager *mqm_tail;
+
+  /**
+   * Pointer to first "ready" entry in @e mqm_head.
+   */
+  struct GCP_MessageQueueManager *mqm_ready_ptr;
+
+  /**
+   * MIN-heap of paths owned by this peer (they also end at this
+   * peer).  Ordered by desirability.
+   */
+  struct GNUNET_CONTAINER_Heap *path_heap;
+
+  /**
+   * Handle to stop the DHT search for paths to this peer
+   */
+  struct GCD_search_handle *search_h;
+
+  /**
+   * Task to clean up @e path_heap asynchronously.
+   */
+  struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
+
+  /**
+   * Task to destroy this entry.
+   */
+  struct GNUNET_SCHEDULER_Task *destroy_task;
+
+  /**
+   * Tunnel to this peer, if any.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Connections that go through this peer; indexed by tid.
+   */
+  struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+  /**
+   * Handle for core transmissions.
+   */
+  struct GNUNET_MQ_Handle *core_mq;
+
+  /**
+   * Hello message of the peer.
+   */
+  struct GNUNET_HELLO_Message *hello;
+
+  /**
+   * Handle to us offering the HELLO to the transport.
+   */
+  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+  /**
+   * Handle to our ATS request asking ATS to suggest an address
+   * to TRANSPORT for this peer (to establish a direct link).
+   */
+  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
+  /**
+   * How many messages are in the queue to this peer.
+   */
+  unsigned int queue_n;
+
+  /**
+   * How many paths do we have to this peer (in all @e path_heads DLLs combined).
+   */
+  unsigned int num_paths;
+
+  /**
+   * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
+   * Used to speed-up @GCP_get_desirability_of_path() calculation.
+   */
+  unsigned int off_sum;
+
+  /**
+   * Number of message queue managers of this peer that have a message in waiting.
+   *
+   * Used to quickly see if we need to bother scanning the @e msm_head DLL.
+   * TODO: could be replaced by another DLL that would then allow us to avoid
+   * the O(n)-scan of the DLL for ready entries!
+   */
+  unsigned int mqm_ready_counter;
+
+  /**
+   * Current length of the @e path_heads and @path_tails arrays.
+   * The arrays should be grown as needed.
+   */
+  unsigned int path_dll_length;
+
+};
+
+
+/**
+ * Get the static string for a peer ID.
+ *
+ * @param cp Peer.
+ * @return Static string for it's ID.
+ */
+const char *
+GCP_2s (const struct CadetPeer *cp)
+{
+  static char buf[32];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "P(%s)",
+                   GNUNET_i2s (&cp->pid));
+  return buf;
+}
+
+
+/**
+ * Calculate how desirable a path is for @a cp if @a cp
+ * is at offset @a off.
+ *
+ * The 'desirability_table.c' program can be used to compute a list of
+ * sample outputs for different scenarios.  Basically, we score paths
+ * lower if there are many alternatives, and higher if they are
+ * shorter than average, and very high if they are much shorter than
+ * average and without many alternatives.
+ *
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in the path
+ * @return score how useful a path is to reach @a cp,
+ *         positive scores mean path is more desirable
+ */
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+                              unsigned int off)
+{
+  unsigned int num_alts = cp->num_paths;
+  unsigned int off_sum;
+  double avg_sum;
+  double path_delta;
+  double weight_alts;
+
+  GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
+  GNUNET_assert (0 != cp->path_dll_length);
+
+  /* We maintain 'off_sum' in 'peer' and thereby
+     avoid the SLOW recalculation each time. Kept here
+     just to document what is going on. */
+#if SLOW
+  off_sum = 0;
+  for (unsigned int j=0;j<cp->path_dll_length;j++)
+    for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
+         NULL != pe;
+         pe = pe->next)
+      off_sum += j;
+  GNUNET_assert (off_sum == cp->off_sum);
+#else
+  off_sum = cp->off_sum;
+#endif
+  avg_sum = off_sum * 1.0 / cp->path_dll_length;
+  path_delta = off - avg_sum;
+  /* path_delta positiv: path off of peer above average (bad path for peer),
+     path_delta negativ: path off of peer below average (good path for peer) */
+  if (path_delta <= - 1.0)
+    weight_alts = - num_alts / path_delta; /* discount alternative paths */
+  else if (path_delta >= 1.0)
+    weight_alts = num_alts * path_delta; /* overcount alternative paths */
+  else
+    weight_alts = num_alts; /* count alternative paths normally */
+
+
+  /* off+1: long paths are generally harder to find and thus count
+     a bit more as they get longer.  However, above-average paths
+     still need to count less, hence the squaring of that factor. */
+  return (off + 1.0) / (weight_alts * weight_alts);
+}
+
+
+/**
+ * This peer is no longer be needed, clean it up now.
+ *
+ * @param cls peer to clean up
+ */
+static void
+destroy_peer (void *cls)
+{
+  struct CadetPeer *cp = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying state about peer %s\n",
+       GCP_2s (cp));
+  cp->destroy_task = NULL;
+  GNUNET_assert (NULL == cp->t);
+  GNUNET_assert (NULL == cp->core_mq);
+  GNUNET_assert (0 == cp->num_paths);
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+    GNUNET_assert (NULL == cp->path_heads[i]);
+  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_remove (peers,
+                                                       &cp->pid,
+                                                       cp));
+  GNUNET_free_non_null (cp->path_heads);
+  GNUNET_free_non_null (cp->path_tails);
+  cp->path_dll_length = 0;
+  if (NULL != cp->search_h)
+  {
+    GCD_search_stop (cp->search_h);
+    cp->search_h = NULL;
+  }
+  /* FIXME: clean up search_delayedXXX! */
+
+  if (NULL != cp->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+    cp->hello_offer = NULL;
+  }
+  if (NULL != cp->connectivity_suggestion)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+    cp->connectivity_suggestion = NULL;
+  }
+  GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
+  if (NULL != cp->path_heap)
+  {
+    GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+    cp->path_heap = NULL;
+  }
+  if (NULL != cp->heap_cleanup_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
+    cp->heap_cleanup_task = NULL;
+  }
+  GNUNET_free_non_null (cp->hello);
+  /* Peer should not be freed if paths exist; if there are no paths,
+     there ought to be no connections, and without connections, no
+     notifications. Thus we can assert that mqm_head is empty at this
+     point. */
+  GNUNET_assert (NULL == cp->mqm_head);
+  GNUNET_assert (NULL == cp->mqm_ready_ptr);
+  GNUNET_free (cp);
+}
+
+
+/**
+ * This peer is now on more "active" duty, activate processes related to it.
+ *
+ * @param cp the more-active peer
+ */
+static void
+consider_peer_activate (struct CadetPeer *cp)
+{
+  uint32_t strength;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Updating peer %s activation state (%u connections)%s%s\n",
+       GCP_2s (cp),
+       GNUNET_CONTAINER_multishortmap_size (cp->connections),
+       (NULL == cp->t) ? "" : " with tunnel",
+       (NULL == cp->core_mq) ? "" : " with CORE link");
+  if (NULL != cp->destroy_task)
+  {
+    /* It's active, do not destory! */
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
+       (NULL == cp->t) )
+  {
+    /* We're just on a path or directly connected; don't bother too much */
+    if (NULL != cp->connectivity_suggestion)
+    {
+      GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+      cp->connectivity_suggestion = NULL;
+    }
+    if (NULL != cp->search_h)
+    {
+      GCD_search_stop (cp->search_h);
+      cp->search_h = NULL;
+    }
+    return;
+  }
+  if (NULL == cp->core_mq)
+  {
+    /* Lacks direct connection, try to create one by querying the DHT */
+    if ( (NULL == cp->search_h) &&
+         (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+      cp->search_h
+        = GCD_search (&cp->pid);
+  }
+  else
+  {
+    /* Have direct connection, stop DHT search if active */
+    if (NULL != cp->search_h)
+    {
+      GCD_search_stop (cp->search_h);
+      cp->search_h = NULL;
+    }
+  }
+
+  /* If we have a tunnel, our urge for connections is much bigger */
+  strength = (NULL != cp->t) ? 32 : 1;
+  if (NULL != cp->connectivity_suggestion)
+    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+  cp->connectivity_suggestion
+    = GNUNET_ATS_connectivity_suggest (ats_ch,
+                                       &cp->pid,
+                                       strength);
+}
+
+
+/**
+ * This peer may no longer be needed, consider cleaning it up.
+ *
+ * @param cp peer to clean up
+ */
+static void
+consider_peer_destroy (struct CadetPeer *cp);
+
+
+/**
+ * We really no longere care about a peer, stop hogging memory with paths to it.
+ * Afterwards, see if there is more to be cleaned up about this peer.
+ *
+ * @param cls a `struct CadetPeer`.
+ */
+static void
+drop_paths (void *cls)
+{
+  struct CadetPeer *cp = cls;
+  struct CadetPeerPath *path;
+
+  cp->destroy_task = NULL;
+  while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+    GCPP_release (path);
+  consider_peer_destroy (cp);
+}
+
+
+/**
+ * This peer may no longer be needed, consider cleaning it up.
+ *
+ * @param cp peer to clean up
+ */
+static void
+consider_peer_destroy (struct CadetPeer *cp)
+{
+  struct GNUNET_TIME_Relative exp;
+
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  if (NULL != cp->t)
+    return; /* still relevant! */
+  if (NULL != cp->core_mq)
+    return; /* still relevant! */
+  if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
+    return; /* still relevant! */
+  if ( (NULL != cp->path_heap) &&
+       (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
+  {
+    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
+                                                     &drop_paths,
+                                                     cp);
+    return;
+  }
+  if (0 != cp->num_paths)
+    return; /* still relevant! */
+  if (NULL != cp->hello)
+  {
+    /* relevant only until HELLO expires */
+    exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
+    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
+                                                     &destroy_peer,
+                                                     cp);
+    return;
+  }
+  cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
+                                                   &destroy_peer,
+                                                   cp);
+}
+
+
+/**
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
+ *
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
+ */
+void
+GCP_set_mq (struct CadetPeer *cp,
+            struct GNUNET_MQ_Handle *mq)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message queue for peer %s is now %p\n",
+       GCP_2s (cp),
+       mq);
+  cp->core_mq = mq;
+  for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
+       NULL != mqm;
+       mqm = next)
+  {
+    /* Save next pointer in case mqm gets freed by the callback */
+    next = mqm->next;
+    if (NULL == mq)
+    {
+      if (NULL != mqm->env)
+      {
+        GNUNET_MQ_discard (mqm->env);
+        mqm->env = NULL;
+        mqm->cb (mqm->cb_cls,
+                 GNUNET_SYSERR);
+      }
+      else
+      {
+        mqm->cb (mqm->cb_cls,
+                 GNUNET_NO);
+      }
+    }
+    else
+    {
+      GNUNET_assert (NULL == mqm->env);
+      mqm->cb (mqm->cb_cls,
+               GNUNET_YES);
+    }
+  }
+  if ( (NULL != mq) ||
+       (NULL != cp->t) )
+    consider_peer_activate (cp);
+  else
+    consider_peer_destroy (cp);
+
+  if ( (NULL != mq) &&
+       (NULL != cp->t) )
+  {
+    /* have a new, direct path to the target, notify tunnel */
+    struct CadetPeerPath *path;
+
+    path = GCPP_get_path_from_route (1,
+                                     &cp->pid);
+    GCT_consider_path (cp->t,
+                       path,
+                       0);
+  }
+}
+
+
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (void)
+{
+  if (0 == drop_percent)
+    return GNUNET_NO;
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                101) < drop_percent)
+    return GNUNET_YES;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
+ *
+ * @param cls the `struct CadetPeeer` where we made progress
+ */
+static void
+mqm_send_done (void *cls);
+
+
+/**
+ * Transmit current envelope from this @a mqm.
+ *
+ * @param mqm mqm to transmit message for now
+ */
+static void
+mqm_execute (struct GCP_MessageQueueManager *mqm)
+{
+  struct CadetPeer *cp = mqm->cp;
+
+  /* Move ready pointer to the next entry that might be ready. */
+  if ( (mqm == cp->mqm_ready_ptr) &&
+       (NULL != mqm->next) )
+    cp->mqm_ready_ptr = mqm->next;
+  /* Move entry to the end of the DLL, to be fair. */
+  if (mqm != cp->mqm_tail)
+  {
+    GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+                                 cp->mqm_tail,
+                                 mqm);
+    GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
+                                      cp->mqm_tail,
+                                      mqm);
+  }
+  cp->mqm_ready_counter--;
+  if (GNUNET_YES == should_I_drop ())
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "DROPPING message to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_discard (mqm->env);
+    mqm->env = NULL;
+    mqm_send_done (cp);
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Sending to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_send (cp->core_mq,
+                    mqm->env);
+    mqm->env = NULL;
+  }
+  mqm->cb (mqm->cb_cls,
+           GNUNET_YES);
+}
+
+
+/**
+ * Find the next ready message in the queue (starting
+ * the search from the `cp->mqm_ready_ptr`) and if possible
+ * execute the transmission.
+ *
+ * @param cp peer to try to send the next ready message to
+ */
+static void
+send_next_ready (struct CadetPeer *cp)
+{
+  struct GCP_MessageQueueManager *mqm;
+
+  if (0 == cp->mqm_ready_counter)
+    return;
+  while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
+          (NULL == mqm->env) )
+    cp->mqm_ready_ptr = mqm->next;
+  if (NULL == mqm)
+    return; /* nothing to do */
+  mqm_execute (mqm);
+}
+
+
+/**
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
+ *
+ * @param cls the `struct CadetPeeer` where we made progress
+ */
+static void
+mqm_send_done (void *cls)
+{
+  struct CadetPeer *cp = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending to peer %s completed\n",
+       GCP_2s (cp));
+  send_next_ready (cp);
+}
+
+
+/**
+ * Send the message in @a env to @a cp.
+ *
+ * @param mqm the message queue manager to use for transmission
+ * @param env envelope with the message to send; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
+ */
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+          struct GNUNET_MQ_Envelope *env)
+{
+  struct CadetPeer *cp = mqm->cp;
+
+  GNUNET_assert (NULL != env);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queueing message to peer %s in MQM %p\n",
+       GCP_2s (cp),
+       mqm);
+  GNUNET_assert (NULL != cp->core_mq);
+  GNUNET_assert (NULL == mqm->env);
+  GNUNET_MQ_notify_sent (env,
+                         &mqm_send_done,
+                         cp);
+  mqm->env = env;
+  cp->mqm_ready_counter++;
+  if (mqm != cp->mqm_ready_ptr)
+    cp->mqm_ready_ptr = cp->mqm_head;
+  if (1 == cp->mqm_ready_counter)
+    cp->mqm_ready_ptr = mqm;
+  if (0 != GNUNET_MQ_get_length (cp->core_mq))
+    return;
+  send_next_ready (cp);
+}
+
+
+/**
+ * Function called to destroy a peer now.
+ *
+ * @param cls NULL
+ * @param pid identity of the peer (unused)
+ * @param value the `struct CadetPeer` to clean up
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_iterator_cb (void *cls,
+                     const struct GNUNET_PeerIdentity *pid,
+                     void *value)
+{
+  struct CadetPeer *cp = value;
+
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  destroy_peer (cp);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
+ */
+void
+GCP_destroy_all_peers ()
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying all peers now\n");
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &destroy_iterator_cb,
+                                         NULL);
+}
+
+
+/**
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
+ *
+ * @param cp peer to drop paths to
+ */
+void
+GCP_drop_owned_paths (struct CadetPeer *cp)
+{
+  struct CadetPeerPath *path;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying all paths to %s\n",
+       GCP_2s (cp));
+  while (NULL != (path =
+                  GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+    GCPP_release (path);
+  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+  cp->path_heap = NULL;
+}
+
+
+/**
+ * Add an entry to the DLL of all of the paths that this peer is on.
+ *
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
+ */
+void
+GCP_path_entry_add (struct CadetPeer *cp,
+                    struct CadetPeerPathEntry *entry,
+                    unsigned int off)
+{
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
+                                                off));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Discovered that peer %s is on path %s at offset %u\n",
+       GCP_2s (cp),
+       GCPP_2s (entry->path),
+       off);
+  if (off >= cp->path_dll_length)
+  {
+    unsigned int len = cp->path_dll_length;
+
+    GNUNET_array_grow (cp->path_heads,
+                       len,
+                       off + 4);
+    GNUNET_array_grow (cp->path_tails,
+                       cp->path_dll_length,
+                       off + 4);
+  }
+  GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
+                               cp->path_tails[off],
+                               entry);
+  cp->off_sum += off;
+  cp->num_paths++;
+
+  /* If we have a tunnel to this peer, tell the tunnel that there is a
+     new path available. */
+  if (NULL != cp->t)
+    GCT_consider_path (cp->t,
+                       entry->path,
+                       off);
+
+  if ( (NULL != cp->search_h) &&
+       (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
+  {
+    /* Now I have enough paths, stop search */
+    GCD_search_stop (cp->search_h);
+    cp->search_h = NULL;
+  }
+  if (NULL != cp->destroy_task)
+  {
+    /* paths changed, this resets the destroy timeout counter
+       and aborts a destroy task that may no longer be valid
+       to have (as we now have more paths via this peer). */
+    consider_peer_destroy (cp);
+  }
+}
+
+
+/**
+ * Remove an entry from the DLL of all of the paths that this peer is on.
+ *
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
+ */
+void
+GCP_path_entry_remove (struct CadetPeer *cp,
+                       struct CadetPeerPathEntry *entry,
+                       unsigned int off)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing knowledge about peer %s beging on path %s at offset %u\n",
+       GCP_2s (cp),
+       GCPP_2s (entry->path),
+       off);
+  GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
+                               cp->path_tails[off],
+                               entry);
+  GNUNET_assert (0 < cp->num_paths);
+  cp->off_sum -= off;
+  cp->num_paths--;
+  if ( (NULL == cp->core_mq) &&
+       (NULL != cp->t) &&
+       (NULL == cp->search_h) &&
+       (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+    cp->search_h
+      = GCD_search (&cp->pid);
+  if (NULL == cp->destroy_task)
+  {
+    /* paths changed, we might now be ready for destruction, check again */
+    consider_peer_destroy (cp);
+  }
+}
+
+
+/**
+ * Prune down the number of paths to this peer, we seem to
+ * have way too many.
+ *
+ * @param cls the `struct CadetPeer` to maintain the path heap for
+ */
+static void
+path_heap_cleanup (void *cls)
+{
+  struct CadetPeer *cp = cls;
+  struct CadetPeerPath *root;
+
+  cp->heap_cleanup_task = NULL;
+  while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+         2 * DESIRED_CONNECTIONS_PER_TUNNEL)
+  {
+    /* Now we have way too many, drop least desirable UNLESS it is in use!
+       (Note that this intentionally keeps highly desireable, but currently
+       unused paths around in the hope that we might be able to switch, even
+       if the number of paths exceeds the threshold.) */
+    root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
+    GNUNET_assert (NULL != root);
+    if (NULL !=
+        GCPP_get_connection (root,
+                             cp,
+                             GCPP_get_length (root) - 1))
+      break; /* can't fix */
+    /* Got plenty of paths to this destination, and this is a low-quality
+       one that we don't care about. Allow it to die. */
+    GNUNET_assert (root ==
+                   GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
+    GCPP_release (root);
+  }
+}
+
+
+/**
+ * Try adding a @a path to this @a peer.  If the peer already
+ * has plenty of paths, return NULL.
+ *
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force force attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
+ */
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 unsigned int off,
+                 int force)
+{
+  GNUNET_CONTAINER_HeapCostType desirability;
+  struct CadetPeerPath *root;
+  GNUNET_CONTAINER_HeapCostType root_desirability;
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  GNUNET_assert (off == GCPP_get_length (path) - 1);
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
+                                                off));
+  if (NULL == cp->path_heap)
+  {
+    /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
+    GNUNET_assert (GNUNET_NO == force);
+    return NULL;
+  }
+  desirability = GCPP_get_desirability (path);
+  if (GNUNET_NO == force)
+  {
+    /* FIXME: desirability is not yet initialized; tricky! */
+    if (GNUNET_NO ==
+        GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
+                                     (void **) &root,
+                                     &root_desirability))
+    {
+      root = NULL;
+      root_desirability = 0;
+    }
+
+    if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
+         (desirability < root_desirability) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Decided to not attach path %p to peer %s due to undesirability\n",
+           GCPP_2s (path),
+           GCP_2s (cp));
+      return NULL;
+    }
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Attaching path %s to peer %s (%s)\n",
+       GCPP_2s (path),
+       GCP_2s (cp),
+       (GNUNET_NO == force) ? "desirable" : "forced");
+
+  /* Yes, we'd like to add this path, add to our heap */
+  hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
+                                     path,
+                                     desirability);
+
+  /* Consider maybe dropping other paths because of the new one */
+  if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+        2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (NULL != cp->heap_cleanup_task) )
+    cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
+                                                      cp);
+  return hn;
+}
+
+
+/**
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
+ *
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
+ */
+void
+GCP_detach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 struct GNUNET_CONTAINER_HeapNode *hn)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Detatching path %s from peer %s\n",
+       GCPP_2s (path),
+       GCP_2s (cp));
+  GNUNET_assert (path ==
+                 GNUNET_CONTAINER_heap_remove_node (hn));
+}
+
+
+/**
+ * Add a @a connection to this @a cp.
+ *
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
+ */
+void
+GCP_add_connection (struct CadetPeer *cp,
+                    struct CadetConnection *cc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding connection %s to peer %s\n",
+       GCC_2s (cc),
+       GCP_2s (cp));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (cp->connections,
+                                                     &GCC_get_id (cc)->connection_of_tunnel,
+                                                     cc,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+}
+
+
+/**
+ * Remove a @a connection that went via this @a cp.
+ *
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
+ */
+void
+GCP_remove_connection (struct CadetPeer *cp,
+                       struct CadetConnection *cc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing connection %s from peer %s\n",
+       GCC_2s (cc),
+       GCP_2s (cp));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
+                                                        &GCC_get_id (cc)->connection_of_tunnel,
+                                                        cc));
+  consider_peer_destroy (cp);
+}
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ *               #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ *         NULL if unknown and not requested @a create
+ */
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+         int create)
+{
+  struct CadetPeer *cp;
+
+  cp = GNUNET_CONTAINER_multipeermap_get (peers,
+                                          peer_id);
+  if (NULL != cp)
+    return cp;
+  if (GNUNET_NO == create)
+    return NULL;
+  cp = GNUNET_new (struct CadetPeer);
+  cp->pid = *peer_id;
+  cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
+                                                           GNUNET_YES);
+  cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_put (peers,
+                                                    &cp->pid,
+                                                    cp,
+                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating peer %s\n",
+       GCP_2s (cp));
+  return cp;
+}
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @return the peer identity
+ */
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp)
+{
+  return &cp->pid;
+}
+
+
+/**
+ * Iterate over all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls)
+{
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         iter,
+                                         cls);
+}
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp)
+{
+  return cp->num_paths;
+}
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+                   GCP_PathIterator callback,
+                   void *callback_cls)
+{
+  unsigned int ret = 0;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Iterating over paths to peer %s%s\n",
+       GCP_2s (cp),
+       (NULL == cp->core_mq) ? "" : " including direct link");
+  if (NULL != cp->core_mq)
+  {
+    struct CadetPeerPath *path;
+
+    path = GCPP_get_path_from_route (1,
+                                     &cp->pid);
+    ret++;
+    if (GNUNET_NO ==
+        callback (callback_cls,
+                  path,
+                  0))
+      return ret;
+  }
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+  {
+    for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
+         NULL != pe;
+         pe = pe->next)
+    {
+      ret++;
+      if (GNUNET_NO ==
+          callback (callback_cls,
+                    pe->path,
+                    i))
+        return ret;
+    }
+  }
+  return ret;
+}
+
+
+/**
+ * Iterate over the paths to @a cp where
+ * @a cp is at distance @a dist from us.
+ *
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a cp to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+                      unsigned int dist,
+                      GCP_PathIterator callback,
+                      void *callback_cls)
+{
+  unsigned int ret = 0;
+
+  if (dist >= cp->path_dll_length)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Asked to look for paths at distance %u, but maximum for me is < %u\n",
+         dist,
+         cp->path_dll_length);
+    return 0;
+  }
+  for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
+       NULL != pe;
+       pe = pe->next)
+  {
+    if (GNUNET_NO ==
+        callback (callback_cls,
+                  pe->path,
+                  dist))
+      return ret;
+    ret++;
+  }
+  return ret;
+}
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *cp,
+                int create)
+{
+  if (NULL == cp)
+    return NULL;
+  if ( (NULL != cp->t) ||
+       (GNUNET_NO == create) )
+    return cp->t;
+  cp->t = GCT_create_tunnel (cp);
+  consider_peer_activate (cp);
+  return cp->t;
+}
+
+
+/**
+ * Hello offer was passed to the transport service. Mark it
+ * as done.
+ *
+ * @param cls the `struct CadetPeer` where the offer completed
+ */
+static void
+hello_offer_done (void *cls)
+{
+  struct CadetPeer *cp = cls;
+
+  cp->hello_offer = NULL;
+}
+
+
+/**
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *cp,
+               const struct GNUNET_HELLO_Message *hello)
+{
+  struct GNUNET_HELLO_Message *mrg;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got %u byte HELLO for peer %s\n",
+       (unsigned int) GNUNET_HELLO_size (hello),
+       GCP_2s (cp));
+  if (NULL != cp->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+    cp->hello_offer = NULL;
+  }
+  if (NULL != cp->hello)
+  {
+    mrg = GNUNET_HELLO_merge (hello,
+                              cp->hello);
+    GNUNET_free (cp->hello);
+    cp->hello = mrg;
+  }
+  else
+  {
+    cp->hello = GNUNET_memdup (hello,
+                               GNUNET_HELLO_size (hello));
+  }
+  cp->hello_offer
+    = GNUNET_TRANSPORT_offer_hello (cfg,
+                                    GNUNET_HELLO_get_header (cp->hello) ,
+                                    &hello_offer_done,
+                                    cp);
+  /* New HELLO means cp's destruction time may change... */
+  consider_peer_destroy (cp);
+}
+
+
+/**
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
+ *
+ * @param cp the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *cp,
+                 struct CadetTunnel *t)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Dropping tunnel %s to peer %s\n",
+       GCT_2s (t),
+       GCP_2s (cp));
+  GNUNET_assert (cp->t == t);
+  cp->t = NULL;
+  consider_peer_destroy (cp);
+}
+
+
+/**
+ * Test if @a cp has a core-level connection
+ *
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
+ */
+int
+GCP_has_core_connection (struct CadetPeer *cp)
+{
+  return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
+}
+
+
+/**
+ * Start message queue change notifications.
+ *
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
+ */
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+                GCP_MessageQueueNotificationCallback cb,
+                void *cb_cls)
+{
+  struct GCP_MessageQueueManager *mqm;
+
+  mqm = GNUNET_new (struct GCP_MessageQueueManager);
+  mqm->cb = cb;
+  mqm->cb_cls = cb_cls;
+  mqm->cp = cp;
+  GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
+                               cp->mqm_tail,
+                               mqm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating MQM %p for peer %s\n",
+       mqm,
+       GCP_2s (cp));
+  if (NULL != cp->core_mq)
+    cb (cb_cls,
+        GNUNET_YES);
+  return mqm;
+}
+
+
+/**
+ * Stops message queue change notifications.
+ *
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
+ */
+void
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+                       struct GNUNET_MQ_Envelope *last_env)
+{
+  struct CadetPeer *cp = mqm->cp;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying MQM %p for peer %s%s\n",
+       mqm,
+       GCP_2s (cp),
+       (NULL == last_env) ? "" : " with last ditch transmission");
+  if (NULL != mqm->env)
+    GNUNET_MQ_discard (mqm->env);
+  if (NULL != last_env)
+  {
+    if (NULL != cp->core_mq)
+    {
+      GNUNET_MQ_notify_sent (last_env,
+                             &mqm_send_done,
+                             cp);
+      GNUNET_MQ_send (cp->core_mq,
+                      last_env);
+    }
+    else
+    {
+      GNUNET_MQ_discard (last_env);
+    }
+  }
+  if (cp->mqm_ready_ptr == mqm)
+    cp->mqm_ready_ptr = mqm->next;
+  GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+                               cp->mqm_tail,
+                               mqm);
+  GNUNET_free (mqm);
+}
+
+
+/**
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP.  Note that
+ * the envelope may be silently discarded as well.
+ *
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
+ */
+void
+GCP_send_ooo (struct CadetPeer *cp,
+              struct GNUNET_MQ_Envelope *env)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message to %s out of management\n",
+       GCP_2s (cp));
+  if (NULL == cp->core_mq)
+  {
+    GNUNET_MQ_discard (env);
+    return;
+  }
+  GNUNET_MQ_notify_sent (env,
+                         &mqm_send_done,
+                         cp);
+  GNUNET_MQ_send (cp->core_mq,
+                  env);
+}
+
+
+
+
+/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h
new file mode 100644 (file)
index 0000000..a2a6c6a
--- /dev/null
@@ -0,0 +1,394 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_peer.h
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_PEER_H
+#define GNUNET_SERVICE_CADET_PEER_H
+
+#include "gnunet-service-cadet.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Get the static string for a peer ID.
+ *
+ * @param peer Peer.
+ *
+ * @return Static string for it's ID.
+ */
+const char *
+GCP_2s (const struct CadetPeer *peer);
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ *               #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ *         NULL if unknown and not requested @a create
+ */
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+         int create);
+
+
+/**
+ * Calculate how desirable a path is for @a cp if
+ * @a cp is at offset @a off in the path.
+ *
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in a path
+ * @return score how useful a path is to reach @a cp,
+ *         positive scores mean path is more desirable
+ */
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+                              unsigned int off);
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @return the peer identity
+ */
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp);
+
+
+/**
+ * Iterate over all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls);
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp);
+
+
+/**
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
+ *
+ * @param cp peer to drop paths to
+ */
+void
+GCP_drop_owned_paths (struct CadetPeer *cp);
+
+
+/**
+ * Peer path iterator.
+ *
+ * @param cls Closure.
+ * @param path Path itself
+ * @param off offset of the target peer in @a path
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
+ */
+typedef int
+(*GCP_PathIterator) (void *cls,
+                     struct CadetPeerPath *path,
+                     unsigned int off);
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+                   GCP_PathIterator callback,
+                   void *callback_cls);
+
+
+/**
+ * Iterate over the paths to @a peer where
+ * @a peer is at distance @a dist from us.
+ *
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a peer to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+                      unsigned int dist,
+                      GCP_PathIterator callback,
+                      void *callback_cls);
+
+
+/**
+ * Remove an entry from the DLL of all of the paths that this peer is on.
+ *
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
+ */
+void
+GCP_path_entry_remove (struct CadetPeer *cp,
+                       struct CadetPeerPathEntry *entry,
+                       unsigned int off);
+
+
+/**
+ * Add an entry to the DLL of all of the paths that this peer is on.
+ *
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
+ */
+void
+GCP_path_entry_add (struct CadetPeer *cp,
+                    struct CadetPeerPathEntry *entry,
+                    unsigned int off);
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *cp,
+                int create);
+
+
+/**
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
+ *
+ * @param cp the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *cp,
+                 struct CadetTunnel *t);
+
+
+/**
+ * Try adding a @a path to this @a cp.  If the peer already
+ * has plenty of paths, return NULL.
+ *
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force for attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
+ */
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 unsigned int off,
+                 int force);
+
+
+/**
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
+ *
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
+ */
+void
+GCP_detach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 struct GNUNET_CONTAINER_HeapNode *hn);
+
+
+/**
+ * Add a @a connection to this @a cp.
+ *
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
+ */
+void
+GCP_add_connection (struct CadetPeer *cp,
+                    struct CadetConnection *cc);
+
+
+/**
+ * Remove a @a connection that went via this @a cp.
+ *
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
+ */
+void
+GCP_remove_connection (struct CadetPeer *cp,
+                       struct CadetConnection *cc);
+
+
+/**
+ * We got a HELLO for a @a cp, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *cp,
+               const struct GNUNET_HELLO_Message *hello);
+
+
+/**
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
+ */
+void
+GCP_destroy_all_peers (void);
+
+
+/**
+ * Data structure used to track whom we have to notify about changes
+ * in our ability to transmit to a given peer.
+ *
+ * All queue managers will be given equal chance for sending messages
+ * to @a cp.  This construct this guarantees fairness for access to @a
+ * cp among the different message queues.  Each connection or route
+ * will have its respective message queue managers for each direction.
+ */
+struct GCP_MessageQueueManager;
+
+
+/**
+ * Function to call with updated message queue object.
+ *
+ * @param cls closure
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
+ */
+typedef void
+(*GCP_MessageQueueNotificationCallback)(void *cls,
+                                        int available);
+
+
+/**
+ * Start message queue change notifications.  Will create a new slot
+ * to manage the message queue to the given @a cp.
+ *
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
+ */
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+                GCP_MessageQueueNotificationCallback cb,
+                void *cb_cls);
+
+
+/**
+ * Test if @a cp has a core-level connection
+ *
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
+ */
+int
+GCP_has_core_connection (struct CadetPeer *cp);
+
+
+/**
+ * Send the message in @a env via a @a mqm.  Must only be called at
+ * most once after the respective
+ * #GCP_MessageQueueNotificationCallback was called with `available`
+ * set to #GNUNET_YES, and not after the callback was called with
+ * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
+ *
+ * @param mqm message queue manager for the transmission
+ * @param env envelope with the message to send; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
+ */
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+          struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP.  Note that
+ * the envelope may be silently discarded as well.
+ *
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
+ */
+void
+GCP_send_ooo (struct CadetPeer *cp,
+              struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * Stops message queue change notifications and sends a last message.
+ * In practice, this is implemented by sending that @a last_env
+ * message immediately (if any), ignoring queue order.
+ *
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
+ */
+void
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+                       struct GNUNET_MQ_Envelope *last_env);
+
+
+/**
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
+ *
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
+ */
+void
+GCP_set_mq (struct CadetPeer *cp,
+            struct GNUNET_MQ_Handle *mq);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c
new file mode 100644 (file)
index 0000000..bcdeeb4
--- /dev/null
@@ -0,0 +1,3440 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2013, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_tunnels.c
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * FIXME:
+ * - proper connection evaluation during connection management:
+ *   + consider quality (or quality spread?) of current connection set
+ *     when deciding how often to do maintenance
+ *   + interact with PEER to drive DHT GET/PUT operations based
+ *     on how much we like our connections
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_signatures.h"
+#include "cadet_protocol.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
+
+/**
+ * How often do we try to decrypt payload with unverified key
+ * material?  Used to limit CPU increase upon receiving bogus
+ * KX.
+ */
+#define MAX_UNVERIFIED_ATTEMPTS 16
+
+/**
+ * How long do we wait until tearing down an idle tunnel?
+ */
+#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
+
+/**
+ * How long do we wait initially before retransmitting the KX?
+ * TODO: replace by 2 RTT if/once we have connection-level RTT data!
+ */
+#define INITIAL_KX_RETRY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
+
+/**
+ * Maximum number of skipped keys we keep in memory per tunnel.
+ */
+#define MAX_SKIPPED_KEYS 64
+
+/**
+ * Maximum number of keys (and thus ratchet steps) we are willing to
+ * skip before we decide this is either a bogus packet or a DoS-attempt.
+ */
+#define MAX_KEY_GAP 256
+
+
+/**
+ * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
+ */
+struct CadetTunnelSkippedKey
+{
+  /**
+   * DLL next.
+   */
+  struct CadetTunnelSkippedKey *next;
+
+  /**
+   * DLL prev.
+   */
+  struct CadetTunnelSkippedKey *prev;
+
+  /**
+   * When was this key stored (for timeout).
+   */
+  struct GNUNET_TIME_Absolute timestamp;
+
+  /**
+   * Header key.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HK;
+
+  /**
+   * Message key.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+
+  /**
+   * Key number for a given HK.
+   */
+  unsigned int Kn;
+};
+
+
+/**
+ * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
+ */
+struct CadetTunnelAxolotl
+{
+  /**
+   * A (double linked) list of stored message keys and associated header keys
+   * for "skipped" messages, i.e. messages that have not been
+   * received despite the reception of more recent messages, (head).
+   */
+  struct CadetTunnelSkippedKey *skipped_head;
+
+  /**
+   * Skipped messages' keys DLL, tail.
+   */
+  struct CadetTunnelSkippedKey *skipped_tail;
+
+  /**
+   * 32-byte root key which gets updated by DH ratchet.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey RK;
+
+  /**
+   * 32-byte header key (currently used for sending).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
+
+  /**
+   * 32-byte header key (currently used for receiving)
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
+
+  /**
+   * 32-byte next header key (for sending), used once the
+   * ratchet advances.  We are sure that the sender has this
+   * key as well only after @e ratchet_allowed is #GNUNET_YES.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
+
+  /**
+   * 32-byte next header key (for receiving).  To be tried
+   * when decrypting with @e HKr fails and thus the sender
+   * may have advanced the ratchet.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy) for
+   * sending messages. Updated for every message.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy) for
+   * receiving messages. Updated for every message. If
+   * messages are skipped, the respective derived MKs
+   * (and the current @HKr) are kept in the @e skipped_head DLL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
+
+  /**
+   * ECDH for key exchange (A0 / B0).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
+
+  /**
+   * ECDH Ratchet key (our private key in the current DH).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
+
+  /**
+   * ECDH Ratchet key (other peer's public key in the current DH).
+   */
+  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
+
+  /**
+   * Time when the current ratchet expires and a new one is triggered
+   * (if @e ratchet_allowed is #GNUNET_YES).
+   */
+  struct GNUNET_TIME_Absolute ratchet_expiration;
+
+  /**
+   * Number of elements in @a skipped_head <-> @a skipped_tail.
+   */
+  unsigned int skipped;
+
+  /**
+   * Message number (reset to 0 with each new ratchet, next message to send).
+   */
+  uint32_t Ns;
+
+  /**
+   * Message number (reset to 0 with each new ratchet, next message to recv).
+   */
+  uint32_t Nr;
+
+  /**
+   * Previous message numbers (# of msgs sent under prev ratchet)
+   */
+  uint32_t PNs;
+
+  /**
+   * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
+   */
+  int ratchet_flag;
+
+  /**
+   * True (#GNUNET_YES) if we have received a message from the
+   * other peer that uses the keys from our last ratchet step.
+   * This implies that we are again allowed to advance the ratchet,
+   * otherwise we have to wait until the other peer sees our current
+   * ephemeral key and advances first.
+   *
+   * #GNUNET_NO if we have advanced the ratched but lack any evidence
+   * that the other peer has noticed this.
+   */
+  int ratchet_allowed;
+
+  /**
+   * Number of messages recieved since our last ratchet advance.
+   *
+   * If this counter = 0, we cannot send a new ratchet key in the next
+   * message.
+   *
+   * If this counter > 0, we could (but don't have to) send a new key.
+   *
+   * Once the @e ratchet_counter is larger than
+   * #ratchet_messages (or @e ratchet_expiration time has past), and
+   * @e ratchet_allowed is #GNUNET_YES, we advance the ratchet.
+   */
+  unsigned int ratchet_counter;
+
+};
+
+
+/**
+ * Struct used to save messages in a non-ready tunnel to send once connected.
+ */
+struct CadetTunnelQueueEntry
+{
+  /**
+   * We are entries in a DLL
+   */
+  struct CadetTunnelQueueEntry *next;
+
+  /**
+   * We are entries in a DLL
+   */
+  struct CadetTunnelQueueEntry *prev;
+
+  /**
+   * Tunnel these messages belong in.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Continuation to call once sent (on the channel layer).
+   */
+  GCT_SendContinuation cont;
+
+  /**
+   * Closure for @c cont.
+   */
+  void *cont_cls;
+
+  /**
+   * Envelope of message to send follows.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+  /**
+   * Where to put the connection identifier into the payload
+   * of the message in @e env once we have it?
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
+};
+
+
+/**
+ * Struct containing all information regarding a tunnel to a peer.
+ */
+struct CadetTunnel
+{
+  /**
+   * Destination of the tunnel.
+   */
+  struct CadetPeer *destination;
+
+  /**
+   * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
+   * ephemeral key changes.
+   */
+  struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
+
+  /**
+   * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
+
+  /**
+   * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
+
+  /**
+   * Axolotl info.
+   */
+  struct CadetTunnelAxolotl ax;
+
+  /**
+   * Unverified Axolotl info, used only if we got a fresh KX (not a
+   * KX_AUTH) while our end of the tunnel was still up.  In this case,
+   * we keep the fresh KX around but do not put it into action until
+   * we got encrypted payload that assures us of the authenticity of
+   * the KX.
+   */
+  struct CadetTunnelAxolotl *unverified_ax;
+
+  /**
+   * Task scheduled if there are no more channels using the tunnel.
+   */
+  struct GNUNET_SCHEDULER_Task *destroy_task;
+
+  /**
+   * Task to trim connections if too many are present.
+   */
+  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
+
+  /**
+   * Task to send messages from queue (if possible).
+   */
+  struct GNUNET_SCHEDULER_Task *send_task;
+
+  /**
+   * Task to trigger KX.
+   */
+  struct GNUNET_SCHEDULER_Task *kx_task;
+
+  /**
+   * Tokenizer for decrypted messages.
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
+
+  /**
+   * Dispatcher for decrypted messages only (do NOT use for sending!).
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * DLL of ready connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_ready_head;
+
+  /**
+   * DLL of ready connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_ready_tail;
+
+  /**
+   * DLL of connections that we maintain that might be used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_busy_head;
+
+  /**
+   * DLL of connections that we maintain that might be used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_busy_tail;
+
+  /**
+   * Channels inside this tunnel. Maps
+   * `struct GNUNET_CADET_ChannelTunnelNumber` to a `struct CadetChannel`.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+  /**
+   * Channel ID for the next created channel in this tunnel.
+   */
+  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_head;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_tail;
+
+  /**
+   * Identification of the connection from which we are currently processing
+   * a message. Only valid (non-NULL) during #handle_decrypted() and the
+   * handle-*()-functions called from our @e mq during that function.
+   */
+  struct CadetTConnection *current_ct;
+
+  /**
+   * How long do we wait until we retry the KX?
+   */
+  struct GNUNET_TIME_Relative kx_retry_delay;
+
+  /**
+   * When do we try the next KX?
+   */
+  struct GNUNET_TIME_Absolute next_kx_attempt;
+
+  /**
+   * Number of connections in the @e connection_ready_head DLL.
+   */
+  unsigned int num_ready_connections;
+
+  /**
+   * Number of connections in the @e connection_busy_head DLL.
+   */
+  unsigned int num_busy_connections;
+
+  /**
+   * How often have we tried and failed to decrypt a message using
+   * the unverified KX material from @e unverified_ax?  Used to
+   * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
+   */
+  unsigned int unverified_attempts;
+
+  /**
+   * Number of entries in the @e tq_head DLL.
+   */
+  unsigned int tq_len;
+
+  /**
+   * State of the tunnel encryption.
+   */
+  enum CadetTunnelEState estate;
+
+  /**
+   * Force triggering KX_AUTH independent of @e estate.
+   */
+  int kx_auth_requested;
+
+};
+
+
+/**
+ * Connection @a ct is now unready, clear it's ready flag
+ * and move it from the ready DLL to the busy DLL.
+ *
+ * @param ct connection to move to unready status
+ */
+static void
+mark_connection_unready (struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = ct->t;
+
+  GNUNET_assert (GNUNET_YES == ct->is_ready);
+  GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
+                               t->connection_ready_tail,
+                               ct);
+  GNUNET_assert (0 < t->num_ready_connections);
+  t->num_ready_connections--;
+  ct->is_ready = GNUNET_NO;
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+}
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t)
+{
+  static char buf[64];
+
+  if (NULL == t)
+    return "Tunnel(NULL)";
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Tunnel %s",
+                   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_AX_RECV:
+    return "CADET_TUNNEL_KEY_AX_RECV";
+  case CADET_TUNNEL_KEY_AX_SENT:
+    return "CADET_TUNNEL_KEY_AX_SENT";
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    return "CADET_TUNNEL_KEY_AX_SENT_AND_RECV";
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
+  case CADET_TUNNEL_KEY_OK:
+    return "CADET_TUNNEL_KEY_OK";
+  default:
+    GNUNET_snprintf (buf,
+                     sizeof (buf),
+                     "%u (UNKNOWN STATE)",
+                     es);
+    return buf;
+  }
+}
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t)
+{
+  return t->destination;
+}
+
+
+/**
+ * Count channels of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of channels.
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t)
+{
+  return GNUNET_CONTAINER_multihashmap32_size (t->channels);
+}
+
+
+/**
+ * Lookup a channel by its @a ctn.
+ *
+ * @param t tunnel to look in
+ * @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 ctn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ntohl (ctn.cn));
+}
+
+
+/**
+ * Count all created connections of a tunnel. Not necessarily ready connections!
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of connections created, either being established or ready.
+ */
+unsigned int
+GCT_count_any_connections (const struct CadetTunnel *t)
+{
+  return t->num_ready_connections + t->num_busy_connections;
+}
+
+
+/**
+ * Find first connection that is ready in the list of
+ * our connections.  Picks ready connections round-robin.
+ *
+ * @param t tunnel to search
+ * @return NULL if we have no connection that is ready
+ */
+static struct CadetTConnection *
+get_ready_connection (struct CadetTunnel *t)
+{
+  struct CadetTConnection *hd = t->connection_ready_head;
+
+  GNUNET_assert ( (NULL == hd) ||
+                  (GNUNET_YES == hd->is_ready) );
+  return hd;
+}
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t)
+{
+  return t->estate;
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param cls the `struct CadetTunnel` to process messages on
+ */
+static void
+trigger_transmissions (void *cls);
+
+
+/* ************************************** start core crypto ***************************** */
+
+
+/**
+ * Create a new Axolotl ephemeral (ratchet) key.
+ *
+ * @param ax key material to update
+ */
+static void
+new_ephemeral (struct CadetTunnelAxolotl *ax)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating new ephemeral ratchet key (DHRs)\n");
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
+}
+
+
+/**
+ * Calculate HMAC.
+ *
+ * @param plaintext Content to HMAC.
+ * @param size Size of @c plaintext.
+ * @param iv Initialization vector for the message.
+ * @param key Key to use.
+ * @param hmac[out] Destination to store the HMAC.
+ */
+static void
+t_hmac (const void *plaintext,
+        size_t size,
+        uint32_t iv,
+        const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+        struct GNUNET_ShortHashCode *hmac)
+{
+  static const char ctx[] = "cadet authentication key";
+  struct GNUNET_CRYPTO_AuthKey auth_key;
+  struct GNUNET_HashCode hash;
+
+  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
+                                 key,
+                                 &iv, sizeof (iv),
+                                 key, sizeof (*key),
+                                 ctx, sizeof (ctx),
+                                 NULL);
+  /* Two step: GNUNET_ShortHash is only 256 bits,
+     GNUNET_HashCode is 512, so we truncate. */
+  GNUNET_CRYPTO_hmac (&auth_key,
+                      plaintext,
+                      size,
+                      &hash);
+  GNUNET_memcpy (hmac,
+                 &hash,
+                 sizeof (*hmac));
+}
+
+
+/**
+ * Perform a HMAC.
+ *
+ * @param key Key to use.
+ * @param[out] hash Resulting HMAC.
+ * @param source Source key material (data to HMAC).
+ * @param len Length of @a source.
+ */
+static void
+t_ax_hmac_hash (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+                struct GNUNET_HashCode *hash,
+                const void *source,
+                unsigned int len)
+{
+  static const char ctx[] = "axolotl HMAC-HASH";
+  struct GNUNET_CRYPTO_AuthKey auth_key;
+
+  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
+                                 key,
+                                 ctx, sizeof (ctx),
+                                 NULL);
+  GNUNET_CRYPTO_hmac (&auth_key,
+                      source,
+                      len,
+                      hash);
+}
+
+
+/**
+ * Derive a symmetric encryption key from an HMAC-HASH.
+ *
+ * @param key Key to use for the HMAC.
+ * @param[out] out Key to generate.
+ * @param source Source key material (data to HMAC).
+ * @param len Length of @a source.
+ */
+static void
+t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
+                   const void *source,
+                   unsigned int len)
+{
+  static const char ctx[] = "axolotl derive key";
+  struct GNUNET_HashCode h;
+
+  t_ax_hmac_hash (key,
+                  &h,
+                  source,
+                  len);
+  GNUNET_CRYPTO_kdf (out, sizeof (*out),
+                     ctx, sizeof (ctx),
+                     &h, sizeof (h),
+                     NULL);
+}
+
+
+/**
+ * Encrypt data with the axolotl tunnel key.
+ *
+ * @param ax key material to use.
+ * @param dst Destination with @a size bytes for the encrypted data.
+ * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
+ * @param size Size of the buffers at @a src and @a dst
+ */
+static void
+t_ax_encrypt (struct CadetTunnelAxolotl *ax,
+              void *dst,
+              const void *src,
+              size_t size)
+{
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  ax->ratchet_counter++;
+  if ( (GNUNET_YES == ax->ratchet_allowed) &&
+       ( (ratchet_messages <= ax->ratchet_counter) ||
+         (0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) )
+  {
+    ax->ratchet_flag = GNUNET_YES;
+  }
+  if (GNUNET_YES == ax->ratchet_flag)
+  {
+    /* Advance ratchet */
+    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
+    struct GNUNET_HashCode dh;
+    struct GNUNET_HashCode hmac;
+    static const char ctx[] = "axolotl ratchet";
+
+    new_ephemeral (ax);
+    ax->HKs = ax->NHKs;
+
+    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
+    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
+                            &ax->DHRr,
+                            &dh);
+    t_ax_hmac_hash (&ax->RK,
+                    &hmac,
+                    &dh,
+                    sizeof (dh));
+    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                       ctx, sizeof (ctx),
+                       &hmac, sizeof (hmac),
+                       NULL);
+    ax->RK = keys[0];
+    ax->NHKs = keys[1];
+    ax->CKs = keys[2];
+
+    ax->PNs = ax->Ns;
+    ax->Ns = 0;
+    ax->ratchet_flag = GNUNET_NO;
+    ax->ratchet_allowed = GNUNET_NO;
+    ax->ratchet_counter = 0;
+    ax->ratchet_expiration
+      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+                                  ratchet_time);
+  }
+
+  t_hmac_derive_key (&ax->CKs,
+                     &MK,
+                     "0",
+                     1);
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &MK,
+                                     NULL, 0,
+                                     NULL);
+
+  out_size = GNUNET_CRYPTO_symmetric_encrypt (src,
+                                              size,
+                                              &MK,
+                                              &iv,
+                                              dst);
+  GNUNET_assert (size == out_size);
+  t_hmac_derive_key (&ax->CKs,
+                     &ax->CKs,
+                     "1",
+                     1);
+}
+
+
+/**
+ * Decrypt data with the axolotl tunnel key.
+ *
+ * @param ax key material to use.
+ * @param dst Destination for the decrypted data, must contain @a size bytes.
+ * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes.
+ * @param size Size of the @a src and @a dst buffers
+ */
+static void
+t_ax_decrypt (struct CadetTunnelAxolotl *ax,
+              void *dst,
+              const void *src,
+              size_t size)
+{
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  t_hmac_derive_key (&ax->CKr,
+                     &MK,
+                     "0",
+                     1);
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &MK,
+                                     NULL, 0,
+                                     NULL);
+  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
+  out_size = GNUNET_CRYPTO_symmetric_decrypt (src,
+                                              size,
+                                              &MK,
+                                              &iv,
+                                              dst);
+  GNUNET_assert (out_size == size);
+  t_hmac_derive_key (&ax->CKr,
+                     &ax->CKr,
+                     "1",
+                     1);
+}
+
+
+/**
+ * Encrypt header with the axolotl header key.
+ *
+ * @param ax key material to use.
+ * @param[in|out] msg Message whose header to encrypt.
+ */
+static void
+t_h_encrypt (struct CadetTunnelAxolotl *ax,
+             struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &ax->HKs,
+                                     NULL, 0,
+                                     NULL);
+  out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->ax_header,
+                                              sizeof (struct GNUNET_CADET_AxHeader),
+                                              &ax->HKs,
+                                              &iv,
+                                              &msg->ax_header);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
+}
+
+
+/**
+ * Decrypt header with the current axolotl header key.
+ *
+ * @param ax key material to use.
+ * @param src Message whose header to decrypt.
+ * @param dst Where to decrypt header to.
+ */
+static void
+t_h_decrypt (struct CadetTunnelAxolotl *ax,
+             const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
+{
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &ax->HKr,
+                                     NULL, 0,
+                                     NULL);
+  out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
+                                              sizeof (struct GNUNET_CADET_AxHeader),
+                                              &ax->HKr,
+                                              &iv,
+                                              &dst->ax_header.Ns);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
+}
+
+
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param ax key material to delete @a key from.
+ * @param key Key to delete.
+ */
+static void
+delete_skipped_key (struct CadetTunnelAxolotl *ax,
+                    struct CadetTunnelSkippedKey *key)
+{
+  GNUNET_CONTAINER_DLL_remove (ax->skipped_head,
+                               ax->skipped_tail,
+                               key);
+  GNUNET_free (key);
+  ax->skipped--;
+}
+
+
+/**
+ * Decrypt and verify data with the appropriate tunnel key and verify that the
+ * data has not been altered since it was sent by the remote peer.
+ *
+ * @param ax key material to use.
+ * @param dst Destination for the plaintext.
+ * @param src Source of the message. Can overlap with @c dst.
+ * @param size Size of the message.
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static ssize_t
+try_old_ax_keys (struct CadetTunnelAxolotl *ax,
+                 void *dst,
+                 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+                 size_t size)
+{
+  struct CadetTunnelSkippedKey *key;
+  struct GNUNET_ShortHashCode *hmac;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
+  struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
+  size_t esize;
+  size_t res;
+  size_t len;
+  unsigned int N;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying skipped keys\n");
+  hmac = &plaintext_header.hmac;
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+
+  /* Find a correct Header Key */
+  valid_HK = NULL;
+  for (key = ax->skipped_head; NULL != key; key = key->next)
+  {
+    t_hmac (&src->ax_header,
+            sizeof (struct GNUNET_CADET_AxHeader) + esize,
+            0,
+            &key->HK,
+            hmac);
+    if (0 == memcmp (hmac,
+                     &src->hmac,
+                     sizeof (*hmac)))
+    {
+      valid_HK = &key->HK;
+      break;
+    }
+  }
+  if (NULL == key)
+    return -1;
+
+  /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
+  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
+  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+  GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
+
+  /* Decrypt header */
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &key->HK,
+                                     NULL, 0,
+                                     NULL);
+  res = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
+                                         sizeof (struct GNUNET_CADET_AxHeader),
+                                         &key->HK,
+                                         &iv,
+                                         &plaintext_header.ax_header.Ns);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == res);
+
+  /* Find the correct message key */
+  N = ntohl (plaintext_header.ax_header.Ns);
+  while ( (NULL != key) &&
+          (N != key->Kn) )
+    key = key->next;
+  if ( (NULL == key) ||
+       (0 != memcmp (&key->HK,
+                     valid_HK,
+                     sizeof (*valid_HK))) )
+    return -1;
+
+  /* Decrypt payload */
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &key->MK,
+                                     NULL,
+                                     0,
+                                     NULL);
+  res = GNUNET_CRYPTO_symmetric_decrypt (&src[1],
+                                         len,
+                                         &key->MK,
+                                         &iv,
+                                         dst);
+  delete_skipped_key (ax,
+                      key);
+  return res;
+}
+
+
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param ax key material to delete from.
+ * @param HKr Header Key to use.
+ */
+static void
+store_skipped_key (struct CadetTunnelAxolotl *ax,
+                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
+{
+  struct CadetTunnelSkippedKey *key;
+
+  key = GNUNET_new (struct CadetTunnelSkippedKey);
+  key->timestamp = GNUNET_TIME_absolute_get ();
+  key->Kn = ax->Nr;
+  key->HK = ax->HKr;
+  t_hmac_derive_key (&ax->CKr,
+                     &key->MK,
+                     "0",
+                     1);
+  t_hmac_derive_key (&ax->CKr,
+                     &ax->CKr,
+                     "1",
+                     1);
+  GNUNET_CONTAINER_DLL_insert (ax->skipped_head,
+                               ax->skipped_tail,
+                               key);
+  ax->skipped++;
+  ax->Nr++;
+}
+
+
+/**
+ * Stage skipped AX keys and calculate the message key.
+ * Stores each HK and MK for skipped messages.
+ *
+ * @param ax key material to use
+ * @param HKr Header key.
+ * @param Np Received meesage number.
+ * @return #GNUNET_OK if keys were stored.
+ *         #GNUNET_SYSERR if an error ocurred (@a Np not expected).
+ */
+static int
+store_ax_keys (struct CadetTunnelAxolotl *ax,
+               const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
+               uint32_t Np)
+{
+  int gap;
+
+  gap = Np - ax->Nr;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Storing skipped keys [%u, %u)\n",
+       ax->Nr,
+       Np);
+  if (MAX_KEY_GAP < gap)
+  {
+    /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */
+    /* TODO: start new key exchange on return */
+    GNUNET_break_op (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Got message %u, expected %u+\n",
+         Np,
+         ax->Nr);
+    return GNUNET_SYSERR;
+  }
+  if (0 > gap)
+  {
+    /* Delayed message: don't store keys, flag to try old keys. */
+    return GNUNET_SYSERR;
+  }
+
+  while (ax->Nr < Np)
+    store_skipped_key (ax,
+                       HKr);
+
+  while (ax->skipped > MAX_SKIPPED_KEYS)
+    delete_skipped_key (ax,
+                        ax->skipped_tail);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Decrypt and verify data with the appropriate tunnel key and verify that the
+ * data has not been altered since it was sent by the remote peer.
+ *
+ * @param ax key material to use
+ * @param dst Destination for the plaintext.
+ * @param src Source of the message. Can overlap with @c dst.
+ * @param size Size of the message.
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static ssize_t
+t_ax_decrypt_and_validate (struct CadetTunnelAxolotl *ax,
+                           void *dst,
+                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+                           size_t size)
+{
+  struct GNUNET_ShortHashCode msg_hmac;
+  struct GNUNET_HashCode hmac;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
+  uint32_t Np;
+  uint32_t PNp;
+  size_t esize; /* Size of encryped payload */
+
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+
+  /* Try current HK */
+  t_hmac (&src->ax_header,
+          sizeof (struct GNUNET_CADET_AxHeader) + esize,
+          0, &ax->HKr,
+          &msg_hmac);
+  if (0 != memcmp (&msg_hmac,
+                   &src->hmac,
+                   sizeof (msg_hmac)))
+  {
+    static const char ctx[] = "axolotl ratchet";
+    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
+    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
+    struct GNUNET_HashCode dh;
+    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
+
+    /* Try Next HK */
+    t_hmac (&src->ax_header,
+            sizeof (struct GNUNET_CADET_AxHeader) + esize,
+            0,
+            &ax->NHKr,
+            &msg_hmac);
+    if (0 != memcmp (&msg_hmac,
+                     &src->hmac,
+                     sizeof (msg_hmac)))
+    {
+      /* Try the skipped keys, if that fails, we're out of luck. */
+      return try_old_ax_keys (ax,
+                              dst,
+                              src,
+                              size);
+    }
+    HK = ax->HKr;
+    ax->HKr = ax->NHKr;
+    t_h_decrypt (ax,
+                 src,
+                 &plaintext_header);
+    Np = ntohl (plaintext_header.ax_header.Ns);
+    PNp = ntohl (plaintext_header.ax_header.PNs);
+    DHRp = &plaintext_header.ax_header.DHRs;
+    store_ax_keys (ax,
+                   &HK,
+                   PNp);
+
+    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
+    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
+                            DHRp,
+                            &dh);
+    t_ax_hmac_hash (&ax->RK,
+                    &hmac,
+                    &dh, sizeof (dh));
+    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                       ctx, sizeof (ctx),
+                       &hmac, sizeof (hmac),
+                       NULL);
+
+    /* Commit "purported" keys */
+    ax->RK = keys[0];
+    ax->NHKr = keys[1];
+    ax->CKr = keys[2];
+    ax->DHRr = *DHRp;
+    ax->Nr = 0;
+    ax->ratchet_allowed = GNUNET_YES;
+  }
+  else
+  {
+    t_h_decrypt (ax,
+                 src,
+                 &plaintext_header);
+    Np = ntohl (plaintext_header.ax_header.Ns);
+    PNp = ntohl (plaintext_header.ax_header.PNs);
+  }
+  if ( (Np != ax->Nr) &&
+       (GNUNET_OK != store_ax_keys (ax,
+                                    &ax->HKr,
+                                    Np)) )
+  {
+    /* Try the skipped keys, if that fails, we're out of luck. */
+    return try_old_ax_keys (ax,
+                            dst,
+                            src,
+                            size);
+  }
+
+  t_ax_decrypt (ax,
+                dst,
+                &src[1],
+                esize);
+  ax->Nr = Np + 1;
+  return esize;
+}
+
+
+/**
+ * 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.
+ *
+ * @param t Tunnel whose encryption state to change, or NULL.
+ * @param state New encryption state.
+ */
+void
+GCT_change_estate (struct CadetTunnel *t,
+                   enum CadetTunnelEState state)
+{
+  enum CadetTunnelEState old = t->estate;
+
+  t->estate = state;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s estate changed from %s to %s\n",
+       GCT_2s (t),
+       estate2s (old),
+       estate2s (state));
+
+  if ( (CADET_TUNNEL_KEY_OK != old) &&
+       (CADET_TUNNEL_KEY_OK == t->estate) )
+  {
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    /* notify all channels that have been waiting */
+    GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                             &notify_tunnel_up_cb,
+                                             t);
+    if (NULL != t->send_task)
+      GNUNET_SCHEDULER_cancel (t->send_task);
+    t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                             t);
+  }
+}
+
+
+/**
+ * Send a KX message.
+ *
+ * @param t tunnel on which to send the KX_AUTH
+ * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
+ *           we are to find one that is ready.
+ * @param ax axolotl key context to use
+ */
+static void
+send_kx (struct CadetTunnel *t,
+         struct CadetTConnection *ct,
+         struct CadetTunnelAxolotl *ax)
+{
+  struct CadetConnection *cc;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
+  enum GNUNET_CADET_KX_Flags flags;
+
+  if ( (NULL == ct) ||
+       (GNUNET_NO == ct->is_ready) )
+    ct = get_ready_connection (t);
+  if (NULL == ct)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Wanted to send %s in state %s, but no connection is ready, deferring\n",
+         GCT_2s (t),
+         estate2s (t->estate));
+    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
+    return;
+  }
+  cc = ct->cc;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending KX on %s via %s in state %s\n",
+       GCT_2s (t),
+       GCC_2s (cc),
+       estate2s (t->estate));
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
+  flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
+  msg->flags = htonl (flags);
+  msg->cid = *GCC_get_id (cc);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
+                                      &msg->ephemeral_key);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
+                                      &msg->ratchet_key);
+  mark_connection_unready (ct);
+  t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
+  t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
+  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT);
+  else if (CADET_TUNNEL_KEY_AX_RECV == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
+  GCC_transmit (cc,
+                env);
+}
+
+
+/**
+ * Send a KX_AUTH message.
+ *
+ * @param t tunnel on which to send the KX_AUTH
+ * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
+ *           we are to find one that is ready.
+ * @param ax axolotl key context to use
+ * @param force_reply Force the other peer to reply with a KX_AUTH message
+ *         (set if we would like to transmit right now, but cannot)
+ */
+static void
+send_kx_auth (struct CadetTunnel *t,
+              struct CadetTConnection *ct,
+              struct CadetTunnelAxolotl *ax,
+              int force_reply)
+{
+  struct CadetConnection *cc;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg;
+  enum GNUNET_CADET_KX_Flags flags;
+
+  if ( (NULL == ct) ||
+       (GNUNET_NO == ct->is_ready) )
+    ct = get_ready_connection (t);
+  if (NULL == ct)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Wanted to send KX_AUTH on %s, but no connection is ready, deferring\n",
+         GCT_2s (t));
+    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
+    t->kx_auth_requested = GNUNET_YES; /* queue KX_AUTH independent of estate */
+    return;
+  }
+  t->kx_auth_requested = GNUNET_NO; /* clear flag */
+  cc = ct->cc;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending KX_AUTH on %s using %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
+  flags = GNUNET_CADET_KX_FLAG_NONE;
+  if (GNUNET_YES == force_reply)
+    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
+  msg->kx.flags = htonl (flags);
+  msg->kx.cid = *GCC_get_id (cc);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
+                                      &msg->kx.ephemeral_key);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
+                                      &msg->kx.ratchet_key);
+  /* Compute authenticator (this is the main difference to #send_kx()) */
+  GNUNET_CRYPTO_hash (&ax->RK,
+                      sizeof (ax->RK),
+                      &msg->auth);
+
+  /* Compute when to be triggered again; actual job will
+     be scheduled via #connection_ready_cb() */
+  t->kx_retry_delay
+    = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
+  t->next_kx_attempt
+    = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
+
+  /* Send via cc, mark it as unready */
+  mark_connection_unready (ct);
+
+  /* Update state machine, unless we are already OK */
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_AUTH_SENT);
+
+  GCC_transmit (cc,
+                env);
+}
+
+
+/**
+ * Cleanup state used by @a ax.
+ *
+ * @param ax state to free, but not memory of @a ax itself
+ */
+static void
+cleanup_ax (struct CadetTunnelAxolotl *ax)
+{
+  while (NULL != ax->skipped_head)
+    delete_skipped_key (ax,
+                        ax->skipped_head);
+  GNUNET_assert (0 == ax->skipped);
+  GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
+  GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
+}
+
+
+/**
+ * Update our Axolotl key state based on the KX data we received.
+ * Computes the new chain keys, and root keys, etc, and also checks
+ * wether this is a replay of the current chain.
+ *
+ * @param[in|out] axolotl chain key state to recompute
+ * @param pid peer identity of the other peer
+ * @param ephemeral_key ephemeral public key of the other peer
+ * @param ratchet_key senders next ephemeral public key
+ * @return #GNUNET_OK on success, #GNUNET_NO if the resulting
+ *       root key is already in @a ax and thus the KX is useless;
+ *       #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id)
+ */
+static int
+update_ax_by_kx (struct CadetTunnelAxolotl *ax,
+                 const struct GNUNET_PeerIdentity *pid,
+                 const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
+                 const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key)
+{
+  struct GNUNET_HashCode key_material[3];
+  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
+  const char salt[] = "CADET Axolotl salt";
+  int am_I_alice;
+
+  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                           pid))
+    am_I_alice = GNUNET_YES;
+  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                                pid))
+    am_I_alice = GNUNET_NO;
+  else
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  if (0 == memcmp (&ax->DHRr,
+                   ratchet_key,
+                   sizeof (*ratchet_key)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ratchet key already known. Ignoring KX.\n");
+    return GNUNET_NO;
+  }
+
+  ax->DHRr = *ratchet_key;
+
+  /* ECDH A B0 */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              ephemeral_key, /* B0 */
+                              &key_material[0]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* B0 */
+                              &pid->public_key,    /* A */
+                              &key_material[0]);
+  }
+
+  /* ECDH A0 B */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* A0 */
+                              &pid->public_key,    /* B */
+                              &key_material[1]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              ephemeral_key, /* B0 */
+                              &key_material[1]);
+
+
+  }
+
+  /* ECDH A0 B0 */
+  /* (This is the triple-DH, we could probably safely skip this,
+     as A0/B0 are already in the key material.) */
+  GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0,             /* A0 or B0 */
+                          ephemeral_key,  /* B0 or A0 */
+                          &key_material[2]);
+
+  /* KDF */
+  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                     salt, sizeof (salt),
+                     &key_material, sizeof (key_material),
+                     NULL);
+
+  if (0 == memcmp (&ax->RK,
+                   &keys[0],
+                   sizeof (ax->RK)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Root key of handshake already known. Ignoring KX.\n");
+    return GNUNET_NO;
+  }
+
+  ax->RK = keys[0];
+  if (GNUNET_YES == am_I_alice)
+  {
+    ax->HKr = keys[1];
+    ax->NHKs = keys[2];
+    ax->NHKr = keys[3];
+    ax->CKr = keys[4];
+    ax->ratchet_flag = GNUNET_YES;
+  }
+  else
+  {
+    ax->HKs = keys[1];
+    ax->NHKr = keys[2];
+    ax->NHKs = keys[3];
+    ax->CKs = keys[4];
+    ax->ratchet_flag = GNUNET_NO;
+    ax->ratchet_expiration
+      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+                                  ratchet_time);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Try to redo the KX or KX_AUTH handshake, if we can.
+ *
+ * @param cls the `struct CadetTunnel` to do KX for.
+ */
+static void
+retry_kx (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTunnelAxolotl *ax;
+
+  t->kx_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to make KX progress on %s in state %s\n",
+       GCT_2s (t),
+       estate2s (t->estate));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
+  case CADET_TUNNEL_KEY_AX_SENT:       /* trying again */
+    send_kx (t,
+             NULL,
+             &t->ax);
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* We are responding, so only require reply
+       if WE have a channel waiting. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Send AX_AUTH so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* How can this be? */
+      GNUNET_break (0);
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  (0 == GCT_count_channels (t))
+                  ? GNUNET_NO
+                  : GNUNET_YES);
+    break;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* We are responding, so only require reply
+       if WE have a channel waiting. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Send AX_AUTH so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* How can this be? */
+      GNUNET_break (0);
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  (0 == GCT_count_channels (t))
+                  ? GNUNET_NO
+                  : GNUNET_YES);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* Must have been the *other* peer asking us to
+       respond with a KX_AUTH. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Sending AX_AUTH in response to AX so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* Sending AX_AUTH in response to AX_AUTH */
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  GNUNET_NO);
+    break;
+  }
+}
+
+
+/**
+ * Handle KX message that lacks authentication (and which will thus
+ * only be considered authenticated after we respond with our own
+ * KX_AUTH and finally successfully decrypt payload).
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx (struct CadetTConnection *ct,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelAxolotl *ax;
+  int ret;
+
+  if (0 ==
+      memcmp (&t->ax.DHRr,
+              &msg->ratchet_key,
+              sizeof (msg->ratchet_key)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got duplicate KX. Firing back KX_AUTH.\n");
+    send_kx_auth (t,
+                  ct,
+                  &t->ax,
+                  GNUNET_NO);
+    return;
+  }
+
+  /* We only keep ONE unverified KX around, so if there is an existing one,
+     clean it up. */
+  if (NULL != t->unverified_ax)
+  {
+    if (0 ==
+        memcmp (&t->unverified_ax->DHRr,
+                &msg->ratchet_key,
+                sizeof (msg->ratchet_key)))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
+           GCT_2s (t));
+      send_kx_auth (t,
+                    ct,
+                    t->unverified_ax,
+                    GNUNET_NO);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping old unverified KX state. Got a fresh KX for %s.\n",
+         GCT_2s (t));
+    memset (t->unverified_ax,
+            0,
+            sizeof (struct CadetTunnelAxolotl));
+    t->unverified_ax->DHRs = t->ax.DHRs;
+    t->unverified_ax->kx_0 = t->ax.kx_0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Creating fresh unverified KX for %s.\n",
+         GCT_2s (t));
+    t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
+    t->unverified_ax->DHRs = t->ax.DHRs;
+    t->unverified_ax->kx_0 = t->ax.kx_0;
+  }
+  /* Set as the 'current' RK/DHRr the one we are currently using,
+     so that the duplicate-detection logic of
+     #update_ax_by_kx can work. */
+  t->unverified_ax->RK = t->ax.RK;
+  t->unverified_ax->DHRr = t->ax.DHRr;
+  t->unverified_attempts = 0;
+  ax = t->unverified_ax;
+
+  /* Update 'ax' by the new key material */
+  ret = update_ax_by_kx (ax,
+                         GCP_get_id (t->destination),
+                         &msg->ephemeral_key,
+                         &msg->ratchet_key);
+  GNUNET_break (GNUNET_SYSERR != ret);
+  if (GNUNET_OK != ret)
+    return; /* duplicate KX, nothing to do */
+
+  /* move ahead in our state machine */
+  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_RECV);
+  else if (CADET_TUNNEL_KEY_AX_SENT == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
+
+  /* KX is still not done, try again our end. */
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+  {
+    if (NULL != t->kx_task)
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+    t->kx_task
+      = GNUNET_SCHEDULER_add_now (&retry_kx,
+                                  t);
+  }
+}
+
+
+/**
+ * Handle KX_AUTH message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx_auth (struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelAxolotl ax_tmp;
+  struct GNUNET_HashCode kx_auth;
+  int ret;
+
+  if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
+       (CADET_TUNNEL_KEY_AX_RECV == t->estate) )
+  {
+    /* Confusing, we got a KX_AUTH before we even send our own
+       KX. This should not happen. We'll send our own KX ASAP anyway,
+       so let's ignore this here. */
+    GNUNET_break_op (0);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Handling KX_AUTH message for %s\n",
+       GCT_2s (t));
+
+  /* We do everything in ax_tmp until we've checked the authentication
+     so we don't clobber anything we care about by accident. */
+  ax_tmp = t->ax;
+
+  /* Update 'ax' by the new key material */
+  ret = update_ax_by_kx (&ax_tmp,
+                         GCP_get_id (t->destination),
+                         &msg->kx.ephemeral_key,
+                         &msg->kx.ratchet_key);
+  if (GNUNET_OK != ret)
+  {
+    if (GNUNET_NO == ret)
+      GNUNET_STATISTICS_update (stats,
+                                "# redundant KX_AUTH received",
+                                1,
+                                GNUNET_NO);
+    else
+      GNUNET_break (0); /* connect to self!? */
+    return;
+  }
+  GNUNET_CRYPTO_hash (&ax_tmp.RK,
+                      sizeof (ax_tmp.RK),
+                      &kx_auth);
+  if (0 != memcmp (&kx_auth,
+                   &msg->auth,
+                   sizeof (kx_auth)))
+  {
+    /* This KX_AUTH is not using the latest KX/KX_AUTH data
+       we transmitted to the sender, refuse it, try KX again. */
+    GNUNET_STATISTICS_update (stats,
+                              "# KX_AUTH not using our last KX received (auth failure)",
+                              1,
+                              GNUNET_NO);
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  }
+  /* Yep, we're good. */
+  t->ax = ax_tmp;
+  if (NULL != t->unverified_ax)
+  {
+    /* We got some "stale" KX before, drop that. */
+    cleanup_ax (t->unverified_ax);
+    GNUNET_free (t->unverified_ax);
+    t->unverified_ax = NULL;
+  }
+
+  /* move ahead in our state machine */
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+  case CADET_TUNNEL_KEY_AX_RECV:
+    /* Checked above, this is impossible. */
+    GNUNET_assert (0);
+    break;
+  case CADET_TUNNEL_KEY_AX_SENT:      /* This is the normal case */
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV: /* both peers started KX */
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT: /* both peers now did KX_AUTH */
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_OK);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* Did not expect another KX_AUTH, but so what, still acceptable.
+       Nothing to do here. */
+    break;
+  }
+}
+
+
+
+/* ************************************** end core crypto ***************************** */
+
+
+/**
+ * Compute the next free channel tunnel number for this tunnel.
+ *
+ * @param t the tunnel
+ * @return unused number that can uniquely identify a channel in the tunnel
+ */
+static struct GNUNET_CADET_ChannelTunnelNumber
+get_next_free_ctn (struct CadetTunnel *t)
+{
+#define HIGH_BIT 0x8000000
+  struct GNUNET_CADET_ChannelTunnelNumber ret;
+  uint32_t ctn;
+  int cmp;
+  uint32_t highbit;
+
+  cmp = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                         GCP_get_id (GCT_get_destination (t)));
+  if (0 < cmp)
+    highbit = HIGH_BIT;
+  else if (0 > cmp)
+    highbit = 0;
+  else
+    GNUNET_assert (0); // loopback must never go here!
+  ctn = ntohl (t->next_ctn.cn);
+  while (NULL !=
+         GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ctn | highbit))
+  {
+    ctn = ((ctn + 1) & (~ HIGH_BIT));
+  }
+  t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
+  ret.cn = htonl (ctn | highbit);
+  return ret;
+}
+
+
+/**
+ * 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
+ * @return unique number identifying @a ch within @a t
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+  ctn = get_next_free_ctn (t);
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding %s to %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    /* waiting for connection to start KX */
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* we're currently waiting for KX to complete */
+    break;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* waiting for OTHER peer to send us data,
+       we might need to prompt more aggressively! */
+    if (NULL == t->kx_task)
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* We are ready. Tell the new channel that we are up. */
+    GCCH_tunnel_up (ch);
+    break;
+  }
+  return ctn;
+}
+
+
+/**
+ * We lost a connection, remove it from our list and clean up
+ * the connection object itself.
+ *
+ * @param ct binding of connection to tunnel of the connection that was lost.
+ */
+void
+GCT_connection_lost (struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = ct->t;
+
+  if (GNUNET_YES == ct->is_ready)
+  {
+    GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
+                                 t->connection_ready_tail,
+                                 ct);
+    t->num_ready_connections--;
+  }
+  else
+  {
+    GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
+                                 t->connection_busy_tail,
+                                 ct);
+    t->num_busy_connections--;
+  }
+  GNUNET_free (ct);
+}
+
+
+/**
+ * Clean up connection @a ct of a tunnel.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param ct connection to clean up
+ */
+static void
+destroy_t_connection (void *cls,
+                      struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetConnection *cc = ct->cc;
+
+  GNUNET_assert (ct->t == t);
+  GCT_connection_lost (ct);
+  GCC_destroy_without_tunnel (cc);
+}
+
+
+/**
+ * This tunnel is no longer used, destroy it.
+ *
+ * @param cls the idle tunnel
+ */
+static void
+destroy_tunnel (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTunnelQueueEntry *tq;
+
+  t->destroy_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying idle %s\n",
+       GCT_2s (t));
+  GNUNET_assert (0 == GCT_count_channels (t));
+  GCT_iterate_connections (t,
+                           &destroy_t_connection,
+                           t);
+  GNUNET_assert (NULL == t->connection_ready_head);
+  GNUNET_assert (NULL == t->connection_busy_head);
+  while (NULL != (tq = t->tq_head))
+  {
+    if (NULL != tq->cont)
+      tq->cont (tq->cont_cls,
+                NULL);
+    GCT_send_cancel (tq);
+  }
+  GCP_drop_tunnel (t->destination,
+                   t);
+  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
+  if (NULL != t->maintain_connections_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
+    t->maintain_connections_task = NULL;
+  }
+  if (NULL != t->send_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->send_task);
+    t->send_task = NULL;
+  }
+  if (NULL != t->kx_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->kx_task);
+    t->kx_task = NULL;
+  }
+  GNUNET_MST_destroy (t->mst);
+  GNUNET_MQ_destroy (t->mq);
+  if (NULL != t->unverified_ax)
+  {
+    cleanup_ax (t->unverified_ax);
+    GNUNET_free (t->unverified_ax);
+  }
+  cleanup_ax (&t->ax);
+  GNUNET_assert (NULL == t->destroy_task);
+  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)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+                                                         ntohl (ctn.cn),
+                                                         ch));
+  if ( (0 ==
+        GCT_count_channels (t)) &&
+       (NULL == t->destroy_task) )
+  {
+    t->destroy_task
+      = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+                                      &destroy_tunnel,
+                                      t);
+  }
+}
+
+
+/**
+ * Destroy remaining channels during shutdown.
+ *
+ * @param cls the `struct CadetTunnel` of the channel
+ * @param key key of the channel
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_remaining_channels (void *cls,
+                            uint32_t key,
+                            void *value)
+{
+  struct CadetChannel *ch = value;
+
+  GCCH_handle_remote_destroy (ch,
+                              NULL);
+  return GNUNET_OK;
+}
+
+
+/**
+ * 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 (GNUNET_YES == shutting_down);
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &destroy_remaining_channels,
+                                           t);
+  GNUNET_assert (0 ==
+                 GCT_count_channels (t));
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  destroy_tunnel (t);
+}
+
+
+/**
+ * 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 */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Not sending payload of %s on ready %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);
+  mark_connection_unready (ct);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending payload of %s on %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+  GCC_transmit (ct->cc,
+                tq->env);
+  if (NULL != tq->cont)
+    tq->cont (tq->cont_cls,
+              GCC_get_id (ct->cc));
+  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.
+ *
+ * @param cls the `struct CadetTConnection` that is @a is_ready
+ * @param is_ready #GNUNET_YES if connection are now ready,
+ *                 #GNUNET_NO if connection are no longer ready
+ */
+static void
+connection_ready_cb (void *cls,
+                     int is_ready)
+{
+  struct CadetTConnection *ct = cls;
+  struct CadetTunnel *t = ct->t;
+
+  if (GNUNET_NO == is_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s no longer ready for %s\n",
+         GCC_2s (ct->cc),
+         GCT_2s (t));
+    mark_connection_unready (ct);
+    return;
+  }
+  GNUNET_assert (GNUNET_NO == ct->is_ready);
+  GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  GNUNET_assert (0 < t->num_busy_connections);
+  t->num_busy_connections--;
+  ct->is_ready = GNUNET_YES;
+  GNUNET_CONTAINER_DLL_insert_tail (t->connection_ready_head,
+                                    t->connection_ready_tail,
+                                    ct);
+  t->num_ready_connections++;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s now ready for %s in state %s\n",
+       GCC_2s (ct->cc),
+       GCT_2s (t),
+       estate2s (t->estate));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    /* Do not begin KX if WE have no channels waiting! */
+    if (0 == GCT_count_channels (t))
+      return;
+    /* We are uninitialized, just transmit immediately,
+       without undue delay. */
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* we're currently waiting for KX to complete, schedule job */
+    if (NULL == t->kx_task)
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    if (GNUNET_YES == t->kx_auth_requested)
+    {
+      if (NULL != t->kx_task)
+      {
+        GNUNET_SCHEDULER_cancel (t->kx_task);
+        t->kx_task = NULL;
+      }
+      send_kx_auth (t,
+                    ct,
+                    &t->ax,
+                    GNUNET_NO);
+      return;
+    }
+    try_send_normal_payload (t,
+                             ct);
+    break;
+  }
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param cls the `struct CadetTunnel` to process messages on
+ */
+static void
+trigger_transmissions (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTConnection *ct;
+
+  t->send_task = NULL;
+  if (NULL == t->tq_head)
+    return; /* no messages pending right now */
+  ct = get_ready_connection (t);
+  if (NULL == ct)
+    return; /* no connections ready */
+  try_send_normal_payload (t,
+                           ct);
+}
+
+
+/**
+ * Closure for #evaluate_connection. Used to assemble summary information
+ * about the existing connections so we can evaluate a new path.
+ */
+struct EvaluationSummary
+{
+
+  /**
+   * Minimum length of any of our connections, `UINT_MAX` if we have none.
+   */
+  unsigned int min_length;
+
+  /**
+   * Maximum length of any of our connections, 0 if we have none.
+   */
+  unsigned int max_length;
+
+  /**
+   * Minimum desirability of any of our connections, UINT64_MAX if we have none.
+   */
+  GNUNET_CONTAINER_HeapCostType min_desire;
+
+  /**
+   * Maximum desirability of any of our connections, 0 if we have none.
+   */
+  GNUNET_CONTAINER_HeapCostType max_desire;
+
+  /**
+   * Path we are comparing against for #evaluate_connection, can be NULL.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Connection deemed the "worst" so far encountered by #evaluate_connection,
+   * NULL if we did not yet encounter any connections.
+   */
+  struct CadetTConnection *worst;
+
+  /**
+   * Numeric score of @e worst, only set if @e worst is non-NULL.
+   */
+  double worst_score;
+
+  /**
+   * Set to #GNUNET_YES if we have a connection over @e path already.
+   */
+  int duplicate;
+
+};
+
+
+/**
+ * Evaluate a connection, updating our summary information in @a cls about
+ * what kinds of connections we have.
+ *
+ * @param cls the `struct EvaluationSummary *` to update
+ * @param ct a connection to include in the summary
+ */
+static void
+evaluate_connection (void *cls,
+                     struct CadetTConnection *ct)
+{
+  struct EvaluationSummary *es = cls;
+  struct CadetConnection *cc = ct->cc;
+  struct CadetPeerPath *ps = GCC_get_path (cc);
+  const struct CadetConnectionMetrics *metrics;
+  GNUNET_CONTAINER_HeapCostType ct_desirability;
+  struct GNUNET_TIME_Relative uptime;
+  struct GNUNET_TIME_Relative last_use;
+  uint32_t ct_length;
+  double score;
+  double success_rate;
+
+  if (ps == es->path)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate path %s.\n",
+         GCPP_2s (es->path));
+    es->duplicate = GNUNET_YES;
+    return;
+  }
+  ct_desirability = GCPP_get_desirability (ps);
+  ct_length = GCPP_get_length (ps);
+  metrics = GCC_get_metrics (cc);
+  uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
+  last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
+  /* We add 1.0 here to avoid division by zero. */
+  success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
+  score
+    = ct_desirability
+    + 100.0 / (1.0 + ct_length) /* longer paths = better */
+    + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
+    - last_use.rel_value_us / 1000L;          /* longer idle = worse */
+  score *= success_rate;        /* weigh overall by success rate */
+
+  if ( (NULL == es->worst) ||
+       (score < es->worst_score) )
+  {
+    es->worst = ct;
+    es->worst_score = score;
+  }
+  es->min_length = GNUNET_MIN (es->min_length,
+                               ct_length);
+  es->max_length = GNUNET_MAX (es->max_length,
+                               ct_length);
+  es->min_desire = GNUNET_MIN (es->min_desire,
+                               ct_desirability);
+  es->max_desire = GNUNET_MAX (es->max_desire,
+                               ct_desirability);
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ * @return #GNUNET_YES (should keep iterating)
+ */
+static int
+consider_path_cb (void *cls,
+                  struct CadetPeerPath *path,
+                  unsigned int off)
+{
+  struct CadetTunnel *t = cls;
+  struct EvaluationSummary es;
+  struct CadetTConnection *ct;
+
+  GNUNET_assert (off < GCPP_get_length (path));
+  es.min_length = UINT_MAX;
+  es.max_length = 0;
+  es.max_desire = 0;
+  es.min_desire = UINT64_MAX;
+  es.path = path;
+  es.duplicate = GNUNET_NO;
+  es.worst = NULL;
+
+  /* Compute evaluation summary over existing connections. */
+  GCT_iterate_connections (t,
+                           &evaluate_connection,
+                           &es);
+  if (GNUNET_YES == es.duplicate)
+    return GNUNET_YES;
+
+  /* FIXME: not sure we should really just count
+     'num_connections' here, as they may all have
+     consistently failed to connect. */
+
+  /* We iterate by increasing path length; if we have enough paths and
+     this one is more than twice as long than what we are currently
+     using, then ignore all of these super-long ones! */
+  if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (es.min_length * 2 < off) &&
+       (es.max_length < off) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring paths of length %u, they are way too long.\n",
+         es.min_length * 2);
+    return GNUNET_NO;
+  }
+  /* If we have enough paths and this one looks no better, ignore it. */
+  if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (es.min_length < GCPP_get_length (path)) &&
+       (es.min_desire > GCPP_get_desirability (path)) &&
+       (es.max_length < off) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring path (%u/%llu) to %s, got something better already.\n",
+         GCPP_get_length (path),
+         (unsigned long long) GCPP_get_desirability (path),
+         GCP_2s (t->destination));
+    return GNUNET_YES;
+  }
+
+  /* Path is interesting (better by some metric, or we don't have
+     enough paths yet). */
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create (t->destination,
+                       path,
+                       off,
+                       GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
+                       ct,
+                       &connection_ready_cb,
+                       ct);
+
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!)
+     => Note: to be done within 'connection'-logic! */
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Found interesting path %s for %s, created %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;
+  struct GNUNET_TIME_Relative delay;
+  struct EvaluationSummary es;
+
+  t->maintain_connections_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Performing connection maintenance for %s.\n",
+       GCT_2s (t));
+
+  es.min_length = UINT_MAX;
+  es.max_length = 0;
+  es.max_desire = 0;
+  es.min_desire = UINT64_MAX;
+  es.path = NULL;
+  es.worst = NULL;
+  es.duplicate = GNUNET_NO;
+  GCT_iterate_connections (t,
+                           &evaluate_connection,
+                           &es);
+  if ( (NULL != es.worst) &&
+       (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
+  {
+    /* Clear out worst-performing connection 'es.worst'. */
+    destroy_t_connection (t,
+                          es.worst);
+  }
+
+  /* Consider additional paths */
+  (void) GCP_iterate_paths (t->destination,
+                            &consider_path_cb,
+                            t);
+
+  /* FIXME: calculate when to try again based on how well we are doing;
+     in particular, if we have to few connections, we might be able
+     to do without this (as PATHS should tell us whenever a new path
+     is available instantly; however, need to make sure this job is
+     restarted after that happens).
+     Furthermore, if the paths we do know are in a reasonably narrow
+     quality band and are plentyful, we might also consider us stabilized
+     and then reduce the frequency accordingly.  */
+  delay = GNUNET_TIME_UNIT_MINUTES;
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_delayed (delay,
+                                    &maintain_connections_cb,
+                                    t);
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Considering %s for %s\n",
+       GCPP_2s (p),
+       GCT_2s (t));
+  (void) consider_path_cb (t,
+                           p,
+                           off);
+}
+
+
+/**
+ * We got a keepalive. Track in statistics.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
+ */
+static void
+handle_plaintext_keepalive (void *cls,
+                            const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetTunnel *t = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received KEEPALIVE on %s\n",
+       GCT_2s (t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives received",
+                            1,
+                            GNUNET_NO);
+}
+
+
+/**
+ * Check that @a msg is well-formed.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
+ * @return #GNUNET_OK (any variable-size payload goes)
+ */
+static int
+check_plaintext_data (void *cls,
+                      const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  return GNUNET_OK;
+}
+
+
+/**
+ * We received payload data for a channel.  Locate the channel
+ * and process the data, or return an error if the channel is unknown.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg the message we received on the tunnel
+ */
+static void
+handle_plaintext_data (void *cls,
+                       const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       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,
+         "Received %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->ctn);
+    return;
+  }
+  GCCH_handle_channel_plaintext_data (ch,
+                                      GCC_get_id (t->current_ct->cc),
+                                      msg);
+}
+
+
+/**
+ * We received an acknowledgement for data we sent on a channel.
+ * Locate the channel and process it, or return an error if the
+ * channel is unknown.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param ack the message we received on the tunnel
+ */
+static void
+handle_plaintext_data_ack (void *cls,
+                           const struct GNUNET_CADET_ChannelDataAckMessage *ack)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       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,
+         "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
+         ntohl (ack->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              ack->ctn);
+    return;
+  }
+  GCCH_handle_channel_plaintext_data_ack (ch,
+                                          GCC_get_id (t->current_ct->cc),
+                                          ack);
+}
+
+
+/**
+ * We have received a request to open a channel to a port from
+ * another peer.  Creates the incoming channel.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param copen the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_open (void *cls,
+                               const struct GNUNET_CADET_ChannelOpenMessage *copen)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                            ntohl (copen->ctn.cn));
+  if (NULL != ch)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
+         GNUNET_h2s (&copen->port),
+         GCT_2s (t),
+         GCCH_2s (ch));
+    GCCH_handle_duplicate_open (ch,
+                                GCC_get_id (t->current_ct->cc));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CHANNEL_OPEN on port %s from %s\n",
+       GNUNET_h2s (&copen->port),
+       GCT_2s (t));
+  ch = GCCH_channel_incoming_new (t,
+                                  copen->ctn,
+                                  &copen->port,
+                                  ntohl (copen->opt));
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (copen->ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+}
+
+
+/**
+ * Send a DESTROY message via the tunnel.
+ *
+ * @param t the tunnel to transmit over
+ * @param ctn ID of the channel to destroy
+ */
+void
+GCT_send_channel_destroy (struct CadetTunnel *t,
+                          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.ctn = ctn;
+  GCT_send (t,
+            &msg.header,
+            NULL,
+            NULL);
+}
+
+
+/**
+ * We have received confirmation from the target peer that the
+ * given channel could be established (the port is open).
+ * Tell the client.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+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->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 %u, sending DESTROY\n",
+         ntohl (cm->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              cm->ctn);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received channel OPEN_ACK on channel %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GCCH_handle_channel_open_ack (ch,
+                                GCC_get_id (t->current_ct->cc));
+}
+
+
+/**
+ * We received a message saying that a channel should be destroyed.
+ * Pass it on to the correct channel.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_destroy (void *cls,
+                                  const struct GNUNET_CADET_ChannelManageMessage *cm)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  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 %u. Ignoring.\n",
+         ntohl (cm->ctn.cn));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received channel DESTROY on %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GCCH_handle_remote_destroy (ch,
+                              GCC_get_id (t->current_ct->cc));
+}
+
+
+/**
+ * Handles a message we decrypted, by injecting it into
+ * our message queue (which will do the dispatching).
+ *
+ * @param cls the `struct CadetTunnel` that got the message
+ * @param msg the message
+ * @return #GNUNET_OK (continue to process)
+ */
+static int
+handle_decrypted (void *cls,
+                  const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetTunnel *t = cls;
+
+  GNUNET_assert (NULL != t->current_ct);
+  GNUNET_MQ_inject_message (t->mq,
+                            msg);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called if we had an error processing
+ * an incoming decrypted message.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param error error code
+ */
+static void
+decrypted_error_cb (void *cls,
+                    enum GNUNET_MQ_Error error)
+{
+  GNUNET_break_op (0);
+}
+
+
+/**
+ * Create a tunnel to @a destionation.  Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination)
+{
+  struct CadetTunnel *t = GNUNET_new (struct CadetTunnel);
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_fixed_size (plaintext_keepalive,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE,
+                             struct GNUNET_MessageHeader,
+                             t),
+    GNUNET_MQ_hd_var_size (plaintext_data,
+                           GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA,
+                           struct GNUNET_CADET_ChannelAppDataMessage,
+                           t),
+    GNUNET_MQ_hd_fixed_size (plaintext_data_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
+                             struct GNUNET_CADET_ChannelDataAckMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
+                             struct GNUNET_CADET_ChannelOpenMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             t),
+    GNUNET_MQ_handler_end ()
+  };
+
+  t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
+  new_ephemeral (&t->ax);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
+  t->destination = destination;
+  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
+                                t);
+  t->mq = GNUNET_MQ_queue_for_callbacks (NULL,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         handlers,
+                                         &decrypted_error_cb,
+                                         t);
+  t->mst = GNUNET_MST_create (&handle_decrypted,
+                              t);
+  return t;
+}
+
+
+/**
+ * Add a @a connection to the @a tunnel.
+ *
+ * @param t a tunnel
+ * @param cid connection identifer to use for the connection
+ * @param options options for the connection
+ * @param path path to use for the connection
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on failure (duplicate connection)
+ */
+int
+GCT_add_inbound_connection (struct CadetTunnel *t,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                            enum GNUNET_CADET_ChannelOption options,
+                            struct CadetPeerPath *path)
+{
+  struct CadetTConnection *ct;
+
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create_inbound (t->destination,
+                               path,
+                               options,
+                               ct,
+                               cid,
+                               &connection_ready_cb,
+                               ct);
+  if (NULL == ct->cc)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s refused inbound %s (duplicate)\n",
+         GCT_2s (t),
+         GCC_2s (ct->cc));
+    GNUNET_free (ct);
+    return GNUNET_SYSERR;
+  }
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!)
+     => Note: to be done within 'connection'-logic! */
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s has new %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle encrypted message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCT_handle_encrypted (struct CadetTConnection *ct,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  uint16_t size = ntohs (msg->header.size);
+  char cbuf [size] GNUNET_ALIGN;
+  ssize_t decrypted_size;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%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:
+  case CADET_TUNNEL_KEY_AX_RECV:
+    /* We did not even SEND our KX, how can the other peer
+       send us encrypted data? Must have been that we went
+       down and the other peer still things we are up.
+       Let's send it KX back. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without any KX",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* We send KX, and other peer send KX to us at the same time.
+       Neither KX is AUTH'ed, so let's try KX_AUTH this time. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without KX_AUTH",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx_auth (t,
+                  ct,
+                  &t->ax,
+                  GNUNET_YES);
+    return;
+  case CADET_TUNNEL_KEY_AX_SENT:
+    /* We did not get the KX of the other peer, but that
+       might have been lost.  Send our KX again immediately. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without KX",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* Great, first payload, we might graduate to OK! */
+  case CADET_TUNNEL_KEY_OK:
+    /* We are up and running, all good. */
+    break;
+  }
+
+  decrypted_size = -1;
+  if (CADET_TUNNEL_KEY_OK == t->estate)
+  {
+    /* We have well-established key material available,
+       try that. (This is the common case.) */
+    decrypted_size = t_ax_decrypt_and_validate (&t->ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+  }
+
+  if ( (-1 == decrypted_size) &&
+       (NULL != t->unverified_ax) )
+  {
+    /* We have un-authenticated KX material available. We should try
+       this as a back-up option, in case the sender crashed and
+       switched keys. */
+    decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+    if (-1 != decrypted_size)
+    {
+      /* It worked! Treat this as authentication of the AX data! */
+      cleanup_ax (&t->ax);
+      t->ax = *t->unverified_ax;
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+    if (CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate)
+    {
+      /* First time it worked, move tunnel into production! */
+      GCT_change_estate (t,
+                         CADET_TUNNEL_KEY_OK);
+      if (NULL != t->send_task)
+        GNUNET_SCHEDULER_cancel (t->send_task);
+      t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                               t);
+    }
+  }
+  if (NULL != t->unverified_ax)
+  {
+    /* We had unverified KX material that was useless; so increment
+       counter and eventually move to ignore it.  Note that we even do
+       this increment if we successfully decrypted with the old KX
+       material and thus didn't even both with the new one.  This is
+       the ideal case, as a malicious injection of bogus KX data
+       basically only causes us to increment a counter a few times. */
+    t->unverified_attempts++;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to decrypt message with unverified KX data %u times\n",
+         t->unverified_attempts);
+    if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
+    {
+      cleanup_ax (t->unverified_ax);
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+  }
+
+  if (-1 == decrypted_size)
+  {
+    /* Decryption failed for good, complain. */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "%s failed to decrypt and validate encrypted data, retrying KX\n",
+         GCT_2s (t));
+    GNUNET_STATISTICS_update (stats,
+                              "# unable to decrypt",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# decrypted bytes",
+                            decrypted_size,
+                            GNUNET_NO);
+
+  /* The MST will ultimately call #handle_decrypted() on each message. */
+  t->current_ct = ct;
+  GNUNET_break_op (GNUNET_OK ==
+                   GNUNET_MST_from_buffer (t->mst,
+                                           cbuf,
+                                           decrypted_size,
+                                           GNUNET_YES,
+                                           GNUNET_NO));
+  t->current_ct = NULL;
+}
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection if not provided.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GCT_SendContinuation cont,
+          void *cont_cls)
+{
+  struct CadetTunnelQueueEntry *tq;
+  uint16_t payload_size;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
+
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  payload_size = ntohs (message->size);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Encrypting %u bytes for %s\n",
+       (unsigned int) payload_size,
+       GCT_2s (t));
+  env = GNUNET_MQ_msg_extra (ax_msg,
+                             payload_size,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
+  t_ax_encrypt (&t->ax,
+                &ax_msg[1],
+                message,
+                payload_size);
+  GNUNET_STATISTICS_update (stats,
+                            "# encrypted bytes",
+                            payload_size,
+                            GNUNET_NO);
+  ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
+  ax_msg->ax_header.PNs = htonl (t->ax.PNs);
+  /* FIXME: we should do this once, not once per message;
+     this is a point multiplication, and DHRs does not
+     change all the time. */
+  GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
+                                      &ax_msg->ax_header.DHRs);
+  t_h_encrypt (&t->ax,
+               ax_msg);
+  t_hmac (&ax_msg->ax_header,
+          sizeof (struct GNUNET_CADET_AxHeader) + payload_size,
+          0,
+          &t->ax.HKs,
+          &ax_msg->hmac);
+
+  tq = GNUNET_malloc (sizeof (*tq));
+  tq->t = t;
+  tq->env = env;
+  tq->cid = &ax_msg->cid; /* will initialize 'ax_msg->cid' once we know the connection */
+  tq->cont = cont;
+  tq->cont_cls = cont_cls;
+  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
+                                    t->tq_tail,
+                                    tq);
+  if (NULL != t->send_task)
+    GNUNET_SCHEDULER_cancel (t->send_task);
+  t->send_task
+    = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                t);
+  return tq;
+}
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send
+ * function is called. Once the continuation is called, the message is
+ * no longer in the queue!
+ *
+ * @param tq Handle to the queue entry to cancel.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
+{
+  struct CadetTunnel *t = tq->t;
+
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  GNUNET_MQ_discard (tq->env);
+  GNUNET_free (tq);
+}
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+                         GCT_ConnectionIterator iter,
+                         void *iter_cls)
+{
+  struct CadetTConnection *n;
+  for (struct CadetTConnection *ct = t->connection_ready_head;
+       NULL != ct;
+       ct = n)
+  {
+    n = ct->next;
+    iter (iter_cls,
+          ct);
+  }
+  for (struct CadetTConnection *ct = t->connection_busy_head;
+       NULL != ct;
+       ct = n)
+  {
+    n = ct->next;
+    iter (iter_cls,
+          ct);
+  }
+}
+
+
+/**
+ * Closure for #iterate_channels_cb.
+ */
+struct ChanIterCls
+{
+  /**
+   * Function to call.
+   */
+  GCT_ChannelIterator iter;
+
+  /**
+   * Closure for @e iter.
+   */
+  void *iter_cls;
+};
+
+
+/**
+ * Helper function for #GCT_iterate_channels.
+ *
+ * @param cls the `struct ChanIterCls`
+ * @param key unused
+ * @param value a `struct CadetChannel`
+ * @return #GNUNET_OK
+ */
+static int
+iterate_channels_cb (void *cls,
+                     uint32_t key,
+                     void *value)
+{
+  struct ChanIterCls *ctx = cls;
+  struct CadetChannel *ch = value;
+
+  ctx->iter (ctx->iter_cls,
+             ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+                      GCT_ChannelIterator iter,
+                      void *iter_cls)
+{
+  struct ChanIterCls ctx;
+
+  ctx.iter = iter;
+  ctx.iter_cls = iter_cls;
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &iterate_channels_cb,
+                                           &ctx);
+
+}
+
+
+/**
+ * Call #GCCH_debug() on a channel.
+ *
+ * @param cls points to the log level to use
+ * @param key unused
+ * @param value the `struct CadetChannel` to dump
+ * @return #GNUNET_OK (continue iteration)
+ */
+static int
+debug_channel (void *cls,
+               uint32_t key,
+               void *value)
+{
+  const enum GNUNET_ErrorType *level = cls;
+  struct CadetChannel *ch = value;
+
+  GCCH_debug (ch, *level);
+  return GNUNET_OK;
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+           enum GNUNET_ErrorType level)
+{
+  struct CadetTConnection *iter_c;
+  int do_log;
+
+  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+                                       "cadet-tun",
+                                       __FILE__, __FUNCTION__, __LINE__);
+  if (0 == do_log)
+    return;
+
+  LOG2 (level,
+        "TTT TUNNEL TOWARDS %s in estate %s tq_len: %u #cons: %u\n",
+        GCT_2s (t),
+        estate2s (t->estate),
+        t->tq_len,
+        GCT_count_any_connections (t));
+  LOG2 (level,
+        "TTT channels:\n");
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &debug_channel,
+                                           &level);
+  LOG2 (level,
+        "TTT connections:\n");
+  for (iter_c = t->connection_ready_head; NULL != iter_c; iter_c = iter_c->next)
+    GCC_debug (iter_c->cc,
+               level);
+  for (iter_c = t->connection_busy_head; NULL != iter_c; iter_c = iter_c->next)
+    GCC_debug (iter_c->cc,
+               level);
+
+  LOG2 (level,
+        "TTT TUNNEL END\n");
+}
+
+
+/* end of gnunet-service-cadet-new_tunnels.c */
diff --git a/src/cadet/gnunet-service-cadet_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h
new file mode 100644 (file)
index 0000000..4a3619a
--- /dev/null
@@ -0,0 +1,370 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_tunnels.h
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
+#define GNUNET_SERVICE_CADET_TUNNELS_H
+
+#include "gnunet-service-cadet.h"
+#include "cadet_protocol.h"
+
+
+/**
+ * How many connections would we like to have per tunnel?
+ */
+#define DESIRED_CONNECTIONS_PER_TUNNEL 3
+
+
+/**
+ * All the encryption states a tunnel can be in.
+ */
+enum CadetTunnelEState
+{
+  /**
+   * Uninitialized status, we need to send KX.  We will stay
+   * in this state until the first connection is up.
+   */
+  CADET_TUNNEL_KEY_UNINITIALIZED,
+
+  /**
+   * KX message sent, waiting for other peer's KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_SENT,
+
+  /**
+   * KX message received, trying to send back KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_RECV,
+
+  /**
+   * KX message sent and received, trying to send back KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_SENT_AND_RECV,
+
+  /**
+   * KX received and we sent KX_AUTH back, but we got no traffic yet,
+   * so we're waiting for either KX_AUTH or ENCRYPED traffic from
+   * the other peer.
+   *
+   * We will not yet send traffic, as this might have been a replay.
+   * The other (initiating) peer should send a CHANNEL_OPEN next
+   * anyway, and then we are in business!
+   */
+  CADET_TUNNEL_KEY_AX_AUTH_SENT,
+
+  /**
+   * Handshake completed: session key available.
+   */
+  CADET_TUNNEL_KEY_OK
+
+};
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t);
+
+
+/**
+ * Create a tunnel to @a destionation.  Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination);
+
+
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t);
+
+
+/**
+ * Add a @a connection to the @a tunnel.
+ *
+ * @param t a tunnel
+ * @param cid connection identifer to use for the connection
+ * @param options options for the connection
+ * @param path path to use for the connection
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on failure (duplicate connection)
+ */
+int
+GCT_add_inbound_connection (struct CadetTunnel *t,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                            enum GNUNET_CADET_ChannelOption options,
+                            struct CadetPeerPath *path);
+
+
+/**
+ * We lost a connection, remove it from our list and clean up
+ * the connection object itself.
+ *
+ * @param ct binding of connection to tunnel of the connection that was lost.
+ */
+void
+GCT_connection_lost (struct CadetTConnection *ct);
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t);
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off);
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch);
+
+
+/**
+ * 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);
+
+
+/**
+ * Send a DESTROY message via the tunnel.
+ *
+ * @param t the tunnel to transmit over
+ * @param ctn ID of the channel to destroy
+ */
+void
+GCT_send_channel_destroy (struct CadetTunnel *t,
+                          struct GNUNET_CADET_ChannelTunnelNumber ctn);
+
+
+/**
+ * Function called when a transmission requested using #GCT_send is done.
+ *
+ * @param cls closure
+ * @param ctn identifier of the connection used for transmission, NULL if
+ *            the transmission failed (to be used to match ACKs to the
+ *            respective connection for connection performance evaluation)
+ */
+typedef void
+(*GCT_SendContinuation)(void *cls,
+                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection if not provided.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GCT_SendContinuation cont,
+          void *cont_cls);
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send
+ * 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.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *q);
+
+
+/**
+ * Return the number of channels using a tunnel.
+ *
+ * @param t tunnel to count obtain the number of channels for
+ * @return number of channels using the tunnel
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t);
+
+
+/**
+ * Return the number of connections available for a tunnel.
+ *
+ * @param t tunnel to count obtain the number of connections for
+ * @return number of connections available for the tunnel
+ */
+unsigned int
+GCT_count_any_connections (const struct CadetTunnel *t);
+
+
+/**
+ * Iterator over connections.
+ *
+ * @param cls closure
+ * @param ct one of the connections
+ */
+typedef void
+(*GCT_ConnectionIterator) (void *cls,
+                           struct CadetTConnection *ct);
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+                         GCT_ConnectionIterator iter,
+                         void *iter_cls);
+
+
+/**
+ * Iterator over channels.
+ *
+ * @param cls closure
+ * @param ch one of the channels
+ */
+typedef void
+(*GCT_ChannelIterator) (void *cls,
+                        struct CadetChannel *ch);
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+                      GCT_ChannelIterator iter,
+                      void *iter_cls);
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t);
+
+
+/**
+ * Handle KX message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx (struct CadetTConnection *ct,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
+
+
+/**
+ * Handle KX_AUTH message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx_auth (struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
+
+
+/**
+ * Handle encrypted message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCT_handle_encrypted (struct CadetTConnection *ct,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+           enum GNUNET_ErrorType level);
+
+
+#endif
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c
new file mode 100644 (file)
index 0000000..4fe43b3
--- /dev/null
@@ -0,0 +1,1105 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2011, 2017 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/test_cadet.c
+ * @author Bart Polot
+ * @author Christian Grothoff
+ * @brief Test for the cadet service using mq API.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "cadet_test_lib.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
+#include <gauger.h>
+
+
+/**
+ * Ugly workaround to unify data handlers on incoming and outgoing channels.
+ */
+struct CadetTestChannelWrapper
+{
+  /**
+   * Channel pointer.
+   */
+  struct GNUNET_CADET_Channel *ch;
+};
+
+/**
+ * How many messages to send by default.
+ */
+#define TOTAL_PACKETS 500       /* Cannot exceed 64k! */
+
+/**
+ * How long until we give up on connecting the peers?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * Time to wait by default  for stuff that should be rather fast.
+ */
+#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
+
+/**
+ * DIFFERENT TESTS TO RUN
+ */
+#define SETUP 0
+#define FORWARD 1
+#define KEEPALIVE 2
+#define SPEED 3
+#define SPEED_ACK 4
+#define SPEED_REL 8
+#define P2P_SIGNAL 10
+
+/**
+ * Which test are we running?
+ */
+static int test;
+
+/**
+ * String with test name
+ */
+static char *test_name;
+
+/**
+ * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
+ */
+static int test_backwards = GNUNET_NO;
+
+/**
+ * How many packets to send.
+ */
+static unsigned int total_packets;
+
+/**
+ * Time to wait for fast operations.
+ */
+static struct GNUNET_TIME_Relative short_time;
+
+/**
+ * How many events have happened
+ */
+static int ok;
+
+/**
+ * Number of events expected to conclude the test successfully.
+ */
+static int ok_goal;
+
+/**
+ * Size of each test packet's payload
+ */
+static size_t size_payload = sizeof (uint32_t);
+
+/**
+ * Operation to get peer ids.
+ */
+static struct GNUNET_TESTBED_Operation *t_op[2];
+
+/**
+ * Peer ids.
+ */
+static struct GNUNET_PeerIdentity *p_id[2];
+
+/**
+ * Port ID
+ */
+static struct GNUNET_HashCode port;
+
+/**
+ * Peer ids counter.
+ */
+static unsigned int p_ids;
+
+/**
+ * Is the setup initialized?
+ */
+static int initialized;
+
+/**
+ * Number of payload packes sent.
+ */
+static int data_sent;
+
+/**
+ * Number of payload packets received.
+ */
+static int data_received;
+
+/**
+ * Number of payload packed acknowledgements sent.
+ */
+static int ack_sent;
+
+/**
+ * Number of payload packed explicitly (app level) acknowledged.
+ */
+static int ack_received;
+
+/**
+ * Total number of peers asked to run.
+ */
+static unsigned long long peers_requested;
+
+/**
+ * Number of currently running peers (should be same as @c peers_requested).
+ */
+static unsigned long long peers_running;
+
+/**
+ * Test context (to shut down).
+ */
+struct GNUNET_CADET_TEST_Context *test_ctx;
+
+/**
+ * Task called to disconnect peers.
+ */
+static struct GNUNET_SCHEDULER_Task *disconnect_task;
+
+/**
+ * Task To perform tests
+ */
+static struct GNUNET_SCHEDULER_Task *test_task;
+
+/**
+ * Task runnining #send_next_msg().
+ */
+static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
+
+/**
+ * Cadet handle for the root peer
+ */
+static struct GNUNET_CADET_Handle *h1;
+
+/**
+ * Cadet handle for the first leaf peer
+ */
+static struct GNUNET_CADET_Handle *h2;
+
+/**
+ * Channel handle for the root peer
+ */
+static struct GNUNET_CADET_Channel *outgoing_ch;
+
+/**
+ * Channel handle for the dest peer
+ */
+static struct GNUNET_CADET_Channel *incoming_ch;
+
+/**
+ * Time we started the data transmission (after channel has been established
+ * and initilized).
+ */
+static struct GNUNET_TIME_Absolute start_time;
+
+/**
+ * Peers handle.
+ */
+static struct GNUNET_TESTBED_Peer **testbed_peers;
+
+/**
+ * Statistics operation handle.
+ */
+static struct GNUNET_TESTBED_Operation *stats_op;
+
+/**
+ * Keepalives sent.
+ */
+static unsigned int ka_sent;
+
+/**
+ * Keepalives received.
+ */
+static unsigned int ka_received;
+
+/**
+ * How many messages were dropped by CADET because of full buffers?
+ */
+static unsigned int msg_dropped;
+
+
+/******************************************************************************/
+
+
+/******************************************************************************/
+
+
+/**
+ * Get the channel considered as the "target" or "receiver", depending on
+ * the test type and size.
+ *
+ * @return Channel handle of the target client, either 0 (for backward tests)
+ *         or the last peer in the line (for other tests).
+ */
+static struct GNUNET_CADET_Channel *
+get_target_channel ()
+{
+  if (SPEED == test && GNUNET_YES == test_backwards)
+    return outgoing_ch;
+  else
+    return incoming_ch;
+}
+
+
+/**
+ * Show the results of the test (banwidth acheived) and log them to GAUGER
+ */
+static void
+show_end_data (void)
+{
+  static struct GNUNET_TIME_Absolute end_time;
+  static struct GNUNET_TIME_Relative total_time;
+
+  end_time = GNUNET_TIME_absolute_get ();
+  total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
+  FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
+  FPRINTF (stderr, "Test time %s\n",
+           GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
+  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000));    // 4bytes * ms
+  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000));     // packets * ms
+  GAUGER ("CADET", test_name,
+          total_packets * 1000.0 / (total_time.rel_value_us / 1000),
+          "packets/s");
+}
+
+
+/**
+ * Disconnect from cadet services af all peers, call shutdown.
+ *
+ * @param cls Closure (line number from which termination was requested).
+ * @param tc Task Context.
+ */
+static void
+disconnect_cadet_peers (void *cls)
+{
+  long line = (long) cls;
+  unsigned int i;
+
+  disconnect_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "disconnecting cadet service of peers, called from line %ld\n",
+              line);
+  for (i = 0; i < 2; i++)
+  {
+    GNUNET_TESTBED_operation_done (t_op[i]);
+  }
+  if (NULL != outgoing_ch)
+  {
+    GNUNET_CADET_channel_destroy (outgoing_ch);
+    outgoing_ch = NULL;
+  }
+  if (NULL != incoming_ch)
+  {
+    GNUNET_CADET_channel_destroy (incoming_ch);
+    incoming_ch = NULL;
+  }
+  GNUNET_CADET_TEST_cleanup (test_ctx);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Shut down peergroup, clean up.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task Context.
+ */
+static void
+shutdown_task (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
+  if (NULL != send_next_msg_task)
+  {
+    GNUNET_SCHEDULER_cancel (send_next_msg_task);
+    send_next_msg_task = NULL;
+  }
+  if (NULL != test_task)
+  {
+    GNUNET_SCHEDULER_cancel (test_task);
+    test_task = NULL;
+  }
+  if (NULL != disconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
+  }
+}
+
+
+/**
+ * Stats callback. Finish the stats testbed operation and when all stats have
+ * been iterated, shutdown the test.
+ *
+ * @param cls Closure (line number from which termination was requested).
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ *          operation has executed successfully.
+ */
+static void
+stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
+              ka_sent, ka_received);
+  if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
+  {
+    GNUNET_break (0);
+    ok--;
+  }
+  GNUNET_TESTBED_operation_done (stats_op);
+
+  if (NULL != disconnect_task)
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+  disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
+}
+
+
+/**
+ * Process statistic values.
+ *
+ * @param cls closure (line number, unused)
+ * @param peer the peer the statistic belong to
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ * @param value the current value
+ * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ */
+static int
+stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
+                const char *subsystem, const char *name, uint64_t value,
+                int is_persistent)
+{
+  static const char *s_sent = "# keepalives sent";
+  static const char *s_recv = "# keepalives received";
+  static const char *rdrops = "# messages dropped due to full buffer";
+  static const char *cdrops = "# messages dropped due to slow client";
+  uint32_t i;
+
+  i = GNUNET_TESTBED_get_index (peer);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
+              subsystem, name, (unsigned long long) value);
+  if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
+    ka_sent = value;
+  if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
+    ka_received = value;
+  if (0 == strncmp (rdrops, name, strlen (rdrops)))
+    msg_dropped += value;
+  if (0 == strncmp (cdrops, name, strlen (cdrops)))
+    msg_dropped += value;
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Task to gather all statistics.
+ *
+ * @param cls Closure (line from which the task was scheduled).
+ */
+static void
+gather_stats_and_exit (void *cls)
+{
+  long l = (long) cls;
+
+  disconnect_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "gathering statistics from line %ld\n",
+              l);
+  if (NULL != outgoing_ch)
+  {
+    GNUNET_CADET_channel_destroy (outgoing_ch);
+    outgoing_ch = NULL;
+  }
+  stats_op = GNUNET_TESTBED_get_statistics (peers_running,
+                                            testbed_peers,
+                                            "cadet",
+                                            NULL,
+                                            &stats_iterator,
+                                            stats_cont,
+                                            cls);
+}
+
+
+
+/**
+ * Abort test: schedule disconnect and shutdown immediately
+ *
+ * @param line Line in the code the abort is requested from (__LINE__).
+ */
+static void
+abort_test (long line)
+{
+  if (NULL != disconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
+  }
+}
+
+
+/**
+ * Send a message on the channel with the appropriate size and payload.
+ *
+ * Update the appropriate *_sent counter.
+ *
+ * @param channel Channel to send the message on.
+ */
+static void
+send_test_message (struct GNUNET_CADET_Channel *channel)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *msg;
+  uint32_t *data;
+  int payload;
+  int size;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending test message on channel %p\n",
+              channel);
+  size = size_payload;
+  if (GNUNET_NO == initialized)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
+    size += 1000;
+    payload = data_sent;
+    if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
+        data_sent++;
+  }
+  else if (SPEED == test || SPEED_ACK == test)
+  {
+    if (get_target_channel() == channel)
+    {
+      payload = ack_sent;
+      size += ack_sent;
+      ack_sent++;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending ACK %u [%d bytes]\n",
+                  payload, size);
+    }
+    else
+    {
+      payload = data_sent;
+      size += data_sent;
+      data_sent++;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending DATA %u [%d bytes]\n",
+                  data_sent, size);
+    }
+  }
+  else if (FORWARD == test)
+  {
+    payload = ack_sent;
+  }
+  else if (P2P_SIGNAL == test)
+  {
+    payload = data_sent;
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
+  env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
+
+  data = (uint32_t *) &msg[1];
+  *data = htonl (payload);
+  GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
+}
+
+/**
+ * Task to request a new data transmission in a SPEED test, without waiting
+ * for previous messages to be sent/arrrive.
+ *
+ * @param cls Closure (unused).
+ */
+static void
+send_next_msg (void *cls)
+{
+  struct GNUNET_CADET_Channel *channel;
+
+  send_next_msg_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
+
+  channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
+  GNUNET_assert (NULL != channel);
+  GNUNET_assert (SPEED == test);
+  send_test_message (channel);
+  if (data_sent < total_packets)
+  {
+    /* SPEED test: Send all messages as soon as possible */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Scheduling message %d\n",
+                data_sent + 1);
+    send_next_msg_task =
+        GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
+                                     &send_next_msg,
+                                     NULL);
+  }
+}
+
+
+/**
+ * Every few messages cancel the timeout task and re-schedule it again, to
+ * avoid timing out when traffic keeps coming.
+ *
+ * @param line Code line number to log if a timeout occurs.
+ */
+static void
+reschedule_timeout_task (long line)
+{
+  if ((ok % 10) == 0)
+  {
+    if (NULL != disconnect_task)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  " reschedule timeout every 10 messages\n");
+      GNUNET_SCHEDULER_cancel (disconnect_task);
+      disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                      &gather_stats_and_exit,
+                                                      (void *) line);
+    }
+  }
+}
+
+
+/**
+ * Check if payload is sane (size contains payload).
+ *
+ * @param cls should match #ch
+ * @param message The actual message.
+ * @return #GNUNET_OK to keep the channel open,
+ *         #GNUNET_SYSERR to close it (signal serious error).
+ */
+static int
+check_data (void *cls, const struct GNUNET_MessageHeader *message)
+{
+  if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;             /* all is well-formed */
+}
+
+
+/**
+ * Function is called whenever a message is received.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect(), peer number)
+ * @param message the actual message
+ */
+static void
+handle_data (void *cls, const struct GNUNET_MessageHeader *message)
+{
+  struct CadetTestChannelWrapper *ch = cls;
+  struct GNUNET_CADET_Channel *channel = ch->ch;
+  uint32_t *data;
+  uint32_t payload;
+  int *counter;
+
+  ok++;
+  GNUNET_CADET_receive_done (channel);
+  counter = get_target_channel () == channel ? &data_received : &ack_received;
+
+  reschedule_timeout_task ((long) __LINE__);
+
+  if (channel == outgoing_ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
+  }
+  else if (channel == incoming_ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
+    GNUNET_assert (0);
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
+  data = (uint32_t *) &message[1];
+  payload = ntohl (*data);
+  if (payload == *counter)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                " payload %u, expected: %u\n",
+                payload, *counter);
+  }
+
+  if (GNUNET_NO == initialized)
+  {
+    initialized = GNUNET_YES;
+    start_time = GNUNET_TIME_absolute_get ();
+    if (SPEED == test)
+    {
+      GNUNET_assert (incoming_ch == channel);
+      send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
+      return;
+    }
+  }
+
+  (*counter)++;
+  if (get_target_channel () == channel) /* Got "data" */
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
+    if (SPEED != test || (ok_goal - 2) == ok)
+    {
+      /* Send ACK */
+      send_test_message (channel);
+      return;
+    }
+    else
+    {
+      if (data_received < total_packets)
+        return;
+    }
+  }
+  else /* Got "ack" */
+  {
+    if (SPEED_ACK == test || SPEED == test)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
+      /* Send more data */
+      send_test_message (channel);
+      if (ack_received < total_packets && SPEED != test)
+        return;
+      if (ok == 2 && SPEED == test)
+        return;
+      show_end_data ();
+    }
+    if (test == P2P_SIGNAL)
+    {
+      GNUNET_CADET_channel_destroy (incoming_ch);
+      incoming_ch = NULL;
+    }
+    else
+    {
+      GNUNET_CADET_channel_destroy (outgoing_ch);
+      outgoing_ch = NULL;
+    }
+  }
+}
+
+
+/**
+ * Method called whenever a peer connects to a port in MQ-based CADET.
+ *
+ * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
+ * @param channel New handle to the channel.
+ * @param source Peer that started this channel.
+ * @return Closure for the incoming @a channel. It's given to:
+ *         - The #GNUNET_CADET_DisconnectEventHandler (given to
+ *           #GNUNET_CADET_open_porT) when the channel dies.
+ *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
+ *           received on the @a channel.
+ */
+static void *
+connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
+                 const struct GNUNET_PeerIdentity *source)
+{
+  struct CadetTestChannelWrapper *ch;
+  long peer = (long) cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Incoming channel from %s to %ld: %p\n",
+              GNUNET_i2s (source), peer, channel);
+  ok++;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
+  if (peer == peers_requested - 1)
+  {
+    if (NULL != incoming_ch)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Duplicate incoming channel for client %lu\n", (long) cls);
+      GNUNET_assert (0);
+    }
+    incoming_ch = channel;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Incoming channel for unexpected peer #%lu\n", (long) cls);
+    GNUNET_assert (0);
+  }
+  if (NULL != disconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+    disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                    &gather_stats_and_exit,
+                                                    (void *) __LINE__);
+  }
+
+  /* TODO: cannot return channel as-is, in order to unify the data handlers */
+  ch = GNUNET_new (struct CadetTestChannelWrapper);
+  ch->ch = channel;
+
+  return ch;
+}
+
+
+/**
+ * Function called whenever an MQ-channel is destroyed, even if the destruction
+ * was requested by #GNUNET_CADET_channel_destroy.
+ * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
+ *
+ * It should clean up any associated state, including cancelling any pending
+ * transmission on this channel.
+ *
+ * @param cls Channel closure (channel wrapper).
+ * @param channel Connection to the other end (henceforth invalid).
+ */
+static void
+disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
+{
+  struct CadetTestChannelWrapper *ch_w = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
+  GNUNET_assert (ch_w->ch == channel);
+  if (channel == incoming_ch)
+  {
+    ok++;
+    incoming_ch = NULL;
+  }
+  else if (outgoing_ch == channel
+  )
+  {
+    if (P2P_SIGNAL == test)
+    {
+      ok++;
+    }
+    outgoing_ch = NULL;
+  }
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
+
+  if (NULL != disconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
+  }
+}
+
+
+/**
+ * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
+ *
+ * Testcase continues when the root receives confirmation of connected peers,
+ * on callback function ch.
+ *
+ * @param cls Closure (unused).
+ */
+static void
+start_test (void *cls)
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (data,
+                           GNUNET_MESSAGE_TYPE_DUMMY,
+                           struct GNUNET_MessageHeader,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
+  struct CadetTestChannelWrapper *ch;
+  enum GNUNET_CADET_ChannelOption flags;
+
+  test_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
+  if (NULL != disconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (disconnect_task);
+    disconnect_task = NULL;
+  }
+
+  flags = GNUNET_CADET_OPTION_DEFAULT;
+  if (SPEED_REL == test)
+  {
+    test = SPEED;
+    flags |= GNUNET_CADET_OPTION_RELIABLE;
+  }
+
+  ch = GNUNET_new (struct CadetTestChannelWrapper);
+  outgoing_ch = GNUNET_CADET_channel_creatE (h1,
+                                             ch,
+                                             p_id[1],
+                                             &port,
+                                             flags,
+                                             NULL,
+                                             &disconnect_handler,
+                                             handlers);
+
+  ch->ch = outgoing_ch;
+
+  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                  &gather_stats_and_exit,
+                                                  (void *) __LINE__);
+  if (KEEPALIVE == test)
+    return;                     /* Don't send any data. */
+
+
+  data_received = 0;
+  data_sent = 0;
+  ack_received = 0;
+  ack_sent = 0;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending data initializer on channel %p...\n",
+              outgoing_ch);
+  send_test_message (outgoing_ch);
+}
+
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed;
+ *             NULL if the operation is successfull
+ */
+static void
+pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
+       const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
+{
+  long i = (long) cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
+
+  if ((NULL == pinfo) || (NULL != emsg))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
+    abort_test (__LINE__);
+    return;
+  }
+  p_id[i] = pinfo->result.id;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
+  p_ids++;
+  if (p_ids < 2)
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
+  test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
+}
+
+
+/**
+ * test main: start test when all peers are connected
+ *
+ * @param cls Closure.
+ * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
+ * @param num_peers Number of peers that are running.
+ * @param peers Array of peers.
+ * @param cadets Handle to each of the CADETs of the peers.
+ */
+static void
+tmain (void *cls,
+       struct GNUNET_CADET_TEST_Context *ctx,
+       unsigned int num_peers,
+       struct GNUNET_TESTBED_Peer **peers,
+       struct GNUNET_CADET_Handle **cadets)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
+  ok = 0;
+  test_ctx = ctx;
+  peers_running = num_peers;
+  GNUNET_assert (peers_running == peers_requested);
+  testbed_peers = peers;
+  h1 = cadets[0];
+  h2 = cadets[num_peers - 1];
+  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                  &disconnect_cadet_peers,
+                                                  (void *) __LINE__);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
+  t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
+                                                 GNUNET_TESTBED_PIT_IDENTITY,
+                                                 &pi_cb,
+                                                 (void *) 0L);
+  t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
+                                                 GNUNET_TESTBED_PIT_IDENTITY,
+                                                 &pi_cb,
+                                                 (void *) 1L);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
+}
+
+
+/**
+ * Main: start test
+ */
+int
+main (int argc, char *argv[])
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (data,
+                           GNUNET_MESSAGE_TYPE_DUMMY,
+                           struct GNUNET_MessageHeader,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
+
+  initialized = GNUNET_NO;
+  static const struct GNUNET_HashCode *ports[2];
+  const char *config_file;
+  char port_id[] = "test port";
+
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    {'t', "time", "short_time",
+     gettext_noop ("set short timeout"),
+     GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time},
+    {'m', "messages", "NUM_MESSAGES",
+     gettext_noop ("set number of messages to send"),
+     GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets},
+
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  GNUNET_log_setup ("test", "DEBUG", NULL);
+
+  total_packets = TOTAL_PACKETS;
+  short_time = SHORT_TIME;
+  if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
+  {
+    FPRINTF (stderr, "test failed: problem with CLI parameters\n");
+    exit (1);
+  }
+
+  config_file = "test_cadet.conf";
+  GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
+
+  /* Find out requested size */
+  if (strstr (argv[0], "_2_") != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
+    peers_requested = 2;
+  }
+  else if (strstr (argv[0], "_5_") != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
+    peers_requested = 5;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
+    peers_requested = 2;
+  }
+
+  /* Find out requested test */
+  if (strstr (argv[0], "_forward") != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
+    test = FORWARD;
+    test_name = "unicast";
+    ok_goal = 4;
+  }
+  else if (strstr (argv[0], "_signal") != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
+    test = P2P_SIGNAL;
+    test_name = "signal";
+    ok_goal = 4;
+  }
+  else if (strstr (argv[0], "_speed_ack") != NULL)
+  {
+    /* Test is supposed to generate the following callbacks:
+     * 1 incoming channel (@dest)
+     * total_packets received data packet (@dest)
+     * total_packets received data packet (@orig)
+     * 1 received channel destroy (@dest)
+     */
+    ok_goal = total_packets * 2 + 2;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
+    test = SPEED_ACK;
+    test_name = "speed ack";
+  }
+  else if (strstr (argv[0], "_speed") != NULL)
+  {
+    /* Test is supposed to generate the following callbacks:
+     * 1 incoming channel (@dest)
+     * 1 initial packet (@dest)
+     * total_packets received data packet (@dest)
+     * 1 received data packet (@orig)
+     * 1 received channel destroy (@dest)
+     */
+    ok_goal = total_packets + 4;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
+    if (strstr (argv[0], "_reliable") != NULL)
+    {
+      test = SPEED_REL;
+      test_name = "speed reliable";
+      config_file = "test_cadet_drop.conf";
+    }
+    else
+    {
+      test = SPEED;
+      test_name = "speed";
+    }
+  }
+  else if (strstr (argv[0], "_keepalive") != NULL)
+  {
+    test = KEEPALIVE;
+    /* Test is supposed to generate the following callbacks:
+     * 1 incoming channel (@dest)
+     * [wait]
+     * 1 received channel destroy (@dest)
+     */
+    ok_goal = 2;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
+    test = SETUP;
+    ok_goal = 0;
+  }
+
+  if (strstr (argv[0], "backwards") != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
+    test_backwards = GNUNET_YES;
+    GNUNET_asprintf (&test_name, "backwards %s", test_name);
+  }
+
+  p_ids = 0;
+  ports[0] = &port;
+  ports[1] = NULL;
+  GNUNET_CADET_TEST_ruN ("test_cadet_small",
+                         config_file,
+                         peers_requested,
+                         &tmain,
+                         NULL,        /* tmain cls */
+                         &connect_handler,
+                         NULL,
+                         &disconnect_handler,
+                         handlers,
+                         ports);
+  if (NULL != strstr (argv[0], "_reliable"))
+    msg_dropped = 0;            /* dropped should be retransmitted */
+
+  if (ok_goal > ok - msg_dropped)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
+    return 1;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
+  return 0;
+}
+
+/* end of test_cadet.c */
diff --git a/src/cadet/test_cadet_new.c b/src/cadet/test_cadet_new.c
deleted file mode 100644 (file)
index 374e86b..0000000
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011, 2017 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/test_cadet_mq.c
- * @author Bart Polot
- * @author Christian Grothoff
- * @brief Test for the cadet service using mq API.
- */
-#include <stdio.h>
-#include "platform.h"
-#include "cadet_test_lib_new.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include <gauger.h>
-
-
-/**
- * Ugly workaround to unify data handlers on incoming and outgoing channels.
- */
-struct CadetTestChannelWrapper
-{
-  /**
-   * Channel pointer.
-   */
-  struct GNUNET_CADET_Channel *ch;
-};
-
-/**
- * How many messages to send by default.
- */
-#define TOTAL_PACKETS 500       /* Cannot exceed 64k! */
-
-/**
- * How long until we give up on connecting the peers?
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
-
-/**
- * Time to wait by default  for stuff that should be rather fast.
- */
-#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
-
-/**
- * DIFFERENT TESTS TO RUN
- */
-#define SETUP 0
-#define FORWARD 1
-#define KEEPALIVE 2
-#define SPEED 3
-#define SPEED_ACK 4
-#define SPEED_REL 8
-#define P2P_SIGNAL 10
-
-/**
- * Which test are we running?
- */
-static int test;
-
-/**
- * String with test name
- */
-static char *test_name;
-
-/**
- * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
- */
-static int test_backwards = GNUNET_NO;
-
-/**
- * How many packets to send.
- */
-static unsigned int total_packets;
-
-/**
- * Time to wait for fast operations.
- */
-static struct GNUNET_TIME_Relative short_time;
-
-/**
- * How many events have happened
- */
-static int ok;
-
-/**
- * Number of events expected to conclude the test successfully.
- */
-static int ok_goal;
-
-/**
- * Size of each test packet's payload
- */
-static size_t size_payload = sizeof (uint32_t);
-
-/**
- * Operation to get peer ids.
- */
-static struct GNUNET_TESTBED_Operation *t_op[2];
-
-/**
- * Peer ids.
- */
-static struct GNUNET_PeerIdentity *p_id[2];
-
-/**
- * Port ID
- */
-static struct GNUNET_HashCode port;
-
-/**
- * Peer ids counter.
- */
-static unsigned int p_ids;
-
-/**
- * Is the setup initialized?
- */
-static int initialized;
-
-/**
- * Number of payload packes sent.
- */
-static int data_sent;
-
-/**
- * Number of payload packets received.
- */
-static int data_received;
-
-/**
- * Number of payload packed acknowledgements sent.
- */
-static int ack_sent;
-
-/**
- * Number of payload packed explicitly (app level) acknowledged.
- */
-static int ack_received;
-
-/**
- * Total number of peers asked to run.
- */
-static unsigned long long peers_requested;
-
-/**
- * Number of currently running peers (should be same as @c peers_requested).
- */
-static unsigned long long peers_running;
-
-/**
- * Test context (to shut down).
- */
-struct GNUNET_CADET_TEST_Context *test_ctx;
-
-/**
- * Task called to disconnect peers.
- */
-static struct GNUNET_SCHEDULER_Task *disconnect_task;
-
-/**
- * Task To perform tests
- */
-static struct GNUNET_SCHEDULER_Task *test_task;
-
-/**
- * Task runnining #send_next_msg().
- */
-static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
-
-/**
- * Cadet handle for the root peer
- */
-static struct GNUNET_CADET_Handle *h1;
-
-/**
- * Cadet handle for the first leaf peer
- */
-static struct GNUNET_CADET_Handle *h2;
-
-/**
- * Channel handle for the root peer
- */
-static struct GNUNET_CADET_Channel *outgoing_ch;
-
-/**
- * Channel handle for the dest peer
- */
-static struct GNUNET_CADET_Channel *incoming_ch;
-
-/**
- * Time we started the data transmission (after channel has been established
- * and initilized).
- */
-static struct GNUNET_TIME_Absolute start_time;
-
-/**
- * Peers handle.
- */
-static struct GNUNET_TESTBED_Peer **testbed_peers;
-
-/**
- * Statistics operation handle.
- */
-static struct GNUNET_TESTBED_Operation *stats_op;
-
-/**
- * Keepalives sent.
- */
-static unsigned int ka_sent;
-
-/**
- * Keepalives received.
- */
-static unsigned int ka_received;
-
-/**
- * How many messages were dropped by CADET because of full buffers?
- */
-static unsigned int msg_dropped;
-
-
-/******************************************************************************/
-
-
-/******************************************************************************/
-
-
-/**
- * Get the channel considered as the "target" or "receiver", depending on
- * the test type and size.
- *
- * @return Channel handle of the target client, either 0 (for backward tests)
- *         or the last peer in the line (for other tests).
- */
-static struct GNUNET_CADET_Channel *
-get_target_channel ()
-{
-  if (SPEED == test && GNUNET_YES == test_backwards)
-    return outgoing_ch;
-  else
-    return incoming_ch;
-}
-
-
-/**
- * Show the results of the test (banwidth acheived) and log them to GAUGER
- */
-static void
-show_end_data (void)
-{
-  static struct GNUNET_TIME_Absolute end_time;
-  static struct GNUNET_TIME_Relative total_time;
-
-  end_time = GNUNET_TIME_absolute_get ();
-  total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
-  FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
-  FPRINTF (stderr, "Test time %s\n",
-           GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
-  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000));    // 4bytes * ms
-  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000));     // packets * ms
-  GAUGER ("CADET", test_name,
-          total_packets * 1000.0 / (total_time.rel_value_us / 1000),
-          "packets/s");
-}
-
-
-/**
- * Disconnect from cadet services af all peers, call shutdown.
- *
- * @param cls Closure (line number from which termination was requested).
- * @param tc Task Context.
- */
-static void
-disconnect_cadet_peers (void *cls)
-{
-  long line = (long) cls;
-  unsigned int i;
-
-  disconnect_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "disconnecting cadet service of peers, called from line %ld\n",
-              line);
-  for (i = 0; i < 2; i++)
-  {
-    GNUNET_TESTBED_operation_done (t_op[i]);
-  }
-  if (NULL != outgoing_ch)
-  {
-    GNUNET_CADET_channel_destroy (outgoing_ch);
-    outgoing_ch = NULL;
-  }
-  if (NULL != incoming_ch)
-  {
-    GNUNET_CADET_channel_destroy (incoming_ch);
-    incoming_ch = NULL;
-  }
-  GNUNET_CADET_TEST_cleanup (test_ctx);
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Shut down peergroup, clean up.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-shutdown_task (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
-  if (NULL != send_next_msg_task)
-  {
-    GNUNET_SCHEDULER_cancel (send_next_msg_task);
-    send_next_msg_task = NULL;
-  }
-  if (NULL != test_task)
-  {
-    GNUNET_SCHEDULER_cancel (test_task);
-    test_task = NULL;
-  }
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
-  }
-}
-
-
-/**
- * Stats callback. Finish the stats testbed operation and when all stats have
- * been iterated, shutdown the test.
- *
- * @param cls Closure (line number from which termination was requested).
- * @param op the operation that has been finished
- * @param emsg error message in case the operation has failed; will be NULL if
- *          operation has executed successfully.
- */
-static void
-stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
-              ka_sent, ka_received);
-  if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
-  {
-    GNUNET_break (0);
-    ok--;
-  }
-  GNUNET_TESTBED_operation_done (stats_op);
-
-  if (NULL != disconnect_task)
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-  disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
-}
-
-
-/**
- * Process statistic values.
- *
- * @param cls closure (line number, unused)
- * @param peer the peer the statistic belong to
- * @param subsystem name of subsystem that created the statistic
- * @param name the name of the datum
- * @param value the current value
- * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
- */
-static int
-stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
-                const char *subsystem, const char *name, uint64_t value,
-                int is_persistent)
-{
-  static const char *s_sent = "# keepalives sent";
-  static const char *s_recv = "# keepalives received";
-  static const char *rdrops = "# messages dropped due to full buffer";
-  static const char *cdrops = "# messages dropped due to slow client";
-  uint32_t i;
-
-  i = GNUNET_TESTBED_get_index (peer);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
-              subsystem, name, (unsigned long long) value);
-  if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
-    ka_sent = value;
-  if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
-    ka_received = value;
-  if (0 == strncmp (rdrops, name, strlen (rdrops)))
-    msg_dropped += value;
-  if (0 == strncmp (cdrops, name, strlen (cdrops)))
-    msg_dropped += value;
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Task to gather all statistics.
- *
- * @param cls Closure (line from which the task was scheduled).
- */
-static void
-gather_stats_and_exit (void *cls)
-{
-  long l = (long) cls;
-
-  disconnect_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "gathering statistics from line %ld\n",
-              l);
-  if (NULL != outgoing_ch)
-  {
-    GNUNET_CADET_channel_destroy (outgoing_ch);
-    outgoing_ch = NULL;
-  }
-  stats_op = GNUNET_TESTBED_get_statistics (peers_running,
-                                            testbed_peers,
-                                            "cadet",
-                                            NULL,
-                                            &stats_iterator,
-                                            stats_cont,
-                                            cls);
-}
-
-
-
-/**
- * Abort test: schedule disconnect and shutdown immediately
- *
- * @param line Line in the code the abort is requested from (__LINE__).
- */
-static void
-abort_test (long line)
-{
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
-  }
-}
-
-
-/**
- * Send a message on the channel with the appropriate size and payload.
- *
- * Update the appropriate *_sent counter.
- *
- * @param channel Channel to send the message on.
- */
-static void
-send_test_message (struct GNUNET_CADET_Channel *channel)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-  uint32_t *data;
-  int payload;
-  int size;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending test message on channel %p\n",
-              channel);
-  size = size_payload;
-  if (GNUNET_NO == initialized)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
-    size += 1000;
-    payload = data_sent;
-    if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
-        data_sent++;
-  }
-  else if (SPEED == test || SPEED_ACK == test)
-  {
-    if (get_target_channel() == channel)
-    {
-      payload = ack_sent;
-      size += ack_sent;
-      ack_sent++;
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Sending ACK %u [%d bytes]\n",
-                  payload, size);
-    }
-    else
-    {
-      payload = data_sent;
-      size += data_sent;
-      data_sent++;
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Sending DATA %u [%d bytes]\n",
-                  data_sent, size);
-    }
-  }
-  else if (FORWARD == test)
-  {
-    payload = ack_sent;
-  }
-  else if (P2P_SIGNAL == test)
-  {
-    payload = data_sent;
-  }
-  else
-  {
-    GNUNET_assert (0);
-  }
-  env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
-
-  data = (uint32_t *) &msg[1];
-  *data = htonl (payload);
-  GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
-}
-
-/**
- * Task to request a new data transmission in a SPEED test, without waiting
- * for previous messages to be sent/arrrive.
- *
- * @param cls Closure (unused).
- */
-static void
-send_next_msg (void *cls)
-{
-  struct GNUNET_CADET_Channel *channel;
-
-  send_next_msg_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
-
-  channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
-  GNUNET_assert (NULL != channel);
-  GNUNET_assert (SPEED == test);
-  send_test_message (channel);
-  if (data_sent < total_packets)
-  {
-    /* SPEED test: Send all messages as soon as possible */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Scheduling message %d\n",
-                data_sent + 1);
-    send_next_msg_task =
-        GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
-                                     &send_next_msg,
-                                     NULL);
-  }
-}
-
-
-/**
- * Every few messages cancel the timeout task and re-schedule it again, to
- * avoid timing out when traffic keeps coming.
- *
- * @param line Code line number to log if a timeout occurs.
- */
-static void
-reschedule_timeout_task (long line)
-{
-  if ((ok % 10) == 0)
-  {
-    if (NULL != disconnect_task)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  " reschedule timeout every 10 messages\n");
-      GNUNET_SCHEDULER_cancel (disconnect_task);
-      disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
-                                                      &gather_stats_and_exit,
-                                                      (void *) line);
-    }
-  }
-}
-
-
-/**
- * Check if payload is sane (size contains payload).
- *
- * @param cls should match #ch
- * @param message The actual message.
- * @return #GNUNET_OK to keep the channel open,
- *         #GNUNET_SYSERR to close it (signal serious error).
- */
-static int
-check_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
-  if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
-    return GNUNET_SYSERR;
-  return GNUNET_OK;             /* all is well-formed */
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect(), peer number)
- * @param message the actual message
- */
-static void
-handle_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
-  struct CadetTestChannelWrapper *ch = cls;
-  struct GNUNET_CADET_Channel *channel = ch->ch;
-  uint32_t *data;
-  uint32_t payload;
-  int *counter;
-
-  ok++;
-  GNUNET_CADET_receive_done (channel);
-  counter = get_target_channel () == channel ? &data_received : &ack_received;
-
-  reschedule_timeout_task ((long) __LINE__);
-
-  if (channel == outgoing_ch)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
-  }
-  else if (channel == incoming_ch)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
-    GNUNET_assert (0);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
-  data = (uint32_t *) &message[1];
-  payload = ntohl (*data);
-  if (payload == *counter)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                " payload %u, expected: %u\n",
-                payload, *counter);
-  }
-
-  if (GNUNET_NO == initialized)
-  {
-    initialized = GNUNET_YES;
-    start_time = GNUNET_TIME_absolute_get ();
-    if (SPEED == test)
-    {
-      GNUNET_assert (incoming_ch == channel);
-      send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
-      return;
-    }
-  }
-
-  (*counter)++;
-  if (get_target_channel () == channel) /* Got "data" */
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
-    if (SPEED != test || (ok_goal - 2) == ok)
-    {
-      /* Send ACK */
-      send_test_message (channel);
-      return;
-    }
-    else
-    {
-      if (data_received < total_packets)
-        return;
-    }
-  }
-  else /* Got "ack" */
-  {
-    if (SPEED_ACK == test || SPEED == test)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
-      /* Send more data */
-      send_test_message (channel);
-      if (ack_received < total_packets && SPEED != test)
-        return;
-      if (ok == 2 && SPEED == test)
-        return;
-      show_end_data ();
-    }
-    if (test == P2P_SIGNAL)
-    {
-      GNUNET_CADET_channel_destroy (incoming_ch);
-      incoming_ch = NULL;
-    }
-    else
-    {
-      GNUNET_CADET_channel_destroy (outgoing_ch);
-      outgoing_ch = NULL;
-    }
-  }
-}
-
-
-/**
- * Method called whenever a peer connects to a port in MQ-based CADET.
- *
- * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
- * @param channel New handle to the channel.
- * @param source Peer that started this channel.
- * @return Closure for the incoming @a channel. It's given to:
- *         - The #GNUNET_CADET_DisconnectEventHandler (given to
- *           #GNUNET_CADET_open_porT) when the channel dies.
- *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
- *           received on the @a channel.
- */
-static void *
-connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
-                 const struct GNUNET_PeerIdentity *source)
-{
-  struct CadetTestChannelWrapper *ch;
-  long peer = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Incoming channel from %s to %ld: %p\n",
-              GNUNET_i2s (source), peer, channel);
-  ok++;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-  if (peer == peers_requested - 1)
-  {
-    if (NULL != incoming_ch)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Duplicate incoming channel for client %lu\n", (long) cls);
-      GNUNET_assert (0);
-    }
-    incoming_ch = channel;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Incoming channel for unexpected peer #%lu\n", (long) cls);
-    GNUNET_assert (0);
-  }
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
-                                                    &gather_stats_and_exit,
-                                                    (void *) __LINE__);
-  }
-
-  /* TODO: cannot return channel as-is, in order to unify the data handlers */
-  ch = GNUNET_new (struct CadetTestChannelWrapper);
-  ch->ch = channel;
-
-  return ch;
-}
-
-
-/**
- * Function called whenever an MQ-channel is destroyed, even if the destruction
- * was requested by #GNUNET_CADET_channel_destroy.
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
- *
- * It should clean up any associated state, including cancelling any pending
- * transmission on this channel.
- *
- * @param cls Channel closure (channel wrapper).
- * @param channel Connection to the other end (henceforth invalid).
- */
-static void
-disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
-{
-  struct CadetTestChannelWrapper *ch_w = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
-  GNUNET_assert (ch_w->ch == channel);
-  if (channel == incoming_ch)
-  {
-    ok++;
-    incoming_ch = NULL;
-  }
-  else if (outgoing_ch == channel
-  )
-  {
-    if (P2P_SIGNAL == test)
-    {
-      ok++;
-    }
-    outgoing_ch = NULL;
-  }
-  else
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
-  }
-}
-
-
-/**
- * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback function ch.
- *
- * @param cls Closure (unused).
- */
-static void
-start_test (void *cls)
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (data,
-                           GNUNET_MESSAGE_TYPE_DUMMY,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-  struct CadetTestChannelWrapper *ch;
-  enum GNUNET_CADET_ChannelOption flags;
-
-  test_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = NULL;
-  }
-
-  flags = GNUNET_CADET_OPTION_DEFAULT;
-  if (SPEED_REL == test)
-  {
-    test = SPEED;
-    flags |= GNUNET_CADET_OPTION_RELIABLE;
-  }
-
-  ch = GNUNET_new (struct CadetTestChannelWrapper);
-  outgoing_ch = GNUNET_CADET_channel_creatE (h1,
-                                             ch,
-                                             p_id[1],
-                                             &port,
-                                             flags,
-                                             NULL,
-                                             &disconnect_handler,
-                                             handlers);
-
-  ch->ch = outgoing_ch;
-
-  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
-                                                  &gather_stats_and_exit,
-                                                  (void *) __LINE__);
-  if (KEEPALIVE == test)
-    return;                     /* Don't send any data. */
-
-
-  data_received = 0;
-  data_sent = 0;
-  ack_received = 0;
-  ack_sent = 0;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending data initializer on channel %p...\n",
-              outgoing_ch);
-  send_test_message (outgoing_ch);
-}
-
-
-/**
- * Callback to be called when the requested peer information is available
- *
- * @param cls the closure from GNUNET_TESTBED_peer_get_information()
- * @param op the operation this callback corresponds to
- * @param pinfo the result; will be NULL if the operation has failed
- * @param emsg error message if the operation has failed;
- *             NULL if the operation is successfull
- */
-static void
-pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
-       const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
-{
-  long i = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
-
-  if ((NULL == pinfo) || (NULL != emsg))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
-    abort_test (__LINE__);
-    return;
-  }
-  p_id[i] = pinfo->result.id;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
-  p_ids++;
-  if (p_ids < 2)
-    return;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
-  test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
-}
-
-
-/**
- * test main: start test when all peers are connected
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadets Handle to each of the CADETs of the peers.
- */
-static void
-tmain (void *cls,
-       struct GNUNET_CADET_TEST_Context *ctx,
-       unsigned int num_peers,
-       struct GNUNET_TESTBED_Peer **peers,
-       struct GNUNET_CADET_Handle **cadets)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
-  ok = 0;
-  test_ctx = ctx;
-  peers_running = num_peers;
-  GNUNET_assert (peers_running == peers_requested);
-  testbed_peers = peers;
-  h1 = cadets[0];
-  h2 = cadets[num_peers - 1];
-  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
-                                                  &disconnect_cadet_peers,
-                                                  (void *) __LINE__);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
-  t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
-                                                 GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb,
-                                                 (void *) 0L);
-  t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
-                                                 GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb,
-                                                 (void *) 1L);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
-}
-
-
-/**
- * Main: start test
- */
-int
-main (int argc, char *argv[])
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (data,
-                           GNUNET_MESSAGE_TYPE_DUMMY,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-
-  initialized = GNUNET_NO;
-  static const struct GNUNET_HashCode *ports[2];
-  const char *config_file;
-  char port_id[] = "test port";
-
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'t', "time", "short_time",
-     gettext_noop ("set short timeout"),
-     GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time},
-    {'m', "messages", "NUM_MESSAGES",
-     gettext_noop ("set number of messages to send"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets},
-
-    GNUNET_GETOPT_OPTION_END
-  };
-
-  GNUNET_log_setup ("test", "DEBUG", NULL);
-
-  total_packets = TOTAL_PACKETS;
-  short_time = SHORT_TIME;
-  if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
-  {
-    FPRINTF (stderr, "test failed: problem with CLI parameters\n");
-    exit (1);
-  }
-
-  config_file = "test_cadet.conf";
-  GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
-
-  /* Find out requested size */
-  if (strstr (argv[0], "_2_") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
-    peers_requested = 2;
-  }
-  else if (strstr (argv[0], "_5_") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
-    peers_requested = 5;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
-    peers_requested = 2;
-  }
-
-  /* Find out requested test */
-  if (strstr (argv[0], "_forward") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
-    test = FORWARD;
-    test_name = "unicast";
-    ok_goal = 4;
-  }
-  else if (strstr (argv[0], "_signal") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
-    test = P2P_SIGNAL;
-    test_name = "signal";
-    ok_goal = 4;
-  }
-  else if (strstr (argv[0], "_speed_ack") != NULL)
-  {
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * total_packets received data packet (@dest)
-     * total_packets received data packet (@orig)
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = total_packets * 2 + 2;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
-    test = SPEED_ACK;
-    test_name = "speed ack";
-  }
-  else if (strstr (argv[0], "_speed") != NULL)
-  {
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * 1 initial packet (@dest)
-     * total_packets received data packet (@dest)
-     * 1 received data packet (@orig)
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = total_packets + 4;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
-    if (strstr (argv[0], "_reliable") != NULL)
-    {
-      test = SPEED_REL;
-      test_name = "speed reliable";
-      config_file = "test_cadet_drop.conf";
-    }
-    else
-    {
-      test = SPEED;
-      test_name = "speed";
-    }
-  }
-  else if (strstr (argv[0], "_keepalive") != NULL)
-  {
-    test = KEEPALIVE;
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * [wait]
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = 2;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
-    test = SETUP;
-    ok_goal = 0;
-  }
-
-  if (strstr (argv[0], "backwards") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
-    test_backwards = GNUNET_YES;
-    GNUNET_asprintf (&test_name, "backwards %s", test_name);
-  }
-
-  p_ids = 0;
-  ports[0] = &port;
-  ports[1] = NULL;
-  GNUNET_CADET_TEST_ruN ("test_cadet_small",
-                         config_file,
-                         peers_requested,
-                         &tmain,
-                         NULL,        /* tmain cls */
-                         &connect_handler,
-                         NULL,
-                         &disconnect_handler,
-                         handlers,
-                         ports);
-  if (NULL != strstr (argv[0], "_reliable"))
-    msg_dropped = 0;            /* dropped should be retransmitted */
-
-  if (ok_goal > ok - msg_dropped)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
-    return 1;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
-  return 0;
-}
-
-/* end of test_cadet.c */