- fixes, debug
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh-new.c
index 6a1eb8b33e17b1a44e5d8bb23bf9cac8f30bb63a..1e37a2a89a7b17361a6214aea6fa0dc3e8791696 100644 (file)
@@ -28,7 +28,7 @@
  * - set ttl relative to path length
  * - add signatures
  * - add encryption
- * - add port numbers
+ * - keep queues until receiving ACK
  * TODO END
  */
 
@@ -669,7 +669,7 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
 
 /**
  * Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
  *
  * @param peer Full identity of the peer.
  *
@@ -681,7 +681,7 @@ peer_get (const struct GNUNET_PeerIdentity *peer);
 
 /**
  * Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
  *
  * @param peer Short identity of the peer.
  *
@@ -744,7 +744,9 @@ tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1,
 
 
 /**
- * Use the given path for the tunnel.
+ * @brief Use the given path for the tunnel.
+ * Update the next and prev hops (and RCs).
+ * (Re)start the path refresh in case the tunnel is locally owned.
  * 
  * @param t Tunnel to update.
  * @param p Path to use.
@@ -920,7 +922,7 @@ client_delete_tunnel (struct MeshClient *c, struct MeshTunnel *t)
 }
 
 /**
- * Notify the appropiate client that a new incoming tunnel was created.
+ * Notify the appropriate client that a new incoming tunnel was created.
  *
  * @param t Tunnel that was created.
  */
@@ -935,6 +937,7 @@ send_client_tunnel_create (struct MeshTunnel *t)
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
   msg.tunnel_id = htonl (t->local_tid_dest);
   msg.port = htonl (t->port);
+  GNUNET_PEER_resolve (t->id.oid, &msg.peer);
   GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
                                               &msg.header, GNUNET_NO);
 }
@@ -943,19 +946,28 @@ send_client_tunnel_create (struct MeshTunnel *t)
 /**
  * Notify dest client that the incoming tunnel is no longer valid.
  *
- * @param t Tunnel that was destroyed.
+ * @param c Client to notify..
+ * @param t Tunnel that is destroyed.
  */
 static void
-send_client_tunnel_destroy (struct MeshTunnel *t)
+send_client_tunnel_destroy (struct MeshClient *c, struct MeshTunnel *t)
 {
   struct GNUNET_MESH_TunnelMessage msg;
 
-  if (NULL == t->client)
+  if (NULL == c)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (c != t->client && c != t->owner)
+  {
+    GNUNET_break (0);
     return;
+  }
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
   msg.tunnel_id = htonl (t->local_tid_dest);
-  GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
+  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
                                               &msg.header, GNUNET_NO);
 }
 
@@ -979,7 +991,7 @@ peer_info_timeout (void *cls,
 
 /**
  * Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
  *
  * @param peer Full identity of the peer.
  *
@@ -1013,7 +1025,7 @@ peer_get (const struct GNUNET_PeerIdentity *peer)
 
 /**
  * Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
  *
  * @param peer Short identity of the peer.
  *
@@ -1059,34 +1071,6 @@ peer_get_best_path (const struct MeshPeerInfo *peer, const struct MeshTunnel *t)
   return best_p;
 }
 
-
-/**
- * Remove the tunnel from the list of tunnels to which a peer is target.
- *
- * @param peer PeerInfo of the peer.
- * @param t Tunnel to remove.
- */
-static void
-peer_remove_tunnel (struct MeshPeerInfo *peer, struct MeshTunnel *t)
-{
-  unsigned int i;
-
-  for (i = 0; i < peer->ntunnels; i++)
-  {
-    if (0 ==
-        memcmp (&peer->tunnels[i]->id, &t->id, sizeof (struct MESH_TunnelID)))
-    {
-      peer->ntunnels--;
-      peer->tunnels[i] = peer->tunnels[peer->ntunnels];
-      peer->tunnels = 
-        GNUNET_realloc (peer->tunnels, 
-                        peer->ntunnels * sizeof(struct MeshTunnel *));
-      return;
-    }
-  }
-}
-
-
 /**
   * Core callback to write a pre-constructed data packet to core buffer
   *
@@ -1238,15 +1222,9 @@ send_path_ack (struct MeshTunnel *t)
 {
   struct MeshPeerInfo *peer;
 
-  if (0 == t->prev_hop)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
   peer = peer_get_short (t->prev_hop);
 
-  queue_add (&t->id,
+  queue_add (t,
              GNUNET_MESSAGE_TYPE_MESH_PATH_ACK,
              sizeof (struct GNUNET_MESH_PathACK),
              peer,
@@ -1428,7 +1406,6 @@ peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path,
     path_destroy (path);
     return;
   }
-  GNUNET_assert (peer_info->id == path->peers[path->length - 1]);
   for (l = 1; l < path->length; l++)
   {
     if (path->peers[l] == myid)
@@ -1493,6 +1470,7 @@ peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path,
  *
  * @param peer_info Peer to add the path to, being the origin of the path.
  * @param path New path to add after being inversed.
+ *             Path will be either used or freed.
  * @param trusted Do we trust that this path is real?
  */
 static void
@@ -1504,6 +1482,30 @@ peer_info_add_path_to_origin (struct MeshPeerInfo *peer_info,
 }
 
 
+
+/**
+ * Remove a tunnel from the list of tunnels a peer participates in.
+ * 
+ * @param p Peer to clean.
+ * @param t Tunnel to remove.
+ */
+static void
+peer_info_remove_tunnel (struct MeshPeerInfo *p, struct MeshTunnel *t)
+{
+  unsigned int i;
+
+  for (i = 0; i < p->ntunnels; i++)
+  {
+    if (p->tunnels[i] == t)
+    {
+      p->tunnels[i] = p->tunnels[p->ntunnels - 1];
+      GNUNET_array_grow (p->tunnels, p->ntunnels, p->ntunnels - 1);
+      return;
+    }
+  }
+}
+
+
 /**
  * Function called if the connection to the peer has been stalled for a while,
  * possibly due to a missed ACK. Poll the peer about its ACK status.
@@ -1658,7 +1660,7 @@ path_add_to_peers (struct MeshPeerPath *p, int confirmed)
     aux = peer_get_short (p->peers[i]);
     copy = path_duplicate (p);
     copy->length = i + 1;
-    peer_info_add_path (aux, copy, GNUNET_NO);
+    peer_info_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
   }
 }
 
@@ -1756,22 +1758,32 @@ tunnel_get (const struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid)
 /**
  * Add a client to a tunnel, initializing all needed data structures.
  * 
- * FIXME: make static after implementing port numbers
- * 
  * @param t Tunnel to which add the client.
  * @param c Client which to add to the tunnel.
  */
-void
+static void
 tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c)
 {
+  struct GNUNET_HashCode hash;
+
   if (NULL != t->client)
   {
     GNUNET_break(0);
     return;
   }
-  if (0 != t->next_hop)
+  GMC_hash32 (t->local_tid_dest, &hash);
+  if (GNUNET_OK !=
+      GNUNET_CONTAINER_multihashmap_put (c->incoming_tunnels, &hash, t,
+                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
   {
-    GNUNET_break(0);
+    GNUNET_break (0);
+    return;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t,
+                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+  {
+    GNUNET_break (0);
     return;
   }
   t->client = c;
@@ -1781,34 +1793,40 @@ tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c)
 static void
 tunnel_use_path (struct MeshTunnel *t, struct MeshPeerPath *p)
 {
-  unsigned int i;
+  unsigned int own_pos;
 
-  for (i = 0; i < p->length; i++)
+  for (own_pos = 0; own_pos < p->length; own_pos++)
   {
-    if (p->peers[i] == myid)
+    if (p->peers[own_pos] == myid)
       break;
   }
-  if (i > p->length - 1)
+  if (own_pos > p->length - 1)
   {
     GNUNET_break (0);
     return;
   }
 
-  if (i < p->length - 1)
-    t->next_hop = p->peers[i + 1];
+  if (own_pos < p->length - 1)
+    t->next_hop = p->peers[own_pos + 1];
   else
-    t->next_hop = 0;
-  if (0 < i)
-    t->prev_hop = p->peers[i - 1];
+    t->next_hop = p->peers[own_pos];
+  GNUNET_PEER_change_rc (t->next_hop, 1);
+  if (0 < own_pos)
+    t->prev_hop = p->peers[own_pos - 1];
   else
-    t->prev_hop = 0;
+    t->prev_hop = p->peers[0];
+  GNUNET_PEER_change_rc (t->prev_hop, 1);
 
   if (NULL != t->path)
     path_destroy (t->path);
   t->path = path_duplicate (p);
-  if (GNUNET_SCHEDULER_NO_TASK == t->maintenance_task)
-    t->maintenance_task =
-        GNUNET_SCHEDULER_add_delayed (refresh_path_time, &path_refresh, t);
+  if (0 == own_pos)
+  {
+    if (GNUNET_SCHEDULER_NO_TASK != t->maintenance_task)
+      GNUNET_SCHEDULER_cancel (t->maintenance_task);
+    t->maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_path_time,
+                                                        &path_refresh, t);
+  }
 }
 
 
@@ -1868,7 +1886,7 @@ send_local_ack (struct MeshTunnel *t, struct MeshClient *c, uint32_t ack)
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
   msg.tunnel_id = htonl (t->owner == c ? t->local_tid : t->local_tid_dest);
-  msg.max_pid = htonl (ack); 
+  msg.ack = htonl (ack); 
   GNUNET_SERVER_notification_context_unicast(nc,
                                               c->handle,
                                               &msg.header,
@@ -1928,6 +1946,7 @@ tunnel_send_fwd_ack (struct MeshTunnel *t, uint16_t type)
     case GNUNET_MESSAGE_TYPE_MESH_ACK:
     case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
       break;
+    case GNUNET_MESSAGE_TYPE_MESH_PATH_ACK:
     case GNUNET_MESSAGE_TYPE_MESH_POLL:
       t->force_ack = GNUNET_YES;
       break;
@@ -1959,10 +1978,10 @@ tunnel_send_fwd_ack (struct MeshTunnel *t, uint16_t type)
   }
 
   t->prev_fc.last_ack_sent = ack;
-  if (0 != t->prev_hop)
-    send_ack (t, t->prev_hop, ack);
-  else if (NULL != t->owner)
+  if (NULL != t->owner)
     send_local_ack (t, t->owner, ack);
+  else if (0 != t->prev_hop)
+    send_ack (t, t->prev_hop, ack);
   else
     GNUNET_break (0);
   debug_fwd_ack++;
@@ -2002,6 +2021,7 @@ tunnel_send_bck_ack (struct MeshTunnel *t, uint16_t type)
     case GNUNET_MESSAGE_TYPE_MESH_ACK:
     case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
       break;
+    case GNUNET_MESSAGE_TYPE_MESH_PATH_ACK:
     case GNUNET_MESSAGE_TYPE_MESH_POLL:
       t->force_ack = GNUNET_YES;
       break;
@@ -2024,16 +2044,82 @@ tunnel_send_bck_ack (struct MeshTunnel *t, uint16_t type)
               ack, t->next_fc.last_ack_sent);
   t->next_fc.last_ack_sent = ack;
 
-  if (0 != t->next_hop)
-    send_ack (t, t->next_hop, ack);
-  else if (NULL != t->client)
+  if (NULL != t->client)
     send_local_ack (t, t->client, ack);
+  else if (0 != t->next_hop)
+    send_ack (t, t->next_hop, ack);
   else
     GNUNET_break (0);
   t->force_ack = GNUNET_NO;
 }
 
 
+/**
+ * Modify the unicast message TID from global to local and send to client.
+ * 
+ * @param t Tunnel on which to send the message.
+ * @param msg Message to modify and send.
+ */
+static void
+tunnel_send_client_ucast (struct MeshTunnel *t,
+                          const struct GNUNET_MESH_Unicast *msg)
+{
+  struct GNUNET_MESH_Unicast *copy;
+  uint16_t size = ntohs (msg->header.size);
+  char cbuf[size];
+
+  if (size < sizeof (struct GNUNET_MESH_Unicast) +
+             sizeof (struct GNUNET_MessageHeader))
+  {
+    GNUNET_break_op (0);
+    return;
+  }
+  if (NULL == t->client)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  copy = (struct GNUNET_MESH_Unicast *) cbuf;
+  memcpy (copy, msg, size);
+  copy->tid = htonl (t->local_tid_dest);
+  GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
+                                              &copy->header, GNUNET_NO);
+}
+
+
+/**
+ * Modify the to_origin  message TID from global to local and send to client.
+ * 
+ * @param t Tunnel on which to send the message.
+ * @param msg Message to modify and send.
+ */
+static void
+tunnel_send_client_to_orig (struct MeshTunnel *t,
+                            const struct GNUNET_MESH_ToOrigin *msg)
+{
+  struct GNUNET_MESH_ToOrigin *copy;
+  uint16_t size = ntohs (msg->header.size);
+  char cbuf[size];
+
+  if (size < sizeof (struct GNUNET_MESH_ToOrigin) +
+             sizeof (struct GNUNET_MessageHeader))
+  {
+    GNUNET_break_op (0);
+    return;
+  }
+  if (NULL == t->owner)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  copy = (struct GNUNET_MESH_ToOrigin *) cbuf;
+  memcpy (cbuf, msg, size);
+  copy->tid = htonl (t->local_tid);
+  GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
+                                              &copy->header, GNUNET_NO);
+}
+
+
 /**
  * @brief Re-initiate traffic to this peer if necessary.
  *
@@ -2081,10 +2167,11 @@ peer_unlock_queue(GNUNET_PEER_Id peer_id)
 
 
 /**
- * Send a message to all peers in this tunnel that the tunnel is no longer
- * valid.
+ * Send a message to all peers and clients in this tunnel that the tunnel
+ * is no longer valid. If some peer or client should not receive the message,
+ * should be zero'ed out before calling this function.
  *
- * @param t The tunnel whose peers to notify.
+ * @param t The tunnel whose peers and clients to notify.
  */
 static void
 tunnel_send_destroy (struct MeshTunnel *t)
@@ -2100,7 +2187,7 @@ tunnel_send_destroy (struct MeshTunnel *t)
               "  sending tunnel destroy for tunnel: %s [%X]\n",
               GNUNET_i2s (&msg.oid), t->id.tid);
 
-  if (0 != t->next_hop)
+  if (NULL == t->client && 0 != t->next_hop)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  child: %u\n", t->next_hop);
     GNUNET_PEER_resolve (t->next_hop, &id);
@@ -2109,7 +2196,7 @@ tunnel_send_destroy (struct MeshTunnel *t)
                 GNUNET_i2s (&id));
     send_prebuilt_message (&msg.header, t->next_hop, t);
   }
-  if (0 != t->prev_hop)
+  if (NULL == t->owner && 0 != t->prev_hop)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  parent: %u\n", t->prev_hop);
     GNUNET_PEER_resolve (t->prev_hop, &id);
@@ -2118,6 +2205,14 @@ tunnel_send_destroy (struct MeshTunnel *t)
                 GNUNET_i2s (&id));
     send_prebuilt_message (&msg.header, t->prev_hop, t);
   }
+  if (NULL != t->owner)
+  {
+    send_client_tunnel_destroy (t->owner, t);
+  }
+  if (NULL != t->client)
+  {
+    send_client_tunnel_destroy (t->client, t);
+  }
 }
 
 
@@ -2134,6 +2229,8 @@ peer_cancel_queues (GNUNET_PEER_Id neighbor, struct MeshTunnel *t)
   struct MeshPeerQueue *pq;
   struct MeshPeerQueue *next;
 
+  if (0 == neighbor)
+    return; /* Was local peer, 0'ed in tunnel_destroy_iterator */
   peer_info = peer_get_short (neighbor);
   for (pq = peer_info->queue_head; NULL != pq; pq = next)
   {
@@ -2158,7 +2255,14 @@ peer_cancel_queues (GNUNET_PEER_Id neighbor, struct MeshTunnel *t)
 
 
 /**
- * Destroy the tunnel and free any allocated resources linked to it.
+ * Destroy the tunnel.
+ * 
+ * This function does not generate any warning traffic to clients or peers.
+ * 
+ * Tasks:
+ * Remove the tunnel from peer_info's and clients' hashmaps.
+ * Cancel messages belonging to this tunnel queued to neighbors.
+ * Free any allocated resources linked to the tunnel.
  *
  * @param t the tunnel to destroy
  *
@@ -2208,6 +2312,7 @@ tunnel_destroy (struct MeshTunnel *t)
 
   if (NULL != t->client)
   {
+    c = t->client;
     GMC_hash32 (t->local_tid_dest, &hash);
     if (GNUNET_YES !=
           GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t))
@@ -2215,31 +2320,40 @@ tunnel_destroy (struct MeshTunnel *t)
       GNUNET_break (0);
       r = GNUNET_SYSERR;
     }
-  }
-  if (GNUNET_YES != 
+    if (GNUNET_YES != 
       GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t))
-  {
-    GNUNET_break (0);
-    r = GNUNET_SYSERR;
+    {
+      GNUNET_break (0);
+      r = GNUNET_SYSERR;
+    }
   }
 
-  peer_cancel_queues (t->next_hop, t);
-  peer_cancel_queues (t->prev_hop, t);
+  if (0 != t->prev_hop)
+  {
+    peer_cancel_queues (t->prev_hop, t);
+    GNUNET_PEER_change_rc (t->prev_hop, -1);
+  }
+  if (0 != t->next_hop)
+  {
+    peer_cancel_queues (t->next_hop, t);
+    GNUNET_PEER_change_rc (t->next_hop, -1);
+  }  
 
   if (GNUNET_SCHEDULER_NO_TASK != t->maintenance_task)
     GNUNET_SCHEDULER_cancel (t->maintenance_task);
 
   n_tunnels--;
   GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
+  path_destroy (t->path);
   GNUNET_free (t);
   return r;
 }
 
-#define TUNNEL_DESTROY_EMPTY_TIME GNUNET_TIME_UNIT_MILLISECONDS
-
 /**
  * Tunnel is empty: destroy it.
  * 
+ * Notifies all participants (peers, cleints) about the destruction.
+ * 
  * @param t Tunnel to destroy. 
  */
 static void
@@ -2256,7 +2370,8 @@ tunnel_destroy_empty (struct MeshTunnel *t)
   }
   #endif
 
-  tunnel_send_destroy (t);
+  if (GNUNET_NO == t->destroy)
+    tunnel_send_destroy (t);
   if (0 == t->pending_messages)
     tunnel_destroy (t);
   else
@@ -2273,8 +2388,8 @@ fc_init (struct MeshFlowControl *fc)
 {
   fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
   fc->last_pid_recv = (uint32_t) -1;
-  fc->last_ack_sent = INITIAL_WINDOW_SIZE - 1;
-  fc->last_ack_recv = INITIAL_WINDOW_SIZE - 1;
+  fc->last_ack_sent = (uint32_t) -1; /* No traffic allowed yet */
+  fc->last_ack_recv = (uint32_t) -1;
   fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
   fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
   fc->queue_n = 0;
@@ -2348,14 +2463,11 @@ tunnel_new (GNUNET_PEER_Id owner,
 
 
 /**
- * tunnel_destroy_iterator: iterator for deleting each tunnel that belongs to a
- * client when the client disconnects. If the client is not the owner, the
- * owner will get notified if no more clients are in the tunnel and the client
- * get removed from the tunnel's list.
+ * Iterator for deleting each tunnel whose client endpoint disconnected.
  *
- * @param cls closure (client that is disconnecting)
- * @param key the hash of the local tunnel id (used to access the hashmap)
- * @param value the value stored at the key (tunnel to destroy)
+ * @param cls Closure (client that has disconnected).
+ * @param key The hash of the local tunnel id (used to access the hashmap).
+ * @param value The value stored at the key (tunnel to destroy).
  *
  * @return GNUNET_OK, keep iterating.
  */
@@ -2367,17 +2479,32 @@ tunnel_destroy_iterator (void *cls,
   struct MeshTunnel *t = value;
   struct MeshClient *c = cls;
 
-  send_client_tunnel_destroy (t);
-  if (c != t->owner)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              " Tunnel %X / %X destroy, due to client %u shutdown.\n",
+              t->local_tid, t->local_tid_dest, c->id);
+  client_delete_tunnel (c, t);
+  if (c == t->client)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %u is destination.\n", c->id);
-    client_delete_tunnel (c, t);
-    tunnel_destroy_empty (t);
-    return GNUNET_OK;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
+    t->client = NULL;
+    GNUNET_PEER_change_rc (t->next_hop, -1);
+    t->next_hop = 0;
   }
-  tunnel_send_destroy (t);
-  t->owner = NULL;
-  t->destroy = GNUNET_YES;
+  else if (c == t->owner)
+  {
+    struct MeshPeerInfo *p;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
+    t->owner = NULL;
+    GNUNET_PEER_change_rc (t->prev_hop, -1);
+    t->prev_hop = 0;
+    p = peer_get_short(t->dest);
+    peer_info_remove_tunnel (p, t);
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+  tunnel_destroy_empty (t);
 
   return GNUNET_OK;
 }
@@ -2402,8 +2529,9 @@ tunnel_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Tunnel %s [%X] timed out. Destroying.\n",
               GNUNET_i2s(&id), t->id.tid);
-  send_client_tunnel_destroy (t);
-  tunnel_destroy (t);
+  if (NULL != t->client)
+    send_client_tunnel_destroy (t->client, t);
+  tunnel_destroy (t); /* Do not notify other */
 }
 
 
@@ -2494,20 +2622,22 @@ send_core_path_create (void *cls, size_t size, void *buf)
 static size_t
 send_core_path_ack (void *cls, size_t size, void *buf)
 {
-  struct MESH_TunnelID *id = cls;
+  struct MeshTunnel *t = cls;
   struct GNUNET_MESH_PathACK *msg = buf;
 
-  GNUNET_assert (NULL != id);
+  GNUNET_assert (NULL != t);
   if (sizeof (struct GNUNET_MESH_PathACK) > size)
   {
     GNUNET_break (0);
     return 0;
   }
+  t->prev_fc.last_ack_sent = t->nobuffer ? 0 : t->queue_max - 1;
   msg->header.size = htons (sizeof (struct GNUNET_MESH_PathACK));
   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
-  GNUNET_PEER_resolve (id->oid, &msg->oid);
-  msg->tid = htonl (id->tid);
+  GNUNET_PEER_resolve (t->id.oid, &msg->oid);
+  msg->tid = htonl (t->id.tid);
   msg->peer_id = my_full_id;
+  msg->ack = htonl (t->prev_fc.last_ack_sent);
 
   /* TODO add signature */
 
@@ -2562,7 +2692,7 @@ queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
                                queue->peer->queue_tail,
                                queue);
 
-  /* Delete from appropiate fc in the tunnel */
+  /* Delete from appropriate fc in the tunnel */
   if (queue->peer->id == queue->tunnel->next_hop)
     fc = &queue->tunnel->next_fc;
   else if (queue->peer->id == queue->tunnel->next_hop)
@@ -2599,12 +2729,12 @@ queue_get_next (const struct MeshPeerInfo *peer)
   uint32_t pid;
   uint32_t ack;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   selecting message\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   selecting message\n");
   for (q = peer->queue_head; NULL != q; q = q->next)
   {
     t = q->tunnel;
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "*********     %s\n",
+                "*     %s\n",
                 GNUNET_MESH_DEBUG_M2S(q->type));
     switch (q->type)
     {
@@ -2620,26 +2750,26 @@ queue_get_next (const struct MeshPeerInfo *peer)
         break;
       default:
         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "*********   OK!\n");
+                    "*   OK!\n");
         return q;
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "*********     ACK: %u, PID: %u\n",
+                "*     ACK: %u, PID: %u\n",
                 ack, pid);
     if (GNUNET_NO == GMC_is_pid_bigger (pid, ack))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "*********   OK!\n");
+                  "*   OK!\n");
       return q;
     }
     else
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "*********     NEXT!\n");
+                  "*     NEXT!\n");
     }
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "*********   nothing found\n");
+                "*   nothing found\n");
   return NULL;
 }
 
@@ -2658,28 +2788,28 @@ queue_send (void *cls, size_t size, void *buf)
 
   peer->core_transmit = NULL;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* Queue send\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Queue send\n");
   queue = queue_get_next (peer);
 
   /* Queue has no internal mesh traffic nor sendable payload */
   if (NULL == queue)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   not ready, return\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   not ready, return\n");
     if (NULL == peer->queue_head)
       GNUNET_break (0); /* Core tmt_rdy should've been canceled */
     return 0;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   not empty\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   not empty\n");
 
   GNUNET_PEER_resolve (peer->id, &dst_id);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "*********   towards %s\n",
+              "*   towards %s\n",
               GNUNET_i2s (&dst_id));
   /* Check if buffer size is enough for the message */
   if (queue->size > size)
   {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "*********   not enough room, reissue\n");
+                  "*   not enough room, reissue\n");
       peer->core_transmit =
           GNUNET_CORE_notify_transmit_ready (core_handle,
                                              GNUNET_NO,
@@ -2691,7 +2821,7 @@ queue_send (void *cls, size_t size, void *buf)
                                              peer);
       return 0;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   size ok\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   size ok\n");
 
   t = queue->tunnel;
   GNUNET_assert (0 < t->pending_messages);
@@ -2709,7 +2839,7 @@ queue_send (void *cls, size_t size, void *buf)
     case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
     case GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE:
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "*********   raw: %s\n",
+                  "*   raw: %s\n",
                   GNUNET_MESH_DEBUG_M2S (queue->type));
       /* Fall through */
     case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
@@ -2719,17 +2849,17 @@ queue_send (void *cls, size_t size, void *buf)
       type = ntohs (msg->type);
       break;
     case GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE:
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   path create\n");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   path create\n");
       data_size = send_core_path_create (queue->cls, size, buf);
       break;
     case GNUNET_MESSAGE_TYPE_MESH_PATH_ACK:
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   path ack\n");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   path ack\n");
       data_size = send_core_path_ack (queue->cls, size, buf);
       break;
     default:
       GNUNET_break (0);
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "*********   type unknown: %u\n",
+                  "*   type unknown: %u\n",
                   queue->type);
       data_size = 0;
   }
@@ -2754,7 +2884,7 @@ queue_send (void *cls, size_t size, void *buf)
 
   if (GNUNET_YES == t->destroy && 0 == t->pending_messages)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********  destroying tunnel!\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*  destroying tunnel!\n");
     tunnel_destroy (t);
   }
 
@@ -2764,7 +2894,7 @@ queue_send (void *cls, size_t size, void *buf)
   {
       struct GNUNET_PeerIdentity id;
 
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********   more data!\n");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*   more data!\n");
       GNUNET_PEER_resolve (peer->id, &id);
       peer->core_transmit =
           GNUNET_CORE_notify_transmit_ready(core_handle,
@@ -2779,7 +2909,7 @@ queue_send (void *cls, size_t size, void *buf)
   else if (NULL != peer->queue_head)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "*********   %s stalled\n",
+                "*   %s stalled\n",
                 GNUNET_i2s (&my_full_id));
     if (peer->id == t->next_hop)
       fc = &t->next_fc;
@@ -2797,7 +2927,7 @@ queue_send (void *cls, size_t size, void *buf)
                                                     &tunnel_poll, fc);
     }
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*********  Return %d\n", data_size);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*  Return %d\n", data_size);
   return data_size;
 }
 
@@ -2897,7 +3027,6 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
   MESH_TunnelNumber tid;
   struct GNUNET_MESH_CreateTunnel *msg;
   struct GNUNET_PeerIdentity *pi;
-  struct GNUNET_HashCode hash;
   struct MeshPeerPath *path;
   struct MeshPeerInfo *dest_peer_info;
   struct MeshPeerInfo *orig_peer_info;
@@ -2920,7 +3049,7 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     return GNUNET_OK;
   }
   size /= sizeof (struct GNUNET_PeerIdentity);
-  if (size < 2)
+  if (size < 1)
   {
     GNUNET_break_op (0);
     return GNUNET_OK;
@@ -2931,9 +3060,9 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
   tid = ntohl (msg->tid);
   pi = (struct GNUNET_PeerIdentity *) &msg[1];
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "    path is for tunnel %s [%X].\n", GNUNET_i2s (pi), tid);
+              "    path is for tunnel %s[%X].\n", GNUNET_i2s (pi), tid);
   t = tunnel_get (pi, tid);
-  if (NULL == t)
+  if (NULL == t) /* might be a local tunnel */
   {
     uint32_t opt;
 
@@ -2956,19 +3085,6 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  nobuffer:%d\n", t->nobuffer);
 
     tunnel_reset_timeout (t);
-    GMC_hash32 (t->local_tid_dest, &hash);
-    if (GNUNET_OK !=
-        GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t,
-                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
-    {
-      tunnel_destroy (t);
-      GNUNET_break (0);
-      return GNUNET_OK;
-    }
-  }
-  else
-  {
-    GNUNET_break_op (0);
   }
   t->state = MESH_TUNNEL_WAITING;
   dest_peer_info =
@@ -3005,9 +3121,8 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
       own_pos = i;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  Own position: %u\n", own_pos);
-  if (own_pos == 0)
+  if (own_pos == 0 && path->peers[own_pos] != myid)
   {
-    /* cannot be self, must be 'not found' */
     /* create path: self not found in path through self */
     GNUNET_break_op (0);
     path_destroy (path);
@@ -3015,8 +3130,8 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     return GNUNET_OK;
   }
   path_add_to_peers (path, GNUNET_NO);
-  t->prev_hop = path->peers[own_pos - 1];
-  GNUNET_PEER_change_rc (t->prev_hop, 1);
+  tunnel_use_path (t, path);
+
   if (own_pos == size - 1)
   {
     struct MeshClient *c;
@@ -3030,7 +3145,6 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
       /* TODO send reject */
       return GNUNET_OK;
     }
-    t->client = c;
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  It's for us!\n");
     peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_YES);
@@ -3042,6 +3156,7 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     t->local_tid_dest = next_local_tid++;
     next_local_tid = next_local_tid | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
 
+    tunnel_add_client (t, c);
     send_client_tunnel_create (t);
     send_path_ack (t);
   }
@@ -3053,17 +3168,98 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     GNUNET_PEER_change_rc(t->next_hop, 1);
 
     /* It's for somebody else! Retransmit. */
-    path2 = path_duplicate (path);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  Retransmitting.\n");
-    peer_info_add_path (dest_peer_info, path2, GNUNET_NO);
     path2 = path_duplicate (path);
-    peer_info_add_path_to_origin (orig_peer_info, path2, GNUNET_NO);
+    peer_info_add_path (dest_peer_info, path2, GNUNET_NO);
+    peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_NO);
     send_create_path (t);
   }
   return GNUNET_OK;
 }
 
 
+
+/**
+ * Core handler for path ACKs
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ *         GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
+                      const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_MESH_PathACK *msg;
+  struct MeshPeerInfo *peer_info;
+  struct MeshPeerPath *p;
+  struct MeshTunnel *t;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n",
+              GNUNET_i2s (&my_full_id));
+  msg = (struct GNUNET_MESH_PathACK *) message;
+  t = tunnel_get (&msg->oid, ntohl(msg->tid));
+  if (NULL == t)
+  {
+    /* TODO notify that we don't know the tunnel */
+    GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  don't know the tunnel %s [%X]!\n",
+                GNUNET_i2s (&msg->oid), ntohl(msg->tid));
+    return GNUNET_OK;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  on tunnel %s [%X]\n",
+              GNUNET_i2s (&msg->oid), ntohl(msg->tid));
+
+  peer_info = peer_get (&msg->peer_id);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  by peer %s\n",
+              GNUNET_i2s (&msg->peer_id));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  via peer %s\n",
+              GNUNET_i2s (peer));
+
+  /* Add path to peers? */
+  p = t->path;
+  if (NULL != p)
+  {
+    path_add_to_peers (p, GNUNET_YES);
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+  t->state = MESH_TUNNEL_READY;
+  t->next_fc.last_ack_recv = (NULL == t->client) ? ntohl (msg->ack) : 0;
+  t->prev_fc.last_ack_sent = ntohl (msg->ack);
+
+  /* Message for us? */
+  if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  It's for us!\n");
+    if (NULL == t->owner)
+    {
+      GNUNET_break_op (0);
+      return GNUNET_OK;
+    }
+    if (NULL != peer_info->dhtget)
+    {
+      GNUNET_DHT_get_stop (peer_info->dhtget);
+      peer_info->dhtget = NULL;
+    }
+    tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
+    tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
+    return GNUNET_OK;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "  not for us, retransmitting...\n");
+  peer_info = peer_get (&msg->oid);
+  send_prebuilt_message (message, t->prev_hop, t);
+  return GNUNET_OK;
+}
+
+
 /**
  * Core handler for notifications of broken paths
  *
@@ -3136,16 +3332,36 @@ handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
                               1, GNUNET_NO);
     return GNUNET_OK;
   }
-  // TODO check owner's signature
   if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
   {
-    /* Tunnel was incoming, notify clients */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "INCOMING TUNNEL %X %X\n",
                 t->local_tid, t->local_tid_dest);
-    send_client_tunnel_destroy (t);
   }
-  tunnel_send_destroy (t);
-  t->destroy = GNUNET_YES;
+  if (GNUNET_PEER_search (peer) == t->prev_hop)
+  {
+    // TODO check owner's signature
+    // TODO add owner's signatue to tunnel for retransmission
+    peer_cancel_queues (t->prev_hop, t);
+    GNUNET_PEER_change_rc (t->prev_hop, -1);
+    t->prev_hop = 0;
+  }
+  else if (GNUNET_PEER_search (peer) == t->next_hop)
+  {
+    // TODO check dest's signature
+    // TODO add dest's signatue to tunnel for retransmission
+    peer_cancel_queues (t->next_hop, t);
+    GNUNET_PEER_change_rc (t->next_hop, -1);
+    t->next_hop = 0;
+  }
+  else
+  {
+    GNUNET_break_op (0);
+    // TODO check both owner AND destination's signature to see which matches
+    // TODO restransmit in appropriate direction
+    return GNUNET_OK;
+  }
+  tunnel_destroy_empty (t);
+
   // TODO: add timeout to destroy the tunnel anyway
   return GNUNET_OK;
 }
@@ -3222,16 +3438,11 @@ handle_mesh_unicast (void *cls, const struct GNUNET_PeerIdentity *peer,
   tunnel_reset_timeout (t);
   if (t->dest == myid)
   {
-    if (NULL == t->client)
-    {
-      GNUNET_break (0);
-      return GNUNET_OK;
-    }
+    /* TODO signature verification */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "  it's for us! sending to clients...\n");
     GNUNET_STATISTICS_update (stats, "# unicast received", 1, GNUNET_NO);
-    GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
-                                                message, GNUNET_NO);
+    tunnel_send_client_ucast (t, msg);
     tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_UNICAST);
     return GNUNET_OK;
   }
@@ -3326,20 +3537,13 @@ handle_mesh_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               " pid %u not seen yet, forwarding\n", pid);
 
-  if (NULL != t->owner)
+  if (myid == t->id.oid)
   {
-    char cbuf[size];
-    struct GNUNET_MESH_ToOrigin *copy;
-
+    /* TODO signature verification */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "  it's for us! sending to clients...\n");
-    /* TODO signature verification */
-    memcpy (cbuf, message, size);
-    copy = (struct GNUNET_MESH_ToOrigin *) cbuf;
-    copy->tid = htonl (t->local_tid);
     GNUNET_STATISTICS_update (stats, "# to origin received", 1, GNUNET_NO);
-    GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
-                                                &copy->header, GNUNET_NO);
+    tunnel_send_client_to_orig (t, msg);
     tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
     return GNUNET_OK;
   }
@@ -3496,82 +3700,6 @@ handle_mesh_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
   return GNUNET_OK;
 }
 
-/**
- * Core handler for path ACKs
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
-                      const struct GNUNET_MessageHeader *message)
-{
-  struct GNUNET_MESH_PathACK *msg;
-  struct MeshPeerInfo *peer_info;
-  struct MeshPeerPath *p;
-  struct MeshTunnel *t;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n",
-              GNUNET_i2s (&my_full_id));
-  msg = (struct GNUNET_MESH_PathACK *) message;
-  t = tunnel_get (&msg->oid, ntohl(msg->tid));
-  if (NULL == t)
-  {
-    /* TODO notify that we don't know the tunnel */
-    GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  don't know the tunnel %s [%X]!\n",
-                GNUNET_i2s (&msg->oid), ntohl(msg->tid));
-    return GNUNET_OK;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  on tunnel %s [%X]\n",
-              GNUNET_i2s (&msg->oid), ntohl(msg->tid));
-
-  peer_info = peer_get (&msg->peer_id);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  by peer %s\n",
-              GNUNET_i2s (&msg->peer_id));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  via peer %s\n",
-              GNUNET_i2s (peer));
-
-  /* Add path to peers? */
-  p = t->path;
-  if (NULL != p)
-  {
-    path_add_to_peers (p, GNUNET_YES);
-  }
-  else
-  {
-    GNUNET_break (0);
-  }
-  t->state = MESH_TUNNEL_READY;
-
-  /* Message for us? */
-  if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  It's for us!\n");
-    if (NULL == t->owner)
-    {
-      GNUNET_break_op (0);
-      return GNUNET_OK;
-    }
-    if (NULL != peer_info->dhtget)
-    {
-      GNUNET_DHT_get_stop (peer_info->dhtget);
-      peer_info->dhtget = NULL;
-    }
-    return GNUNET_OK;
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "  not for us, retransmitting...\n");
-  peer_info = peer_get (&msg->oid);
-  send_prebuilt_message (message, t->prev_hop, t);
-  return GNUNET_OK;
-}
-
 
 /**
  * Core handler for mesh keepalives.
@@ -3963,9 +4091,9 @@ handle_local_tunnel_create (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  t->port = ntohl (t->port);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s [%x] (%x)\n",
-              GNUNET_i2s (&my_full_id), t->id.tid, t->local_tid);
+  t->port = ntohl (t_msg->port);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s[%x]:%u (%x)\n",
+              GNUNET_i2s (&my_full_id), t->id.tid, t->port, t->local_tid);
 
   peer_info = peer_get (&t_msg->peer);
   GNUNET_array_append (peer_info->tunnels, peer_info->ntunnels, t);
@@ -4023,21 +4151,22 @@ handle_local_tunnel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
+
+  /* Cleanup after the tunnel */
+  client_delete_tunnel (c, t);
   if (c == t->client)
   {
-    tunnel_destroy_empty (t);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
+    t->client = NULL;
+  }
+  else if (c == t->owner)
+  {
+    peer_info_remove_tunnel (peer_get_short(t->dest), t);
+    t->owner = NULL;
   }
-  send_client_tunnel_destroy (t);
-  client_delete_tunnel (c, t);
 
-  /* Don't try to ACK the client about the tunnel_destroy multicast packet */
-  t->owner = NULL;
-  tunnel_send_destroy (t);
-  peer_remove_tunnel (peer_get_short(t->dest), t);
-  t->destroy = GNUNET_YES;
   /* The tunnel will be destroyed when the last message is transmitted. */
+  tunnel_destroy_empty (t);
+
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
   return;
 }
@@ -4341,7 +4470,7 @@ handle_local_ack (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
 
-  ack = ntohl (msg->max_pid);
+  ack = ntohl (msg->ack);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  ack %u\n", ack);
 
   /* Does client own tunnel? I.E: Is this an ACK for BCK traffic? */
@@ -4607,6 +4736,24 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
 }
 
 
+/**
+ * Install server (service) handlers and start listening to clients.
+ */
+static void
+server_init (void)
+{
+  GNUNET_SERVER_add_handlers (server_handle, client_handlers);
+  GNUNET_SERVER_disconnect_notify (server_handle,
+                                   &handle_local_client_disconnect, NULL);
+  nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
+
+  clients_head = NULL;
+  clients_tail = NULL;
+  next_client_id = 0;
+  GNUNET_SERVER_resume (server_handle);
+}
+
+
 /**
  * To be called on core init/fail.
  *
@@ -4622,7 +4769,7 @@ core_init (void *cls, struct GNUNET_CORE_Handle *server,
   static int i = 0;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
-  core_handle = server;
+  GNUNET_break (core_handle == server);
   if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)) ||
     NULL == server)
   {
@@ -4647,7 +4794,8 @@ core_init (void *cls, struct GNUNET_CORE_Handle *server,
     if (10 < i++)
       GNUNET_abort();
   }
-    return;
+  server_init ();
+  return;
 }
 
 
@@ -4762,11 +4910,11 @@ key_generation_cb (void *cls,
   struct MeshPeerInfo *peer;
   struct MeshPeerPath *p;
 
-  keygen = NULL;  
+  keygen = NULL;
   if (NULL == pk)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Mesh service could not access hostkey: %s. Exiting.\n"),
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Could not access hostkey: %s. Exiting.\n"),
                 emsg);
     GNUNET_SCHEDULER_shutdown ();
     return;
@@ -4800,17 +4948,6 @@ key_generation_cb (void *cls,
   next_tid = 0;
   next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
 
-
-  GNUNET_SERVER_add_handlers (server_handle, client_handlers);
-  nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
-  GNUNET_SERVER_disconnect_notify (server_handle,
-                                   &handle_local_client_disconnect, NULL);
-
-
-  clients_head = NULL;
-  clients_tail = NULL;
-  next_client_id = 0;
-
   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls);
 
   /* Create a peer_info for the local peer */
@@ -4819,7 +4956,7 @@ key_generation_cb (void *cls,
   p->peers[0] = myid;
   GNUNET_PEER_change_rc (myid, 1);
   peer_info_add_path (peer, p, GNUNET_YES);
-  GNUNET_SERVER_resume (server_handle);
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n");
 }
 
@@ -4839,6 +4976,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
   server_handle = server;
+  GNUNET_SERVER_suspend (server_handle);
 
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
@@ -4956,7 +5094,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
   }
   stats = GNUNET_STATISTICS_create ("mesh", c);
 
-  GNUNET_SERVER_suspend (server_handle);
   /* Scheduled the task to clean up when shutdown is called */
   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
                                 NULL);