- doxygen
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_channel.c
index 971b8279f8f585f1a402628b04aeffa57543dab4..d33425489ca591080d318d8d157bc06d39c7f837 100644 (file)
 
 
 #include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+
 #include "mesh_enc.h"
 #include "mesh_protocol_enc.h"
+
 #include "gnunet-service-mesh_channel.h"
 #include "gnunet-service-mesh_local.h"
+#include "gnunet-service-mesh_tunnel.h"
+#include "gnunet-service-mesh_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"mesh-chn",__VA_ARGS__)
 
+#define MESH_RETRANSMIT_TIME    GNUNET_TIME_UNIT_SECONDS
+#define MESH_RETRANSMIT_MARGIN  4
 
 
 /**
@@ -43,7 +54,7 @@ enum MeshChannelState
   MESH_CHANNEL_SENT,
 
   /**
-   * Connection confirmed, ready to carry traffic..
+   * Connection confirmed, ready to carry traffic.
    */
   MESH_CHANNEL_READY,
 };
@@ -132,6 +143,11 @@ struct MeshChannelReliability
      */
   int                               client_ready;
 
+  /**
+   * Can the client send data to us?
+   */
+  int                               client_allowed;
+
     /**
      * Task to resend/poll in case no ACK is received.
      */
@@ -157,13 +173,7 @@ struct MeshChannel
     /**
      * Tunnel this channel is in.
      */
-  struct MeshTunnel2 *t;
-
-    /**
-     * Double linked list.
-     */
-  struct MeshChannel    *next;
-  struct MeshChannel    *prev;
+  struct MeshTunnel3 *t;
 
     /**
      * Destination port of the channel.
@@ -244,6 +254,35 @@ struct MeshChannel
 };
 
 
+/******************************************************************************/
+/*******************************   GLOBALS  ***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+
+/******************************************************************************/
+/********************************   STATIC  ***********************************/
+/******************************************************************************/
+
+/**
+ * Destroy a reliable message after it has been acknowledged, either by
+ * direct mid ACK or bitfield. Updates the appropriate data structures and
+ * timers and frees all memory.
+ *
+ * @param copy Message that is no longer needed: remote peer got it.
+ */
+static void
+rel_message_free (struct MeshReliableMessage *copy);
+
 /**
  * We have received a message out of order, or the client is not ready.
  * Buffer it until we receive an ACK from the client or the missing
@@ -264,7 +303,7 @@ add_buffered_data (const struct GNUNET_MESH_Data *msg,
   size = ntohs (msg->header.size);
   mid = ntohl (msg->mid);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid);
 
   copy = GNUNET_malloc (sizeof (*copy) + size);
   copy->mid = mid;
@@ -277,24 +316,54 @@ add_buffered_data (const struct GNUNET_MESH_Data *msg,
   // FIXME start from the end (most messages are the latest ones)
   for (prev = rel->head_recv; NULL != prev; prev = prev->next)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
     if (GMC_is_pid_bigger (prev->mid, mid))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
       GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv,
                                           prev, copy);
       return;
     }
   }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n");
     GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
+}
+
+/**
+ * Add a destination client to a channel, initializing all data structures
+ * in the channel and the client.
+ *
+ * @param ch Channel to which add the destination.
+ * @param c Client which to add to the channel.
+ */
+static void
+add_destination (struct MeshChannel *ch, struct MeshClient *c)
+{
+  if (NULL != ch->dest)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  /* Assign local id as destination */
+  ch->lid_dest = GML_get_next_chid (c);
+
+  /* Store in client's hashmap */
+  GML_channel_add (c, ch->lid_dest, ch);
+
+  GNUNET_break (NULL == ch->dest_rel);
+  ch->dest_rel = GNUNET_new (struct MeshChannelReliability);
+  ch->dest_rel->ch = ch;
+  ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME;
+
+  ch->dest = c;
 }
 
 
 /**
  * Send data to a client.
- * 
+ *
  * If the client is ready, send directly, otherwise buffer while listening
  * for a local ACK.
  *
@@ -310,14 +379,14 @@ send_client_data (struct MeshChannel *ch,
   if (fwd)
   {
     if (ch->dest_rel->client_ready)
-      GML_send_data (ch, msg, ch->dest, ch->lid_dest);
+      GML_send_data (ch->dest, msg, ch->lid_dest);
     else
       add_buffered_data (msg, ch->dest_rel);
   }
   else
   {
     if (ch->root_rel->client_ready)
-      GML_send_data (ch, msg, ch->root, ch->lid_root);
+      GML_send_data (ch->root, msg, ch->lid_root);
     else
       add_buffered_data (msg, ch->root_rel);
   }
@@ -325,163 +394,93 @@ send_client_data (struct MeshChannel *ch,
 
 
 /**
- * Search for a channel among the channels for a client
- *
- * @param c the client whose channels to search in
- * @param chid the local id of the channel
+ * Send a buffered message to the client, for in order delivery or
+ * as result of client ACK.
  *
- * @return channel handler, NULL if doesn't exist
+ * @param ch Channel on which to empty the message buffer.
+ * @param c Client to send to.
+ * @param fwd Is this to send FWD data?.
  */
-static struct MeshChannel *
-channel_get_by_local_id (struct MeshClient *c, MESH_ChannelNumber chid)
+static void
+send_client_buffered_data (struct MeshChannel *ch,
+                           struct MeshClient *c,
+                           int fwd)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   -- get CHID %X\n", chid);
-  if (0 == (chid & GNUNET_MESH_LOCAL_CHANNEL_ID_CLI))
+  struct MeshReliableMessage *copy;
+  struct MeshChannelReliability *rel;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
+  rel = fwd ? ch->dest_rel : ch->root_rel;
+  if (GNUNET_NO == rel->client_ready)
   {
-    GNUNET_break_op (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
-    return NULL;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
+    return;
   }
-  if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
-    return GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels, chid);
-  return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid);
-}
-
-
-
-/**
- * Search for a channel by global ID using full PeerIdentities.
- *
- * @param t Tunnel containing the channel.
- * @param chid Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-static struct MeshChannel *
-channel_get (struct MeshTunnel2 *t, MESH_ChannelNumber chid)
-{
-  struct MeshChannel *ch;
 
-  if (NULL == t)
-    return NULL;
-
-  for (ch = t->channel_head; NULL != ch; ch = ch->next)
+  copy = rel->head_recv;
+  /* We never buffer channel management messages */
+  if (NULL != copy)
   {
-    if (ch->gid == chid)
-      break;
-  }
+    if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
+    {
+      struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) &copy[1];
 
-  return ch;
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+                  " have %u! now expecting %u\n",
+                  copy->mid, rel->mid_recv + 1);
+      send_client_data (ch, msg, fwd);
+      rel->n_recv--;
+      rel->mid_recv++;
+      GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
+      GNUNET_free (copy);
+    }
+    else
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+                  " reliable && don't have %u, next is %u\n",
+                  rel->mid_recv,
+                  copy->mid);
+      return;
+    }
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
 }
 
 
 /**
- * Add a client to a channel, initializing all needed data structures.
- * 
- * @param ch Channel to which add the client.
- * @param c Client which to add to the channel.
+ * Allow a client to send more data.
+ *
+ * In case the client was already allowed to send data, do nothing.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
  */
 static void
-channel_add_client (struct MeshChannel *ch, struct MeshClient *c)
+send_client_ack (struct MeshChannel *ch, int fwd)
 {
-  struct MeshTunnel2 *t = ch->t;
+  struct MeshChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
 
-  if (NULL != ch->dest)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "  sending %s ack to client on channel %s\n",
+       fwd ? "FWD" : "BCK", GMCH_2s (ch));
+
+  if (NULL == rel)
   {
     GNUNET_break (0);
     return;
   }
 
-  /* Assign local id as destination */
-  while (NULL != channel_get_by_local_id (c, t->next_local_chid))
-    t->next_local_chid = (t->next_local_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
-  ch->lid_dest = t->next_local_chid++;
-  t->next_local_chid = t->next_local_chid | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
-
-  /* Store in client's hashmap */
-  if (GNUNET_OK !=
-      GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
-                                           ch->lid_dest, ch,
-                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+  if (GNUNET_YES == rel->client_allowed)
   {
-    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  already allowed\n");
     return;
   }
+  rel->client_allowed = GNUNET_YES;
 
-  GNUNET_break (NULL == ch->dest_rel);
-  ch->dest_rel = GNUNET_new (struct MeshChannelReliability);
-  ch->dest_rel->ch = ch;
-  ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME;
-
-  ch->dest = c;
-}
-
-
-
-/**
- * Is the root client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return GNUNET_YES in case it is.
- */
-static int
-channel_is_origin (struct MeshChannel *ch, int fwd)
-{
-  struct MeshClient *c;
-
-  c = fwd ? ch->root : ch->dest;
-  return NULL != c;
-}
-
-
-/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return GNUNET_YES in case it is.
- */
-static int
-channel_is_terminal (struct MeshChannel *ch, int fwd)
-{
-  struct MeshClient *c;
-
-  c = fwd ? ch->dest : ch->root;
-  return NULL != c;
-}
-
-
-/**
- * Get free buffer space towards the client on a specific channel.
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - 64]
- */
-static unsigned int
-channel_get_buffer (struct MeshChannel *ch, int fwd)
-{
-  struct MeshChannelReliability *rel;
-  
-  rel = fwd ? ch->dest_rel : ch->root_rel;
-
-  /* If rel is NULL it means that the end is not yet created,
-   * most probably is a loopback channel at the point of sending
-   * the ChannelCreate to itself.
-   */
-  if (NULL == rel)
-    return 64;
-
-  return (64 - rel->n_recv);
+  GML_send_ack (fwd ? ch->root : ch->dest, fwd ? ch->lid_root : ch->lid_dest);
 }
 
 
-
-
 /**
  * Destroy all reliable messages queued for a channel,
  * during a channel destruction.
@@ -536,45 +535,45 @@ channel_rel_free_sent (struct MeshChannelReliability *rel,
 
   bitfield = msg->futures;
   mid = ntohl (msg->mid);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
               "free_sent_reliable %u %llX\n",
               mid, bitfield);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
               " rel %p, head %p\n",
               rel, rel->head_sent);
   for (i = 0, copy = rel->head_sent;
        i < 64 && NULL != copy && 0 != bitfield;
        i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
                 " trying bit %u (mid %u)\n",
                 i, mid + i + 1);
     mask = 0x1LL << i;
     if (0 == (bitfield & mask))
      continue;
 
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " set!\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n");
     /* Bit was set, clear the bit from the bitfield */
     bitfield &= ~mask;
 
     /* The i-th bit was set. Do we have that copy? */
     /* Skip copies with mid < target */
     target = mid + i + 1;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
     while (NULL != copy && GMC_is_pid_bigger (target, copy->mid))
      copy = copy->next;
 
     /* Did we run out of copies? (previously freed, it's ok) */
     if (NULL == copy)
     {
-     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
+     LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
      return;
     }
 
     /* Did we overshoot the target? (previously freed, it's ok) */
     if (GMC_is_pid_bigger (copy->mid, target))
     {
-     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
+     LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
      continue;
     }
 
@@ -583,7 +582,7 @@ channel_rel_free_sent (struct MeshChannelReliability *rel,
     rel_message_free (copy);
     copy = next;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
 }
 
 
@@ -599,11 +598,8 @@ channel_retransmit_message (void *cls,
 {
   struct MeshChannelReliability *rel = cls;
   struct MeshReliableMessage *copy;
-  struct MeshPeerQueue *q;
   struct MeshChannel *ch;
-  struct MeshConnection *c;
   struct GNUNET_MESH_Data *payload;
-  struct MeshPeer *hop;
   int fwd;
 
   rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
@@ -628,33 +624,34 @@ channel_retransmit_message (void *cls,
    * - not sending the new one could cause terrible delays the old connection
    *   is stalled.
    */
+//   FIXME access to queue elements is limited
   payload = (struct GNUNET_MESH_Data *) &copy[1];
   fwd = (rel == ch->root_rel);
-  c = tunnel_get_connection (ch->t, fwd);
-  hop = connection_get_hop (c, fwd);
-  for (q = hop->queue_head; NULL != q; q = q->next)
-  {
-    if (ntohs (payload->header.type) == q->type && ch == q->ch)
-    {
-      struct GNUNET_MESH_Data *queued_data = q->cls;
-
-      if (queued_data->mid == payload->mid)
-        break;
-    }
-  }
+//   c = GMT_get_connection (ch->t, fwd);
+//   hop = connection_get_hop (c, fwd);
+//   for (q = hop->queue_head; NULL != q; q = q->next)
+//   {
+//     if (ntohs (payload->header.type) == q->type && ch == q->ch)
+//     {
+//       struct GNUNET_MESH_Data *queued_data = q->cls;
+// 
+//       if (queued_data->mid == payload->mid)
+//         break;
+//     }
+//   }
 
   /* Message not found in the queue that we are going to use. */
-  if (NULL == q)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid);
+//   if (NULL == q)
+//   {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid);
 
-    send_prebuilt_message_channel (&payload->header, ch, fwd);
+    GMCH_send_prebuilt_message (&payload->header, ch, fwd);
     GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! ALREADY IN QUEUE %u\n", copy->mid);
-  }
+//   }
+//   else
+//   {
+//     LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! ALREADY IN QUEUE %u\n", copy->mid);
+//   }
 
   rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
   rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
@@ -663,79 +660,11 @@ channel_retransmit_message (void *cls,
 }
 
 
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param ch Channel which has some free buffer space.
- * @param fwd Is this in for FWD traffic? (ACK goes dest->root)
- */
-static void
-channel_send_connections_ack (struct MeshChannel *ch,
-                              unsigned int buffer,
-                              int fwd)
-{
-  struct MeshTunnel2 *t = ch->t;
-  struct MeshConnection *c;
-  struct MeshFlowControl *fc;
-  uint32_t allowed;
-  uint32_t to_allow;
-  uint32_t allow_per_connection;
-  unsigned int cs;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Channel send connection %s ack on %s:%X\n",
-              fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
-
-  /* Count connections, how many messages are already allowed */
-  for (cs = 0, allowed = 0, c = t->connection_head; NULL != c; c = c->next)
-  {
-    fc = fwd ? &c->fwd_fc : &c->bck_fc;
-    if (GMC_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
-    {
-      GNUNET_break (0);
-      continue;
-    }
-    allowed += fc->last_ack_sent - fc->last_pid_recv;
-    cs++;
-  }
-
-  /* Make sure there is no overflow */
-  if (allowed > buffer)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Authorize connections to send more data */
-  to_allow = buffer - allowed;
-
-  for (c = t->connection_head; NULL != c && to_allow > 0; c = c->next)
-  {
-    allow_per_connection = to_allow/cs;
-    to_allow -= allow_per_connection;
-    cs--;
-    fc = fwd ? &c->fwd_fc : &c->bck_fc;
-    if (fc->last_ack_sent - fc->last_pid_recv > 64 / 3)
-    {
-      continue;
-    }
-    connection_send_ack (c, allow_per_connection, fwd);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Channel send connection %s ack on %s:%X\n",
-                fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
-  GNUNET_break (to_allow == 0);
-}
-
-
 /**
  * Destroy a reliable message after it has been acknowledged, either by
  * direct mid ACK or bitfield. Updates the appropriate data structures and
  * timers and frees all memory.
- * 
+ *
  * @param copy Message that is no longer needed: remote peer got it.
  */
 static void
@@ -750,11 +679,11 @@ rel_message_free (struct MeshReliableMessage *copy)
   rel->expected_delay.rel_value_us += time.rel_value_us;
   rel->expected_delay.rel_value_us /= 8;
   rel->n_sent--;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "    n_sent %u\n", rel->n_sent);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!!  took %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "    n_sent %u\n", rel->n_sent);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "!!!  took %s\n",
               GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!!  new expected delay %s\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "!!!  new expected delay %s\n",
               GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
                                                       GNUNET_NO));
   rel->retry_timer = rel->expected_delay;
@@ -763,12 +692,33 @@ rel_message_free (struct MeshReliableMessage *copy)
 }
 
 
+/**
+ * Confirm we got a channel create.
+ *
+ * @param ch The channel to confirm.
+ * @param fwd Should we send a FWD ACK? (going dest->root)
+ */
+static void
+channel_send_ack (struct MeshChannel *ch, int fwd)
+{
+  struct GNUNET_MESH_ChannelManage msg;
+
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+              "  sending channel %s ack for channel %s\n",
+              fwd ? "FWD" : "BCK", GMCH_2s (ch));
+
+  msg.chid = htonl (ch->gid);
+  GMCH_send_prebuilt_message (&msg.header, ch, !fwd);
+}
+
 
 /**
  * Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
  *
  * @param ch Channel to mark as ready.
- * @param fwd Was the CREATE message sent fwd?
+ * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
  */
 static void
 channel_confirm (struct MeshChannel *ch, int fwd)
@@ -777,12 +727,13 @@ channel_confirm (struct MeshChannel *ch, int fwd)
   struct MeshReliableMessage *copy;
   struct MeshReliableMessage *next;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
               "  channel confirm %s %s:%X\n",
-              fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
+              fwd ? "FWD" : "BCK", GMT_2s (ch->t), ch->gid);
   ch->state = MESH_CHANNEL_READY;
 
   rel = fwd ? ch->root_rel : ch->dest_rel;
+  rel->client_ready = GNUNET_YES;
   for (copy = rel->head_sent; NULL != copy; copy = next)
   {
     struct GNUNET_MessageHeader *msg;
@@ -795,7 +746,11 @@ channel_confirm (struct MeshChannel *ch, int fwd)
       /* TODO return? */
     }
   }
-  send_ack (NULL, ch, fwd);
+  send_client_ack (ch, fwd);
+
+  /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
+  if (fwd)
+    channel_send_ack (ch, !fwd);
 }
 
 
@@ -824,7 +779,7 @@ channel_save_copy (struct MeshChannel *ch,
   type = ntohs (msg->type);
   size = ntohs (msg->size);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u\n", mid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u\n", mid);
   copy = GNUNET_malloc (sizeof (struct MeshReliableMessage) + size);
   copy->mid = mid;
   copy->timestamp = GNUNET_TIME_absolute_get ();
@@ -832,7 +787,7 @@ channel_save_copy (struct MeshChannel *ch,
   copy->type = type;
   memcpy (&copy[1], msg, size);
   rel->n_sent++;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " n_sent %u\n", rel->n_sent);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, " n_sent %u\n", rel->n_sent);
   GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy);
   if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task)
   {
@@ -847,106 +802,39 @@ channel_save_copy (struct MeshChannel *ch,
 }
 
 
-
 /**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
+ * Destroy a channel and free all resources.
  *
- * @param ch Channel on which to empty the message buffer.
- * @param c Client to send to.
- * @param rel Reliability structure to corresponding peer.
- *            If rel == bck_rel, this is FWD data.
+ * @param ch Channel to destroy.
  */
 static void
-send_client_buffered_data (struct MeshChannel *ch,
-                                   struct MeshClient *c,
-                                   int fwd)
+channel_destroy (struct MeshChannel *ch)
 {
-  struct MeshReliableMessage *copy;
-  struct MeshChannelReliability *rel;
+  struct MeshClient *c;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
-  rel = fwd ? ch->dest_rel : ch->root_rel;
-  if (GNUNET_NO == rel->client_ready)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
+  if (NULL == ch)
     return;
-  }
-
-  copy = rel->head_recv;
-  /* We never buffer channel management messages */
-  if (NULL != copy)
-  {
-    if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
-    {
-      struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) &copy[1];
-
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  " have %u! now expecting %u\n",
-                  copy->mid, rel->mid_recv + 1);
-      send_client_data (ch, msg, fwd);
-      rel->n_recv--;
-      rel->mid_recv++;
-      GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
-      GNUNET_free (copy);
-    }
-    else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  " reliable && don't have %u, next is %u\n",
-                  rel->mid_recv,
-                  copy->mid);
-      return;
-    }
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
-}
-
-
-
-
-/**
- * Destroy a channel and free all resources.
- * 
- * @param ch Channel to destroy.
- */
-static void
-channel_destroy (struct MeshChannel *ch)
-{
-  struct MeshClient *c;
-
-  if (NULL == ch)
-    return;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
-              peer2s (ch->t->peer), ch->gid);
-  channel_debug (ch);
-
-  c = ch->root;
-  if (NULL != c)
-  {
-    if (GNUNET_YES != GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
-                                                              ch->lid_root, ch))
-    {
-      GNUNET_break (0);
-    }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
+              GMT_2s (ch->t), ch->gid);
+  GMCH_debug (ch);
+
+  c = ch->root;
+  if (NULL != c)
+  {
+    GML_channel_remove (c, ch->lid_root, ch);
   }
 
   c = ch->dest;
   if (NULL != c)
   {
-    if (GNUNET_YES !=
-        GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
-                                                ch->lid_dest, ch))
-    {
-      GNUNET_break (0);
-    }
+    GML_channel_remove (c, ch->lid_dest, ch);
   }
 
   channel_rel_free_all (ch->root_rel);
   channel_rel_free_all (ch->dest_rel);
 
-  GNUNET_CONTAINER_DLL_remove (ch->t->channel_head, ch->t->channel_tail, ch);
+  GMT_remove_channel (ch->t, ch);
   GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
 
   GNUNET_free (ch);
@@ -963,8 +851,9 @@ channel_destroy (struct MeshChannel *ch)
  * @return A new initialized channel. NULL on error.
  */
 static struct MeshChannel *
-channel_new (struct MeshTunnel2 *t,
-             struct MeshClient *owner, MESH_ChannelNumber lid_root)
+channel_new (struct MeshTunnel3 *t,
+             struct MeshClient *owner,
+             MESH_ChannelNumber lid_root)
 {
   struct MeshChannel *ch;
 
@@ -977,26 +866,10 @@ channel_new (struct MeshTunnel2 *t,
 
   if (NULL != owner)
   {
-    while (NULL != channel_get (t, t->next_chid))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists (%p)...\n",
-                  t->next_chid, channel_get (t, t->next_chid));
-      t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
-    }
-    ch->gid = t->next_chid;
-    t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
-
-    if (GNUNET_OK !=
-        GNUNET_CONTAINER_multihashmap32_put (owner->own_channels, lid_root, ch,
-                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-    {
-      GNUNET_break (0);
-      channel_destroy (ch);
-      GNUNET_SERVER_receive_done (owner->handle, GNUNET_SYSERR);
-      return NULL;
-    }
+    ch->gid = GMT_get_next_chid (t);
+    GML_channel_add (owner, lid_root, ch);
   }
-  GNUNET_CONTAINER_DLL_insert (t->channel_head, t->channel_tail, ch);
+  GMT_add_channel (t, ch);
 
   return ch;
 }
@@ -1004,7 +877,7 @@ channel_new (struct MeshTunnel2 *t,
 
 /**
  * Set options in a channel, extracted from a bit flag field
- * 
+ *
  * @param ch Channel to set options to.
  * @param options Bit array in host byte order.
  */
@@ -1019,87 +892,176 @@ channel_set_options (struct MeshChannel *ch, uint32_t options)
 
 
 /**
- * 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).
+ * Handle a loopback message: call the appropriate handler for the message type.
  *
- * @return GNUNET_OK, keep iterating.
+ * @param ch Channel this message is on.
+ * @param msgh Message header.
+ * @param fwd Is this FWD traffic?
  */
-static int
-channel_destroy_iterator (void *cls,
-                          uint32_t key,
-                          void *value)
+void
+handle_loopback (struct MeshChannel *ch,
+                 const struct GNUNET_MessageHeader *msgh,
+                 int fwd)
 {
-  struct MeshChannel *ch = value;
-  struct MeshClient *c = cls;
-  struct MeshTunnel2 *t;
+  uint16_t type;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              " Channel %X (%X / %X) destroy, due to client %u shutdown.\n",
-              ch->gid, ch->lid_root, ch->lid_dest, c->id);
-  channel_debug (ch);
+  type = ntohs (msgh->type);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Loopback %s %s message!\n",
+       fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (type));
 
-  if (c == ch->dest)
+  switch (type)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
-  }
-  if (c == ch->root)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
+    case GNUNET_MESSAGE_TYPE_MESH_DATA:
+      /* Don't send hop ACK, wait for client to ACK */
+      GMCH_handle_data (ch, (struct GNUNET_MESH_Data *) msgh, fwd);
+      break;
+
+    case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK:
+      GMCH_handle_data_ack (ch, (struct GNUNET_MESH_DataACK *) msgh, fwd);
+      break;
+
+    case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
+      GMCH_handle_create (ch->t,
+                          (struct GNUNET_MESH_ChannelCreate *) msgh,
+                          fwd);
+      break;
+
+    case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK:
+      GMCH_handle_ack (ch,
+                       (struct GNUNET_MESH_ChannelManage *) msgh,
+                       fwd);
+      break;
+
+    case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
+      GMCH_handle_destroy (ch,
+                           (struct GNUNET_MESH_ChannelManage *) msgh,
+                           fwd);
+      break;
+
+    default:
+      GNUNET_break_op (0);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "end-to-end message not known (%u)\n",
+           ntohs (msgh->type));
   }
+}
 
-  t = ch->t;
-  channel_send_destroy (ch);
-  channel_destroy (ch);
-  tunnel_destroy_if_empty (t);
 
-  return GNUNET_OK;
+
+/******************************************************************************/
+/********************************    API    ***********************************/
+/******************************************************************************/
+
+
+/**
+ * Get channel ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID
+ */
+MESH_ChannelNumber
+GMCH_get_id (const struct MeshChannel *ch)
+{
+  return ch->gid;
 }
 
 
 /**
- * Sends an already built message on a channel, properly registering
- * all used resources and encrypting the message with the tunnel's key.
+ * Get the channel tunnel.
  *
- * @param message Message to send. Function makes a copy of it.
- * @param ch Channel on which this message is transmitted.
- * @param fwd Is this a fwd message?
+ * @param ch Channel to get the tunnel from.
+ *
+ * @return tunnel of the channel.
  */
-static void
-send (const struct GNUNET_MessageHeader *message,
-      struct MeshChannel *ch, int fwd)
+struct MeshTunnel3 *
+GMCH_get_tunnel (const struct MeshChannel *ch)
 {
-  struct GNUNET_MESH_Encrypted *msg;
-  size_t size = ntohs (message->size);
-  char *cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size];
-  uint16_t type;
-  uint64_t iv;
+  return ch->t;
+}
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send on Channel %s:%X %s\n",
-              peer2s (ch->t->peer), ch->gid, fwd ? "FWD" : "BCK");
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
-              GNUNET_MESH_DEBUG_M2S (ntohs (message->type)));
 
-  if (channel_is_terminal (ch, fwd) || ch->t->peer->id == myid)
-  {
-    handle_decrypted (ch->t, message, fwd);
-    return;
-  }
+/**
+ * Get free buffer space towards the client on a specific channel.
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - 64]
+ */
+unsigned int
+GMCH_get_buffer (struct MeshChannel *ch, int fwd)
+{
+  struct MeshChannelReliability *rel;
+
+  rel = fwd ? ch->dest_rel : ch->root_rel;
+
+  /* If rel is NULL it means that the end is not yet created,
+   * most probably is a loopback channel at the point of sending
+   * the ChannelCreate to itself.
+   */
+  if (NULL == rel)
+    return 64;
+
+  return (64 - rel->n_recv);
+}
+
+
+/**
+ * Get flow control status of end point: is client allow to send?
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic? (Request root status).
+ *
+ * @return GNUNET_YES if client is allowed to send us data.
+ */
+int
+GMCH_get_allowed (struct MeshChannel *ch, int fwd)
+{
+  struct MeshChannelReliability *rel;
+
+  rel = fwd ? ch->root_rel : ch->dest_rel;
+
+  return rel->client_allowed;
+}
+
 
-  type = fwd ? GNUNET_MESSAGE_TYPE_MESH_FWD : GNUNET_MESSAGE_TYPE_MESH_BCK;
-  iv = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
+/**
+ * Is the root client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return GNUNET_YES in case it is.
+ */
+int
+GMCH_is_origin (struct MeshChannel *ch, int fwd)
+{
+  struct MeshClient *c;
 
-  msg = (struct GNUNET_MESH_Encrypted *) cbuf;
-  msg->header.type = htons (type);
-  msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + size);
-  msg->iv = GNUNET_htonll (iv);
-  tunnel_encrypt (ch->t, &msg[1], message, size, iv, fwd);
-  send_prebuilt_message_tunnel (msg, ch->t, ch, fwd);
+  c = fwd ? ch->root : ch->dest;
+  return NULL != c;
 }
 
 
+/**
+ * Is the destination client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return GNUNET_YES in case it is.
+ */
+int
+GMCH_is_terminal (struct MeshChannel *ch, int fwd)
+{
+  struct MeshClient *c;
+
+  c = fwd ? ch->dest : ch->root;
+  return NULL != c;
+}
+
 
 /**
  * Notify the destination client that a new incoming channel was created.
@@ -1107,10 +1069,8 @@ send (const struct GNUNET_MessageHeader *message,
  * @param ch Channel that was created.
  */
 void
-GMCH_send_channel_create (struct MeshChannel *ch)
+GMCH_send_create (struct MeshChannel *ch)
 {
-  struct GNUNET_MESH_ChannelMessage msg;
-  struct MeshTunnel2 *t = ch->t;
   uint32_t opt;
 
   if (NULL == ch->dest)
@@ -1120,7 +1080,7 @@ GMCH_send_channel_create (struct MeshChannel *ch)
   opt |= GNUNET_YES == ch->reliable ? GNUNET_MESH_OPTION_RELIABLE : 0;
   opt |= GNUNET_YES == ch->nobuffer ? GNUNET_MESH_OPTION_NOBUFFER : 0;
   GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt,
-                           GNUNET_PEER_resolve2 (t->peer->id));
+                           GMT_get_destination (ch->t));
 
 }
 
@@ -1128,24 +1088,36 @@ GMCH_send_channel_create (struct MeshChannel *ch)
  * Notify a client that the channel is no longer valid.
  *
  * @param ch Channel that is destroyed.
- * @param fwd Forward notification (owner->dest)?
  */
 void
-GMCH_send_channel_destroy (struct MeshChannel *ch, int fwd)
+GMCH_send_destroy (struct MeshChannel *ch)
 {
-  struct GNUNET_MeshClient *c = fwd ? ch->dest : ch->root;
-  uint32_t id = fwd ? ch->lid_dest : ch->lid_root;
+  struct GNUNET_MESH_ChannelManage msg;
 
-  if (NULL == c)
-    return;
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
+  msg.header.size = htons (sizeof (msg));
+  msg.chid = htonl (ch->gid);
 
-  GML_send_channel_destroy (c, id);
+  /* If root is not NULL, notify.
+   * If it's NULL, check lid_root. When a local destroy comes in, root 
+   * is set to NULL but lid_root is left untouched. In this case, do nothing,
+   * the client is the one who reuqested the channel to be destroyed.
+   */
+  if (NULL != ch->root)
+    GML_send_channel_destroy (ch->root, ch->lid_root);
+  else if (0 == ch->lid_root)
+    GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO);
+
+  if (NULL != ch->dest)
+    GML_send_channel_destroy (ch->dest, ch->lid_dest);
+  else if (0 == ch->lid_dest)
+    GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES);
 }
 
 
 /**
  * Send data on a channel.
- * 
+ *
  * If the destination is local, send it to client, otherwise encrypt and
  * send to next hop.
  *
@@ -1158,6 +1130,16 @@ GMCH_send_data (struct MeshChannel *ch,
                 const struct GNUNET_MESH_Data *msg,
                 int fwd)
 {
+  if (GMCH_is_terminal (ch, fwd))
+  {
+    GML_send_data (fwd ? ch->dest : ch->root,
+                   msg,
+                   fwd ? ch->lid_dest : ch->lid_root);
+  }
+  else
+  {
+    GMT_send_prebuilt_message (&msg->header, ch->t, ch, fwd);
+  }
 }
 
 
@@ -1169,8 +1151,8 @@ GMCH_send_data (struct MeshChannel *ch,
  * @param ch Channel this is about.
  * @param fwd Is for FWD traffic? (ACK dest->owner)
  */
-static void
-GMCH_send_ack (struct MeshChannel *ch, int fwd)
+void
+GMCH_send_data_ack (struct MeshChannel *ch, int fwd)
 {
   struct GNUNET_MESH_DataACK msg;
   struct MeshChannelReliability *rel;
@@ -1184,7 +1166,7 @@ GMCH_send_ack (struct MeshChannel *ch, int fwd)
     return;
   }
   rel = fwd ? ch->dest_rel : ch->root_rel;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
               "send_data_ack for %u\n",
               rel->mid_recv - 1);
 
@@ -1203,14 +1185,30 @@ GMCH_send_ack (struct MeshChannel *ch, int fwd)
       break;
     mask = 0x1LL << delta;
     msg.futures |= mask;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
                 " setting bit for %u (delta %u) (%llX) -> %llX\n",
                 copy->mid, delta, mask, msg.futures);
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " final futures %llX\n", msg.futures);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, " final futures %llX\n", msg.futures);
+
+  GMCH_send_prebuilt_message (&msg.header, ch, fwd);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
+}
 
-  send_prebuilt_message_channel (&msg.header, ch, fwd);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
+
+/**
+ * Allow a client to send us more data, in case it was choked.
+ *
+ * @param ch Channel.
+ * @param fwd Is this about FWD traffic? (Root client).
+ */
+void
+GMCH_allow_client (struct MeshChannel *ch, int fwd)
+{
+  if (MESH_CHANNEL_READY != ch->state)
+    return;
+
+  send_client_ack (ch, fwd);
 }
 
 
@@ -1224,29 +1222,534 @@ GMCH_debug (struct MeshChannel *ch)
 {
   if (NULL == ch)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n");
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n",
-              peer2s (ch->t->peer), ch->gid, ch);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  root %p/%p\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n",
+              GMT_2s (ch->t), ch->gid, ch);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  root %p/%p\n",
               ch->root, ch->root_rel);
   if (NULL != ch->root)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  cli %u\n", ch->root->id);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  ready %s\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cli %s\n", GML_2s (ch->root));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  ready %s\n",
                 ch->root_rel->client_ready ? "YES" : "NO");
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id %X\n", ch->lid_root);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  id %X\n", ch->lid_root);
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  dest %p/%p\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  dest %p/%p\n",
               ch->dest, ch->dest_rel);
   if (NULL != ch->dest)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  cli %u\n", ch->dest->id);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  ready %s\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cli %s\n", GML_2s (ch->dest));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  ready %s\n",
                 ch->dest_rel->client_ready ? "YES" : "NO");
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id %X\n", ch->lid_dest);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  id %X\n", ch->lid_dest);
   }
 }
 
 
+/**
+ * Handle an ACK given by a client.
+ *
+ * Mark client as ready and send him any buffered data we could have for him.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK)
+ */
+void
+GMCH_handle_local_ack (struct MeshChannel *ch, int fwd)
+{
+  struct MeshChannelReliability *rel;
+  struct MeshClient *c;
+
+  rel = fwd ? ch->dest_rel : ch->root_rel;
+  c   = fwd ? ch->dest     : ch->root;
+
+  rel->client_ready = GNUNET_YES;
+  send_client_buffered_data (ch, c, fwd);
+  GMT_send_acks (ch->t, fwd);
+}
+
+
+/**
+ * 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 c Client which sent the data.
+ * @param message Message.
+ * @param fwd Is this a FWD data?
+ *
+ * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error.
+ */
+int
+GMCH_handle_local_data (struct MeshChannel *ch,
+                        struct MeshClient *c,
+                        struct GNUNET_MessageHeader *message,
+                        int fwd)
+{
+  struct MeshChannelReliability *rel;
+  struct GNUNET_MESH_Data *payload;
+  size_t size = ntohs (message->size);
+  uint16_t p2p_size = sizeof(struct GNUNET_MESH_Data) + size;
+  unsigned char cbuf[p2p_size];
+
+  /* Is the client in the channel? */
+  if ( !( (fwd &&
+           ch->root == c)
+         ||
+          (!fwd &&
+           ch->dest == c) ) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  rel = fwd ? ch->root_rel : ch->dest_rel;
+
+  rel->client_allowed = GNUNET_NO;
+
+  /* Ok, everything is correct, send the message. */
+  payload = (struct GNUNET_MESH_Data *) cbuf;
+  payload->mid = htonl (rel->mid_send);
+  rel->mid_send++;
+  memcpy (&payload[1], message, size);
+  payload->header.size = htons (p2p_size);
+  payload->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_DATA);
+  payload->chid = htonl (ch->gid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on channel...\n");
+  if (GNUNET_YES == ch->reliable)
+    channel_save_copy (ch, &payload->header, fwd);
+  GMCH_send_prebuilt_message (&payload->header, ch, fwd);
+
+  if (GMT_get_buffer (ch->t, fwd) > 0)
+  {
+    send_client_ack (ch, fwd);
+  }
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle a channel destroy requested by a client.
+ *
+ * Destroy the channel and the tunnel in case this was the last channel.
+ *
+ * @param ch Channel.
+ * @param c Client that requested the destruction (to avoid notifying him).
+ */
+void
+GMCH_handle_local_destroy (struct MeshChannel *ch,
+                           struct MeshClient *c)
+{
+  struct MeshTunnel3 *t;
+
+  /* Cleanup after the tunnel */
+  if (c == ch->dest)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c));
+    GML_client_delete_channel (c, ch, ch->lid_dest);
+    ch->dest = NULL;
+  }
+  if (c == ch->root)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
+    GML_client_delete_channel (c, ch, ch->lid_root);
+    ch->root = NULL;
+  }
+
+  t = ch->t;
+  GMCH_send_destroy (ch);
+  channel_destroy (ch);
+  GMT_destroy_if_empty (t);
+}
+
+
+/**
+ * Handle a channel create requested by a client.
+ *
+ * Create the channel and the tunnel in case this was the first0 channel.
+ *
+ * @param c Client that requested the creation (will be the root).
+ * @param msg Create Channel message.
+ *
+ * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
+ */
+int
+GMCH_handle_local_create (struct MeshClient *c,
+                          struct GNUNET_MESH_ChannelMessage *msg)
+{
+  struct MeshChannel *ch;
+  struct MeshTunnel3 *t;
+  struct MeshPeer *peer;
+  MESH_ChannelNumber chid;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  towards %s:%u\n",
+              GNUNET_i2s (&msg->peer), ntohl (msg->port));
+  chid = ntohl (msg->channel_id);
+
+  /* Sanity check for duplicate channel IDs */
+  if (NULL != GML_channel_get (c, chid))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  peer = GMP_get (&msg->peer);
+  GMP_add_tunnel (peer);
+  t = GMP_get_tunnel (peer);
+
+  if (GMP_get_short_id (peer) == myid)
+  {
+    GMT_change_state (t, MESH_TUNNEL3_READY);
+  }
+  else
+  {
+    GMP_connect (peer);
+  }
+
+  /* Create channel */
+  ch = channel_new (t, c, chid);
+  if (NULL == ch)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  ch->port = ntohl (msg->port);
+  channel_set_options (ch, ntohl (msg->opt));
+
+  /* In unreliable channels, we'll use the DLL to buffer BCK data */
+  ch->root_rel = GNUNET_new (struct MeshChannelReliability);
+  ch->root_rel->ch = ch;
+  ch->root_rel->expected_delay = MESH_RETRANSMIT_TIME;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch));
+
+  /* Send create channel */
+  {
+    struct GNUNET_MESH_ChannelCreate msgcc;
+
+    msgcc.header.size = htons (sizeof (msgcc));
+    msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
+    msgcc.chid = htonl (ch->gid);
+    msgcc.port = msg->port;
+    msgcc.opt = msg->opt;
+
+    GMT_queue_data (t, ch, &msgcc.header, GNUNET_YES);
+  }
+  return GNUNET_OK;
+}
+
+/**
+ * Handler for mesh network payload traffic.
+ *
+ * @param ch Channel for the message.
+ * @param msg Unencryted data message.
+ * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ */
+void
+GMCH_handle_data (struct MeshChannel *ch,
+                  const struct GNUNET_MESH_Data *msg,
+                  int fwd)
+{
+  struct MeshChannelReliability *rel;
+  struct MeshClient *c;
+  uint32_t mid;
+
+  /*  Initialize FWD/BCK data */
+  c   = fwd ? ch->dest     : ch->root;
+  rel = fwd ? ch->dest_rel : ch->root_rel;
+
+  if (NULL == c)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO);
+
+  mid = ntohl (msg->mid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, " mid %u\n", mid);
+
+  if (GNUNET_NO == ch->reliable ||
+      ( !GMC_is_pid_bigger (rel->mid_recv, mid) &&
+        GMC_is_pid_bigger (rel->mid_recv + 64, mid) ) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RECV %u\n", mid);
+    if (GNUNET_YES == ch->reliable)
+    {
+      /* Is this the exact next expected messasge? */
+      if (mid == rel->mid_recv)
+      {
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "as expected\n");
+        rel->mid_recv++;
+        send_client_data (ch, msg, fwd);
+      }
+      else
+      {
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "save for later\n");
+        add_buffered_data (msg, rel);
+      }
+    }
+    else
+    {
+      /* Tunnel is unreliable: send to clients directly */
+      /* FIXME: accept Out Of Order traffic */
+      rel->mid_recv = mid + 1;
+      send_client_data (ch, msg, fwd);
+    }
+  }
+  else
+  {
+    GNUNET_break_op (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+                " MID %u not expected (%u - %u), dropping!\n",
+                mid, rel->mid_recv, rel->mid_recv + 64);
+  }
+
+  GMCH_send_data_ack (ch, fwd);
+}
+
+
+/**
+ * Handler for mesh network traffic end-to-end ACKs.
+ *
+ * @param t Tunnel on which we got this message.
+ * @param msg Data message.
+ * @param fwd Is this a fwd ACK? (dest->orig)
+ */
+void
+GMCH_handle_data_ack (struct MeshChannel *ch,
+                      const struct GNUNET_MESH_DataACK *msg,
+                      int fwd)
+{
+  struct MeshChannelReliability *rel;
+  struct MeshReliableMessage *copy;
+  struct MeshReliableMessage *next;
+  uint32_t ack;
+  int work;
+
+  ack = ntohl (msg->mid);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! %s ACK %u\n",
+              (GNUNET_YES == fwd) ? "FWD" : "BCK", ack);
+
+  if (GNUNET_YES == fwd)
+  {
+    rel = ch->root_rel;
+  }
+  else
+  {
+    rel = ch->dest_rel;
+  }
+  if (NULL == rel)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
+  {
+    if (GMC_is_pid_bigger (copy->mid, ack))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "!!!  head %u, out!\n", copy->mid);
+      channel_rel_free_sent (rel, msg);
+      break;
+    }
+    work = GNUNET_YES;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "!!!  id %u\n", copy->mid);
+    next = copy->next;
+    rel_message_free (copy);
+  }
+  /* ACK client if needed */
+//   channel_send_ack (t, type, GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK == type);
+
+  /* If some message was free'd, update the retransmission delay*/
+  if (GNUNET_YES == work)
+  {
+    if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
+    {
+      GNUNET_SCHEDULER_cancel (rel->retry_task);
+      if (NULL == rel->head_sent)
+      {
+        rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+      }
+      else
+      {
+        struct GNUNET_TIME_Absolute new_target;
+        struct GNUNET_TIME_Relative delay;
+
+        delay = GNUNET_TIME_relative_multiply (rel->retry_timer,
+                                               MESH_RETRANSMIT_MARGIN);
+        new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
+                                               delay);
+        delay = GNUNET_TIME_absolute_get_remaining (new_target);
+        rel->retry_task =
+            GNUNET_SCHEDULER_add_delayed (delay,
+                                          &channel_retransmit_message,
+                                          rel);
+      }
+    }
+    else
+      GNUNET_break (0);
+  }
+}
+
+
+/**
+ * Handler for channel create messages.
+ *
+ * @param t Tunnel this channel will be in.
+ * @param msg Message.
+ * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ */
+struct MeshChannel *
+GMCH_handle_create (struct MeshTunnel3 *t,
+                    const struct GNUNET_MESH_ChannelCreate *msg,
+                    int fwd)
+{
+  MESH_ChannelNumber chid;
+  struct MeshChannel *ch;
+  struct MeshClient *c;
+  uint32_t port;
+
+  chid = ntohl (msg->chid);
+
+  ch = GMT_get_channel (t, chid);
+  if (NULL == ch)
+  {
+    /* Create channel */
+    ch = channel_new (t, NULL, 0);
+    ch->gid = chid;
+  }
+  channel_set_options (ch, ntohl (msg->opt));
+
+  /* Find a destination client */
+  port = ntohl (msg->port);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "   port %u\n", port);
+  c = GML_client_get_by_port (port);
+  if (NULL == c)
+  {
+    /* TODO send reject */
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no client has port registered\n");
+    channel_destroy (ch);
+    return NULL;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  client %p has port registered\n", c);
+  }
+
+  add_destination (ch, c);
+  if (GNUNET_YES == ch->reliable)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
+  else
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n");
+
+  GMCH_send_create (ch);
+  channel_send_ack (ch, fwd);
+
+  return ch;
+}
+
+
+/**
+ * Handler for channel ack messages.
+ *
+ * @param ch Channel.
+ * @param msg Message.
+ * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ */
+void
+GMCH_handle_ack (struct MeshChannel *ch,
+                 const struct GNUNET_MESH_ChannelManage *msg,
+                 int fwd)
+{
+  channel_confirm (ch, !fwd);
+}
+
+
+/**
+ * Handler for channel destroy messages.
+ *
+ * @param ch Channel to be destroyed of.
+ * @param msg Message.
+ * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ */
+void
+GMCH_handle_destroy (struct MeshChannel *ch,
+                     const struct GNUNET_MESH_ChannelManage *msg,
+                     int fwd)
+{
+  struct MeshTunnel3 *t;
+
+  GMCH_debug (ch);
+  if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
+  {
+    /* Not for us (don't destroy twice a half-open loopback channel) */
+    return;
+  }
+
+  t = ch->t;
+  GMCH_send_destroy (ch);
+  channel_destroy (ch);
+  GMT_destroy_if_empty (t);
+}
+
+
+/**
+ * Sends an already built message on a channel.
+ *
+ * If the channel is on a loopback tunnel, notifies the appropriate destination
+ * client locally.
+ *
+ * On a normal channel passes the message to the tunnel for encryption and
+ * sending on a connection.
+ *
+ * This function DOES NOT save the message for retransmission.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * @param ch Channel on which this message is transmitted.
+ * @param fwd Is this a fwd message?
+ */
+void
+GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+                            struct MeshChannel *ch, int fwd)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH Send %s %s on channel %s\n",
+       fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (ntohs (message->type)), 
+       GMCH_2s (ch));
+
+  if (GMT_is_loopback (ch->t))
+  {
+    handle_loopback (ch, message, fwd);
+    return;
+  }
+
+  GMT_send_prebuilt_message (message, ch->t, ch, fwd);
+}
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GMCH_2s (const struct MeshChannel *ch)
+{
+  static char buf[64];
+
+  if (NULL == ch)
+    return "(NULL Channel)";
+
+  sprintf (buf, "%s:%X (%X / %X)",
+           GMT_2s (ch->t), ch->gid, ch->lid_root, ch->lid_dest);
+
+  return buf;
+}