gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated (16fd15965 -> 9a8457f1b)


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated (16fd15965 -> 9a8457f1b)
Date: Sun, 15 Jan 2017 21:50:15 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository gnunet.

    from 16fd15965 block size of 0 is also valid
     new 5b32752cd indentation fixes
     new 4270685ca fix format string issue
     new 71785fccb cleaning up some CADET logic, improving types used
     new 9a8457f1b starting re-implementation of CADET service

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/cadet/Makefile.am                              |   36 +-
 src/cadet/cadet.h                                  |   53 +-
 src/cadet/cadet_api.c                              |  404 +++---
 src/cadet/cadet_protocol.h                         |   11 +-
 src/cadet/gnunet-cadet.c                           |   13 +-
 src/cadet/gnunet-service-cadet-new.c               | 1302 ++++++++++++++++++++
 src/cadet/gnunet-service-cadet-new.h               |  144 +++
 src/cadet/gnunet-service-cadet-new_channel.c       | 1154 +++++++++++++++++
 src/cadet/gnunet-service-cadet-new_channel.h       |  173 +++
 .../gnunet-service-cadet-new_connection.c}         |   47 +-
 .../gnunet-service-cadet-new_connection.h}         |   42 +-
 src/cadet/gnunet-service-cadet-new_dht.c           |  337 +++++
 ...-cadet_dht.h => gnunet-service-cadet-new_dht.h} |   33 +-
 src/cadet/gnunet-service-cadet-new_hello.c         |  142 +++
 ...et_hello.h => gnunet-service-cadet-new_hello.h} |   10 +-
 src/cadet/gnunet-service-cadet-new_paths.c         |   94 ++
 src/cadet/gnunet-service-cadet-new_paths.h         |   83 ++
 src/cadet/gnunet-service-cadet-new_peer.c          |  509 ++++++++
 src/cadet/gnunet-service-cadet-new_peer.h          |  170 +++
 src/cadet/gnunet-service-cadet-new_tunnels.c       |  830 +++++++++++++
 src/cadet/gnunet-service-cadet-new_tunnels.h       |  314 +++++
 src/cadet/gnunet-service-cadet_channel.c           |   81 +-
 src/cadet/gnunet-service-cadet_channel.h           |    4 +-
 src/cadet/gnunet-service-cadet_connection.c        |    2 +-
 src/cadet/gnunet-service-cadet_dht.c               |   16 +-
 src/cadet/gnunet-service-cadet_hello.h             |    5 +-
 src/cadet/gnunet-service-cadet_local.c             |  182 +--
 src/cadet/gnunet-service-cadet_local.h             |   30 +-
 src/cadet/gnunet-service-cadet_peer.c              |    4 +-
 src/cadet/gnunet-service-cadet_peer.h              |    5 +-
 src/cadet/gnunet-service-cadet_tunnel.c            |   96 +-
 src/cadet/gnunet-service-cadet_tunnel.h            |    4 +-
 src/cadet/test_cadet_local.c                       |    5 +-
 src/dht/gnunet-service-dht_hello.c                 |   20 +-
 src/dht/gnunet-service-dht_routing.c               |   36 +-
 src/include/gnunet_cadet_service.h                 |   29 +-
 src/include/gnunet_protocols.h                     |    5 +
 src/nat/gnunet-service-nat_helper.c                |   24 +-
 38 files changed, 5964 insertions(+), 485 deletions(-)
 create mode 100644 src/cadet/gnunet-service-cadet-new.c
 create mode 100644 src/cadet/gnunet-service-cadet-new.h
 create mode 100644 src/cadet/gnunet-service-cadet-new_channel.c
 create mode 100644 src/cadet/gnunet-service-cadet-new_channel.h
 copy src/{dht/gnunet-service-xdht_hello.h => 
cadet/gnunet-service-cadet-new_connection.c} (57%)
 copy src/{peerinfo-tool/gnunet-peerinfo_plugins.h => 
cadet/gnunet-service-cadet-new_connection.h} (56%)
 create mode 100644 src/cadet/gnunet-service-cadet-new_dht.c
 copy src/cadet/{gnunet-service-cadet_dht.h => gnunet-service-cadet-new_dht.h} 
(75%)
 create mode 100644 src/cadet/gnunet-service-cadet-new_hello.c
 copy src/cadet/{gnunet-service-cadet_hello.h => 
gnunet-service-cadet-new_hello.h} (91%)
 create mode 100644 src/cadet/gnunet-service-cadet-new_paths.c
 create mode 100644 src/cadet/gnunet-service-cadet-new_paths.h
 create mode 100644 src/cadet/gnunet-service-cadet-new_peer.c
 create mode 100644 src/cadet/gnunet-service-cadet-new_peer.h
 create mode 100644 src/cadet/gnunet-service-cadet-new_tunnels.c
 create mode 100644 src/cadet/gnunet-service-cadet-new_tunnels.h

diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am
index d823b4872..ba93bee18 100644
--- a/src/cadet/Makefile.am
+++ b/src/cadet/Makefile.am
@@ -22,7 +22,9 @@ plugindir = $(libdir)/gnunet
 AM_CLFAGS = -g
 
 libexec_PROGRAMS = \
- gnunet-service-cadet $(EXP_LIBEXEC)
+ gnunet-service-cadet \
+ gnunet-service-cadet-new \
+ $(EXP_LIBEXEC)
 
 bin_PROGRAMS = \
  gnunet-cadet
@@ -46,6 +48,26 @@ gnunet_cadet_LDADD = \
   libgnunetcadet.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_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 = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/ats/libgnunetats.la \
+  $(top_builddir)/src/core/libgnunetcore.la \
+  $(top_builddir)/src/dht/libgnunetdht.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/transport/libgnunettransport.la \
+  $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+  $(top_builddir)/src/hello/libgnunethello.la \
+  $(top_builddir)/src/block/libgnunetblock.la
+
 gnunet_service_cadet_SOURCES = \
  gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \
  gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
@@ -87,6 +109,11 @@ libgnunetcadettest_a_LIBADD = \
 
 if HAVE_TESTING
 check_PROGRAMS = \
+  test_cadet_2_speed_reliable_backwards \
+  test_cadet_5_speed \
+  test_cadet_5_speed_ack \
+  test_cadet_5_speed_reliable \
+  test_cadet_5_speed_reliable_backwards \
   test_cadet_single \
   test_cadet_local \
   test_cadet_2_forward \
@@ -96,15 +123,10 @@ check_PROGRAMS = \
   test_cadet_2_speed_ack \
   test_cadet_2_speed_backwards \
   test_cadet_2_speed_reliable \
-  test_cadet_2_speed_reliable_backwards \
   test_cadet_5_forward \
   test_cadet_5_signal \
   test_cadet_5_keepalive \
-  test_cadet_5_speed \
-  test_cadet_5_speed_ack \
-  test_cadet_5_speed_backwards \
-  test_cadet_5_speed_reliable \
-  test_cadet_5_speed_reliable_backwards
+  test_cadet_5_speed_backwards
 endif
 
 ld_cadet_test_lib = \
diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h
index f3f6fb6b4..163734c06 100644
--- a/src/cadet/cadet.h
+++ b/src/cadet/cadet.h
@@ -57,6 +57,7 @@ extern "C"
 #include "gnunet_util_lib.h"
 #include "gnunet_peer_lib.h"
 #include "gnunet_core_service.h"
+#include "gnunet_cadet_service.h"
 #include "gnunet_protocols.h"
 #include <gnunet_cadet_service.h>
 
@@ -64,12 +65,22 @@ extern "C"
 /**************************       CONSTANTS      
******************************/
 
/******************************************************************************/
 
+/**
+ * Minimum value for channel IDs of local clients.
+ */
 #define GNUNET_CADET_LOCAL_CHANNEL_ID_CLI        0x80000000
-#define GNUNET_CADET_LOCAL_CHANNEL_ID_SERV       0xB0000000
 
+/**
+ * FIXME.
+ */
 #define HIGH_PID                                0xFF000000
+
+/**
+ * FIXME.
+ */
 #define LOW_PID                                 0x00FFFFFF
 
+
 /**
  * Test if the two PIDs (of type `uint32_t`) are in the range where we
  * have to worry about overflows.  This is the case when @a pid is
@@ -86,6 +97,22 @@ GNUNET_NETWORK_STRUCT_BEGIN
 
 
 /**
+ * Number uniquely identifying a channel of a client.
+ */
+struct GNUNET_CADET_ClientChannelNumber
+{
+  /**
+   * Values for channel numbering.
+   * Local channel numbers given by the service (incoming) are
+   * smaller than #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI.
+   * Local channel numbers given by the client (created) are
+   * larger than #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI.
+   */
+  uint32_t channel_of_client GNUNET_PACKED;
+};
+
+
+/**
  * Message for a client to create and destroy channels.
  */
 struct GNUNET_CADET_PortMessage
@@ -104,14 +131,6 @@ struct GNUNET_CADET_PortMessage
   struct GNUNET_HashCode port GNUNET_PACKED;
 };
 
-/**
- * Type for channel numbering.
- * - Local channel numbers given by the service (incoming) are >= 0xB0000000
- * - Local channel numbers given by the client (created) are >= 0x80000000
- * - Global channel numbers are < 0x80000000
- */
-typedef uint32_t CADET_ChannelNumber;
-
 
 /**
  * Message for a client to create channels.
@@ -128,7 +147,7 @@ struct GNUNET_CADET_ChannelCreateMessage
   /**
    * ID of a channel controlled by this client.
    */
-  CADET_ChannelNumber channel_id GNUNET_PACKED;
+  struct GNUNET_CADET_ClientChannelNumber channel_id;
 
   /**
    * Channel's peer
@@ -158,11 +177,11 @@ struct GNUNET_CADET_ChannelDestroyMessage
    * Size: sizeof(struct GNUNET_CADET_ChannelDestroyMessage)
    */
   struct GNUNET_MessageHeader header;
-  
+
   /**
    * ID of a channel controlled by this client.
    */
-  CADET_ChannelNumber channel_id GNUNET_PACKED;
+  struct GNUNET_CADET_ClientChannelNumber channel_id;
 };
 
 
@@ -179,7 +198,7 @@ struct GNUNET_CADET_LocalData
   /**
    * ID of the channel
    */
-  uint32_t id GNUNET_PACKED;
+  struct GNUNET_CADET_ClientChannelNumber id;
 
   /**
    * Payload follows
@@ -201,7 +220,7 @@ struct GNUNET_CADET_LocalAck
   /**
    * ID of the channel allowed to send more data.
    */
-  CADET_ChannelNumber channel_id GNUNET_PACKED;
+  struct GNUNET_CADET_ClientChannelNumber channel_id;
 
 };
 
@@ -220,7 +239,7 @@ struct GNUNET_CADET_LocalInfo
   /**
    * ID of the channel allowed to send more data.
    */
-  CADET_ChannelNumber channel_id GNUNET_PACKED;
+  struct GNUNET_CADET_ClientChannelNumber channel_id;
 
   /**
    * ID of the owner of the channel (can be local peer).
@@ -264,6 +283,7 @@ struct GNUNET_CADET_LocalInfoPeer
    * (each path ends in destination) */
 };
 
+
 /**
  * Message to inform the client about one of the tunnels in the service.
  */
@@ -300,7 +320,7 @@ struct GNUNET_CADET_LocalInfoTunnel
    */
   uint16_t cstate GNUNET_PACKED;
 
-  /* If TUNNEL (no 'S'): GNUNET_PeerIdentity connection_ids[connections] */
+  /* If TUNNEL (no 'S'): struct GNUNET_CADET_ConnectionTunnelIdentifier 
connection_ids[connections] */
   /* If TUNNEL (no 'S'): uint32_t channel_ids[channels] */
 };
 
@@ -366,6 +386,7 @@ GC_min_pid (uint32_t a, uint32_t b);
 const struct GNUNET_HashCode *
 GC_h2hc (const struct GNUNET_CADET_Hash *id);
 
+
 /**
  * Get a string from a Cadet Hash (256 bits).
  * WARNING: Not reentrant (based on GNUNET_h2s).
diff --git a/src/cadet/cadet_api.c b/src/cadet/cadet_api.c
index 23305d8a9..57a14639d 100644
--- a/src/cadet/cadet_api.c
+++ b/src/cadet/cadet_api.c
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
+     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
@@ -19,7 +19,7 @@
 */
 /**
  * @file cadet/cadet_api.c
- * @brief cadet api: client implementation of new cadet service
+ * @brief cadet api: client implementation of cadet service
  * @author Bartlomiej Polot
  */
 
@@ -41,46 +41,48 @@
  */
 struct GNUNET_CADET_TransmitHandle
 {
-    /**
-     * Double Linked list
-     */
+  /**
+   * Double Linked list
+   */
   struct GNUNET_CADET_TransmitHandle *next;
 
-    /**
-     * Double Linked list
-     */
+  /**
+   * Double Linked list
+   */
   struct GNUNET_CADET_TransmitHandle *prev;
 
-    /**
-     * Channel this message is sent on / for (may be NULL for control 
messages).
-     */
+  /**
+   * Channel this message is sent on / for (may be NULL for control messages).
+   */
   struct GNUNET_CADET_Channel *channel;
 
-    /**
-     * Request data task.
-     */
+  /**
+   * Request data task.
+   */
   struct GNUNET_SCHEDULER_Task *request_data_task;
 
-    /**
-     * Callback to obtain the message to transmit, or NULL if we
-     * got the message in 'data'.  Notice that messages built
-     * by 'notify' need to be encapsulated with information about
-     * the 'target'.
-     */
+  /**
+   * Callback to obtain the message to transmit, or NULL if we
+   * got the message in 'data'.  Notice that messages built
+   * by 'notify' need to be encapsulated with information about
+   * the 'target'.
+   */
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-    /**
-     * Closure for 'notify'
-     */
+  /**
+   * Closure for 'notify'
+   */
   void *notify_cls;
 
-    /**
-     * Size of the payload.
-     */
+  /**
+   * Size of the payload.
+   */
   size_t size;
 };
 
-union CadetInfoCB {
+
+union CadetInfoCB
+{
 
   /**
    * Channel callback.
@@ -114,14 +116,14 @@ union CadetInfoCB {
  */
 struct GNUNET_CADET_Handle
 {
-    /**
-     * Message queue (if available).
-     */
+  /**
+   * Message queue (if available).
+   */
   struct GNUNET_MQ_Handle *mq;
 
-    /**
-     * Set of handlers used for processing incoming messages in the channels
-     */
+  /**
+   * Set of handlers used for processing incoming messages in the channels
+   */
   const struct GNUNET_CADET_MessageHandler *message_handlers;
 
   /**
@@ -134,40 +136,40 @@ struct GNUNET_CADET_Handle
    */
   struct GNUNET_CONTAINER_MultiHashMap *ports;
 
-    /**
-     * Double linked list of the channels this client is connected to, head.
-     */
+  /**
+   * Double linked list of the channels this client is connected to, head.
+   */
   struct GNUNET_CADET_Channel *channels_head;
 
-    /**
-     * Double linked list of the channels this client is connected to, tail.
-     */
+  /**
+   * Double linked list of the channels this client is connected to, tail.
+   */
   struct GNUNET_CADET_Channel *channels_tail;
 
-    /**
-     * Callback for inbound channel disconnection
-     */
+  /**
+   * Callback for inbound channel disconnection
+   */
   GNUNET_CADET_ChannelEndHandler *cleaner;
 
-    /**
-     * Closure for all the handlers given by the client
-     */
+  /**
+   * Closure for all the handlers given by the client
+   */
   void *cls;
 
-    /**
-     * Messages to send to the service, head.
-     */
+  /**
+   * Messages to send to the service, head.
+   */
   struct GNUNET_CADET_TransmitHandle *th_head;
 
-    /**
-     * Messages to send to the service, tail.
-     */
+  /**
+   * Messages to send to the service, tail.
+   */
   struct GNUNET_CADET_TransmitHandle *th_tail;
 
-    /**
-     * chid of the next channel to create (to avoid reusing IDs often)
-     */
-  CADET_ChannelNumber next_chid;
+  /**
+   * child of the next channel to create (to avoid reusing IDs often)
+   */
+  struct GNUNET_CADET_ClientChannelNumber next_chid;
 
   /**
    * Configuration given by the client, in case of reconnection
@@ -201,9 +203,9 @@ struct GNUNET_CADET_Handle
  */
 struct GNUNET_CADET_Peer
 {
-    /**
-     * ID of the peer in short form
-     */
+  /**
+   * ID of the peer in short form
+   */
   GNUNET_PEER_Id id;
 
   /**
@@ -218,34 +220,34 @@ struct GNUNET_CADET_Peer
  */
 struct GNUNET_CADET_Channel
 {
-    /**
-     * DLL next
-     */
+  /**
+   * DLL next
+   */
   struct GNUNET_CADET_Channel *next;
 
-    /**
-     * DLL prev
-     */
+  /**
+   * DLL prev
+   */
   struct GNUNET_CADET_Channel *prev;
 
-    /**
-     * Handle to the cadet this channel belongs to
-     */
+  /**
+   * Handle to the cadet this channel belongs to
+   */
   struct GNUNET_CADET_Handle *cadet;
 
-    /**
-     * Local ID of the channel
-     */
-  CADET_ChannelNumber chid;
+  /**
+   * Local ID of the channel
+   */
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
-    /**
-     * Channel's port, if any.
-     */
+  /**
+   * Channel's port, if any.
+   */
   struct GNUNET_CADET_Port *port;
 
-    /**
-     * Other end of the channel.
-     */
+  /**
+   * Other end of the channel.
+   */
   GNUNET_PEER_Id peer;
 
   /**
@@ -253,46 +255,47 @@ struct GNUNET_CADET_Channel
    */
   void *ctx;
 
-    /**
-     * Size of packet queued in this channel
-     */
+  /**
+   * Size of packet queued in this channel
+   */
   unsigned int packet_size;
 
-    /**
-     * Channel options: reliability, etc.
-     */
+  /**
+   * Channel options: reliability, etc.
+   */
   enum GNUNET_CADET_ChannelOption options;
 
-    /**
-     * Are we allowed to send to the service?
-     */
+  /**
+   * Are we allowed to send to the service?
+   */
   int allow_send;
 
 };
 
+
 /**
  * Opaque handle to a port.
  */
 struct GNUNET_CADET_Port
 {
-    /**
-     * Handle to the CADET session this port belongs to.
-     */
+  /**
+   * Handle to the CADET session this port belongs to.
+   */
   struct GNUNET_CADET_Handle *cadet;
 
-    /**
-     * Port ID.
-     */
+  /**
+   * Port ID.
+   */
   struct GNUNET_HashCode *hash;
 
-    /**
-     * Callback handler for incoming channels on this port.
-     */
+  /**
+   * Callback handler for incoming channels on this port.
+   */
   GNUNET_CADET_InboundChannelNotificationHandler *handler;
 
-    /**
-     * Closure for @a handler.
-     */
+  /**
+   * Closure for @a handler.
+   */
   void *cls;
 };
 
@@ -356,22 +359,20 @@ find_port (const struct GNUNET_CADET_Handle *h,
 
 /**
  * Get the channel handler for the channel specified by id from the given 
handle
+ *
  * @param h Cadet handle
  * @param chid ID of the wanted channel
  * @return handle to the required channel or NULL if not found
  */
 static struct GNUNET_CADET_Channel *
-retrieve_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
+retrieve_channel (struct GNUNET_CADET_Handle *h,
+                  struct GNUNET_CADET_ClientChannelNumber chid)
 {
   struct GNUNET_CADET_Channel *ch;
 
-  ch = h->channels_head;
-  while (ch != NULL)
-  {
-    if (ch->chid == chid)
+  for (ch = h->channels_head; NULL != ch; ch = ch->next)
+    if (ch->chid.channel_of_client == chid.channel_of_client)
       return ch;
-    ch = ch->next;
-  }
   return NULL;
 }
 
@@ -385,21 +386,27 @@ retrieve_channel (struct GNUNET_CADET_Handle *h, 
CADET_ChannelNumber chid)
  * @return Handle to the created channel.
  */
 static struct GNUNET_CADET_Channel *
-create_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
+create_channel (struct GNUNET_CADET_Handle *h,
+                struct GNUNET_CADET_ClientChannelNumber chid)
 {
   struct GNUNET_CADET_Channel *ch;
 
   ch = GNUNET_new (struct GNUNET_CADET_Channel);
-  GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch);
+  GNUNET_CONTAINER_DLL_insert (h->channels_head,
+                               h->channels_tail,
+                               ch);
   ch->cadet = h;
-  if (0 == chid)
+  if (0 == chid.channel_of_client)
   {
     ch->chid = h->next_chid;
-    while (NULL != retrieve_channel (h, h->next_chid))
+    while (NULL != retrieve_channel (h,
+                                     h->next_chid))
     {
-      h->next_chid++;
-      h->next_chid &= ~GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
-      h->next_chid |= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+      h->next_chid.channel_of_client
+        = htonl (1 + ntohl (h->next_chid.channel_of_client));
+      if (0 == ntohl (h->next_chid.channel_of_client))
+        h->next_chid.channel_of_client
+          = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
     }
   }
   else
@@ -440,7 +447,9 @@ destroy_channel (struct GNUNET_CADET_Channel *ch, int 
call_cleaner)
   }
   h = ch->cadet;
 
-  GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch);
+  GNUNET_CONTAINER_DLL_remove (h->channels_head,
+                               h->channels_tail,
+                               ch);
 
   /* signal channel destruction */
   if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner) 
)
@@ -466,7 +475,7 @@ destroy_channel (struct GNUNET_CADET_Channel *ch, int 
call_cleaner)
   if (0 != ch->peer)
     GNUNET_PEER_change_rc (ch->peer, -1);
   GNUNET_free (ch);
-  return;
+
 }
 
 
@@ -516,13 +525,15 @@ send_ack (struct GNUNET_CADET_Channel *ch)
   struct GNUNET_CADET_LocalAck *msg;
   struct GNUNET_MQ_Envelope *env;
 
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid);
-  msg->channel_id = htonl (ch->chid);
-  GNUNET_MQ_send (ch->cadet->mq, env);
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
 
-  return;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending ACK on channel %X\n",
+       ch->chid.channel_of_client);
+  msg->channel_id = ch->chid;
+  GNUNET_MQ_send (ch->cadet->mq,
+                  env);
 }
 
 
@@ -555,13 +566,16 @@ request_data (void *cls)
   th->channel->packet_size = 0;
   remove_from_queue (th);
 
-  env = GNUNET_MQ_msg_extra (msg, th->size,
+  env = GNUNET_MQ_msg_extra (msg,
+                             th->size,
                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  msg->id = htonl (th->channel->chid);
-  osize = th->notify (th->notify_cls, th->size, &msg[1]);
+  msg->id = th->channel->chid;
+  osize = th->notify (th->notify_cls,
+                      th->size,
+                      &msg[1]);
   GNUNET_assert (osize == th->size);
-  GNUNET_MQ_send (th->channel->cadet->mq, env);
-
+  GNUNET_MQ_send (th->channel->cadet->mq,
+                  env);
   GNUNET_free (th);
 }
 
@@ -580,13 +594,15 @@ handle_channel_created (void *cls,
   struct GNUNET_CADET_Channel *ch;
   struct GNUNET_CADET_Port *port;
   const struct GNUNET_HashCode *port_number;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
-  chid = ntohl (msg->channel_id);
+  chid = msg->channel_id;
   port_number = &msg->port;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X [%s]\n",
-       chid, GNUNET_h2s (port_number));
-  if (chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating incoming channel %X [%s]\n",
+       ntohl (chid.channel_of_client),
+       GNUNET_h2s (port_number));
+  if (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
   {
     GNUNET_break (0);
     return;
@@ -636,18 +652,24 @@ handle_channel_destroy (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
   struct GNUNET_CADET_Channel *ch;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
-  chid = ntohl (msg->channel_id);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X Destroy from service\n", chid);
-  ch = retrieve_channel (h, chid);
+  chid = msg->channel_id;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Channel %X Destroy from service\n",
+       ntohl (chid.channel_of_client));
+  ch = retrieve_channel (h,
+                         chid);
 
   if (NULL == ch)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "channel %X unknown\n",
+         ntohl (chid.channel_of_client));
     return;
   }
-  destroy_channel (ch, GNUNET_YES);
+  destroy_channel (ch,
+                   GNUNET_YES);
 }
 
 
@@ -674,7 +696,8 @@ check_local_data (void *cls,
     return GNUNET_SYSERR;
   }
 
-  ch = retrieve_channel (h, ntohl (message->id));
+  ch = retrieve_channel (h,
+                         message->id);
   if (NULL == ch)
   {
     GNUNET_break_op (0);
@@ -702,14 +725,17 @@ handle_local_data (void *cls,
   unsigned int i;
   uint16_t type;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n");
-  ch = retrieve_channel (h, ntohl (message->id));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got a data message!\n");
+  ch = retrieve_channel (h, message->id);
   GNUNET_assert (NULL != ch);
 
   payload = (struct GNUNET_MessageHeader *) &message[1];
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  %s data on channel %s [%X]\n",
-       GC_f2s (ch->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV),
-       GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (message->id));
+       GC_f2s (ntohl (ch->chid.channel_of_client) >=
+               GNUNET_CADET_LOCAL_CHANNEL_ID_CLI),
+       GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)),
+       ntohl (message->id.channel_of_client));
 
   type = ntohs (payload->type);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  payload type %s\n", GC_m2s (type));
@@ -751,17 +777,21 @@ handle_local_ack (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
   struct GNUNET_CADET_Channel *ch;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
-  chid = ntohl (message->channel_id);
+  chid = message->channel_id;
   ch = retrieve_channel (h, chid);
   if (NULL == ch)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "ACK on unknown channel %X\n",
+         ntohl (chid.channel_of_client));
     return;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X!\n", ch->chid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "  on channel %X!\n",
+       ntohl (ch->chid.channel_of_client));
   ch->allow_send = GNUNET_YES;
   if (0 < ch->packet_size)
   {
@@ -1132,9 +1162,12 @@ handle_get_tunnels (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
 
-  h->info_cb.tunnels_cb (h->info_cls, &msg->destination,
-                         ntohl (msg->channels), ntohl (msg->connections),
-                         ntohs (msg->estate), ntohs (msg->cstate));
+  h->info_cb.tunnels_cb (h->info_cls,
+                         &msg->destination,
+                         ntohl (msg->channels),
+                         ntohl (msg->connections),
+                         ntohs (msg->estate),
+                         ntohs (msg->cstate));
 
 }
 
@@ -1170,13 +1203,14 @@ check_get_tunnel (void *cls,
   if (esize > msize)
   {
     GNUNET_break_op (0);
-    h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+    h->info_cb.tunnel_cb (h->info_cls,
+                          NULL, 0, 0, NULL, NULL, 0, 0);
     goto clean_cls;
   }
   ch_n = ntohl (msg->channels);
   c_n = ntohl (msg->connections);
-  esize += ch_n * sizeof (CADET_ChannelNumber);
-  esize += c_n * sizeof (struct GNUNET_CADET_Hash);
+  esize += ch_n * sizeof (struct GNUNET_CADET_ChannelNumber);
+  esize += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
   if (msize != esize)
   {
     GNUNET_break_op (0);
@@ -1186,7 +1220,8 @@ check_get_tunnel (void *cls,
                 (unsigned int) esize,
                 ch_n,
                 c_n);
-    h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+    h->info_cb.tunnel_cb (h->info_cls,
+                          NULL, 0, 0, NULL, NULL, 0, 0);
     goto clean_cls;
   }
 
@@ -1212,18 +1247,23 @@ handle_get_tunnel (void *cls,
   struct GNUNET_CADET_Handle *h = cls;
   unsigned int ch_n;
   unsigned int c_n;
-  struct GNUNET_CADET_Hash *conns;
-  CADET_ChannelNumber *chns;
+  const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
+  const struct GNUNET_CADET_ChannelNumber *chns;
 
   ch_n = ntohl (msg->channels);
   c_n = ntohl (msg->connections);
 
   /* Call Callback with tunnel info. */
-  conns = (struct GNUNET_CADET_Hash *) &msg[1];
-  chns = (CADET_ChannelNumber *) &conns[c_n];
-  h->info_cb.tunnel_cb (h->info_cls, &msg->destination,
-                        ch_n, c_n, chns, conns,
-                        ntohs (msg->estate), ntohs (msg->cstate));
+  conns = (const struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  chns = (const struct GNUNET_CADET_ChannelNumber *) &conns[c_n];
+  h->info_cb.tunnel_cb (h->info_cls,
+                        &msg->destination,
+                        ch_n,
+                        c_n,
+                        chns,
+                        conns,
+                        ntohs (msg->estate),
+                        ntohs (msg->cstate));
 }
 
 
@@ -1343,9 +1383,10 @@ reconnect (struct GNUNET_CADET_Handle *h)
 
/******************************************************************************/
 
 struct GNUNET_CADET_Handle *
-GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
-                     GNUNET_CADET_ChannelEndHandler cleaner,
-                     const struct GNUNET_CADET_MessageHandler *handlers)
+GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                      void *cls,
+                      GNUNET_CADET_ChannelEndHandler cleaner,
+                      const struct GNUNET_CADET_MessageHandler *handlers)
 {
   struct GNUNET_CADET_Handle *h;
 
@@ -1364,7 +1405,7 @@ GNUNET_CADET_connect (const struct 
GNUNET_CONFIGURATION_Handle *cfg, void *cls,
   }
   h->cls = cls;
   h->message_handlers = handlers;
-  h->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+  h->next_chid.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
   h->reconnect_task = NULL;
 
@@ -1384,21 +1425,24 @@ GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle 
*handle)
   struct GNUNET_CADET_Channel *aux;
   struct GNUNET_CADET_TransmitHandle *th;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET DISCONNECT\n");
-
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "CADET DISCONNECT\n");
   ch = handle->channels_head;
   while (NULL != ch)
   {
     aux = ch->next;
-    if (ch->chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+    if (ntohl (ch->chid.channel_of_client) >= 
GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
     {
       GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "channel %X not destroyed\n",
+           ntohl (ch->chid.channel_of_client));
     }
-    destroy_channel (ch, GNUNET_YES);
+    destroy_channel (ch,
+                     GNUNET_YES);
     ch = aux;
   }
-  while ( (th = handle->th_head) != NULL)
+  while (NULL != (th = handle->th_head))
   {
     struct GNUNET_MessageHeader *msg;
 
@@ -1534,24 +1578,27 @@ GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle 
*h,
   struct GNUNET_CADET_ChannelCreateMessage *msg;
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_CADET_Channel *ch;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Creating new channel to %s:%u\n",
        GNUNET_i2s (peer), port);
-  ch = create_channel (h, 0);
+  chid.channel_of_client = htonl (0);
+  ch = create_channel (h, chid);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  at %p\n", ch);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  number %X\n", ch->chid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  number %X\n",
+       ntohl (ch->chid.channel_of_client));
   ch->ctx = channel_ctx;
   ch->peer = GNUNET_PEER_intern (peer);
 
   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
-  msg->channel_id = htonl (ch->chid);
+  msg->channel_id = ch->chid;
   msg->port = *port;
   msg->peer = *peer;
   msg->opt = htonl (options);
   ch->allow_send = GNUNET_NO;
-  GNUNET_MQ_send (h->mq, env);
-
+  GNUNET_MQ_send (h->mq,
+                  env);
   return ch;
 }
 
@@ -1590,7 +1637,7 @@ GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel 
*channel)
   }
 
   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
-  msg->channel_id = htonl (channel->chid);
+  msg->channel_id = channel->chid;
   GNUNET_MQ_send (h->mq, env);
 
   destroy_channel (channel, GNUNET_YES);
@@ -1617,7 +1664,7 @@ GNUNET_CADET_channel_get_info (struct 
GNUNET_CADET_Channel *channel,
   {
     case GNUNET_CADET_OPTION_NOBUFFER:
     case GNUNET_CADET_OPTION_RELIABLE:
-    case GNUNET_CADET_OPTION_OOORDER:
+    case GNUNET_CADET_OPTION_OUT_OF_ORDER:
       if (0 != (option & channel->options))
         bool_flag = GNUNET_YES;
       else
@@ -1651,7 +1698,8 @@ GNUNET_CADET_notify_transmit_ready (struct 
GNUNET_CADET_Channel *channel,
   LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "    on channel %X\n", channel->chid);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "    allow_send %d\n", channel->allow_send);
-  if (channel->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+  if (ntohl (channel->chid.channel_of_client) >=
+      GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to origin\n");
   else
     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to destination\n");
@@ -1946,7 +1994,7 @@ GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h,
 
   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
   msg->peer = *initiator;
-  msg->channel_id = htonl (channel_number);
+  msg->channel_id.channel_of_client = htonl (channel_number);
   GNUNET_MQ_send (h->mq, env);
 
   h->info_cb.channel_cb = callback;
diff --git a/src/cadet/cadet_protocol.h b/src/cadet/cadet_protocol.h
index d034c63b0..c555d6155 100644
--- a/src/cadet/cadet_protocol.h
+++ b/src/cadet/cadet_protocol.h
@@ -70,7 +70,7 @@ struct GNUNET_CADET_ConnectionCreate
    * For alignment.
    */
   uint32_t reserved GNUNET_PACKED;
-  
+
   /**
    * ID of the connection
    */
@@ -322,6 +322,7 @@ struct GNUNET_CADET_Encrypted
 /*******************************   CHANNEL  
***********************************/
 
/******************************************************************************/
 
+
 /**
  * Message to create a Channel.
  */
@@ -345,7 +346,7 @@ struct GNUNET_CADET_ChannelCreate
   /**
    * ID of the channel
    */
-  CADET_ChannelNumber chid GNUNET_PACKED;
+  struct GNUNET_CADET_ChannelNumber chid;
 };
 
 
@@ -362,7 +363,7 @@ struct GNUNET_CADET_ChannelManage
   /**
    * ID of the channel
    */
-  CADET_ChannelNumber chid GNUNET_PACKED;
+  struct GNUNET_CADET_ChannelNumber chid;
 };
 
 
@@ -385,7 +386,7 @@ struct GNUNET_CADET_Data
   /**
    * ID of the channel
    */
-  CADET_ChannelNumber chid GNUNET_PACKED;
+  struct GNUNET_CADET_ChannelNumber chid;
 
   /**
    * Payload follows
@@ -406,7 +407,7 @@ struct GNUNET_CADET_DataACK
   /**
    * ID of the channel
    */
-  CADET_ChannelNumber chid GNUNET_PACKED;
+  struct GNUNET_CADET_ChannelNumber chid;
 
   /**
    * Bitfield of already-received newer messages
diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c
index 5afb64e24..eeef2ff89 100644
--- a/src/cadet/gnunet-cadet.c
+++ b/src/cadet/gnunet-cadet.c
@@ -727,8 +727,8 @@ tunnel_callback (void *cls,
                  const struct GNUNET_PeerIdentity *peer,
                  unsigned int n_channels,
                  unsigned int n_connections,
-                 uint32_t *channels,
-                 struct GNUNET_CADET_Hash *connections,
+                 const struct GNUNET_CADET_ChannelNumber *channels,
+                 const struct GNUNET_CADET_ConnectionTunnelIdentifier 
*connections,
                  unsigned int estate,
                  unsigned int cstate)
 {
@@ -739,10 +739,10 @@ tunnel_callback (void *cls,
     FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
     FPRINTF (stdout, "\t%u channels\n", n_channels);
     for (i = 0; i < n_channels; i++)
-      FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i]));
+      FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i].cn));
     FPRINTF (stdout, "\t%u connections\n", n_connections);
     for (i = 0; i < n_connections; i++)
-      FPRINTF (stdout, "\t\t%s\n", GC_h2s (&connections[i]));
+      FPRINTF (stdout, "\t\t%s\n", GC_h2s 
(&connections[i].connection_of_tunnel));
     FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
     FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
   }
@@ -827,7 +827,10 @@ show_tunnel (void *cls)
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-  GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
+  GNUNET_CADET_get_tunnel (mh,
+                           &pid,
+                           &tunnel_callback,
+                           NULL);
 }
 
 
diff --git a/src/cadet/gnunet-service-cadet-new.c 
b/src/cadet/gnunet-service-cadet-new.c
new file mode 100644
index 000000000..f367c4c73
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new.c
@@ -0,0 +1,1302 @@
+/*
+     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_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
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
+
+  /**
+   * Tunnels this client has accepted, indexed by incoming local id
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
+
+  /**
+   * Channel ID for the next incoming channel.
+   */
+  struct GNUNET_CADET_ClientChannelNumber next_chid;
+
+  /**
+   * 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;
+
+  /**
+   * Whether the client is active or shutting down (don't send confirmations
+   * to a client that is shutting down).
+   */
+  int shutting_down;
+
+  /**
+   * ID of the client, mainly for debug messages
+   */
+  unsigned int id;
+};
+
+/******************************************************************************/
+/***********************      GLOBAL VARIABLES     
****************************/
+/******************************************************************************/
+
+/****************************** Global variables 
******************************/
+
+/**
+ * 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 recover 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;
+
+
+
+/**
+ * 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];
+
+  if (NULL == c)
+    return "Client(NULL)";
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Client(%u)",
+                   c->id);
+  return buf;
+}
+
+
+/**
+ * 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_lid (struct CadetClient *c)
+{
+  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_chid;
+
+  /* increment until we have a free one... */
+  while (NULL !=
+         GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels,
+                                              ntohl (ccn.channel_of_client)))
+  {
+    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_chid.channel_of_client
+    = htonl (1 + (ntohl (ccn.channel_of_client)));
+  return ccn;
+}
+
+
+/**
+ * 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)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ChannelCreateMessage *msg;
+  struct GNUNET_CADET_ClientChannelNumber lid;
+
+  lid = client_get_next_lid (c);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
+                                                      ntohl 
(lid.channel_of_client),
+                                                      ch,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+  /* notify local client about incoming connection! */
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+  msg->channel_id = lid;
+  msg->port = *port;
+  msg->opt = htonl (options);
+  GCP_id (dest,
+          &msg->peer);
+  GSC_send_to_client (c,
+                      env);
+  return lid;
+}
+
+
+/******************************************************************************/
+/************************      MAIN FUNCTIONS      
****************************/
+/******************************************************************************/
+
+/**
+ * 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;
+
+  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;
+  }
+  /* All 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 != 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;
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * Handler for port open requests.
+ *
+ * @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 client %u\n",
+       GNUNET_h2s (&pmsg->port),
+       c->id);
+  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;
+  }
+  /* store in global hashmap */
+  /* FIXME only allow one client to have the port open,
+   *       have a backup hashmap with waiting clients */
+  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.
+ *
+ * @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,
+       "Open port %s requested by client %u\n",
+       GNUNET_h2s (&pmsg->port),
+       c->id);
+  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 of new channels.
+ *
+ * @param cls Identification of the client.
+ * @param ccm The actual message.
+ */
+static void
+handle_channel_create (void *cls,
+                       const struct GNUNET_CADET_ChannelCreateMessage *ccm)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+  struct GNUNET_CADET_ClientChannelNumber chid;
+  struct CadetPeer *dst;
+
+  chid = ccm->channel_id;
+  if (ntohl (chid.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 = GNUNET_CONTAINER_multihashmap32_get (c->own_channels,
+                                            ntohl (chid.channel_of_client));
+  if (NULL != ch)
+  {
+    /* Channel ID already in use. Not allowed. */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+
+  dst = GCP_get (&ccm->peer,
+                 GNUNET_YES);
+
+  /* Create channel */
+  ch = GCCH_channel_local_new (c,
+                               chid,
+                               dst,
+                               &ccm->port,
+                               ntohl (ccm->opt));
+  if (NULL == ch)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->own_channels,
+                                                      ntohl 
(chid.channel_of_client),
+                                                      ch,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "New channel %s to %s at port %s requested by client %u\n",
+       GCCH_2s (ch),
+       GNUNET_i2s (&ccm->peer),
+       GNUNET_h2s (&ccm->port),
+       c->id);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Return the map which we use for client @a c for a channel ID of @a chid
+ *
+ * @param c client to find map for
+ * @param chid chid to find map for
+ * @return applicable map we use
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *
+get_map_by_chid (struct CadetClient *c,
+                 struct GNUNET_CADET_ClientChannelNumber chid)
+{
+  return (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+    ? c->own_channels
+    : c->incoming_channels;
+}
+
+
+/**
+ * Handler for requests of deleting tunnels
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+                        const struct GNUNET_CADET_ChannelDestroyMessage *msg)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_CADET_ClientChannelNumber chid;
+  struct GNUNET_CONTAINER_MultiHashMap32 *map;
+  struct CadetChannel *ch;
+
+  /* Retrieve tunnel */
+  chid = msg->channel_id;
+  map = get_map_by_chid (c,
+                         chid);
+  ch = GNUNET_CONTAINER_multihashmap32_get (map,
+                                            ntohl (chid.channel_of_client));
+  if (NULL == ch)
+  {
+    /* Client attempted to destroy unknown channel */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Client %u is destroying channel %s\n",
+       c->id,
+       GCCH_2s (ch));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (map,
+                                                         ntohl 
(chid.channel_of_client),
+                                                         ch));
+  GCCH_channel_local_destroy (ch);
+  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_data (void *cls,
+            const struct GNUNET_CADET_LocalData *msg)
+{
+  const struct GNUNET_MessageHeader *payload;
+  size_t payload_size;
+  size_t payload_claimed_size;
+
+  /* Sanity check for message size */
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  if ( (payload_size < sizeof (struct GNUNET_MessageHeader)) ||
+       (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_size) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  payload = (struct GNUNET_MessageHeader *) &msg[1];
+  payload_claimed_size = ntohs (payload->size);
+  if (payload_size != payload_claimed_size)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client traffic
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_data (void *cls,
+             const struct GNUNET_CADET_LocalData *msg)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_CONTAINER_MultiHashMap32 *map;
+  struct GNUNET_CADET_ClientChannelNumber chid;
+  struct CadetChannel *ch;
+  const struct GNUNET_MessageHeader *payload;
+
+  chid = msg->id;
+  map = get_map_by_chid (c,
+                         chid);
+  ch = GNUNET_CONTAINER_multihashmap32_get (map,
+                                            ntohl (chid.channel_of_client));
+  if (NULL == ch)
+  {
+    /* Channel does not exist! */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+
+  payload = (const struct GNUNET_MessageHeader *) &msg[1];
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received %u bytes payload from client %u for channel %s\n",
+       ntohs (payload->size),
+       c->id,
+       GCCH_2s (ch));
+  if (GNUNET_OK !=
+      GCCH_handle_local_data (ch,
+                              payload))
+  {
+    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_ack (void *cls,
+            const struct GNUNET_CADET_LocalAck *msg)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_CONTAINER_MultiHashMap32 *map;
+  struct GNUNET_CADET_ClientChannelNumber chid;
+  struct CadetChannel *ch;
+
+  chid = msg->channel_id;
+  map = get_map_by_chid (c,
+                         chid);
+  ch = GNUNET_CONTAINER_multihashmap32_get (map,
+                                            ntohl (chid.channel_of_client));
+  if (NULL == ch)
+  {
+    /* Channel does not exist! */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got a local ACK from client %u for channel %s\n",
+       c->id,
+       GCCH_2s (ch));
+  GCCH_handle_local_ack (ch);
+  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 peer Peer this path is towards.
+ * @param path Path itself
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
+ */
+static int
+path_info_iterator (void *cls,
+                    struct CadetPeer *peer,
+                    struct CadetPeerPath *path)
+{
+  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 < path_length - 1; i++)
+    GCPP_get_pid_at_offset (path,
+                            i + 1,
+                            &id[i]);
+  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 ((uint16_t) GCT_get_cstate (t));
+  msg->estate = htons ((uint16_t) GCT_get_estate (t));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_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);
+}
+
+
+/**
+ * FIXME.
+ */
+static void
+iter_connection (void *cls,
+                 struct CadetConnection *c)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
+
+  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  h[msg->connections++] = *(GCC_get_id (c));
+}
+
+
+/**
+ * FIXME.
+ */
+static void
+iter_channel (void *cls,
+              struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1];
+  struct GCT_ChannelTunnelNumber *chn
+    = (struct GCT_ChannelTunnelNumber *) &h[msg->connections];
+
+  chn[msg->channels++] = GCCH_get_id (ch);
+}
+
+
+/**
+ * Handler for client's SHOW_TUNNEL request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_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_Hash) +
+                             ch_n * sizeof (struct GCT_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 (GCT_get_cstate (t));
+  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, own channels: %u, incoming 
channels: %u\n",
+         ci->id,
+         ci,
+         ci->client,
+         (NULL != c->ports)
+         ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
+         : 0,
+         GNUNET_CONTAINER_multihashmap32_size (ci->own_channels),
+         GNUNET_CONTAINER_multihashmap32_size (ci->incoming_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->own_channels
+    = GNUNET_CONTAINER_multihashmap32_create (32);
+  c->incoming_channels
+    = GNUNET_CONTAINER_multihashmap32_create (32);
+  GNUNET_CONTAINER_DLL_insert (clients_head,
+                               clients_tail,
+                               c);
+  GNUNET_STATISTICS_update (stats,
+                            "# clients",
+                            +1,
+                            GNUNET_NO);
+  return c;
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id (used to access the hashmap).
+ * @param value The value stored at the key (channel to destroy).
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+own_channel_destroy_iterator (void *cls,
+                              uint32_t key,
+                              void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch = value;
+
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
+                                                         key,
+                                                         ch));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying own channel %s, due to client %u shutdown.\n",
+       GCCH_2s (ch),
+       c->id);
+  GCCH_channel_local_destroy (ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id (used to access the hashmap).
+ * @param value The value stored at the key (channel to destroy).
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+incoming_channel_destroy_iterator (void *cls,
+                                   uint32_t key,
+                                   void *value)
+{
+  struct CadetChannel *ch = value;
+  struct CadetClient *c = cls;
+
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
+                                                         key,
+                                                         ch));
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying incoming channel %s due to client %u shutdown.\n",
+       GCCH_2s (ch),
+       c->id);
+  GCCH_channel_incoming_destroy (ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key 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;
+
+  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);
+  c->shutting_down = GNUNET_YES;
+  if (NULL != c->own_channels)
+  {
+    GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
+                                             &own_channel_destroy_iterator,
+                                             c);
+    GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
+  }
+  if (NULL != c->incoming_channels)
+  {
+    GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
+                                             
&incoming_channel_destroy_iterator,
+                                             c);
+    GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_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);
+}
+
+
+/**
+ * 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)
+{
+  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);
+  GCH_init (c);
+  GCD_init (c);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "CADET starting at 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_CHANNEL_CREATE,
+                          struct GNUNET_CADET_ChannelCreateMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (channel_destroy,
+                          GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+                          struct GNUNET_CADET_ChannelDestroyMessage,
+                          NULL),
+ GNUNET_MQ_hd_var_size (data,
+                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
+                        struct GNUNET_CADET_LocalData,
+                        NULL),
+ GNUNET_MQ_hd_fixed_size (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 (get_tunnels,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (show_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
new file mode 100644
index 000000000..f5e979ee5
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new.h
@@ -0,0 +1,144 @@
+
+/*
+     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
+
+/**
+ * A client to the CADET service.
+ */
+struct CadetClient;
+
+/**
+ * A peer in the GNUnet network.
+ */
+struct CadetPeer;
+
+/**
+ * Tunnel from us to another peer.
+ */
+struct CadetTunnel;
+
+/**
+ * Entry in the message queue of a `struct CadetTunnel`
+ */
+struct CadetTunnelQueueEntry;
+
+/**
+ * A path of peer in the GNUnet network.
+ */
+struct CadetPeerPath;
+
+/**
+ * Active path through the network (used by a tunnel).
+ */
+struct CadetConnection;
+
+/**
+ * Logical end-to-end conenction between clients.
+ */
+struct CadetChannel;
+
+/**
+ * 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 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;
+
+
+/**
+ * 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);
+
+
+/**
+ * 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
new file mode 100644
index 000000000..00bdf569e
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_channel.c
@@ -0,0 +1,1154 @@
+
+/*
+     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
+ */
+
+#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 (level,__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)
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Number used to uniquely identify messages in a CADET Channel.
+ */
+struct ChannelMessageIdentifier
+{
+  /**
+   * Unique ID of the message, cycles around, in NBO.
+   */
+  uint32_t mid GNUNET_PACKED;
+};
+
+
+/**
+ * Message to create a Channel.
+ */
+struct GNUNET_CADET_ChannelCreate
+{
+  /**
+   * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Channel options.
+   */
+  uint32_t opt GNUNET_PACKED;
+
+  /**
+   * Destination port.
+   */
+  struct GNUNET_HashCode port;
+
+  /**
+   * ID of the channel
+   */
+  struct GCT_ChannelTunnelNumber gid;
+};
+
+
+
+/**
+ * Message for cadet data traffic.
+ */
+struct GNUNET_CADET_Data
+{
+  /**
+   * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
+   *       #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Unique ID of the payload message.
+   */
+  struct ChannelMessageIdentifier mid;
+
+  /**
+   * ID of the channel
+   */
+  struct GCT_ChannelTunnelNumber gid;
+
+  /**
+   * Payload follows
+   */
+};
+
+
+/**
+ * Message to acknowledge end-to-end data.
+ */
+struct GNUNET_CADET_DataACK
+{
+  /**
+   * Type: #GNUNET_MESSAGE_TYPE_CADET_DATA_ACK
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * ID of the channel
+   */
+  struct GCT_ChannelTunnelNumber gid;
+
+  /**
+   * Bitfield of already-received messages past @e mid.
+   * pid +  1 @ LSB
+   * pid + 64 @ MSB
+   */
+  uint64_t futures GNUNET_PACKED;
+
+  /**
+   * Last message ID received.
+   */
+  struct ChannelMessageIdentifier mid;
+};
+
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * All the states a connection can be in.
+ */
+enum CadetChannelState
+{
+  /**
+   * Uninitialized status, should never appear in operation.
+   */
+  CADET_CHANNEL_NEW,
+
+  /**
+   * Connection create message sent, waiting for ACK.
+   */
+  CADET_CHANNEL_CREATE_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;
+
+  /**
+   * 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;
+
+  /**
+   * Data message we are trying to send.
+   */
+  struct GNUNET_CADET_Data data_message;
+
+  /* followed by variable-size payload */
+};
+
+
+/**
+ * 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 (ACK needed to free)
+   */
+  struct ChannelMessageIdentifier mid;
+
+  /**
+   * The envelope with the payload of the out-of-order message
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+};
+
+
+/**
+ * Struct containing all information regarding a channel to a remote client.
+ */
+struct CadetChannel
+{
+  /**
+   * Tunnel this channel is in.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Last entry in the tunnel's queue relating to control messages
+   * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE or
+   * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK).  Used to cancel
+   * transmission in case we receive updated information.
+   */
+  struct CadetTunnelQueueEntry *last_control_qe;
+
+  /**
+   * Client owner of the tunnel, if any.
+   * (Used if this channel represends the initiating end of the tunnel.)
+   */
+  struct CadetClient *owner;
+
+  /**
+   * Client destination of the tunnel, if any.
+   * (Used if this channel represents the listening end of the tunnel.)
+   */
+  struct CadetClient *dest;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /**
+   * Task to resend/poll in case no ACK is received.
+   */
+  struct GNUNET_SCHEDULER_Task *retry_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;
+
+  /**
+   * How long does it usually take to get an ACK.
+   */
+  struct GNUNET_TIME_Relative expected_delay;
+
+  /**
+   * 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 GCT_ChannelTunnelNumber gid;
+
+  /**
+   * Local tunnel number for local client owning the channel.
+   * ( >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
+   */
+  struct GNUNET_CADET_ClientChannelNumber lid;
+
+  /**
+   * Channel state.
+   */
+  enum CadetChannelState state;
+
+  /**
+   * Can we send data to the client?
+   */
+  int client_ready;
+
+  /**
+   * Can the client send data to us?
+   */
+  int client_allowed;
+
+  /**
+   * Is the tunnel bufferless (minimum latency)?
+   */
+  int nobuffer;
+
+  /**
+   * Is the tunnel reliable?
+   */
+  int reliable;
+
+  /**
+   * Is the tunnel out-of-order?
+   */
+  int out_of_order;
+
+  /**
+   * 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];
+
+  if (NULL == ch)
+    return "(NULL Channel)";
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "%s:%s gid:%X (%X)",
+                   GCT_2s (ch->t),
+                   GNUNET_h2s (&ch->port),
+                   ch->gid,
+                   ntohl (ch->lid.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 GCT_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch)
+{
+  return ch->gid;
+}
+
+
+/**
+ * Destroy the given channel.
+ *
+ * @param ch channel to destroy
+ */
+static void
+channel_destroy (struct CadetChannel *ch)
+{
+  struct CadetReliableMessage *crm;
+  struct CadetOutOfOrderMessage *com;
+
+  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);
+  }
+  while (NULL != (com = ch->head_recv))
+  {
+    GNUNET_CONTAINER_DLL_remove (ch->head_recv,
+                                 ch->tail_recv,
+                                 com);
+    GNUNET_MQ_discard (com->env);
+    GNUNET_free (com);
+  }
+  if (NULL != ch->last_control_qe)
+  {
+    GCT_send_cancel (ch->last_control_qe);
+    ch->last_control_qe = NULL;
+  }
+  if (NULL != ch->retry_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_task);
+    ch->retry_task = NULL;
+  }
+  GCT_remove_channel (ch->t,
+                      ch,
+                      ch->gid);
+  GNUNET_free (ch);
+}
+
+
+/**
+ * Send a channel create message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_create (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`.
+ */
+static void
+create_sent_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+
+  ch->last_control_qe = NULL;
+  ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
+  ch->retry_task = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
+                                                 &send_create,
+                                                 ch);
+}
+
+
+/**
+ * Send a channel create message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_create (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct GNUNET_CADET_ChannelCreate msgcc;
+  uint32_t options;
+
+  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_CREATE);
+  msgcc.opt = htonl (options);
+  msgcc.port = ch->port;
+  msgcc.gid = ch->gid;
+  ch->state = CADET_CHANNEL_CREATE_SENT;
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msgcc.header,
+                                  &create_sent_cb,
+                                  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)
+{
+  struct CadetChannel *ch;
+
+  ch = GNUNET_new (struct CadetChannel);
+  ch->max_pending_messages = 32; /* FIXME: allow control via options
+                                    or adjust dynamically... */
+  ch->owner = owner;
+  ch->lid = owner_id;
+  ch->port = *port;
+  ch->t = GCP_get_tunnel (destination,
+                          GNUNET_YES);
+  ch->gid = GCT_add_channel (ch->t,
+                             ch);
+  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->retry_task = GNUNET_SCHEDULER_add_now (&send_create,
+                                             ch);
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+  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_task = NULL;
+  channel_destroy (ch);
+}
+
+
+/**
+ * Create a new channel.
+ *
+ * @param t tunnel to the remote peer
+ * @param gid 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 GCT_ChannelTunnelNumber gid,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options)
+{
+  struct CadetChannel *ch;
+  struct CadetClient *c;
+
+  ch = GNUNET_new (struct CadetChannel);
+  ch->max_pending_messages = 32; /* FIXME: allow control via options
+                                    or adjust dynamically... */
+  ch->port = *port;
+  ch->t = t;
+  ch->gid = gid;
+  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));
+  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 */
+    (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+                                              port,
+                                              ch,
+                                              
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+    ch->retry_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
+                                                   &timeout_closed_cb,
+                                                   ch);
+  }
+  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`.
+ */
+static void
+send_ack_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+
+  ch->last_control_qe = NULL;
+}
+
+
+/**
+ * Compute and send the current ACK to the other peer.
+ *
+ * @param ch channel to send the ACK for
+ */
+static void
+send_channel_ack (struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_DataACK msg;
+
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK);
+  msg.header.size = htons (sizeof (msg));
+  msg.gid = ch->gid;
+  msg.mid.mid = htonl (ntohl (ch->mid_recv.mid) - 1);
+  msg.futures = GNUNET_htonll (ch->mid_futures);
+  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 ACK to the client confirming that the
+ * connection is up.
+ *
+ * @param cls the `struct CadetChannel`
+ */
+static void
+send_connect_ack (void *cls)
+{
+  struct CadetChannel *ch = cls;
+
+  ch->retry_task = NULL;
+  send_channel_ack (ch);
+}
+
+
+/**
+ * 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;
+
+  if (NULL != ch->retry_task)
+  {
+    /* there might be a timeout task here */
+    GNUNET_SCHEDULER_cancel (ch->retry_task);
+    ch->retry_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;
+  ch->dest = c;
+  ch->lid = GSC_bind (c,
+                      ch,
+                      GCT_get_destination (ch->t),
+                      &ch->port,
+                      options);
+  ch->mid_recv.mid = htonl (1); /* The CONNECT counts as message 0! */
+
+  /* notify other peer that we accepted the connection */
+  ch->retry_task = GNUNET_SCHEDULER_add_now (&send_connect_ack,
+                                             ch);
+}
+
+
+/**
+ * Destroy locally created channel.  Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch)
+{
+  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)
+  {
+    /* allow send queue to train first */
+    ch->destroy = GNUNET_YES;
+    return;
+  }
+  /* Nothing left to do, just finish destruction */
+  channel_destroy (ch);
+}
+
+
+/**
+ * Destroy channel that was incoming.  Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_incoming_destroy (struct CadetChannel *ch)
+{
+  if (GNUNET_YES == ch->destroy)
+  {
+    /* other end already destroyed, with the remote client gone, no need
+       to finish transmissions, just destroy immediately. */
+    channel_destroy (ch);
+    return;
+  }
+  if (NULL != ch->head_recv)
+  {
+    /* allow local client to see all data first */
+    ch->destroy = GNUNET_YES;
+    return;
+  }
+  /* Nothing left to do, just finish destruction */
+  channel_destroy (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
+ */
+static void
+data_sent_cb (void *cls);
+
+
+/**
+ * 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;
+
+  GNUNET_assert (NULL == crm->qe);
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message.header,
+                      &data_sent_cb,
+                      crm);
+}
+
+
+/**
+ * Check if we can now allow the client to transmit, and if so,
+ * let the client know about it.
+ *
+ * @param ch channel to check
+ */
+static void
+GCCH_check_allow_client (struct CadetChannel *ch)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalAck *msg;
+
+  if (GNUNET_YES == ch->client_allowed)
+    return; /* client already allowed! */
+  if (CADET_CHANNEL_READY != ch->state)
+  {
+    /* destination did not yet ACK our CREATE! */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Channel %s not yet ready, throttling client until ACK.\n",
+         GCCH_2s (ch));
+    return;
+  }
+  if (ch->pending_messages > ch->max_pending_messages)
+  {
+    /* Too many messages in queue. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Message queue still too long on channel %s, throttling client until 
ACK.\n",
+         GCCH_2s (ch));
+    return;
+  }
+  if ( (NULL != ch->head_sent) &&
+       (64 <= ntohl (ch->mid_send.mid) - ntohl 
(ch->head_sent->data_message.mid.mid)) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Gap in ACKs too big on channel %s, throttling client until ACK.\n",
+         GCCH_2s (ch));
+    return;
+  }
+  ch->client_allowed = GNUNET_YES;
+
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending local ack to channel %s client\n",
+       GCCH_2s (ch));
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+  msg->channel_id = ch->lid;
+  GSC_send_to_client (ch->owner ? ch->owner : ch->dest,
+                      env);
+}
+
+
+/**
+ * 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
+ */
+static void
+data_sent_cb (void *cls)
+{
+  struct CadetReliableMessage *crm = cls;
+  struct CadetChannel *ch = crm->ch;
+  struct CadetReliableMessage *off;
+
+  crm->qe = NULL;
+  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
+  if (GNUNET_NO == ch->reliable)
+  {
+    GNUNET_free (crm);
+    ch->pending_messages--;
+    GCCH_check_allow_client (ch);
+    return;
+  }
+  if (0 == crm->retry_delay.rel_value_us)
+    crm->retry_delay = ch->expected_delay;
+  crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
+
+  /* find position for re-insertion into the DLL */
+  if ( (NULL == ch->head_sent) ||
+       (crm->next_retry.abs_value_us < ch->head_sent->next_retry.abs_value_us) 
)
+  {
+    /* insert at HEAD, also (re)schedule retry task! */
+    GNUNET_CONTAINER_DLL_insert (ch->head_sent,
+                                 ch->tail_sent,
+                                 crm);
+    if (NULL != ch->retry_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_task);
+    ch->retry_task = GNUNET_SCHEDULER_add_delayed (crm->retry_delay,
+                                                   &retry_transmission,
+                                                   ch);
+    return;
+  }
+  for (off = ch->head_sent; NULL != off; off = off->next)
+    if (crm->next_retry.abs_value_us < off->next_retry.abs_value_us)
+      break;
+  if (NULL == off)
+  {
+    /* insert at tail */
+    GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
+                                      ch->tail_sent,
+                                      crm);
+  }
+  else
+  {
+    /* insert before off */
+    GNUNET_CONTAINER_DLL_insert_after (ch->head_sent,
+                                       ch->tail_sent,
+                                       off->prev,
+                                       crm);
+  }
+}
+
+
+/**
+ * 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 message payload to transmit.
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+                        const struct GNUNET_MessageHeader *message)
+{
+  uint16_t payload_size = ntohs (message->size);
+  struct CadetReliableMessage *crm;
+
+  if (GNUNET_NO == ch->client_allowed)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  ch->client_allowed = GNUNET_NO;
+  ch->pending_messages++;
+
+  /* Everything is correct, send the message. */
+  crm = GNUNET_malloc (sizeof (*crm) + payload_size);
+  crm->ch = ch;
+  crm->data_message.header.size = htons (sizeof (struct GNUNET_CADET_Data) + 
payload_size);
+  crm->data_message.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA);
+  ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
+  crm->data_message.mid = ch->mid_send;
+  crm->data_message.gid = ch->gid;
+  GNUNET_memcpy (&crm[1],
+                 message,
+                 payload_size);
+  GNUNET_CONTAINER_DLL_insert (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending %u bytes from local client to channel %s\n",
+       payload_size,
+       GCCH_2s (ch));
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message.header,
+                      &data_sent_cb,
+                      crm);
+  GCCH_check_allow_client (ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Try to deliver messages to the local client, if it is ready for more.
+ *
+ * @param ch channel to process
+ */
+static void
+send_client_buffered_data (struct CadetChannel *ch)
+{
+  struct CadetOutOfOrderMessage *com;
+
+  if (GNUNET_NO == ch->client_ready)
+    return; /* client not ready */
+  com = ch->head_recv;
+  if (NULL == com)
+    return; /* none pending */
+  if ( (com->mid.mid != ch->mid_recv.mid) &&
+       (GNUNET_NO == ch->out_of_order) )
+    return; /* missing next one in-order */
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Passing payload message to client on channel %s\n",
+              GCCH_2s (ch));
+
+  /* all good, pass next message to client */
+  GNUNET_CONTAINER_DLL_remove (ch->head_recv,
+                               ch->tail_recv,
+                               com);
+  ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
+  ch->mid_futures >>= 1; /* equivalent to division by 2 */
+  GSC_send_to_client (ch->owner ? ch->owner : ch->dest,
+                      com->env);
+  GNUNET_free (com);
+  if ( (0xFFULL == (ch->mid_futures & 0xFFULL)) &&
+       (GNUNET_YES == ch->reliable) )
+  {
+    /* The next 15 messages were also already received (0xFF), this
+       suggests that the sender may be blocked on flow control
+       urgently waiting for an ACK from us. (As we have an inherent
+       maximum of 64 bits, and 15 is getting too close for comfort.)
+       So we should send one now. */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Sender on channel %s likely blocked on flow-control, sending 
ACK now.\n",
+                GCCH_2s (ch));
+    if (GNUNET_YES == ch->reliable)
+      send_channel_ack (ch);
+  }
+
+  if (NULL != ch->head_recv)
+    return;
+  if (GNUNET_NO == ch->destroy)
+    return;
+  channel_destroy (ch);
+}
+
+
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch)
+{
+  ch->client_ready = GNUNET_YES;
+  send_client_buffered_data (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 Channel %s:%X (%p)\n",
+        GCT_2s (ch->t),
+        ch->gid,
+        ch);
+  if (NULL != ch->owner)
+  {
+    LOG2 (level,
+          "CHN origin %s ready %s local-id: %u\n",
+          GSC_2s (ch->owner),
+          ch->client_ready ? "YES" : "NO",
+          ntohl (ch->lid.channel_of_client));
+  }
+  if (NULL != ch->dest)
+  {
+    LOG2 (level,
+          "CHN destination %s ready %s local-id: %u\n",
+          GSC_2s (ch->dest),
+          ch->client_ready ? "YES" : "NO",
+          ntohl (ch->lid.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
new file mode 100644
index 000000000..5cf42a894
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_channel.h
@@ -0,0 +1,173 @@
+
+/*
+     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"
+
+
+/**
+ * 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 GCT_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
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch);
+
+
+/**
+ * Create a new channel.
+ *
+ * @param t tunnel to the remote peer
+ * @param gid 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 GCT_ChannelTunnelNumber gid,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options);
+
+
+/**
+ * Destroy channel that was incoming.  Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_incoming_destroy (struct CadetChannel *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 message payload to transmit.
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+                        const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch);
+
+#endif
diff --git a/src/dht/gnunet-service-xdht_hello.h 
b/src/cadet/gnunet-service-cadet-new_connection.c
similarity index 57%
copy from src/dht/gnunet-service-xdht_hello.h
copy to src/cadet/gnunet-service-cadet-new_connection.c
index 7e7a79bcf..b24e4bd49 100644
--- a/src/dht/gnunet-service-xdht_hello.h
+++ b/src/cadet/gnunet-service-cadet-new_connection.c
@@ -1,6 +1,7 @@
+
 /*
      This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
+     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
@@ -19,37 +20,37 @@
 */
 
 /**
- * @file dht/gnunet-service-xdht_hello.h
- * @brief GNUnet DHT integration with peerinfo
+ * @file cadet/gnunet-service-cadet-new_connection.c
+ * @brief
+ * @author Bartlomiej Polot
  * @author Christian Grothoff
  */
-#ifndef GNUNET_SERVICE_XDHT_HELLO_H
-#define GNUNET_SERVICE_XDHT_HELLO_H
+#include "platform.h"
+#include "gnunet-service-cadet-new_connection.h"
 
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
 
 /**
- * Obtain a peer's HELLO if available
+ * Obtain unique ID for the connection.
  *
- * @param peer peer to look for a HELLO from
- * @return HELLO for the given peer
- */
-const struct GNUNET_HELLO_Message *
-GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer);
-
-
-/**
- * Initialize HELLO subsystem.
+ * @param cc connection.
+ * @return unique number of the connection
  */
-void
-GDS_HELLO_init (void);
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
+{
+  GNUNET_assert (0); // FIXME
+  return NULL;
+}
 
 
 /**
- * Shutdown HELLO subsystem.
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
  */
 void
-GDS_HELLO_done (void);
-
-#endif
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level)
+{
+}
diff --git a/src/peerinfo-tool/gnunet-peerinfo_plugins.h 
b/src/cadet/gnunet-service-cadet-new_connection.h
similarity index 56%
copy from src/peerinfo-tool/gnunet-peerinfo_plugins.h
copy to src/cadet/gnunet-service-cadet-new_connection.h
index 728029bb2..7745e4fec 100644
--- a/src/peerinfo-tool/gnunet-peerinfo_plugins.h
+++ b/src/cadet/gnunet-service-cadet-new_connection.h
@@ -1,6 +1,7 @@
+
 /*
      This file is part of GNUnet.
-     Copyright (C) 2010,2011 GNUnet e.V.
+     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
@@ -19,40 +20,39 @@
 */
 
 /**
- * @file peerinfo-tool/gnunet-peerinfo_plugins.h
- * @brief plugin management API
+ * @file cadet/gnunet-service-cadet-new_connection.h
+ * @brief
+ * @author Bartlomiej Polot
  * @author Christian Grothoff
  */
-#ifndef GNUNET_PEERINFO_PLUGINS_H
-#define GNUNET_PEERINFO_PLUGINS_H
+#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"
 
-/**
- * Load transport plugins.
- *
- * @param cfg configuration to use
- */
-void
-GPI_plugins_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
 /**
- * Unload all plugins
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
  */
-void
-GPI_plugins_unload (void);
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
 
 
 /**
- * Obtain the plugin API based on a plugin name.
+ * Log connection info.
  *
- * @param name name of the plugin
- * @return the plugin's API, NULL if the plugin is not loaded
+ * @param cc connection
+ * @param level Debug level to use.
  */
-struct GNUNET_TRANSPORT_PluginFunctions *
-GPI_plugins_find (const char *name);
+void
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level);
 
 
 #endif
-/* end of file gnunet-peerinfo_plugins.h */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c 
b/src/cadet/gnunet-service-cadet-new_dht.c
new file mode 100644
index 000000000..fbd8b95f1
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_dht.c
@@ -0,0 +1,337 @@
+/*
+     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"
+
+#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;
+
+  /**
+   * Provided callback to call when a path is found.
+   */
+  GCD_search_callback callback;
+
+  /**
+   * Provided closure.
+   */
+  void *cls;
+
+};
+
+
+/**
+ * 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)
+{
+  struct GCD_search_handle *h = cls;
+  const struct GNUNET_HELLO_Message *hello = data;
+  struct CadetPeerPath *p;
+  struct CadetPeer *peer;
+
+  p = GCPP_path_from_dht (get_path,
+                          get_path_length,
+                          put_path,
+                          put_path_length);
+  h->callback (h->cls, p);
+  GCPP_path_destroy (p);
+
+  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 */
+}
+
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "init\n");
+  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_now (&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
+ * @param callback function to call with results
+ * @param callback_cls closure for @a callback
+ * @return handle to abort search
+ */
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id,
+            GCD_search_callback callback,
+            void *callback_cls)
+{
+  struct GNUNET_HashCode phash;
+  struct GCD_search_handle *h;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting DHT GET for peer %s\n",
+       GNUNET_i2s (peer_id));
+  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->callback = callback;
+  h->cls = callback_cls;
+  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);
+  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)
+{
+  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-new_dht.h
similarity index 75%
copy from src/cadet/gnunet-service-cadet_dht.h
copy to src/cadet/gnunet-service-cadet-new_dht.h
index b70dfe975..70f834de5 100644
--- a/src/cadet/gnunet-service-cadet_dht.h
+++ b/src/cadet/gnunet-service-cadet-new_dht.h
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     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
@@ -22,10 +22,10 @@
  * @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 GMD (Gnunet Cadet Dht)
+ * 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
 
@@ -40,6 +40,9 @@ extern "C"
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
+/**
+ * Handle for DHT search operation.
+ */
 struct GCD_search_handle;
 
 
@@ -54,9 +57,6 @@ typedef void
 (*GCD_search_callback) (void *cls,
                         const struct CadetPeerPath *path);
 
-/******************************************************************************/
-/********************************    API    
***********************************/
-/******************************************************************************/
 
 /**
  * Initialize the DHT subsystem.
@@ -73,14 +73,29 @@ void
 GCD_shutdown (void);
 
 
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @param callback function to call with results
+ * @param callback_cls closure for @a callback
+ * @return handle to abort search
+ */
 struct GCD_search_handle *
 GCD_search (const struct GNUNET_PeerIdentity *peer_id,
-            GCD_search_callback callback, void *cls);
+            GCD_search_callback callback,
+            void *callback_cls);
 
 
+/**
+ * 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
@@ -88,6 +103,6 @@ GCD_search_stop (struct GCD_search_handle *h);
 }
 #endif
 
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
 #endif
-/* end of gnunet-cadet-service_LOCAL.h */
+/* 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
new file mode 100644
index 000000000..9d4635021
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_hello.c
@@ -0,0 +1,142 @@
+/*
+     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.
+*/
+
+#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_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);
+    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-new_hello.h
similarity index 91%
copy from src/cadet/gnunet-service-cadet_hello.h
copy to src/cadet/gnunet-service-cadet-new_hello.h
index 5f535b496..4291ae985 100644
--- a/src/cadet/gnunet-service-cadet_hello.h
+++ b/src/cadet/gnunet-service-cadet-new_hello.h
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2014 GNUnet e.V.
+     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
@@ -22,8 +22,9 @@
  * @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 GMH (Gnunet Cadet Hello)
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
  */
 
 #ifndef GNUNET_SERVICE_CADET_HELLO_H
@@ -50,11 +51,13 @@ extern "C"
 void
 GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
 
+
 /**
  * Shut down the hello subsystem.
  */
 void
-GCH_shutdown ();
+GCH_shutdown (void);
+
 
 /**
  * Get own hello message.
@@ -64,6 +67,7 @@ GCH_shutdown ();
 const struct GNUNET_HELLO_Message *
 GCH_get_mine (void);
 
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c 
b/src/cadet/gnunet-service-cadet-new_paths.c
new file mode 100644
index 000000000..a338cc20e
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_paths.c
@@ -0,0 +1,94 @@
+
+/*
+     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_paths.h"
+
+/**
+ * Create a peer path based on the result of a DHT lookup.
+ *
+ * @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
+ */
+struct CadetPeerPath *
+GCPP_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)
+{
+  GNUNET_break (0);
+  return NULL;
+}
+
+
+/**
+ * Destroy a path, we no longer need it.
+ *
+ * @param p path to destroy.
+ */
+void
+GCPP_path_destroy (struct CadetPeerPath *p)
+{
+  GNUNET_assert (0);
+}
+
+
+/**
+ * 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)
+{
+  GNUNET_assert (0);
+  return -1;
+}
+
+
+/**
+ * Obtain the identity of 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
+ * @param[out] pid where to write the pid, must not be NULL
+ */
+void
+GCPP_get_pid_at_offset (struct CadetPeerPath *path,
+                        unsigned int off,
+                        struct GNUNET_PeerIdentity *pid)
+{
+  GNUNET_assert (0);
+}
+
+
+/* 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
new file mode 100644
index 000000000..9354c3f72
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_paths.h
@@ -0,0 +1,83 @@
+
+/*
+     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.
+ *
+ * @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
+ */
+struct CadetPeerPath *
+GCPP_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);
+
+
+/**
+ * Destroy a path, we no longer need it.
+ *
+ * @param p path to destroy.
+ */
+void
+GCPP_path_destroy (struct CadetPeerPath *p);
+
+
+/**
+ * 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);
+
+
+/**
+ * Obtain the identity of 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
+ * @param[out] pid where to write the pid, must not be NULL
+ */
+void
+GCPP_get_pid_at_offset (struct CadetPeerPath *path,
+                        unsigned int off,
+                        struct GNUNET_PeerIdentity *pid);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c 
b/src/cadet/gnunet-service-cadet-new_peer.c
new file mode 100644
index 000000000..824936943
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_peer.c
@@ -0,0 +1,509 @@
+
+/*
+     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
+ */
+#include "platform.h"
+#include "gnunet_util_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 "cadet_path.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_dht.h"
+#include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_tunnels.h"
+
+/**
+ * How long do we wait until tearing down an idle peer?
+ */
+#define IDLE_PEER_TIMEOUT 
GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
+
+
+/**
+ * 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
+   */
+  struct GNUNET_TIME_Absolute last_contact;
+
+  /**
+   * Paths to reach the peer, ordered by ascending hop count
+   */
+  struct CadetPeerPath *path_head;
+
+  /**
+   * Paths to reach the peer, ordered by ascending hop count
+   */
+  struct CadetPeerPath *path_tail;
+
+  /**
+   * Handle to stop the DHT search for paths to this peer
+   */
+  struct GCD_search_handle *search_h;
+
+  /**
+   * Task to stop the DHT search for paths to this peer
+   */
+  struct GNUNET_SCHEDULER_Task *search_delayed;
+
+  /**
+   * 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_MultiHashMap *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 the @e path_head DLL).
+   */
+  unsigned int num_paths;
+
+};
+
+
+/**
+ * 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)
+{
+  if (NULL == peer)
+    return "PEER(NULL)";
+  return GNUNET_i2s (&peer->pid);
+}
+
+
+/**
+ * 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;
+
+  cp->destroy_task = NULL;
+  GNUNET_assert (NULL == cp->t);
+  GNUNET_assert (NULL == cp->core_mq);
+  GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_remove (peers,
+                                                       &cp->pid,
+                                                       cp));
+  /* FIXME: clean up paths! */
+  /* FIXME: clean up search_h! */
+  /* FIXME: clean up search_delayed! */
+
+  GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
+  GNUNET_free_non_null (cp->hello);
+  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_free (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);
+  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 ()
+{
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &destroy_iterator_cb,
+                                         NULL);
+}
+
+
+/**
+ * This peer may no longer be needed, consider cleaning it up.
+ *
+ * @param peer peer to clean up
+ */
+static void
+consider_peer_destroy (struct CadetPeer *peer)
+{
+  struct GNUNET_TIME_Relative exp;
+
+  if (NULL != peer->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (peer->destroy_task);
+    peer->destroy_task = NULL;
+  }
+  if (NULL != peer->t)
+    return; /* still relevant! */
+  if (NULL != peer->core_mq)
+    return; /* still relevant! */
+  if (0 != GNUNET_CONTAINER_multihashmap_size (peer->connections))
+    return; /* still relevant! */
+  if (NULL != peer->hello)
+  {
+    /* relevant only until HELLO expires */
+    exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration 
(peer->hello));
+    peer->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
+                                                       &destroy_peer,
+                                                       peer);
+    return;
+  }
+  peer->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
+                                                     &destroy_peer,
+                                                     peer);
+}
+
+
+/**
+ * Function called when the DHT finds a @a path to the peer (@a cls).
+ *
+ * @param cls the `struct CadetPeer`
+ * @param path the path that was found
+ */
+static void
+dht_result_cb (void *cls,
+               const struct CadetPeerPath *path)
+{
+  struct CadetPeer *peer = cls;
+
+  // FIXME: handle path!
+}
+
+
+/**
+ * This peer is now on more "active" duty, activate processes related to it.
+ *
+ * @param peer the more-active peer
+ */
+static void
+consider_peer_activate (struct CadetPeer *peer)
+{
+  uint32_t strength;
+
+  if (NULL != peer->destroy_task)
+  {
+    /* It's active, do not destory! */
+    GNUNET_SCHEDULER_cancel (peer->destroy_task);
+    peer->destroy_task = NULL;
+  }
+  if (NULL == peer->core_mq)
+  {
+    /* Lacks direct connection, try to create one by querying the DHT */
+    if ( (NULL == peer->search_h) &&
+         (DESIRED_CONNECTIONS_PER_TUNNEL < peer->num_paths) )
+      peer->search_h
+        = GCD_search (&peer->pid,
+                      &dht_result_cb,
+                      peer);
+  }
+  else
+  {
+    /* Have direct connection, stop DHT search if active */
+    if (NULL != peer->search_h)
+    {
+      GCD_search_stop (peer->search_h);
+      peer->search_h = NULL;
+    }
+  }
+
+  /* If we have a tunnel, our urge for connections is much bigger */
+  strength = (NULL != peer->t) ? 32 : 1;
+  if (NULL != peer->connectivity_suggestion)
+    GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
+  peer->connectivity_suggestion
+    = GNUNET_ATS_connectivity_suggest (ats_ch,
+                                       &peer->pid,
+                                       strength);
+}
+
+
+/**
+ * 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_multihashmap_create (32,
+                                                          GNUNET_YES);
+  cp->search_h = NULL; // FIXME: start search immediately!?
+  cp->connectivity_suggestion = NULL; // FIXME: request with ATS!?
+
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_put (peers,
+                                                    &cp->pid,
+                                                    cp,
+                                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  return cp;
+}
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @param[out] peer_id where to write the peer identity
+ */
+void
+GCP_id (struct CadetPeer *cp,
+        struct GNUNET_PeerIdentity *peer_id)
+{
+  *peer_id = cp->pid;
+}
+
+
+/**
+ * Create a peer path based on the result of a DHT lookup.
+ *
+ * @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
+ */
+struct CadetPeerPath *
+GCP_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)
+{
+  GNUNET_assert (0); // FIXME: implement!
+  return NULL;
+}
+
+
+/**
+ * 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 peer Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *peer)
+{
+  return peer->num_paths;
+}
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer 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 *peer,
+                   GCP_PathIterator callback,
+                   void *callback_cls)
+{
+  unsigned int ret = 0;
+
+  for (struct CadetPeerPath *path = peer->path_head;
+       NULL != path;
+       path = path->next)
+  {
+    if (GNUNET_NO ==
+        callback (callback_cls,
+                  peer,
+                  path))
+      return ret;
+    ret++;
+  }
+  return ret;
+}
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer 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 *peer,
+                int create)
+{
+  if (NULL == peer)
+    return NULL;
+  if ( (NULL != peer->t) ||
+       (GNUNET_NO == create) )
+    return peer->t;
+  peer->t = GCT_create_tunnel (peer);
+  consider_peer_activate (peer);
+  return peer->t;
+}
+
+
+/**
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param peer the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *peer,
+               const struct GNUNET_HELLO_Message *hello)
+{
+  /* FIXME! */
+
+  consider_peer_destroy (peer);
+}
+
+
+/**
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
+ *
+ * @param peer the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *peer,
+                 struct CadetTunnel *t)
+{
+  GNUNET_assert (peer->t == t);
+  peer->t = NULL;
+  consider_peer_destroy (peer);
+}
+
+
+/* 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
new file mode 100644
index 000000000..d76874dbc
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_peer.h
@@ -0,0 +1,170 @@
+
+/*
+     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);
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @param[out] peer_id where to write the peer identity
+ */
+void
+GCP_id (struct CadetPeer *cp,
+        struct GNUNET_PeerIdentity *peer_id);
+
+
+/**
+ * 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 peer Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *peer);
+
+
+/**
+ * Peer path iterator.
+ *
+ * @param cls Closure.
+ * @param peer Peer this path is towards.
+ * @param path Path itself
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
+ *
+ * FIXME: path argument should be redundant; remove!
+ */
+typedef int
+(*GCP_PathIterator) (void *cls,
+                     struct CadetPeer *peer,
+                     struct CadetPeerPath *path);
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer 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 *peer,
+                   GCP_PathIterator callback,
+                   void *callback_cls);
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer 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 *peer,
+                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 peer the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *peer,
+                 struct CadetTunnel *t);
+
+
+/**
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param peer the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *peer,
+               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);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c 
b/src/cadet/gnunet-service-cadet-new_tunnels.c
new file mode 100644
index 000000000..4299d5bf7
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.c
@@ -0,0 +1,830 @@
+
+/*
+     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
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_signatures.h"
+#include "cadet_protocol.h"
+#include "cadet_path.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"
+
+
+/**
+ * How long do we wait until tearing down an idle tunnel?
+ */
+#define IDLE_DESTROY_DELAY 
GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
+
+
+/**
+ * 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 (send).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
+
+  /**
+   * 32-byte header key (recv)
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
+
+  /**
+   * 32-byte next header key (send).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
+
+  /**
+   * 32-byte next header key (recv).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy updating, send).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy updating, recv).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
+
+  /**
+   * ECDH for key exchange (A0 / B0).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
+
+  /**
+   * ECDH Ratchet key (send).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs;
+
+  /**
+   * ECDH Ratchet key (recv).
+   */
+  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
+
+  /**
+   * When does this ratchet expire and a new one is triggered.
+   */
+  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;
+
+  /**
+   * Number of messages recieved since our last ratchet advance.
+   * - If this counter = 0, we cannot send a new ratchet key in next msg.
+   * - If this counter > 0, we can (but don't yet have to) send a new key.
+   */
+  unsigned int ratchet_allowed;
+
+  /**
+   * Number of messages recieved since our last ratchet advance.
+   * - If this counter = 0, we cannot send a new ratchet key in next msg.
+   * - If this counter > 0, we can (but don't yet have to) send a new key.
+   */
+  unsigned int ratchet_counter;
+
+};
+
+
+/**
+ * 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 *c;
+
+  /**
+   * Creation time, to keep oldest connection alive.
+   */
+  struct GNUNET_TIME_Absolute created;
+
+  /**
+   * Connection throughput, to keep fastest connection alive.
+   */
+  uint32_t throughput;
+};
+
+
+/**
+ * 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).
+   */
+  GNUNET_SCHEDULER_TaskCallback cont;
+
+  /**
+   * Closure for @c cont.
+   */
+  void *cont_cls;
+
+  /**
+   * (Encrypted) message to send follows.
+   */
+  /* struct GNUNET_MessageHeader *msg; */
+};
+
+
+/**
+ * Struct containing all information regarding a tunnel to a peer.
+ */
+struct CadetTunnel
+{
+  /**
+   * Endpoint of the tunnel.
+   */
+  struct CadetPeer *peer;
+
+  /**
+   * 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;
+
+  /**
+   * State of the tunnel connectivity.
+   */
+  enum CadetTunnelCState cstate;
+
+  /**
+   * State of the tunnel encryption.
+   */
+  enum CadetTunnelEState estate;
+
+  /**
+   * Task to start the rekey process.
+   */
+  struct GNUNET_SCHEDULER_Task *rekey_task;
+
+  /**
+   * DLL of connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_head;
+
+  /**
+   * DLL of connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_tail;
+
+  /**
+   * Channels inside this tunnel. Maps
+   * `struct GCT_ChannelTunnelNumber` to a `struct CadetChannel`.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+  /**
+   * Channel ID for the next created channel in this tunnel.
+   */
+  struct GCT_ChannelTunnelNumber next_chid;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_head;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_tail;
+
+  /**
+   * 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 *trim_connections_task;
+
+  /**
+   * Ephemeral message in the queue (to avoid queueing more than one).
+   */
+  struct CadetConnectionQueue *ephm_hKILL;
+
+  /**
+   * Pong message in the queue.
+   */
+  struct CadetConnectionQueue *pong_hKILL;
+
+  /**
+   * Number of connections in the @e connection_head DLL.
+   */
+  unsigned int num_connections;
+
+  /**
+   * Number of entries in the @e tq_head DLL.
+   */
+  unsigned int tq_len;
+};
+
+
+/**
+ * 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 "T(NULL)";
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "T(%s)",
+                   GCP_2s (t->peer));
+  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->peer;
+}
+
+
+/**
+ * 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);
+}
+
+
+/**
+ * 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 (struct CadetTunnel *t)
+{
+  return t->num_connections;
+}
+
+
+/**
+ * Get the connectivity state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's connectivity state.
+ */
+enum CadetTunnelCState
+GCT_get_cstate (struct CadetTunnel *t)
+{
+  return t->cstate;
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GCT_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch)
+{
+  struct GCT_ChannelTunnelNumber ret;
+  uint32_t chid;
+
+  chid = ntohl (t->next_chid.channel_in_tunnel);
+  while (NULL !=
+         GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              chid))
+    chid++;
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      chid,
+                                                      ch,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  t->next_chid.channel_in_tunnel = htonl (chid + 1);
+  ret.channel_in_tunnel = htonl (chid);
+  return ret;
+}
+
+
+/**
+ * This tunnel is no longer used, destroy it.
+ *
+ * @param cls the idle tunnel
+ */
+static void
+destroy_tunnel (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  t->destroy_task = NULL;
+
+  // FIXME: implement!
+  GCP_drop_tunnel (t->peer,
+                   t);
+  GNUNET_free (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)
+{
+  struct CadetTunnel *t;
+
+  t = GNUNET_new (struct CadetTunnel);
+  t->peer = destination;
+  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
+
+  return t;
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param gid unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GCT_ChannelTunnelNumber gid)
+{
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+                                                         ntohl 
(gid.channel_in_tunnel),
+                                                         ch));
+  if (0 ==
+      GNUNET_CONTAINER_multihashmap32_size (t->channels))
+  {
+    t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+                                                    &destroy_tunnel,
+                                                    t);
+  }
+}
+
+
+/**
+ * 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. NULL if @c cont is NULL.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GNUNET_SCHEDULER_TaskCallback cont,
+          void *cont_cls)
+{
+  struct CadetTunnelQueueEntry *q;
+  uint16_t payload_size;
+
+  payload_size = ntohs (message->size);
+
+  q = GNUNET_malloc (sizeof (*q) +
+                     payload_size);
+  /* FIXME: encrypt 'message' to end of 'q' */
+  q->t = t;
+  q->cont = cont;
+  q->cont_cls = cont_cls;
+  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
+                                    t->tq_tail,
+                                    q);
+  /* FIXME: initiate transmission process! */
+  return q;
+}
+
+
+/**
+ * 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)
+{
+  struct CadetTunnel *t = q->t;
+
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               q);
+  GNUNET_free (q);
+}
+
+
+/**
+ * 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)
+{
+  for (struct CadetTConnection *ct = t->connection_head;
+       NULL != ct;
+       ct = ct->next)
+    iter (iter_cls,
+          ct->c);
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * Get string description for tunnel connectivity state.
+ *
+ * @param cs Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+cstate2s (enum CadetTunnelCState cs)
+{
+  static char buf[32];
+
+  switch (cs)
+  {
+    case CADET_TUNNEL_NEW:
+      return "CADET_TUNNEL_NEW";
+    case CADET_TUNNEL_SEARCHING:
+      return "CADET_TUNNEL_SEARCHING";
+    case CADET_TUNNEL_WAITING:
+      return "CADET_TUNNEL_WAITING";
+    case CADET_TUNNEL_READY:
+      return "CADET_TUNNEL_READY";
+    case CADET_TUNNEL_SHUTDOWN:
+      return "CADET_TUNNEL_SHUTDOWN";
+    default:
+      SPRINTF (buf, "%u (UNKNOWN STATE)", cs);
+      return buf;
+  }
+}
+
+
+/**
+ * Get string description for tunnel encryption state.
+ *
+ * @param es Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+estate2s (enum CadetTunnelEState es)
+{
+  static char buf[32];
+
+  switch (es)
+  {
+    case CADET_TUNNEL_KEY_UNINITIALIZED:
+      return "CADET_TUNNEL_KEY_UNINITIALIZED";
+    case CADET_TUNNEL_KEY_SENT:
+      return "CADET_TUNNEL_KEY_SENT";
+    case CADET_TUNNEL_KEY_PING:
+      return "CADET_TUNNEL_KEY_PING";
+    case CADET_TUNNEL_KEY_OK:
+      return "CADET_TUNNEL_KEY_OK";
+    case CADET_TUNNEL_KEY_REKEY:
+      return "CADET_TUNNEL_KEY_REKEY";
+    default:
+      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
+      return buf;
+  }
+}
+
+
+#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 cstate %s, estate %s tq_len: %u #cons: %u\n",
+        GCT_2s (t),
+        cstate2s (t->cstate),
+        estate2s (t->estate),
+        t->tq_len,
+        t->num_connections);
+#if DUMP_KEYS_TO_STDERR
+  ax_debug (t->ax, level);
+#endif
+  LOG2 (level,
+        "TTT channels:\n");
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &debug_channel,
+                                           &level);
+  LOG2 (level,
+        "TTT connections:\n");
+  for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next)
+    GCC_debug (iter_c->c, 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
new file mode 100644
index 000000000..5e06559d5
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.h
@@ -0,0 +1,314 @@
+
+/*
+     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
+
+
+/**
+ * How many connections would we like to have per tunnel?
+ */
+#define DESIRED_CONNECTIONS_PER_TUNNEL 3
+
+
+/**
+ * All the connectivity states a tunnel can be in.
+ */
+enum CadetTunnelCState
+{
+  /**
+   * Uninitialized status, should never appear in operation.
+   */
+  CADET_TUNNEL_NEW,
+
+  /**
+   * No path to the peer known yet.
+   */
+  CADET_TUNNEL_SEARCHING,
+
+  /**
+   * Request sent, not yet answered.
+   */
+  CADET_TUNNEL_WAITING,
+
+  /**
+   * Peer connected and ready to accept data.
+   */
+  CADET_TUNNEL_READY,
+
+  /**
+   * Tunnel being shut down, don't try to keep it alive.
+   */
+  CADET_TUNNEL_SHUTDOWN
+};
+
+
+
+/**
+ * All the encryption states a tunnel can be in.
+ */
+enum CadetTunnelEState
+{
+  /**
+   * Uninitialized status, should never appear in operation.
+   */
+  CADET_TUNNEL_KEY_UNINITIALIZED,
+
+  /**
+   * Ephemeral key sent, waiting for peer's key.
+   */
+  CADET_TUNNEL_KEY_SENT,
+
+  /**
+   * In OTR: New ephemeral key and ping sent, waiting for pong.
+   *
+   * This means that we DO have the peer's ephemeral key, otherwise the
+   * state would be KEY_SENT. We DO NOT have a valid session key (either no
+   * previous key or previous key expired).
+   *
+   *
+   * In Axolotl: Key sent and received but no deciphered traffic yet.
+   *
+   * This means that we can send traffic (otherwise we would never complete
+   * the handshake), but we don't have complete confirmation. Since the first
+   * traffic MUST be a complete channel creation 3-way handshake, no payload
+   * will be sent before confirmation.
+   */
+  CADET_TUNNEL_KEY_PING,
+
+  /**
+   * Handshake completed: session key available.
+   */
+  CADET_TUNNEL_KEY_OK,
+
+  /**
+   * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING,
+   * we still have a valid session key and therefore we *can* still send
+   * traffic on the tunnel.
+   */
+  CADET_TUNNEL_KEY_REKEY
+};
+
+
+/**
+ * Number uniquely identifying a channel within a tunnel.
+ */
+struct GCT_ChannelTunnelNumber
+{
+  uint32_t channel_in_tunnel GNUNET_PACKED;
+};
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GCT_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch);
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param gid unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GCT_ChannelTunnelNumber gid);
+
+
+/**
+ * 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. NULL if @c cont is NULL.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GNUNET_SCHEDULER_TaskCallback 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 (struct CadetTunnel *t);
+
+
+/**
+ * Iterator over connections.
+ *
+ * @param cls closure
+ * @param c one of the connections
+ */
+typedef void
+(*GCT_ConnectionIterator) (void *cls,
+                           struct CadetConnection *c);
+
+
+/**
+ * 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 connectivity state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's connectivity state.
+ */
+enum CadetTunnelCState
+GCT_get_cstate (struct CadetTunnel *t);
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t);
+
+
+/**
+ * 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_channel.c 
b/src/cadet/gnunet-service-cadet_channel.c
index d2d176e83..6bc3dc590 100644
--- a/src/cadet/gnunet-service-cadet_channel.c
+++ b/src/cadet/gnunet-service-cadet_channel.c
@@ -58,7 +58,7 @@ enum CadetChannelState
   /**
    * Connection confirmed, ready to carry traffic.
    */
-  CADET_CHANNEL_READY,
+  CADET_CHANNEL_READY
 };
 
 
@@ -216,19 +216,19 @@ struct CadetChannel
   /**
    * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
    */
-  CADET_ChannelNumber gid;
+  struct GNUNET_CADET_ChannelNumber gid;
 
   /**
    * Local tunnel number for root (owner) client.
    * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
    */
-  CADET_ChannelNumber lid_root;
-  
+  struct GNUNET_CADET_ClientChannelNumber lid_root;
+
   /**
    * Local tunnel number for local destination clients (incoming number)
    * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
    */
-  CADET_ChannelNumber lid_dest;
+  struct GNUNET_CADET_ClientChannelNumber lid_dest;
 
   /**
    * Channel state.
@@ -517,7 +517,7 @@ send_destroy (struct CadetChannel *ch, int local_only)
 
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
   msg.header.size = htons (sizeof (msg));
-  msg.chid = htonl (ch->gid);
+  msg.chid = ch->gid;
 
   /* If root is not NULL, notify.
    * If it's NULL, check lid_root. When a local destroy comes in, root
@@ -526,12 +526,12 @@ send_destroy (struct CadetChannel *ch, int local_only)
    */
   if (NULL != ch->root)
     GML_send_channel_destroy (ch->root, ch->lid_root);
-  else if (0 == ch->lid_root && GNUNET_NO == local_only)
+  else if (0 == ch->lid_root.channel_of_client && GNUNET_NO == local_only)
     GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
 
   if (NULL != ch->dest)
     GML_send_channel_destroy (ch->dest, ch->lid_dest);
-  else if (0 == ch->lid_dest && GNUNET_NO == local_only)
+  else if (0 == ch->lid_dest.channel_of_client && GNUNET_NO == local_only)
     GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
 }
 
@@ -552,7 +552,10 @@ send_client_create (struct CadetChannel *ch)
   opt = 0;
   opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0;
   opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0;
-  GML_send_channel_create (ch->dest, ch->lid_dest, &ch->port, opt,
+  GML_send_channel_create (ch->dest,
+                           ch->lid_dest,
+                           &ch->port,
+                           opt,
                            GCT_get_destination (ch->t));
 
 }
@@ -883,7 +886,7 @@ send_create (struct CadetChannel *ch)
 
   msgcc.header.size = htons (sizeof (msgcc));
   msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
-  msgcc.chid = htonl (ch->gid);
+  msgcc.chid = ch->gid;
   msgcc.port = ch->port;
   msgcc.opt = htonl (channel_get_options (ch));
 
@@ -904,10 +907,11 @@ send_ack (struct CadetChannel *ch, int fwd)
 
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending channel %s ack for channel %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "  sending channel %s ack for channel %s\n",
        GC_f2s (fwd), GCCH_2s (ch));
 
-  msg.chid = htonl (ch->gid);
+  msg.chid =ch->gid;
   GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
 }
 
@@ -925,8 +929,9 @@ fire_and_forget (const struct GNUNET_MessageHeader *msg,
                  struct CadetChannel *ch,
                  int force)
 {
-  GNUNET_break (NULL == GCT_send_prebuilt_message (msg, ch->t, NULL,
-                                                   force, NULL, NULL));
+  GNUNET_break (NULL ==
+                GCT_send_prebuilt_message (msg, ch->t, NULL,
+                                           force, NULL, NULL));
 }
 
 
@@ -946,7 +951,7 @@ send_nack (struct CadetChannel *ch)
        "  sending channel NACK for channel %s\n",
        GCCH_2s (ch));
 
-  msg.chid = htonl (ch->gid);
+  msg.chid = ch->gid;
   GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
 }
 
@@ -1252,7 +1257,7 @@ channel_save_copy (struct CadetChannel *ch,
 static struct CadetChannel *
 channel_new (struct CadetTunnel *t,
              struct CadetClient *owner,
-             CADET_ChannelNumber lid_root)
+             struct GNUNET_CADET_ClientChannelNumber lid_root)
 {
   struct CadetChannel *ch;
 
@@ -1393,7 +1398,7 @@ GCCH_destroy (struct CadetChannel *ch)
  *
  * @return ID used to identify the channel with the remote peer.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ChannelNumber
 GCCH_get_id (const struct CadetChannel *ch)
 {
   return ch->gid;
@@ -1533,7 +1538,7 @@ GCCH_send_data_ack (struct CadetChannel *ch, int fwd)
 
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK);
   msg.header.size = htons (sizeof (msg));
-  msg.chid = htonl (ch->gid);
+  msg.chid = ch->gid;
   msg.mid = htonl (ack);
 
   msg.futures = 0LL;
@@ -1657,7 +1662,7 @@ GCCH_debug (struct CadetChannel *ch, enum 
GNUNET_ErrorType level)
   {
     LOG2 (level, "CHN   cli %s\n", GML_2s (ch->root));
     LOG2 (level, "CHN   ready %s\n", ch->root_rel->client_ready ? "YES" : 
"NO");
-    LOG2 (level, "CHN   id %X\n", ch->lid_root);
+    LOG2 (level, "CHN   id %X\n", ch->lid_root.channel_of_client);
     LOG2 (level, "CHN   recv %d\n", ch->root_rel->n_recv);
     LOG2 (level, "CHN   MID r: %d, s: %d\n",
           ch->root_rel->mid_recv, ch->root_rel->mid_send);
@@ -1733,11 +1738,12 @@ GCCH_handle_local_ack (struct CadetChannel *ch, int fwd)
  * @param message Data message.
  * @param size Size of data.
  *
- * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en 
error.
+ * @return #GNUNET_OK if everything goes well, #GNUNET_SYSERR in case of en 
error.
  */
 int
 GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct CadetClient *c, int fwd,
+                        struct CadetClient *c,
+                        int fwd,
                         const struct GNUNET_MessageHeader *message,
                         size_t size)
 {
@@ -1775,7 +1781,7 @@ GCCH_handle_local_data (struct CadetChannel *ch,
   GNUNET_memcpy (&payload[1], message, size);
   payload->header.size = htons (p2p_size);
   payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA);
-  payload->chid = htonl (ch->gid);
+  payload->chid = ch->gid;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on channel...\n");
   GCCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
 
@@ -1845,11 +1851,11 @@ GCCH_handle_local_create (struct CadetClient *c,
   struct CadetChannel *ch;
   struct CadetTunnel *t;
   struct CadetPeer *peer;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  towards %s:%u\n",
        GNUNET_i2s (&msg->peer), GNUNET_h2s (&msg->port));
-  chid = ntohl (msg->channel_id);
+  chid = msg->channel_id;
 
   /* Sanity check for duplicate channel IDs */
   if (NULL != GML_channel_get (c, chid))
@@ -2147,20 +2153,21 @@ struct CadetChannel *
 GCCH_handle_create (struct CadetTunnel *t,
                     const struct GNUNET_CADET_ChannelCreate *msg)
 {
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
+  struct GNUNET_CADET_ChannelNumber gid;
   struct CadetChannel *ch;
   struct CadetClient *c;
   int new_channel;
   const struct GNUNET_HashCode *port;
 
-  chid = ntohl (msg->chid);
-
-  ch = GCT_get_channel (t, chid);
+  gid = msg->chid;
+  ch = GCT_get_channel (t, gid);
   if (NULL == ch)
   {
     /* Create channel */
-    ch = channel_new (t, NULL, 0);
-    ch->gid = chid;
+    chid.channel_of_client = htonl (0);
+    ch = channel_new (t, NULL, chid);
+    ch->gid = gid;
     channel_set_options (ch, ntohl (msg->opt));
     new_channel = GNUNET_YES;
   }
@@ -2403,7 +2410,7 @@ GCCH_send_prebuilt_message (const struct 
GNUNET_MessageHeader *message,
     {
       struct GNUNET_CADET_ChannelCreate *cc_msg;
       cc_msg = (struct GNUNET_CADET_ChannelCreate *) message;
-      SPRINTF (info, "  0x%08X", ntohl (cc_msg->chid));
+      SPRINTF (info, "  0x%08X", ntohl (cc_msg->chid.cn));
       break;
     }
     case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
@@ -2412,7 +2419,7 @@ GCCH_send_prebuilt_message (const struct 
GNUNET_MessageHeader *message,
     {
       struct GNUNET_CADET_ChannelManage *m_msg;
       m_msg = (struct GNUNET_CADET_ChannelManage *) message;
-      SPRINTF (info, "  0x%08X", ntohl (m_msg->chid));
+      SPRINTF (info, "  0x%08X", ntohl (m_msg->chid.cn));
       break;
     }
     default:
@@ -2542,9 +2549,13 @@ GCCH_2s (const struct CadetChannel *ch)
   if (NULL == ch)
     return "(NULL Channel)";
 
-  SPRINTF (buf, "%s:%s gid:%X (%X / %X)",
-           GCT_2s (ch->t), GNUNET_h2s (&ch->port),
-           ch->gid, ch->lid_root, ch->lid_dest);
+  SPRINTF (buf,
+           "%s:%s gid:%X (%X / %X)",
+           GCT_2s (ch->t),
+           GNUNET_h2s (&ch->port),
+           ntohl (ch->gid.cn),
+           ntohl (ch->lid_root.channel_of_client),
+           ntohl (ch->lid_dest.channel_of_client));
 
   return buf;
 }
diff --git a/src/cadet/gnunet-service-cadet_channel.h 
b/src/cadet/gnunet-service-cadet_channel.h
index eeea02712..8faad2e86 100644
--- a/src/cadet/gnunet-service-cadet_channel.h
+++ b/src/cadet/gnunet-service-cadet_channel.h
@@ -69,7 +69,7 @@ GCCH_destroy (struct CadetChannel *ch);
  *
  * @return ID used to identify the channel with the remote peer.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ChannelNumber
 GCCH_get_id (const struct CadetChannel *ch);
 
 /**
@@ -347,6 +347,8 @@ const char *
 GCCH_2s (const struct CadetChannel *ch);
 
 
+
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/cadet/gnunet-service-cadet_connection.c 
b/src/cadet/gnunet-service-cadet_connection.c
index 343e372b2..e727ef199 100644
--- a/src/cadet/gnunet-service-cadet_connection.c
+++ b/src/cadet/gnunet-service-cadet_connection.c
@@ -2464,7 +2464,7 @@ check_message (const struct GNUNET_MessageHeader *message,
   if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type)
   {
     fc = fwd ? &c->bck_fc : &c->fwd_fc;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected %u - %u)\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected in interval [%u,%u])\n",
          pid,
         fc->last_pid_recv + 1,
         fc->last_ack_sent);
diff --git a/src/cadet/gnunet-service-cadet_dht.c 
b/src/cadet/gnunet-service-cadet_dht.c
index 43b1c8252..22673b167 100644
--- a/src/cadet/gnunet-service-cadet_dht.c
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -42,16 +42,24 @@
  */
 struct GCD_search_handle
 {
-  /** DHT_GET handle. */
+  /**
+   * DHT_GET handle.
+   */
   struct GNUNET_DHT_GetHandle *dhtget;
 
-  /** Provided callback to call when a path is found. */
+  /**
+   * Provided callback to call when a path is found.
+   */
   GCD_search_callback callback;
 
-  /** Provided closure. */
+  /**
+   * Provided closure.
+   */
   void *cls;
 
-  /** Peer ID searched for */
+  /**
+   * Peer ID searched for
+   */
   GNUNET_PEER_Id peer_id;
 };
 
diff --git a/src/cadet/gnunet-service-cadet_hello.h 
b/src/cadet/gnunet-service-cadet_hello.h
index 5f535b496..34121e1e0 100644
--- a/src/cadet/gnunet-service-cadet_hello.h
+++ b/src/cadet/gnunet-service-cadet_hello.h
@@ -50,11 +50,13 @@ extern "C"
 void
 GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
 
+
 /**
  * Shut down the hello subsystem.
  */
 void
-GCH_shutdown ();
+GCH_shutdown (void);
+
 
 /**
  * Get own hello message.
@@ -64,6 +66,7 @@ GCH_shutdown ();
 const struct GNUNET_HELLO_Message *
 GCH_get_mine (void);
 
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/cadet/gnunet-service-cadet_local.c 
b/src/cadet/gnunet-service-cadet_local.c
index 9be1224c1..743fbf054 100644
--- a/src/cadet/gnunet-service-cadet_local.c
+++ b/src/cadet/gnunet-service-cadet_local.c
@@ -61,7 +61,7 @@ struct CadetClient
    * Tunnels that belong to this client, indexed by local id
    */
   struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
-  
+
   /**
    * Tunnels this client has accepted, indexed by incoming local id
    */
@@ -70,7 +70,7 @@ struct CadetClient
   /**
    * Channel ID for the next incoming channel.
    */
-  CADET_ChannelNumber next_chid;
+  struct GNUNET_CADET_ClientChannelNumber next_chid;
 
   /**
    * Handle to communicate with the client
@@ -188,7 +188,9 @@ channel_destroy_iterator (void *cls,
        " Channel %s destroy, due to client %s shutdown.\n",
        GCCH_2s (ch), GML_2s (c));
 
-  GCCH_handle_local_destroy (ch, c, key < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
+  GCCH_handle_local_destroy (ch,
+                             c,
+                             key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
   return GNUNET_OK;
 }
 
@@ -247,7 +249,6 @@ client_new (struct GNUNET_SERVER_Client *client)
   c = GNUNET_new (struct CadetClient);
   c->handle = client;
   c->id = next_client_id++; /* overflow not important: just for debug */
-  c->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
 
   c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
   c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
@@ -474,7 +475,7 @@ handle_channel_destroy (void *cls, struct 
GNUNET_SERVER_Client *client,
   struct GNUNET_CADET_ChannelDestroyMessage *msg;
   struct CadetClient *c;
   struct CadetChannel *ch;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
 
@@ -499,7 +500,7 @@ handle_channel_destroy (void *cls, struct 
GNUNET_SERVER_Client *client,
   msg = (struct GNUNET_CADET_ChannelDestroyMessage *) message;
 
   /* Retrieve tunnel */
-  chid = ntohl (msg->channel_id);
+  chid = msg->channel_id;
   ch = GML_channel_get (c, chid);
 
   LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n",
@@ -515,7 +516,9 @@ handle_channel_destroy (void *cls, struct 
GNUNET_SERVER_Client *client,
     return;
   }
 
-  GCCH_handle_local_destroy (ch, c, chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
+  GCCH_handle_local_destroy (ch,
+                             c,
+                             ntohl (chid.channel_of_client) < 
GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
   return;
@@ -537,7 +540,7 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client,
   struct GNUNET_CADET_LocalData *msg;
   struct CadetClient *c;
   struct CadetChannel *ch;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
   size_t message_size;
   size_t payload_size;
   size_t payload_claimed_size;
@@ -583,12 +586,12 @@ handle_data (void *cls, struct GNUNET_SERVER_Client 
*client,
     return;
   }
 
-  chid = ntohl (msg->id);
+  chid = msg->id;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  %u bytes (%u payload) by client %u\n",
        payload_size, payload_claimed_size, c->id);
 
   /* Channel exists? */
-  fwd = chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+  fwd = ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
   ch = GML_channel_get (c, chid);
   if (NULL == ch)
   {
@@ -626,7 +629,7 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
   struct GNUNET_CADET_LocalAck *msg;
   struct CadetChannel *ch;
   struct CadetClient *c;
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
   int fwd;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
@@ -644,13 +647,16 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client 
*client,
   msg = (struct GNUNET_CADET_LocalAck *) message;
 
   /* Channel exists? */
-  chid = ntohl (msg->channel_id);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X\n", chid);
+  chid = msg->channel_id;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X\n",
+       ntohl (chid.channel_of_client));
   ch = GML_channel_get (c, chid);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "   -- ch %p\n", ch);
   if (NULL == ch)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Channel %X unknown.\n",
+         ntohl (chid.channel_of_client));
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  for client %u.\n", c->id);
     GNUNET_STATISTICS_update (stats,
                               "# client ack messages on unknown channel",
@@ -661,12 +667,10 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client 
*client,
 
   /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
   /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
-  fwd = chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+  fwd = ntohl (chid.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
 
   GCCH_handle_local_ack (ch, fwd);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  return;
 }
 
 
@@ -972,9 +976,9 @@ iter_channel (void *cls, struct CadetChannel *ch)
 {
   struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
   struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1];
-  CADET_ChannelNumber *chn = (CADET_ChannelNumber *) &h[msg->connections];
+  struct GNUNET_CADET_ChannelNumber *chn = (struct GNUNET_CADET_ChannelNumber 
*) &h[msg->connections];
 
-  chn[msg->channels] = htonl (GCCH_get_id (ch));
+  chn[msg->channels] = GCCH_get_id (ch);
   msg->channels++;
 }
 
@@ -1040,7 +1044,7 @@ handle_show_tunnel (void *cls, struct 
GNUNET_SERVER_Client *client,
 
   size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
   size += c_n * sizeof (struct GNUNET_CADET_Hash);
-  size += ch_n * sizeof (CADET_ChannelNumber);
+  size += ch_n * sizeof (struct GNUNET_CADET_ChannelNumber);
 
   resp = GNUNET_malloc (size);
   resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
@@ -1214,26 +1218,16 @@ GML_shutdown (void)
  * @return non-NULL if channel exists in the clients lists
  */
 struct CadetChannel *
-GML_channel_get (struct CadetClient *c, CADET_ChannelNumber chid)
+GML_channel_get (struct CadetClient *c,
+                 struct GNUNET_CADET_ClientChannelNumber chid)
 {
   struct GNUNET_CONTAINER_MultiHashMap32 *map;
 
-  if (0 == (chid & GNUNET_CADET_LOCAL_CHANNEL_ID_CLI))
-  {
-    GNUNET_break_op (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
-    return NULL;
-  }
-
-  if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
-    map = c->incoming_channels;
-  else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+  if (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
     map = c->own_channels;
   else
-  {
-    GNUNET_break (0);
-    map = NULL;
-  }
+    map = c->incoming_channels;
+
   if (NULL == map)
   {
     GNUNET_break (0);
@@ -1242,7 +1236,8 @@ GML_channel_get (struct CadetClient *c, 
CADET_ChannelNumber chid)
          GML_2s (c), chid);
     return NULL;
   }
-  return GNUNET_CONTAINER_multihashmap32_get (map, chid);
+  return GNUNET_CONTAINER_multihashmap32_get (map,
+                                              chid.channel_of_client);
 }
 
 
@@ -1255,17 +1250,19 @@ GML_channel_get (struct CadetClient *c, 
CADET_ChannelNumber chid)
  */
 void
 GML_channel_add (struct CadetClient *client,
-                 uint32_t chid,
+                 struct GNUNET_CADET_ClientChannelNumber chid,
                  struct CadetChannel *ch)
 {
-  if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
-    GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch,
-                                         
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-  else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-    GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch,
+  if (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+    GNUNET_CONTAINER_multihashmap32_put (client->own_channels,
+                                         chid.channel_of_client,
+                                         ch,
                                          
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
   else
-    GNUNET_break (0);
+    GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels,
+                                         chid.channel_of_client,
+                                         ch,
+                                         
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
 }
 
 
@@ -1278,19 +1275,17 @@ GML_channel_add (struct CadetClient *client,
  */
 void
 GML_channel_remove (struct CadetClient *client,
-                    uint32_t chid,
+                    struct GNUNET_CADET_ClientChannelNumber chid,
                     struct CadetChannel *ch)
 {
-  if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= chid)
-    GNUNET_break (GNUNET_YES ==
-                  GNUNET_CONTAINER_multihashmap32_remove 
(client->incoming_channels,
-                                                          chid, ch));
-  else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= chid)
-    GNUNET_break (GNUNET_YES ==
-                  GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
-                                                          chid, ch));
+  if (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+    GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
+                                            chid.channel_of_client,
+                                            ch);
   else
-    GNUNET_break (0);
+    GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels,
+                                            chid.channel_of_client,
+                                            ch);
 }
 
 
@@ -1301,18 +1296,26 @@ GML_channel_remove (struct CadetClient *client,
  *
  * @return LID of a channel free to use.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ClientChannelNumber
 GML_get_next_chid (struct CadetClient *c)
 {
-  CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ClientChannelNumber chid;
 
-  while (NULL != GML_channel_get (c, c->next_chid))
+  while (NULL != GML_channel_get (c,
+                                  c->next_chid))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid);
-    c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Channel %u exists...\n",
+         c->next_chid);
+    c->next_chid.channel_of_client
+      = htonl (1 + (ntohl (c->next_chid.channel_of_client)));
+    if (ntohl (c->next_chid.channel_of_client) >=
+        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+      c->next_chid.channel_of_client = htonl (0);
   }
   chid = c->next_chid;
-  c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+  c->next_chid.channel_of_client
+    = htonl (1 + (ntohl (c->next_chid.channel_of_client)));
 
   return chid;
 }
@@ -1330,9 +1333,11 @@ GML_client_get (struct GNUNET_SERVER_Client *client)
 {
   if (NULL == client)
     return NULL;
-  return GNUNET_SERVER_client_get_user_context (client, struct CadetClient);
+  return GNUNET_SERVER_client_get_user_context (client,
+                                                struct CadetClient);
 }
 
+
 /**
  * Find a client that has opened a port
  *
@@ -1357,27 +1362,25 @@ GML_client_get_by_port (const struct GNUNET_HashCode 
*port)
 void
 GML_client_delete_channel (struct CadetClient *c,
                            struct CadetChannel *ch,
-                           CADET_ChannelNumber id)
+                           struct GNUNET_CADET_ClientChannelNumber id)
 {
   int res;
 
-  if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= id)
-  {
-    res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
-                                                  id, ch);
-    if (GNUNET_YES != res)
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
-  }
-  else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= id)
+  if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
   {
     res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
-                                                  id, ch);
+                                                  id.channel_of_client,
+                                                  ch);
     if (GNUNET_YES != res)
       LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
   }
   else
   {
-    GNUNET_break (0);
+    res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
+                                                  id.channel_of_client,
+                                                  ch);
+    if (GNUNET_YES != res)
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
   }
 }
 
@@ -1390,17 +1393,21 @@ GML_client_delete_channel (struct CadetClient *c,
  * @param id Channel ID to use
  */
 void
-GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id)
+GML_send_ack (struct CadetClient *c,
+              struct GNUNET_CADET_ClientChannelNumber id)
 {
   struct GNUNET_CADET_LocalAck msg;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-              "send local %s ack on %X towards %p\n",
-              id < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c);
+       "send local %s ack on %X towards %p\n",
+       ntohl (id.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI
+       ? "FWD" : "BCK",
+       ntohl (id.channel_of_client),
+       c);
 
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-  msg.channel_id = htonl (id);
+  msg.channel_id = id;
   GNUNET_SERVER_notification_context_unicast (nc,
                                               c->handle,
                                               &msg.header,
@@ -1421,14 +1428,16 @@ GML_send_ack (struct CadetClient *c, 
CADET_ChannelNumber id)
  */
 void
 GML_send_channel_create (struct CadetClient *c,
-                         uint32_t id, struct GNUNET_HashCode *port,
-                         uint32_t opt, const struct GNUNET_PeerIdentity *peer)
+                         struct GNUNET_CADET_ClientChannelNumber id,
+                         const struct GNUNET_HashCode *port,
+                         uint32_t opt,
+                         const struct GNUNET_PeerIdentity *peer)
 {
   struct GNUNET_CADET_ChannelCreateMessage msg;
 
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
-  msg.channel_id = htonl (id);
+  msg.channel_id = id;
   msg.port = *port;
   msg.opt = htonl (opt);
   msg.peer = *peer;
@@ -1444,17 +1453,19 @@ GML_send_channel_create (struct CadetClient *c,
  * @param id Channel ID to use
  */
 void
-GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id)
+GML_send_channel_nack (struct CadetClient *c,
+                       struct GNUNET_CADET_ClientChannelNumber id)
 {
   struct GNUNET_CADET_LocalAck msg;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "send local nack on %X towards %p\n",
-       id, c);
+       ntohl (id.channel_of_client),
+       c);
 
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK);
-  msg.channel_id = htonl (id);
+  msg.channel_id = id;
   GNUNET_SERVER_notification_context_unicast (nc,
                                               c->handle,
                                               &msg.header,
@@ -1469,7 +1480,8 @@ GML_send_channel_nack (struct CadetClient *c, 
CADET_ChannelNumber id)
  * @param id ID of the channel that is destroyed.
  */
 void
-GML_send_channel_destroy (struct CadetClient *c, uint32_t id)
+GML_send_channel_destroy (struct CadetClient *c,
+                          struct GNUNET_CADET_ClientChannelNumber id)
 {
   struct GNUNET_CADET_ChannelDestroyMessage msg;
 
@@ -1482,7 +1494,7 @@ GML_send_channel_destroy (struct CadetClient *c, uint32_t 
id)
     return;
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
-  msg.channel_id = htonl (id);
+  msg.channel_id = id;
   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
                                               &msg.header, GNUNET_NO);
 }
@@ -1498,7 +1510,7 @@ GML_send_channel_destroy (struct CadetClient *c, uint32_t 
id)
 void
 GML_send_data (struct CadetClient *c,
                const struct GNUNET_CADET_Data *msg,
-               CADET_ChannelNumber id)
+               struct GNUNET_CADET_ClientChannelNumber id)
 {
   struct GNUNET_CADET_LocalData *copy;
   uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_Data);
@@ -1518,7 +1530,7 @@ GML_send_data (struct CadetClient *c,
   GNUNET_memcpy (&copy[1], &msg[1], size);
   copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size);
   copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  copy->id = htonl (id);
+  copy->id = id;
   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
                                               &copy->header, GNUNET_NO);
 }
diff --git a/src/cadet/gnunet-service-cadet_local.h 
b/src/cadet/gnunet-service-cadet_local.h
index f89745092..9b6e5bf05 100644
--- a/src/cadet/gnunet-service-cadet_local.h
+++ b/src/cadet/gnunet-service-cadet_local.h
@@ -80,7 +80,8 @@ GML_shutdown (void);
  * @return non-NULL if channel exists in the clients lists
  */
 struct CadetChannel *
-GML_channel_get (struct CadetClient *c, uint32_t chid);
+GML_channel_get (struct CadetClient *c,
+                 struct GNUNET_CADET_ClientChannelNumber chid);
 
 /**
  * Add a channel to a client
@@ -91,7 +92,7 @@ GML_channel_get (struct CadetClient *c, uint32_t chid);
  */
 void
 GML_channel_add (struct CadetClient *client,
-                 uint32_t chid,
+                 struct GNUNET_CADET_ClientChannelNumber chid,
                  struct CadetChannel *ch);
 
 /**
@@ -103,7 +104,7 @@ GML_channel_add (struct CadetClient *client,
  */
 void
 GML_channel_remove (struct CadetClient *client,
-                    uint32_t chid,
+                    struct GNUNET_CADET_ClientChannelNumber chid,
                     struct CadetChannel *ch);
 
 /**
@@ -113,7 +114,7 @@ GML_channel_remove (struct CadetClient *client,
  *
  * @return LID of a channel free to use.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ClientChannelNumber
 GML_get_next_chid (struct CadetClient *c);
 
 /**
@@ -146,7 +147,7 @@ GML_client_get_by_port (const struct GNUNET_HashCode *port);
 void
 GML_client_delete_channel (struct CadetClient *c,
                            struct CadetChannel *ch,
-                           CADET_ChannelNumber id);
+                           struct GNUNET_CADET_ClientChannelNumber id);
 
 /**
  * Build a local ACK message and send it to a local client, if needed.
@@ -157,7 +158,8 @@ GML_client_delete_channel (struct CadetClient *c,
  * @param id Channel ID to use
  */
 void
-GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id);
+GML_send_ack (struct CadetClient *c,
+              struct GNUNET_CADET_ClientChannelNumber id);
 
 /**
  * Notify the appropriate client that a new incoming channel was created.
@@ -170,8 +172,10 @@ GML_send_ack (struct CadetClient *c, CADET_ChannelNumber 
id);
  */
 void
 GML_send_channel_create (struct CadetClient *c,
-                         uint32_t id, struct GNUNET_HashCode *port,
-                         uint32_t opt, const struct GNUNET_PeerIdentity *peer);
+                         struct GNUNET_CADET_ClientChannelNumber id,
+                         const struct GNUNET_HashCode *port,
+                         uint32_t opt,
+                         const struct GNUNET_PeerIdentity *peer);
 
 /**
  * Build a local channel NACK message and send it to a local client.
@@ -180,7 +184,9 @@ GML_send_channel_create (struct CadetClient *c,
  * @param id Channel ID to use
  */
 void
-GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id);
+GML_send_channel_nack (struct CadetClient *c,
+                       struct GNUNET_CADET_ClientChannelNumber id);
+
 
 /**
  * Notify a client that a channel is no longer valid.
@@ -189,7 +195,9 @@ GML_send_channel_nack (struct CadetClient *c, 
CADET_ChannelNumber id);
  * @param id ID of the channel that is destroyed.
  */
 void
-GML_send_channel_destroy (struct CadetClient *c, uint32_t id);
+GML_send_channel_destroy (struct CadetClient *c,
+                          struct GNUNET_CADET_ClientChannelNumber id);
+
 
 /**
  * Modify the cadet message ID from global to local and send to client.
@@ -201,7 +209,7 @@ GML_send_channel_destroy (struct CadetClient *c, uint32_t 
id);
 void
 GML_send_data (struct CadetClient *c,
                const struct GNUNET_CADET_Data *msg,
-               CADET_ChannelNumber id);
+               struct GNUNET_CADET_ClientChannelNumber id);
 
 /**
  * Get the static string to represent a client.
diff --git a/src/cadet/gnunet-service-cadet_peer.c 
b/src/cadet/gnunet-service-cadet_peer.c
index c1e2d3224..b2ad1124c 100644
--- a/src/cadet/gnunet-service-cadet_peer.c
+++ b/src/cadet/gnunet-service-cadet_peer.c
@@ -76,7 +76,7 @@ struct CadetPeerQueue {
      * Task to asynchronously run the drop continuation.
      */
     struct GNUNET_SCHEDULER_Task *drop_task;
-  
+
     /**
      * Time when message was queued for sending.
      */
@@ -1145,7 +1145,7 @@ static void
 drop_cb (void *cls)
 {
   struct CadetPeerQueue *q = cls;
-  
+
   GNUNET_MQ_discard (q->env);
   call_peer_cont (q, GNUNET_YES);
   GNUNET_free (q);
diff --git a/src/cadet/gnunet-service-cadet_peer.h 
b/src/cadet/gnunet-service-cadet_peer.h
index 093cfa21a..37d735bf5 100644
--- a/src/cadet/gnunet-service-cadet_peer.h
+++ b/src/cadet/gnunet-service-cadet_peer.h
@@ -122,6 +122,7 @@ GCP_shutdown (void);
 struct CadetPeer *
 GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create);
 
+
 /**
  * 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.
@@ -136,6 +137,7 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id, int 
create);
 struct CadetPeer *
 GCP_get_short (const GNUNET_PEER_Id peer, int create);
 
+
 /**
  * Try to establish a new connection to this peer (in its tunnel).
  * If the peer doesn't have any path to it yet, try to get one.
@@ -440,7 +442,8 @@ GCP_iterate_paths (struct CadetPeer *peer,
  * @param cls Closure for @c iter.
  */
 void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls);
 
 
 /**
diff --git a/src/cadet/gnunet-service-cadet_tunnel.c 
b/src/cadet/gnunet-service-cadet_tunnel.c
index 6ddcf6598..2e17774d4 100644
--- a/src/cadet/gnunet-service-cadet_tunnel.c
+++ b/src/cadet/gnunet-service-cadet_tunnel.c
@@ -63,7 +63,7 @@ struct CadetTChannel
 
 
 /**
- * Connection list and metadata.
+ * Entry in list of connections used by tunnel, with metadata.
  */
 struct CadetTConnection
 {
@@ -243,6 +243,7 @@ struct CadetTunnelAxolotl
   struct GNUNET_TIME_Absolute ratchet_expiration;
 };
 
+
 /**
  * Struct containing all information regarding a tunnel to a peer.
  */
@@ -309,7 +310,7 @@ struct CadetTunnel
   /**
    * Channel ID for the next created channel.
    */
-  CADET_ChannelNumber next_chid;
+  struct GNUNET_CADET_ChannelNumber next_chid;
 
   /**
    * Destroy flag: if true, destroy on last message.
@@ -1401,7 +1402,11 @@ send_prebuilt_message (const struct GNUNET_MessageHeader 
*message,
       GNUNET_break (0);
       LOG (GNUNET_ERROR_TYPE_ERROR, "type %s not valid\n", GC_m2s (type));
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GC_m2s (type));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message of type %s with PID %u and CID %s\n",
+       GC_m2s (type),
+       htonl (ax_msg->pid),
+       GC_h2s (&ax_msg->cid));
 
   if (NULL == cont)
   {
@@ -1562,17 +1567,19 @@ destroy_iterator (void *cls,
  * @param gid ID of the channel.
  */
 static void
-send_channel_destroy (struct CadetTunnel *t, unsigned int gid)
+send_channel_destroy (struct CadetTunnel *t,
+                      struct GNUNET_CADET_ChannelNumber gid)
 {
   struct GNUNET_CADET_ChannelManage msg;
 
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
   msg.header.size = htons (sizeof (msg));
-  msg.chid = htonl (gid);
+  msg.chid = gid;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "WARNING destroying unknown channel %u on tunnel %s\n",
-       gid, GCT_2s (t));
+       ntohl (gid.cn),
+       GCT_2s (t));
   send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
 }
 
@@ -1613,13 +1620,17 @@ handle_data (struct CadetTunnel *t,
 
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL == ch)
   {
-    GNUNET_STATISTICS_update (stats, "# data on unknown channel",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "channel 0x%X unknown\n", ntohl (msg->chid));
-    send_channel_destroy (t, ntohl (msg->chid));
+    GNUNET_STATISTICS_update (stats,
+                              "# data on unknown channel",
+                              1,
+                              GNUNET_NO);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "channel 0x%X unknown\n",
+         ntohl (msg->chid.cn));
+    send_channel_destroy (t, msg->chid);
     return;
   }
 
@@ -1654,13 +1665,13 @@ handle_data_ack (struct CadetTunnel *t,
   }
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL == ch)
   {
     GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
                               1, GNUNET_NO);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
-         ntohl (msg->chid));
+         ntohl (msg->chid.cn));
     return;
   }
 
@@ -1690,7 +1701,7 @@ handle_ch_create (struct CadetTunnel *t,
   }
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL != ch && ! GCT_is_loopback (t))
   {
     /* Probably a retransmission, safe to ignore */
@@ -1725,13 +1736,14 @@ handle_ch_nack (struct CadetTunnel *t,
   }
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL == ch)
   {
     GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
                               1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
-         ntohl (msg->chid));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "WARNING channel %u unknown\n",
+         ntohl (msg->chid.cn));
     return;
   }
 
@@ -1766,13 +1778,16 @@ handle_ch_ack (struct CadetTunnel *t,
   }
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL == ch)
   {
-    GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
-         ntohl (msg->chid));
+    GNUNET_STATISTICS_update (stats,
+                              "# channel ack on unknown channel",
+                              1,
+                              GNUNET_NO);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "WARNING channel %u unknown\n",
+         ntohl (msg->chid.cn));
     return;
   }
 
@@ -1807,7 +1822,7 @@ handle_ch_destroy (struct CadetTunnel *t,
   }
 
   /* Check channel */
-  ch = GCT_get_channel (t, ntohl (msg->chid));
+  ch = GCT_get_channel (t, msg->chid);
   if (NULL == ch)
   {
     /* Probably a retransmission, safe to ignore */
@@ -2200,7 +2215,7 @@ GCT_new (struct CadetPeer *destination)
   struct CadetTunnel *t;
 
   t = GNUNET_new (struct CadetTunnel);
-  t->next_chid = 0;
+  t->next_chid.cn = 0;
   t->peer = destination;
 
   if (GNUNET_OK !=
@@ -2442,7 +2457,8 @@ GCT_remove_connection (struct CadetTunnel *t,
  * @param ch Channel.
  */
 void
-GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch)
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch)
 {
   struct CadetTChannel *aux;
 
@@ -2510,7 +2526,8 @@ GCT_remove_channel (struct CadetTunnel *t, struct 
CadetChannel *ch)
  * @return channel handler, NULL if doesn't exist
  */
 struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t, CADET_ChannelNumber chid)
+GCT_get_channel (struct CadetTunnel *t,
+                 struct GNUNET_CADET_ChannelNumber chid)
 {
   struct CadetTChannel *iter;
 
@@ -2519,7 +2536,7 @@ GCT_get_channel (struct CadetTunnel *t, 
CADET_ChannelNumber chid)
 
   for (iter = t->channel_head; NULL != iter; iter = iter->next)
   {
-    if (GCCH_get_id (iter->ch) == chid)
+    if (GCCH_get_id (iter->ch).cn == chid.cn)
       break;
   }
 
@@ -2966,11 +2983,11 @@ GCT_get_destination (struct CadetTunnel *t)
  *
  * @return GID of a channel free to use.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ChannelNumber
 GCT_get_next_chid (struct CadetTunnel *t)
 {
-  CADET_ChannelNumber chid;
-  CADET_ChannelNumber mask;
+  struct GNUNET_CADET_ChannelNumber chid;
+  struct GNUNET_CADET_ChannelNumber mask;
   int result;
 
   /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID.
@@ -2979,20 +2996,22 @@ GCT_get_next_chid (struct CadetTunnel *t)
    */
   result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer));
   if (0 > result)
-    mask = 0x40000000;
+    mask.cn = htonl (0x40000000);
   else
-    mask = 0x0;
-  t->next_chid |= mask;
+    mask.cn = 0x0;
+  t->next_chid.cn |= mask.cn;
 
   while (NULL != GCT_get_channel (t, t->next_chid))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid);
-    t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-    t->next_chid |= mask;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Channel %u exists...\n",
+         t->next_chid.cn);
+    t->next_chid.cn = htonl ((ntohl (t->next_chid.cn) + 1) & 
~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+    t->next_chid.cn |= mask.cn;
   }
   chid = t->next_chid;
-  t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-  t->next_chid |= mask;
+  t->next_chid.cn = (t->next_chid.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+  t->next_chid.cn |= mask.cn;
 
   return chid;
 }
@@ -3486,4 +3505,3 @@ GCT_iterate_channels (struct CadetTunnel *t, 
GCT_chan_iter iter, void *cls)
   for (cht = t->channel_head; NULL != cht; cht = cht->next)
     iter (cls, cht->ch);
 }
-
diff --git a/src/cadet/gnunet-service-cadet_tunnel.h 
b/src/cadet/gnunet-service-cadet_tunnel.h
index e3ca57e9c..2d9a2b528 100644
--- a/src/cadet/gnunet-service-cadet_tunnel.h
+++ b/src/cadet/gnunet-service-cadet_tunnel.h
@@ -291,7 +291,7 @@ GCT_remove_channel (struct CadetTunnel *t, struct 
CadetChannel *ch);
  * @return channel handler, NULL if doesn't exist
  */
 struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t, CADET_ChannelNumber chid);
+GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelNumber 
chid);
 
 
 /**
@@ -427,7 +427,7 @@ GCT_get_destination (struct CadetTunnel *t);
  *
  * @return ID of a channel free to use.
  */
-CADET_ChannelNumber
+struct GNUNET_CADET_ChannelNumber
 GCT_get_next_chid (struct CadetTunnel *t);
 
 
diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c
index c226563d5..d15785cb0 100644
--- a/src/cadet/test_cadet_local.c
+++ b/src/cadet/test_cadet_local.c
@@ -178,7 +178,8 @@ inbound_channel (void *cls,
  *                    with the channel is stored
  */
 static void
-channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
+channel_end (void *cls,
+             const struct GNUNET_CADET_Channel *channel,
              void *channel_ctx)
 {
   long id = (long) cls;
@@ -191,6 +192,8 @@ channel_end (void *cls, const struct GNUNET_CADET_Channel 
*channel,
     GNUNET_CADET_notify_transmit_ready_cancel (mth);
     mth = NULL;
   }
+  if (channel == ch)
+    ch = NULL;
   if (GNUNET_NO == got_data)
   {
     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
diff --git a/src/dht/gnunet-service-dht_hello.c 
b/src/dht/gnunet-service-dht_hello.c
index 3716ea3af..5a5c41567 100644
--- a/src/dht/gnunet-service-dht_hello.c
+++ b/src/dht/gnunet-service-dht_hello.c
@@ -69,13 +69,15 @@ GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer)
  * FIXME this is called once per address. Merge instead of replacing?
  */
 static void
-process_hello (void *cls, const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_HELLO_Message *hello, const char *err_msg)
+process_hello (void *cls,
+               const struct GNUNET_PeerIdentity *peer,
+               const struct GNUNET_HELLO_Message *hello,
+               const char *err_msg)
 {
   struct GNUNET_TIME_Absolute ex;
   struct GNUNET_HELLO_Message *hm;
 
-  if (hello == NULL)
+  if (NULL == hello)
     return;
   ex = GNUNET_HELLO_get_last_expiration (hello);
   if (0 == GNUNET_TIME_absolute_get_remaining (ex).rel_value_us)
@@ -100,8 +102,12 @@ process_hello (void *cls, const struct GNUNET_PeerIdentity 
*peer,
 void
 GDS_HELLO_init ()
 {
-  pnc = GNUNET_PEERINFO_notify (GDS_cfg, GNUNET_NO, &process_hello, NULL);
-  peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
+  pnc = GNUNET_PEERINFO_notify (GDS_cfg,
+                                GNUNET_NO,
+                                &process_hello,
+                                NULL);
+  peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256,
+                                                        GNUNET_NO);
 }
 
 
@@ -131,7 +137,9 @@ GDS_HELLO_done ()
   }
   if (NULL != peer_to_hello)
   {
-    GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello, &free_hello, NULL);
+    GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello,
+                                           &free_hello,
+                                           NULL);
     GNUNET_CONTAINER_multipeermap_destroy (peer_to_hello);
   }
 }
diff --git a/src/dht/gnunet-service-dht_routing.c 
b/src/dht/gnunet-service-dht_routing.c
index 38e5fc1c7..978c46d73 100644
--- a/src/dht/gnunet-service-dht_routing.c
+++ b/src/dht/gnunet-service-dht_routing.c
@@ -160,7 +160,9 @@ struct ProcessContext
  *         #GNUNET_SYSERR if the result is malformed or type unsupported
  */
 static int
-process (void *cls, const struct GNUNET_HashCode * key, void *value)
+process (void *cls,
+         const struct GNUNET_HashCode *key,
+         void *value)
 {
   struct ProcessContext *pc = cls;
   struct RecentRequest *rr = value;
@@ -170,7 +172,8 @@ process (void *cls, const struct GNUNET_HashCode * key, 
void *value)
   struct GNUNET_HashCode hc;
   const struct GNUNET_HashCode *eval_key;
 
-  if ((rr->type != GNUNET_BLOCK_TYPE_ANY) && (rr->type != pc->type))
+  if ( (rr->type != GNUNET_BLOCK_TYPE_ANY) &&
+       (rr->type != pc->type) )
     return GNUNET_OK;           /* type missmatch */
 
   if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE))
@@ -192,7 +195,8 @@ process (void *cls, const struct GNUNET_HashCode * key, 
void *value)
      * we fake it by changing the key to the actual PID ... */
     GNUNET_BLOCK_get_key (GDS_block_context,
                          GNUNET_BLOCK_TYPE_DHT_HELLO,
-                          pc->data, pc->data_size,
+                          pc->data,
+                          pc->data_size,
                          &hc);
     eval_key = &hc;
   }
@@ -200,8 +204,8 @@ process (void *cls, const struct GNUNET_HashCode * key, 
void *value)
   {
     eval_key = key;
   }
-  eval =
-      GNUNET_BLOCK_evaluate (GDS_block_context,
+  eval
+    = GNUNET_BLOCK_evaluate (GDS_block_context,
                              pc->type,
                              GNUNET_BLOCK_EO_NONE,
                              eval_key,
@@ -310,7 +314,10 @@ GDS_ROUTING_process (void *cls,
     pc.data_size = 0;
     pc.data = ""; /* something not null */
   }
-  GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, &process, &pc);
+  GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
+                                              key,
+                                              &process,
+                                              &pc);
 }
 
 
@@ -347,11 +354,13 @@ expire_oldest_entry ()
  * @param cls the new 'struct RecentRequest' (to discard upon successful 
combination)
  * @param key the query
  * @param value the existing 'struct RecentRequest' (to update upon successful 
combination)
- * @return GNUNET_OK (continue to iterate),
- *         GNUNET_SYSERR if the request was successfully combined
+ * @return #GNUNET_OK (continue to iterate),
+ *         #GNUNET_SYSERR if the request was successfully combined
  */
 static int
-try_combine_recent (void *cls, const struct GNUNET_HashCode * key, void *value)
+try_combine_recent (void *cls,
+                    const struct GNUNET_HashCode *key,
+                    void *value)
 {
   struct RecentRequest *in = cls;
   struct RecentRequest *rr = value;
@@ -398,7 +407,8 @@ void
 GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
                  enum GNUNET_BLOCK_Type type,
                  enum GNUNET_DHT_RouteOption options,
-                 const struct GNUNET_HashCode * key, const void *xquery,
+                 const struct GNUNET_HashCode *key,
+                 const void *xquery,
                  size_t xquery_size,
                  const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
                  uint32_t reply_bf_mutator)
@@ -421,8 +431,10 @@ GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
   recent_req->xquery_size = xquery_size;
   recent_req->reply_bf_mutator = reply_bf_mutator;
   if (GNUNET_SYSERR ==
-      GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key,
-                                                 &try_combine_recent, 
recent_req))
+      GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
+                                                  key,
+                                                 &try_combine_recent,
+                                                  recent_req))
   {
     GNUNET_STATISTICS_update (GDS_stats,
                               gettext_noop
diff --git a/src/include/gnunet_cadet_service.h 
b/src/include/gnunet_cadet_service.h
index c32311643..c6b683370 100644
--- a/src/include/gnunet_cadet_service.h
+++ b/src/include/gnunet_cadet_service.h
@@ -102,9 +102,9 @@ enum GNUNET_CADET_ChannelOption
 
   /**
    * Enable out of order delivery of messages.
-   * Yes/No.
+   * Set bit for out-of-order delivery.
    */
-  GNUNET_CADET_OPTION_OOORDER    = 0x4,
+  GNUNET_CADET_OPTION_OUT_OF_ORDER = 0x4,
 
   /**
    * Who is the peer at the other end of the channel.
@@ -332,7 +332,8 @@ union GNUNET_CADET_ChannelInfo
  */
 const union GNUNET_CADET_ChannelInfo *
 GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
-                              enum GNUNET_CADET_ChannelOption option, ...);
+                              enum GNUNET_CADET_ChannelOption option,
+                               ...);
 
 
 /**
@@ -491,6 +492,24 @@ typedef void
 
 
 /**
+ * Hash uniquely identifying a connection below a tunnel.
+ */
+struct GNUNET_CADET_ConnectionTunnelIdentifier
+{
+  struct GNUNET_CADET_Hash connection_of_tunnel;
+};
+
+
+/**
+ * Number identifying a CADET channel.
+ */
+struct GNUNET_CADET_ChannelNumber
+{
+  uint32_t cn GNUNET_PACKED;
+};
+
+
+/**
  * Method called to retrieve information about a specific tunnel the cadet peer
  * has established, o`r is trying to establish.
  *
@@ -508,8 +527,8 @@ typedef void
                           const struct GNUNET_PeerIdentity *peer,
                           unsigned int n_channels,
                           unsigned int n_connections,
-                          uint32_t *channels,
-                          struct GNUNET_CADET_Hash *connections,
+                          const struct GNUNET_CADET_ChannelNumber *channels,
+                          const struct GNUNET_CADET_ConnectionTunnelIdentifier 
*connections,
                           unsigned int estate,
                           unsigned int cstate);
 
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 6c56315a6..9e91a958c 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -2776,6 +2776,11 @@ extern "C"
  */
 #define GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP 1038
 
+/**
+ * End of local information about all peers known to the service.
+ */
+#define GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END 1039
+
 /********************************  Application  
*******************************/
 
 /**
diff --git a/src/nat/gnunet-service-nat_helper.c 
b/src/nat/gnunet-service-nat_helper.c
index b850c8a6b..e91f63beb 100644
--- a/src/nat/gnunet-service-nat_helper.c
+++ b/src/nat/gnunet-service-nat_helper.c
@@ -49,7 +49,7 @@ struct HelperContext
    * Closure for @e cb.
    */
   void *cb_cls;
-  
+
   /**
    * How long do we wait for restarting a crashed gnunet-helper-nat-server?
    */
@@ -126,7 +126,7 @@ nat_server_read (void *cls)
   memset (mybuf,
          0,
          sizeof (mybuf));
-  bytes 
+  bytes
     = GNUNET_DISK_file_read (h->server_stdout_handle,
                             mybuf,
                             sizeof (mybuf));
@@ -134,7 +134,7 @@ nat_server_read (void *cls)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Finished reading from server stdout with code: %d\n",
-               bytes);
+               (int) bytes);
     if (0 != GNUNET_OS_process_kill (h->server_proc,
                                     GNUNET_TERM_SIG))
       GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
@@ -185,7 +185,7 @@ nat_server_read (void *cls)
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("gnunet-helper-nat-server generated malformed address 
`%s'\n"),
                mybuf);
-    h->server_read_task 
+    h->server_read_task
       = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                         h->server_stdout_handle,
                                         &nat_server_read,
@@ -199,7 +199,7 @@ nat_server_read (void *cls)
              port);
   h->cb (h->cb_cls,
         &sin_addr);
-  h->server_read_task 
+  h->server_read_task
     = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                       h->server_stdout_handle,
                                      &nat_server_read,
@@ -219,9 +219,9 @@ restart_nat_server (void *cls)
   struct HelperContext *h = cls;
   char *binary;
   char ia[INET_ADDRSTRLEN];
-  
+
   h->server_read_task = NULL;
-  h->server_stdout 
+  h->server_stdout
     = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
                        GNUNET_NO, GNUNET_YES);
   if (NULL == h->server_stdout)
@@ -243,7 +243,7 @@ restart_nat_server (void *cls)
   /* Start the server process */
   binary
     = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
-  h->server_proc 
+  h->server_proc
     = GNUNET_OS_start_process (GNUNET_NO,
                               0,
                               NULL,
@@ -267,10 +267,10 @@ restart_nat_server (void *cls)
   /* Close the write end of the read pipe */
   GNUNET_DISK_pipe_close_end (h->server_stdout,
                              GNUNET_DISK_PIPE_END_WRITE);
-  h->server_stdout_handle 
+  h->server_stdout_handle
     = GNUNET_DISK_pipe_handle (h->server_stdout,
                               GNUNET_DISK_PIPE_END_READ);
-  h->server_read_task 
+  h->server_read_task
     = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                      h->server_stdout_handle,
                                      &nat_server_read,
@@ -316,7 +316,7 @@ GN_start_gnunet_nat_server_ (const struct in_addr 
*internal_address,
  */
 void
 GN_stop_gnunet_nat_server_ (struct HelperContext *h)
-{  
+{
   if (NULL != h->server_read_task)
   {
     GNUNET_SCHEDULER_cancel (h->server_read_task);
@@ -384,7 +384,7 @@ GN_request_connection_reversal (const struct in_addr 
*internal_address,
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
                         "inet_ntop");
     return GNUNET_SYSERR;
-  }  
+  }
   GNUNET_snprintf (port_as_string,
                    sizeof (port_as_string),
                    "%d",

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]