pass only CadetTunnelAxolotl if it suffices, preparation for having ambiguous KX...
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new.c
index 3e149e9bbc70c13ec8e7c4e710270a0533f91a92..d40d4f10e8deabc40911e2d72e1062ab869f3ab1 100644 (file)
@@ -66,19 +66,10 @@ struct CadetClient
   struct CadetClient *prev;
 
   /**
-   * Tunnels that belong to this client, indexed by local id
+   * Tunnels that belong to this client, indexed by local id,
+   * value is a `struct CadetChannel`.
    */
-  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;
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
 
   /**
    * Handle to communicate with the client
@@ -97,13 +88,13 @@ struct CadetClient
   struct GNUNET_CONTAINER_MultiHashMap *ports;
 
   /**
-   * Whether the client is active or shutting down (don't send confirmations
-   * to a client that is shutting down).
+   * Channel ID to use for the next incoming channel for this client.
+   * Wraps around (in theory).
    */
-  int shutting_down;
+  struct GNUNET_CADET_ClientChannelNumber next_ccn;
 
   /**
-   * ID of the client, mainly for debug messages
+   * ID of the client, mainly for debug messages. Purely internal to this file.
    */
   unsigned int id;
 };
@@ -114,6 +105,11 @@ struct CadetClient
 
 /****************************** Global variables ******************************/
 
+/**
+ * Handle to our configuration.
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
 /**
  * Handle to the statistics service.
  */
@@ -135,7 +131,7 @@ struct GNUNET_PeerIdentity my_full_id;
 struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
 
 /**
- * Signal that shutdown is happening: prevent recover measures.
+ * Signal that shutdown is happening: prevent recovery measures.
  */
 int shutting_down;
 
@@ -187,6 +183,15 @@ unsigned long long ratchet_messages;
  */
 struct GNUNET_TIME_Relative ratchet_time;
 
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+unsigned long long drop_percent;
 
 
 /**
@@ -215,8 +220,6 @@ GSC_2s (struct CadetClient *c)
 {
   static char buf[32];
 
-  if (NULL == c)
-    return "Client(NULL)";
   GNUNET_snprintf (buf,
                    sizeof (buf),
                    "Client(%u)",
@@ -225,6 +228,22 @@ GSC_2s (struct CadetClient *c)
 }
 
 
+/**
+ * Lookup channel of client @a c by @a ccn.
+ *
+ * @param c client to look in
+ * @param ccn channel ID to look up
+ * @return NULL if no such channel exists
+ */
+static struct CadetChannel *
+lookup_channel (struct CadetClient *c,
+                struct GNUNET_CADET_ClientChannelNumber ccn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (c->channels,
+                                              ntohl (ccn.channel_of_client));
+}
+
+
 /**
  * Obtain the next LID to use for incoming connections to
  * the given client.
@@ -232,14 +251,14 @@ GSC_2s (struct CadetClient *c)
  * @param c client handle
  */
 static struct GNUNET_CADET_ClientChannelNumber
-client_get_next_lid (struct CadetClient *c)
+client_get_next_ccn (struct CadetClient *c)
 {
-  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_chid;
+  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
 
   /* increment until we have a free one... */
   while (NULL !=
-         GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels,
-                                              ntohl (ccn.channel_of_client)))
+         lookup_channel (c,
+                         ccn))
   {
     ccn.channel_of_client
       = htonl (1 + (ntohl (ccn.channel_of_client)));
@@ -247,15 +266,16 @@ client_get_next_lid (struct CadetClient *c)
         GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
       ccn.channel_of_client = htonl (0);
   }
-  c->next_chid.channel_of_client
+  c->next_ccn.channel_of_client
     = htonl (1 + (ntohl (ccn.channel_of_client)));
   return ccn;
 }
 
 
 /**
- * Bind incoming channel to this client, and notify client
- * about incoming connection.
+ * Bind incoming channel to this client, and notify client about
+ * incoming connection.  Caller is responsible for notifying the other
+ * peer about our acceptance of the channel.
  *
  * @param c client to bind to
  * @param ch channel to be bound
@@ -272,45 +292,86 @@ GSC_bind (struct CadetClient *c,
           uint32_t options)
 {
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_ChannelOpenMessageMessage *msg;
-  struct GNUNET_CADET_ClientChannelNumber lid;
+  struct GNUNET_CADET_LocalChannelCreateMessage *cm;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
 
-  lid = client_get_next_lid (c);
+  ccn = client_get_next_ccn (c);
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
-                                                      ntohl (lid.channel_of_client),
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (ccn.channel_of_client),
                                                       ch,
                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
+       GCCH_2s (ch),
+       GCP_2s (dest),
+       GNUNET_h2s (port),
+       ntohl (options),
+       ntohl (ccn.channel_of_client));
   /* notify local client about incoming connection! */
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
-  msg->channel_id = lid;
-  msg->port = *port;
-  msg->opt = htonl (options);
-  msg->peer = *GCP_get_id (dest);
+  env = GNUNET_MQ_msg (cm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
+  cm->ccn = ccn;
+  cm->port = *port;
+  cm->opt = htonl (options);
+  cm->peer = *GCP_get_id (dest);
   GSC_send_to_client (c,
                       env);
-  return lid;
+  return ccn;
 }
 
 
-/******************************************************************************/
-/************************      MAIN FUNCTIONS      ****************************/
-/******************************************************************************/
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_tunnels_now (void *cls,
+                     const struct GNUNET_PeerIdentity *pid,
+                     void *value)
+{
+  struct CadetPeer *cp = value;
+  struct CadetTunnel *t = GCP_get_tunnel (cp,
+                                          GNUNET_NO);
+
+  if (NULL != t)
+    GCT_destroy_tunnel_now (t);
+  return GNUNET_OK;
+}
+
 
 /**
- * Task run during shutdown.
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
  *
- * @param cls unused
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_paths_now (void *cls,
+                   const struct GNUNET_PeerIdentity *pid,
+                   void *value)
+{
+  struct CadetPeer *cp = value;
+
+  GCP_drop_owned_paths (cp);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown everything once the clients have disconnected.
  */
 static void
-shutdown_task (void *cls)
+shutdown_rest ()
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "shutting down\n");
-  shutting_down = GNUNET_YES;
-  GCO_shutdown ();
   if (NULL != stats)
   {
     GNUNET_STATISTICS_destroy (stats,
@@ -327,7 +388,13 @@ shutdown_task (void *cls)
     GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
     loose_channels = NULL;
   }
-  /* All channels, connections and CORE must be down before this point. */
+  /* Destroy tunnels.  Note that all channels must be destroyed first! */
+  GCP_iterate_all (&destroy_tunnels_now,
+                   NULL);
+  /* All tunnels, channels, connections and CORE must be down before this point. */
+  GCP_iterate_all (&destroy_paths_now,
+                   NULL);
+  /* All paths, tunnels, channels, connections and CORE must be down before this point. */
   GCP_destroy_all_peers ();
   if (NULL != peers)
   {
@@ -351,6 +418,23 @@ shutdown_task (void *cls)
 }
 
 
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ */
+static void
+shutdown_task (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Shutting down\n");
+  shutting_down = GNUNET_YES;
+  GCO_shutdown ();
+  if (NULL == clients_head)
+    shutdown_rest ();
+}
+
+
 /**
  * We had a remote connection @a value to port @a port before
  * client @a cls opened port @a port.  Bind them now.
@@ -379,7 +463,10 @@ bind_loose_channel (void *cls,
 
 
 /**
- * Handler for port open requests.
+ * Handle port open request.  Creates a mapping from the
+ * port to the respective client and checks whether we have
+ * loose channels trying to bind to the port.  If so, those
+ * are bound.
  *
  * @param cls Identification of the client.
  * @param pmsg The actual message.
@@ -391,12 +478,12 @@ handle_port_open (void *cls,
   struct CadetClient *c = cls;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Open port %s requested by client %u\n",
+       "Open port %s requested by %s\n",
        GNUNET_h2s (&pmsg->port),
-       c->id);
+       GSC_2s (c));
   if (NULL == c->ports)
     c->ports = GNUNET_CONTAINER_multihashmap_create (4,
-                                                     GNUNET_NO);
+                                                      GNUNET_NO);
   if (GNUNET_OK !=
       GNUNET_CONTAINER_multihashmap_put (c->ports,
                                          &pmsg->port,
@@ -407,13 +494,10 @@ handle_port_open (void *cls,
     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);
+  (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
+                                            &pmsg->port,
+                                            c,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
   GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
                                               &pmsg->port,
                                               &bind_loose_channel,
@@ -423,7 +507,10 @@ handle_port_open (void *cls,
 
 
 /**
- * Handler for port close requests.
+ * Handler for port close requests.  Marks this port as closed
+ * (unless of course we have another client with the same port
+ * open).  Note that existing channels accepted on the port are
+ * not affected.
  *
  * @param cls Identification of the client.
  * @param pmsg The actual message.
@@ -435,9 +522,9 @@ handle_port_close (void *cls,
   struct CadetClient *c = cls;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Open port %s requested by client %u\n",
+       "Closing port %s as requested by %s\n",
        GNUNET_h2s (&pmsg->port),
-       c->id);
+       GSC_2s (c));
   if (GNUNET_YES !=
       GNUNET_CONTAINER_multihashmap_remove (c->ports,
                                             &pmsg->port,
@@ -451,36 +538,32 @@ handle_port_close (void *cls,
                  GNUNET_CONTAINER_multihashmap_remove (open_ports,
                                                        &pmsg->port,
                                                        c));
-
   GNUNET_SERVICE_client_continue (c->client);
 }
 
 
 /**
- * Handler for requests of new channels.
+ * Handler for requests for us creating a new channel to another peer and port.
  *
  * @param cls Identification of the client.
- * @param ccm The actual message.
+ * @param tcm The actual message.
  */
 static void
 handle_channel_create (void *cls,
-                       const struct GNUNET_CADET_ChannelOpenMessageMessage *ccm)
+                       const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
 {
   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)
+  if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
   {
     /* Channel ID not in allowed range. */
     GNUNET_break (0);
     GNUNET_SERVICE_client_drop (c->client);
     return;
   }
-  ch = GNUNET_CONTAINER_multihashmap32_get (c->own_channels,
-                                            ntohl (chid.channel_of_client));
+  ch = lookup_channel (c,
+                       tcm->ccn);
   if (NULL != ch)
   {
     /* Channel ID already in use. Not allowed. */
@@ -488,16 +571,19 @@ handle_channel_create (void *cls,
     GNUNET_SERVICE_client_drop (c->client);
     return;
   }
-
-  dst = GCP_get (&ccm->peer,
-                 GNUNET_YES);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "New channel to %s at port %s requested by %s\n",
+       GNUNET_i2s (&tcm->peer),
+       GNUNET_h2s (&tcm->port),
+       GSC_2s (c));
 
   /* Create channel */
   ch = GCCH_channel_local_new (c,
-                               chid,
-                               dst,
-                               &ccm->port,
-                               ntohl (ccm->opt));
+                               tcm->ccn,
+                               GCP_get (&tcm->peer,
+                                        GNUNET_YES),
+                               &tcm->port,
+                               ntohl (tcm->opt));
   if (NULL == ch)
   {
     GNUNET_break (0);
@@ -505,59 +591,30 @@ handle_channel_create (void *cls,
     return;
   }
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->own_channels,
-                                                      ntohl (chid.channel_of_client),
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (tcm->ccn.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
+ * Handler for requests of destroying an existing channel.
  *
  * @param cls client identification of the client
  * @param msg the actual message
  */
 static void
 handle_channel_destroy (void *cls,
-                        const struct GNUNET_CADET_ChannelDestroyMessage *msg)
+                        const struct GNUNET_CADET_LocalChannelDestroyMessage *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));
+  ch = lookup_channel (c,
+                       msg->ccn);
   if (NULL == ch)
   {
     /* Client attempted to destroy unknown channel */
@@ -566,46 +623,70 @@ handle_channel_destroy (void *cls,
     return;
   }
   LOG (GNUNET_ERROR_TYPE_INFO,
-       "Client %u is destroying channel %s\n",
-       c->id,
+       "%s is destroying %s\n",
+       GSC_2s(c),
        GCCH_2s (ch));
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (map,
-                                                         ntohl (chid.channel_of_client),
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (msg->ccn.channel_of_client),
                                                          ch));
-  GCCH_channel_local_destroy (ch);
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              msg->ccn);
   GNUNET_SERVICE_client_continue (c->client);
 }
 
 
 /**
- * Check for client traffic data message is well-formed
+ * 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)
+check_local_data (void *cls,
+                  const struct GNUNET_CADET_LocalData *msg)
 {
-  const struct GNUNET_MessageHeader *payload;
   size_t payload_size;
   size_t payload_claimed_size;
-
+  const char *buf;
+  struct GNUNET_MessageHeader pa;
+
+  /* FIXME: what is the format we shall allow for @a msg?
+     ONE payload item or multiple? Seems current cadet_api
+     at least in theory allows more than one. Next-gen
+     cadet_api will likely no more, so we could then
+     simplify this mess again. */
   /* Sanity check for message size */
   payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  if ( (payload_size < sizeof (struct GNUNET_MessageHeader)) ||
-       (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_size) )
+  buf = (const char *) &msg[1];
+  while (payload_size >= sizeof (struct GNUNET_MessageHeader))
   {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
+    /* need to memcpy() for alignment */
+    GNUNET_memcpy (&pa,
+                   buf,
+                   sizeof (pa));
+    payload_claimed_size = ntohs (pa.size);
+    if ( (payload_size < payload_claimed_size) ||
+         (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
+         (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
+    {
+      GNUNET_break (0);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Local data of %u total size had sub-message %u at %u with %u bytes\n",
+           ntohs (msg->header.size),
+           ntohs (pa.type),
+           (unsigned int) (buf - (const char *) &msg[1]),
+           (unsigned int) payload_claimed_size);
+      return GNUNET_SYSERR;
+    }
+    payload_size -= payload_claimed_size;
+    buf += payload_claimed_size;
   }
-  payload = (struct GNUNET_MessageHeader *) &msg[1];
-  payload_claimed_size = ntohs (payload->size);
-  if (payload_size != payload_claimed_size)
+  if (0 != payload_size)
   {
-    GNUNET_break (0);
+    GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -613,26 +694,23 @@ check_data (void *cls,
 
 
 /**
- * Handler for client traffic
+ * Handler for client payload traffic to be send on a channel to
+ * another peer.
  *
  * @param cls identification of the client
  * @param msg the actual message
  */
 static void
-handle_data (void *cls,
-             const struct GNUNET_CADET_LocalData *msg)
+handle_local_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;
+  size_t payload_size;
+  const char *buf;
 
-  chid = msg->id;
-  map = get_map_by_chid (c,
-                         chid);
-  ch = GNUNET_CONTAINER_multihashmap32_get (map,
-                                            ntohl (chid.channel_of_client));
+  ch = lookup_channel (c,
+                       msg->ccn);
   if (NULL == ch)
   {
     /* Channel does not exist! */
@@ -640,16 +718,18 @@ handle_data (void *cls,
     GNUNET_SERVICE_client_drop (c->client);
     return;
   }
-
-  payload = (const struct GNUNET_MessageHeader *) &msg[1];
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  buf = (const char *) &msg[1];
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received %u bytes payload from client %u for channel %s\n",
-       ntohs (payload->size),
-       c->id,
+       "Received %u bytes payload from %s for %s\n",
+       (unsigned int) payload_size,
+       GSC_2s (c),
        GCCH_2s (ch));
   if (GNUNET_OK !=
       GCCH_handle_local_data (ch,
-                              payload))
+                              msg->ccn,
+                              buf,
+                              payload_size))
   {
     GNUNET_SERVICE_client_drop (c->client);
     return;
@@ -665,19 +745,14 @@ handle_data (void *cls,
  * @param msg The actual message.
  */
 static void
-handle_ack (void *cls,
-            const struct GNUNET_CADET_LocalAck *msg)
+handle_local_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));
+  ch = lookup_channel (c,
+                       msg->ccn);
   if (NULL == ch)
   {
     /* Channel does not exist! */
@@ -686,10 +761,11 @@ handle_ack (void *cls,
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got a local ACK from client %u for channel %s\n",
-       c->id,
+       "Got a local ACK from %s for %s\n",
+       GSC_2s(c),
        GCCH_2s (ch));
-  GCCH_handle_local_ack (ch);
+  GCCH_handle_local_ack (ch,
+                         msg->ccn);
   GNUNET_SERVICE_client_continue (c->client);
 }
 
@@ -855,7 +931,7 @@ get_all_tunnels_iterator (void *cls,
   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->cstate = htons (0);
   msg->estate = htons ((uint16_t) GCT_get_estate (t));
   GNUNET_MQ_send (c->mq,
                   env);
@@ -864,14 +940,14 @@ get_all_tunnels_iterator (void *cls,
 
 
 /**
- * Handler for client's INFO TUNNELS request.
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
  *
  * @param cls client Identification of the client.
  * @param message The actual message.
  */
 static void
-handle_get_tunnels (void *cls,
-                    const struct GNUNET_MessageHeader *message)
+handle_info_tunnels (void *cls,
+                     const struct GNUNET_MessageHeader *message)
 {
   struct CadetClient *c = cls;
   struct GNUNET_MQ_Envelope *env;
@@ -888,7 +964,10 @@ handle_get_tunnels (void *cls,
 
 
 /**
- * FIXME.
+ * Update the message with information about the connection.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param c a connection about which we should store information in @a cls
  */
 static void
 iter_connection (void *cls,
@@ -903,7 +982,10 @@ iter_connection (void *cls,
 
 
 /**
- * FIXME.
+ * Update the message with information about the channel.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ch a channel about which we should store information in @a cls
  */
 static void
 iter_channel (void *cls,
@@ -911,21 +993,21 @@ iter_channel (void *cls,
 {
   struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
   struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  struct GCT_ChannelTunnelNumber *chn
-    = (struct GCT_ChannelTunnelNumber *) &h[msg->connections];
+  struct GNUNET_CADET_ChannelTunnelNumber *chn
+    = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
 
   chn[msg->channels++] = GCCH_get_id (ch);
 }
 
 
 /**
- * Handler for client's SHOW_TUNNEL request.
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
  *
  * @param cls Identification of the client.
  * @param msg The actual message.
  */
 static void
-handle_show_tunnel (void *cls,
+handle_info_tunnel (void *cls,
                     const struct GNUNET_CADET_LocalInfo *msg)
 {
   struct CadetClient *c = cls;
@@ -963,7 +1045,7 @@ handle_show_tunnel (void *cls,
   c_n = GCT_count_any_connections (t);
   env = GNUNET_MQ_msg_extra (resp,
                              c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
-                             ch_n * sizeof (struct GCT_ChannelTunnelNumber),
+                             ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
   resp->destination = msg->peer;
   /* Do not reorder! #iter_channel needs counters in HBO! */
@@ -975,7 +1057,7 @@ handle_show_tunnel (void *cls,
                         resp);
   resp->connections = htonl (resp->connections);
   resp->channels = htonl (resp->channels);
-  resp->cstate = htons (GCT_get_cstate (t));
+  resp->cstate = htons (0);
   resp->estate = htons (GCT_get_estate (t));
   GNUNET_MQ_send (c->mq,
                   env);
@@ -1028,18 +1110,19 @@ handle_info_dump (void *cls,
 
   LOG (GNUNET_ERROR_TYPE_ERROR,
        "*************************** DUMP START ***************************\n");
-  for (struct CadetClient *ci = clients_head; NULL != ci; ci = ci->next)
+  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",
+         "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
          ci->id,
          ci,
          ci->client,
          (NULL != c->ports)
          ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
          : 0,
-         GNUNET_CONTAINER_multihashmap32_size (ci->own_channels),
-         GNUNET_CONTAINER_multihashmap32_size (ci->incoming_channels));
+         GNUNET_CONTAINER_multihashmap32_size (ci->channels));
   }
   LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
   GCP_iterate_all (&show_peer_iterator,
@@ -1072,9 +1155,7 @@ client_connect_cb (void *cls,
   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
+  c->channels
     = GNUNET_CONTAINER_multihashmap32_create (32);
   GNUNET_CONTAINER_DLL_insert (clients_head,
                                clients_tail,
@@ -1083,36 +1164,37 @@ client_connect_cb (void *cls,
                             "# clients",
                             +1,
                             GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s connected\n",
+       GSC_2s (c));
   return c;
 }
 
 
 /**
- * Iterator for deleting each channel whose client endpoint disconnected.
+ * A channel was destroyed by the other peer. Tell our client.
  *
- * @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.
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
  */
-static int
-own_channel_destroy_iterator (void *cls,
-                              uint32_t key,
-                              void *value)
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+                                   struct GNUNET_CADET_ClientChannelNumber ccn,
+                                   struct CadetChannel *ch)
 {
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch = value;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
 
+  env = GNUNET_MQ_msg (tdm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
+  tdm->ccn = ccn;
+  GSC_send_to_client (c,
+                      env);
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
-                                                         key,
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (ccn.channel_of_client),
                                                          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;
 }
 
 
@@ -1120,28 +1202,31 @@ own_channel_destroy_iterator (void *cls,
  * 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 key The local channel id in host byte order
  * @param value The value stored at the key (channel to destroy).
  * @return #GNUNET_OK, keep iterating.
  */
 static int
-incoming_channel_destroy_iterator (void *cls,
-                                   uint32_t key,
-                                   void *value)
+channel_destroy_iterator (void *cls,
+                          uint32_t key,
+                          void *value)
 {
-  struct CadetChannel *ch = value;
   struct CadetClient *c = cls;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+  struct CadetChannel *ch = value;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying %s, due to %s disconnecting.\n",
+       GCCH_2s (ch),
+       GSC_2s (c));
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
+                 GNUNET_CONTAINER_multihashmap32_remove (c->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);
+  ccn.channel_of_client = htonl (key);
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              ccn);
   return GNUNET_OK;
 }
 
@@ -1150,7 +1235,7 @@ incoming_channel_destroy_iterator (void *cls,
  * Remove client's ports from the global hashmap on disconnect.
  *
  * @param cls Closure (unused).
- * @param key Port.
+ * @param key the port.
  * @param value the `struct CadetClient` to remove
  * @return #GNUNET_OK, keep iterating.
  */
@@ -1161,6 +1246,10 @@ client_release_ports (void *cls,
 {
   struct CadetClient *c = value;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing port %s due to %s disconnect.\n",
+       GNUNET_h2s (key),
+       GSC_2s (c));
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (open_ports,
                                                        key,
@@ -1188,20 +1277,15 @@ client_disconnect_cb (void *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)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s is disconnecting.\n",
+       GSC_2s (c));
+  if (NULL != c->channels)
   {
-    GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
-                                             &incoming_channel_destroy_iterator,
+    GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
+                                             &channel_destroy_iterator,
                                              c);
-    GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
+    GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
   }
   if (NULL != c->ports)
   {
@@ -1218,6 +1302,9 @@ client_disconnect_cb (void *cls,
                             -1,
                             GNUNET_NO);
   GNUNET_free (c);
+  if ( (NULL == clients_head) &&
+       (GNUNET_YES == shutting_down) )
+    shutdown_rest ();
 }
 
 
@@ -1233,6 +1320,7 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *c,
      struct GNUNET_SERVICE_Handle *service)
 {
+  cfg = c;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (c,
                                              "CADET",
@@ -1257,7 +1345,34 @@ run (void *cls,
                                "need delay value");
     ratchet_time = GNUNET_TIME_UNIT_HOURS;
   }
-
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "REFRESH_CONNECTION_TIME",
+                                           &keepalive_period))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "REFRESH_CONNECTION_TIME",
+                               "need delay value");
+    keepalive_period = GNUNET_TIME_UNIT_MINUTES;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "DROP_PERCENT",
+                                             &drop_percent))
+  {
+    drop_percent = 0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+  }
   my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
   if (NULL == my_private_key)
   {
@@ -1285,7 +1400,7 @@ run (void *cls,
   GCD_init (c);
   GCO_init (c);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "CADET starting at peer %s\n",
+              "CADET started for peer %s\n",
               GNUNET_i2s (&my_full_id));
 
 }
@@ -1310,18 +1425,18 @@ GNUNET_SERVICE_MAIN
                           struct GNUNET_CADET_PortMessage,
                           NULL),
  GNUNET_MQ_hd_fixed_size (channel_create,
-                          GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
-                          struct GNUNET_CADET_ChannelOpenMessageMessage,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
+                          struct GNUNET_CADET_LocalChannelCreateMessage,
                           NULL),
  GNUNET_MQ_hd_fixed_size (channel_destroy,
-                          GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
-                          struct GNUNET_CADET_ChannelDestroyMessage,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
+                          struct GNUNET_CADET_LocalChannelDestroyMessage,
                           NULL),
- GNUNET_MQ_hd_var_size (data,
+ GNUNET_MQ_hd_var_size (local_data,
                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
                         struct GNUNET_CADET_LocalData,
                         NULL),
- GNUNET_MQ_hd_fixed_size (ack,
+ GNUNET_MQ_hd_fixed_size (local_ack,
                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
                           struct GNUNET_CADET_LocalAck,
                           NULL),
@@ -1333,11 +1448,11 @@ GNUNET_SERVICE_MAIN
                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
                           struct GNUNET_CADET_LocalInfo,
                           NULL),
- GNUNET_MQ_hd_fixed_size (get_tunnels,
+ GNUNET_MQ_hd_fixed_size (info_tunnels,
                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
                           struct GNUNET_MessageHeader,
                           NULL),
- GNUNET_MQ_hd_fixed_size (show_tunnel,
+ GNUNET_MQ_hd_fixed_size (info_tunnel,
                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
                           struct GNUNET_CADET_LocalInfo,
                           NULL),