- dht debug path
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_local.c
index 6ee23e6e0140c84cd958fb156e888fa11b897d3f..84adb7d0e6692405c84b430704be6d9b30733b17 100644 (file)
 
 #include "gnunet_statistics_service.h"
 
-#include "mesh_enc.h"
-#include "mesh_protocol_enc.h" // GNUNET_MESH_Data is shared
+#include "mesh.h"
+#include "mesh_protocol.h" /* GNUNET_MESH_Data is shared */
 
 #include "gnunet-service-mesh_local.h"
+#include "gnunet-service-mesh_channel.h"
+
+/* INFO DEBUG */
+#include "gnunet-service-mesh_tunnel.h"
+#include "gnunet-service-mesh_peer.h"
 
 #define LOG(level, ...) GNUNET_log_from(level,"mesh-loc",__VA_ARGS__)
 
@@ -179,6 +184,7 @@ handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
 {
   struct MeshClient *c;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client);
   if (NULL == client)
     return;
   c = GNUNET_new (struct MeshClient);
@@ -191,6 +197,31 @@ handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
 }
 
 
+/**
+ * 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
+channel_destroy_iterator (void *cls,
+                          uint32_t key,
+                          void *value)
+{
+  struct MeshChannel *ch = value;
+  struct MeshClient *c = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+              " Channel %s destroy, due to client %s shutdown.\n",
+              GMCH_2s (ch), GML_2s (c));
+
+  GMCH_handle_local_destroy (ch, c, key < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV);
+  return GNUNET_OK;
+}
+
 /**
  * Handler for client disconnection
  *
@@ -210,7 +241,7 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
     return;
   }
 
-  c = client_get (client);
+  c = GML_client_get (client);
   if (NULL != c)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
@@ -268,6 +299,7 @@ handle_new_client (void *cls, struct GNUNET_SERVER_Client *client,
   uint32_t *p;
   unsigned int i;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client);
 
   /* Check data sanity */
@@ -328,17 +360,13 @@ static void
 handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
                        const struct GNUNET_MessageHeader *message)
 {
-  struct GNUNET_MESH_ChannelMessage *msg;
-  struct MeshPeer *peer;
-  struct MeshTunnel2 *t;
-  struct MeshChannel *ch;
   struct MeshClient *c;
-  MESH_ChannelNumber chid;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
 
   /* Sanity check for client registration */
-  if (NULL == (c = client_get (client)))
+  if (NULL == (c = GML_client_get (client)))
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
@@ -354,66 +382,13 @@ handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
 
-  msg = (struct GNUNET_MESH_ChannelMessage *) message;
-  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 != channel_get_by_local_id (c, chid))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  peer = peer_get (&msg->peer);
-  if (NULL == peer->tunnel)
-  {
-    peer->tunnel = tunnel_new ();
-    peer->tunnel->peer = peer;
-    if (peer->id == myid)
-    {
-      tunnel_change_state (peer->tunnel, MESH_TUNNEL_READY);
-    }
-    else
-    {
-      peer_connect (peer);
-    }
-  }
-  t = peer->tunnel;
-
-  /* Create channel */
-  ch = channel_new (t, c, chid);
-  if (NULL == ch)
+  if (GNUNET_OK !=
+      GMCH_handle_local_create (c,
+                                (struct GNUNET_MESH_ChannelMessage *) message))
   {
-    GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  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[%x]:%u (%x)\n",
-              peer2s (t->peer), ch->gid, ch->port, ch->lid_root);
-
-  /* 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);
-  }
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
   return;
@@ -436,8 +411,7 @@ handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
   struct MeshChannel *ch;
   MESH_ChannelNumber chid;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-              "Got a DESTROY CHANNEL from client!\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
 
   /* Sanity check for client registration */
   if (NULL == (c = GML_client_get (client)))
@@ -460,16 +434,19 @@ handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
 
   /* Retrieve tunnel */
   chid = ntohl (msg->channel_id);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  for channel %X\n", chid);
   ch = GML_channel_get (c, chid);
   if (NULL == ch)
   {
-    LOG (GNUNET_ERROR_TYPE_ERROR, "  channel %X not found\n", chid);
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  channel %X not found\n", chid);
+    GNUNET_STATISTICS_update (stats,
+                              "# client destroy messages on unknown channel",
+                              1, GNUNET_NO);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
 
-  GMCH_handle_local_destroy (ch, c, chid);
+  GMCH_handle_local_destroy (ch, c, chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV);
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
   return;
@@ -494,8 +471,7 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client,
   size_t size;
   int fwd;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-              "Got data from a client!\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client!\n");
 
   /* Sanity check for client registration */
   if (NULL == (c = GML_client_get (client)))
@@ -519,12 +495,15 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client,
 
   /* Channel exists? */
   chid = ntohl (msg->id);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X\n", chid);
   fwd = chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
   ch = GML_channel_get (c, chid);
   if (NULL == ch)
   {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_STATISTICS_update (stats,
+                              "# client data messages on unknown channel",
+                              1, GNUNET_NO);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
 
@@ -560,6 +539,7 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
   MESH_ChannelNumber chid;
   int fwd;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
 
   /* Sanity check for client registration */
@@ -580,15 +560,17 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
   LOG (GNUNET_ERROR_TYPE_DEBUG, "   -- ch %p\n", ch);
   if (NULL == ch)
   {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Channel %X unknown.\n", chid);
-    LOG (GNUNET_ERROR_TYPE_WARNING, "  for client %u.\n", c->id);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  for client %u.\n", c->id);
+    GNUNET_STATISTICS_update (stats,
+                              "# client ack messages on unknown channel",
+                              1, GNUNET_NO);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
 
-  /* If client is root, the ACK is going FWD, therefore this is "BCK". */
-  /* If client is dest, the ACK is going BCK, therefore this is "FWD" */
+  /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
+  /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
   fwd = chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
 
   GMCH_handle_local_ack (ch, fwd);
@@ -598,41 +580,114 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *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 GNUNET_SERVER_Client *client = cls;
+  struct MeshPeer *p = value;
+  struct GNUNET_MESH_LocalInfoPeer msg;
+
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_PEERS);
+  msg.destination = *peer;
+  msg.paths = htons (GMP_count_paths (p));
+  msg.tunnel = htons (NULL != GMP_get_tunnel (p));
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n",
+       GNUNET_i2s (peer));
+
+  GNUNET_SERVER_notification_context_unicast (nc, client,
+                                              &msg.header, GNUNET_NO);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Closure (unused).
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client,
+                    const struct GNUNET_MessageHeader *message)
+{
+  struct MeshClient *c;
+  struct GNUNET_MessageHeader reply;
+
+  /* Sanity check for client registration */
+  if (NULL == (c = GML_client_get (client)))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received get peers request from client %u (%p)\n",
+       c->id, client);
+
+  GMP_iterate_all (get_all_peers_iterator, client);
+  reply.size = htons (sizeof (reply));
+  reply.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_PEERS);
+  GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Get peers request from client %u completed\n", c->id);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
  * Iterator over all tunnels to send a monitoring client info about each tunnel.
  *
- * @param cls Closure (client handle).
- * @param key Key (hashed tunnel ID, unused).
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
  * @param value Tunnel info.
  *
- * @return GNUNET_YES, to keep iterating.
+ * @return #GNUNET_YES, to keep iterating.
  */
-// static int
-// monitor_all_tunnels_iterator (void *cls,
-//                               const struct GNUNET_HashCode * key,
-//                               void *value)
-// {
-//   struct GNUNET_SERVER_Client *client = cls;
-//   struct MeshChannel *ch = value;
-//   struct GNUNET_MESH_LocalMonitor *msg;
-//
-//   msg = GNUNET_malloc (sizeof(struct GNUNET_MESH_LocalMonitor));
-//   msg->channel_id = htonl (ch->gid);
-//   msg->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor));
-//   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
-//
-//   LOG (GNUNET_ERROR_TYPE_INFO,
-//               "*  sending info about tunnel %s\n",
-//               GNUNET_i2s (&msg->owner));
-//
-//   GNUNET_SERVER_notification_context_unicast (nc, client,
-//                                               &msg->header, GNUNET_NO);
-//   return GNUNET_YES;
-// }
+static int
+get_all_tunnels_iterator (void *cls,
+                          const struct GNUNET_PeerIdentity * peer,
+                          void *value)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct MeshTunnel3 *t = value;
+  struct GNUNET_MESH_LocalInfoTunnel msg;
+
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
+  msg.destination = *peer;
+  msg.channels = htonl (GMT_count_channels (t));
+  msg.connections = htonl (GMT_count_connections (t));
+  msg.cstate = htons ((uint16_t) GMT_get_cstate (t));
+  msg.estate = htons ((uint16_t) GMT_get_estate (t));
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n",
+       GNUNET_i2s (peer));
+
+  GNUNET_SERVER_notification_context_unicast (nc, client,
+                                              &msg.header, GNUNET_NO);
+  return GNUNET_YES;
+}
 
 
 /**
- * Handler for client's MONITOR request.
+ * Handler for client's INFO TUNNELS request.
  *
  * @param cls Closure (unused).
  * @param client Identification of the client.
@@ -643,6 +698,7 @@ handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
                     const struct GNUNET_MessageHeader *message)
 {
   struct MeshClient *c;
+  struct GNUNET_MessageHeader reply;
 
   /* Sanity check for client registration */
   if (NULL == (c = GML_client_get (client)))
@@ -652,21 +708,45 @@ handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
 
-  LOG (GNUNET_ERROR_TYPE_INFO,
-              "Received get tunnels request from client %u\n",
-              c->id);
-//   GNUNET_CONTAINER_multihashmap_iterate (tunnels,
-//                                          monitor_all_tunnels_iterator,
-//                                          client);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-              "Get tunnels request from client %u completed\n",
-              c->id);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received get tunnels request from client %u (%p)\n",
+       c->id, client);
+
+  GMT_iterate_all (get_all_tunnels_iterator, client);
+  reply.size = htons (sizeof (reply));
+  reply.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
+  GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Get tunnels request from client %u completed\n", c->id);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
+static void
+iter_connection (void *cls, struct MeshConnection *c)
+{
+  struct GNUNET_MESH_LocalInfoTunnel *msg = cls;
+  struct GNUNET_MeshHash *h = (struct GNUNET_MeshHash *) &msg[1];
+
+  h[msg->connections] = *(GMC_get_id (c));
+  msg->connections++;
+}
+
+static void
+iter_channel (void *cls, struct MeshChannel *ch)
+{
+  struct GNUNET_MESH_LocalInfoTunnel *msg = cls;
+  struct GNUNET_HashCode *h = (struct GNUNET_HashCode *) &msg[1];
+  MESH_ChannelNumber *chn = (MESH_ChannelNumber *) &h[msg->connections];
+
+  chn[msg->channels] = GMCH_get_id (ch);
+  msg->channels++;
+}
+
+
 /**
- * Handler for client's MONITOR_TUNNEL request.
+ * Handler for client's SHOW_TUNNEL request.
  *
  * @param cls Closure (unused).
  * @param client Identification of the client.
@@ -676,10 +756,13 @@ void
 handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
                     const struct GNUNET_MessageHeader *message)
 {
-  const struct GNUNET_MESH_LocalMonitor *msg;
-  struct GNUNET_MESH_LocalMonitor *resp;
+  const struct GNUNET_MESH_LocalInfo *msg;
+  struct GNUNET_MESH_LocalInfoTunnel *resp;
   struct MeshClient *c;
-  struct MeshChannel *ch;
+  struct MeshTunnel3 *t;
+  unsigned int ch_n;
+  unsigned int c_n;
+  size_t size;
 
   /* Sanity check for client registration */
   if (NULL == (c = GML_client_get (client)))
@@ -689,20 +772,27 @@ handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
 
-  msg = (struct GNUNET_MESH_LocalMonitor *) message;
+  msg = (struct GNUNET_MESH_LocalInfo *) message;
   LOG (GNUNET_ERROR_TYPE_INFO,
-              "Received tunnel info request from client %u for tunnel %s[%X]\n",
-              c->id,
-              &msg->owner,
-              ntohl (msg->channel_id));
-//   ch = channel_get (&msg->owner, ntohl (msg->channel_id));
-  ch = NULL; // FIXME
-  if (NULL == ch)
+       "Received tunnel info request from client %u for tunnel %s\n",
+       c->id, GNUNET_i2s_full(&msg->peer));
+
+  t = GMP_get_tunnel (GMP_get (&msg->peer));
+  if (NULL == t)
   {
     /* We don't know the tunnel */
-    struct GNUNET_MESH_LocalMonitor warn;
+    struct GNUNET_MESH_LocalInfoTunnel warn;
+
+    LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n",
+         GNUNET_i2s_full(&msg->peer), sizeof (warn));
+    warn.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL);
+    warn.header.size = htons (sizeof (warn));
+    warn.destination = msg->peer;
+    warn.channels = htonl (0);
+    warn.connections = htonl (0);
+    warn.cstate = htons (0);
+    warn.estate = htons (0);
 
-    warn = *msg;
     GNUNET_SERVER_notification_context_unicast (nc, client,
                                                 &warn.header,
                                                 GNUNET_NO);
@@ -711,16 +801,31 @@ handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
   }
 
   /* Initialize context */
-  resp = GNUNET_malloc (sizeof (struct GNUNET_MESH_LocalMonitor));
-  *resp = *msg;
-  resp->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor));
+  ch_n = GMT_count_channels (t);
+  c_n = GMT_count_connections (t);
+
+  size = sizeof (struct GNUNET_MESH_LocalInfoTunnel);
+  size += c_n * sizeof (struct GNUNET_HashCode);
+  size += ch_n * sizeof (MESH_ChannelNumber);
+
+  resp = GNUNET_malloc (size);
+  resp->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL);
+  resp->header.size = htons (size);
+  GMT_iterate_connections (t, &iter_connection, resp);
+  GMT_iterate_channels (t, &iter_channel, resp);
+  /* Do not interleave with iterators, iter_channel needs conn in HBO */
+  resp->destination = msg->peer;
+  resp->connections = htonl (resp->connections);
+  resp->channels = htonl (resp->channels);
+  resp->cstate = htons (GMT_get_cstate (t));
+  resp->estate = htons (GMT_get_estate (t));
   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
                                               &resp->header, GNUNET_NO);
   GNUNET_free (resp);
 
   LOG (GNUNET_ERROR_TYPE_INFO,
-              "Monitor tunnel request from client %u completed\n",
-              c->id);
+       "Show tunnel request from client %u completed. %u conn, %u ch\n",
+       c->id, c_n, ch_n);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -737,10 +842,12 @@ static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
   {&handle_data, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA, 0},
   {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK,
    sizeof (struct GNUNET_MESH_LocalAck)},
+  {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_PEERS,
+   sizeof (struct GNUNET_MessageHeader)},
   {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS,
    sizeof (struct GNUNET_MessageHeader)},
   {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL,
-   sizeof (struct GNUNET_MESH_LocalMonitor)},
+   sizeof (struct GNUNET_MESH_LocalInfo)},
   {NULL, NULL, 0, 0}
 };
 
@@ -758,6 +865,7 @@ static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
 void
 GML_init (struct GNUNET_SERVER_Handle *handle)
 {
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
   server_handle = handle;
   GNUNET_SERVER_suspend (server_handle);
   ports = GNUNET_CONTAINER_multihashmap32_create (32);
@@ -798,25 +906,43 @@ GML_shutdown (void)
 
 
 /**
- * Get a chennel from a client
+ * Get a channel from a client.
  *
- * @param c the client to check
- * @param chid Channel ID, must be local (> 0x800...)
+ * @param c Client to check.
+ * @param chid Channel ID, must be local (> 0x800...).
  *
  * @return non-NULL if channel exists in the clients lists
  */
 struct MeshChannel *
 GML_channel_get (struct MeshClient *c, MESH_ChannelNumber chid)
 {
+  struct GNUNET_CONTAINER_MultiHashMap32 *map;
+
   if (0 == (chid & GNUNET_MESH_LOCAL_CHANNEL_ID_CLI))
   {
     GNUNET_break_op (0);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
     return NULL;
   }
+
   if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
-    return GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels, chid);
-  return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid);
+    map = c->incoming_channels;
+  else if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI)
+    map = c->own_channels;
+  else
+  {
+    GNUNET_break (0);
+    map = NULL;
+  }
+  if (NULL == map)
+  {
+    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Client %s does no t have a valid map for CHID %X\n",
+         GML_2s (c), chid);
+    return NULL;
+  }
+  return GNUNET_CONTAINER_multihashmap32_get (map, chid);
 }
 
 
@@ -844,7 +970,7 @@ GML_channel_add (struct MeshClient *client,
 
 
 /**
- * Remove a channel from a client
+ * Remove a channel from a client.
  *
  * @param client Client.
  * @param chid Channel ID.
@@ -856,9 +982,13 @@ GML_channel_remove (struct MeshClient *client,
                     struct MeshChannel *ch)
 {
   if (GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= chid)
-    GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, chid, ch);
+    GNUNET_break (GNUNET_YES ==
+                  GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels,
+                                                          chid, ch));
   else if (GNUNET_MESH_LOCAL_CHANNEL_ID_CLI <= chid)
-    GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, chid, ch);
+    GNUNET_break (GNUNET_YES ==
+                  GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
+                                                          chid, ch));
   else
     GNUNET_break (0);
 }
@@ -977,10 +1107,15 @@ GML_send_ack (struct MeshClient *c, MESH_ChannelNumber id)
 }
 
 
+
 /**
  * Notify the client that a new incoming channel was created.
  *
- * @param ch Channel that was created.
+ * @param c Client to notify.
+ * @param id Channel ID.
+ * @param port Channel's destination port.
+ * @param opt Options (bit array).
+ * @param peer Origin peer.
  */
 void
 GML_send_channel_create (struct MeshClient *c,
@@ -990,7 +1125,7 @@ GML_send_channel_create (struct MeshClient *c,
   struct GNUNET_MESH_ChannelMessage msg;
 
   msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
   msg.channel_id = htonl (id);
   msg.port = htonl (port);
   msg.opt = htonl (opt);
@@ -1000,6 +1135,31 @@ GML_send_channel_create (struct MeshClient *c,
 }
 
 
+/**
+ * Build a local channel NACK message and send it to a local client.
+ *
+ * @param c Client to whom send the NACK.
+ * @param id Channel ID to use
+ */
+void
+GML_send_channel_nack (struct MeshClient *c, MESH_ChannelNumber id)
+{
+  struct GNUNET_MESH_LocalAck msg;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "send local nack on %X towards %p\n",
+       id, c);
+
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK);
+  msg.channel_id = htonl (id);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              c->handle,
+                                              &msg.header,
+                                              GNUNET_NO);
+
+}
+
 /**
  * Notify a client that a channel is no longer valid.
  *
@@ -1016,8 +1176,10 @@ GML_send_channel_destroy (struct MeshClient *c, uint32_t id)
     GNUNET_break (0);
     return;
   }
+  if (GNUNET_YES == c->shutting_down)
+    return;
   msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
   msg.channel_id = htonl (id);
   msg.port = htonl (0);
   memset (&msg.peer, 0, sizeof (msg.peer));