gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [gnunet] 04/04: starting re-implementation of CADET service


From: gnunet
Subject: [GNUnet-SVN] [gnunet] 04/04: starting re-implementation of CADET service
Date: Sun, 15 Jan 2017 21:50:19 +0100

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

grothoff pushed a commit to branch master
in repository gnunet.

commit 9a8457f1bbce39b73ab7c03bc9706b10f80fbf0c
Author: Christian Grothoff <address@hidden>
AuthorDate: Sun Jan 15 21:49:27 2017 +0100

    starting re-implementation of CADET service
---
 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 +++
 src/cadet/gnunet-service-cadet-new_connection.c |   56 +
 src/cadet/gnunet-service-cadet-new_connection.h |   58 +
 src/cadet/gnunet-service-cadet-new_dht.c        |  337 ++++++
 src/cadet/gnunet-service-cadet-new_dht.h        |  108 ++
 src/cadet/gnunet-service-cadet-new_hello.c      |  142 +++
 src/cadet/gnunet-service-cadet-new_hello.h      |   80 ++
 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 ++++++
 16 files changed, 5554 insertions(+)

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/cadet/gnunet-service-cadet-new_connection.c 
b/src/cadet/gnunet-service-cadet-new_connection.c
new file mode 100644
index 000000000..b24e4bd49
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_connection.c
@@ -0,0 +1,56 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_connection.c
+ * @brief
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet-new_connection.h"
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
+{
+  GNUNET_assert (0); // FIXME
+  return NULL;
+}
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level)
+{
+}
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h 
b/src/cadet/gnunet-service-cadet-new_connection.h
new file mode 100644
index 000000000..7745e4fec
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_connection.h
@@ -0,0 +1,58 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_connection.h
+ * @brief
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
+#define GNUNET_SERVICE_CADET_CONNECTION_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_peer.h"
+
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level);
+
+
+#endif
diff --git a/src/cadet/gnunet-service-cadet-new_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-new_dht.h 
b/src/cadet/gnunet-service-cadet-new_dht.h
new file mode 100644
index 000000000..70f834de5
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_dht.h
@@ -0,0 +1,108 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2013, 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_dht.h
+ * @brief cadet service; dealing with DHT requests and results
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
+ */
+#ifndef GNUNET_SERVICE_CADET_DHT_H
+#define GNUNET_SERVICE_CADET_DHT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Handle for DHT search operation.
+ */
+struct GCD_search_handle;
+
+
+/**
+ * Callback called on each path found over the DHT.
+ *
+ * @param cls Closure.
+ * @param path An unchecked, unoptimized path to the target node.
+ *             After callback will no longer be valid!
+ */
+typedef void
+(*GCD_search_callback) (void *cls,
+                        const struct CadetPeerPath *path);
+
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GCD_shutdown (void);
+
+
+/**
+ * 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);
+
+
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
+void
+GCD_search_stop (struct GCD_search_handle *h);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
+#endif
+/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c 
b/src/cadet/gnunet-service-cadet-new_hello.c
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-new_hello.h 
b/src/cadet/gnunet-service-cadet-new_hello.h
new file mode 100644
index 000000000..4291ae985
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_hello.h
@@ -0,0 +1,80 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2014, 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_hello.h
+ * @brief cadet service; dealing with hello messages
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_HELLO_H
+#define GNUNET_SERVICE_CADET_HELLO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GCH_shutdown (void);
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GCH_get_mine (void);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
+#endif
+/* end of gnunet-cadet-service_hello.h */
diff --git a/src/cadet/gnunet-service-cadet-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

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



reply via email to

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