Implemented workaround for #2071
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh.c
index a5113e52b9580f8f2774312fb6b124cf437a721e..63700504860f550761679d45ac7bb822cfb332f4 100644 (file)
@@ -41,6 +41,7 @@
  * - speed requirement specification (change?) in mesh API -- API call
  * - add ping message
  * - relay corking down to core
+ * - set ttl relative to tree depth
  */
 
 #include "platform.h"
 #define UNACKNOWLEDGED_WAIT     GNUNET_TIME_relative_multiply(\
                                     GNUNET_TIME_UNIT_SECONDS,\
                                     2)
+#define DEFAULT_TTL     64
 
 #define MESH_DEBUG_DHT GNUNET_NO
 
+
+
 /******************************************************************************/
 /************************      DATA STRUCTURES     ****************************/
 /******************************************************************************/
 /** FWD declaration */
 struct MeshPeerInfo;
 
+
+/**
+ * Struct representing a piece of data being sent to other peers
+ */
+struct MeshData
+{
+  /** Tunnel it belongs to. */
+  struct MeshTunnel *t;
+
+  /** In case of a multicast, task to allow a client to send more data if
+   * some neighbor is too slow. */
+  GNUNET_SCHEDULER_TaskIdentifier *task;
+
+  /** How many remaining neighbors we need to send this to. */
+  unsigned int *reference_counter;
+
+  /** Size of the data. */
+  size_t data_len;
+
+  /** Data itself */
+  void *data;
+};
+
+
 /**
  * Struct containing all info possibly needed to build a package when called
  * back by core.
  */
-struct MeshDataDescriptor
+struct MeshTransmissionDescriptor
 {
     /** ID of the tunnel this packet travels in */
   struct MESH_TunnelID *origin;
 
-    /** Data itself */
-  void *data;
-
-    /** Client that asked for the transmission, if any */
-  struct GNUNET_SERVER_Client *client;
-
     /** Who was this message being sent to */
   struct MeshPeerInfo *peer;
 
     /** Ultimate destination of the packet */
   GNUNET_PEER_Id destination;
 
-    /** Number of identical messages sent to different hops (multicast) */
-  unsigned int *copies;
-
     /** Which handler was used to request the transmission */
   unsigned int handler_n;
 
-    /** Size of the data */
-  size_t size;
-
-    /** Used to allow a client send more traffic to the service after a
-     * previous packet was tried to be sent to a neighbor and couldn't */
-  GNUNET_SCHEDULER_TaskIdentifier *timeout_task;
+    /** Data descriptor */
+  struct MeshData* mesh_data;
 };
 
 
@@ -261,6 +276,16 @@ struct MeshTunnel
      */
   MESH_TunnelNumber local_tid;
 
+      /**
+     * Local tunnel number for local destination clients
+     */
+  MESH_TunnelNumber local_tid_dest;
+
+    /**
+     * ID of the last multicast packet seen/sent.
+     */
+  uint32_t mid;
+
     /**
      * Last time the tunnel was used
      */
@@ -396,7 +421,7 @@ struct MeshClient
 /************************      DEBUG FUNCTIONS     ****************************/
 /******************************************************************************/
 
-
+#if MESH_DEBUG
 /**
  * GNUNET_SCHEDULER_Task for printing a message after some operation is done
  * @param cls string to print
@@ -413,7 +438,7 @@ mesh_debug (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: %s\n", s);
 }
-
+#endif
 
 /******************************************************************************/
 /***********************      GLOBAL VARIABLES     ****************************/
@@ -714,17 +739,18 @@ client_is_subscribed (uint16_t message_type, struct MeshClient *c)
 static void
 client_allow_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct MeshDataDescriptor *info = cls;
+  struct MeshData *mdata = cls;
 
   if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason)
     return;
 #if MESH_DEBUG
+  GNUNET_assert (NULL != mdata->reference_counter);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "MESH: CLIENT ALLOW SEND DESPITE %u COPIES PENDING\n",
-              *(info->copies));
+              mdata->reference_counter);
 #endif
-  *(info->timeout_task) = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_SERVER_receive_done (info->client, GNUNET_OK);
+  *(mdata->task) = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_SERVER_receive_done (mdata->t->client->handle, GNUNET_OK);
 }
 
 
@@ -760,6 +786,7 @@ tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1,
  * Send the message to all clients that have subscribed to its type
  *
  * @param msg Pointer to the message itself
+ * @param payload Pointer to the payload of the message.
  * @return number of clients this message was sent to
  */
 static unsigned int
@@ -774,9 +801,11 @@ send_subscribed_clients (const struct GNUNET_MessageHeader *msg,
   uint16_t type;
   char cbuf[htons (msg->size)];
 
+#if MESH_DEBUG
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Sending to clients...\n");
   type = ntohs (payload->type);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: message of type %u\n", type);
+#endif
 
   memcpy (cbuf, msg, sizeof (cbuf));
   switch (htons (msg->type))
@@ -810,10 +839,16 @@ send_subscribed_clients (const struct GNUNET_MessageHeader *msg,
     GNUNET_break (0);
     return 0;
   }
-  *tid = htonl (t->local_tid);
+  // FIXME proper client differentiation mechanism required
+  if (htons (msg->type) == GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN)
+    *tid = htonl (t->local_tid);
+  else
+    *tid = htonl (t->local_tid_dest != 0 ? t->local_tid_dest : t->local_tid);
   for (count = 0, c = clients; c != NULL; c = c->next)
   {
+#if MESH_DEBUG
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:    client %u\n", c->id);
+#endif
     if (client_is_subscribed (type, c))
     {
       count++;
@@ -900,29 +935,30 @@ send_core_data_multicast (void *cls, size_t size, void *buf);
 /**
  * Decrements the reference counter and frees all resources if needed
  *
- * @param dd Data Descriptor used in a multicast message
+ * @param dd Data Descriptor used in a multicast message. Freed if needed.
  */
 static void
-data_descriptor_decrement_multicast (struct MeshDataDescriptor *dd)
+data_descriptor_decrement_multicast (struct MeshData *mesh_data)
 {
-  if (0 == --(*(dd->copies)))
+  /* Make sure it's a multicast packet */
+  GNUNET_assert (NULL != mesh_data->reference_counter);
+
+  if (0 == --(*(mesh_data->reference_counter)))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Last copy!\n");
-    if (NULL != dd->client)
+    if (NULL != mesh_data->task)
     {
-      if (GNUNET_SCHEDULER_NO_TASK != *(dd->timeout_task))
+      if (GNUNET_SCHEDULER_NO_TASK != *(mesh_data->task))
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "MESH:  cancelling client timeout (%u)...\n",
-                    *(dd->timeout_task));
-        GNUNET_SCHEDULER_cancel (*(dd->timeout_task));
+        GNUNET_SCHEDULER_cancel (*(mesh_data->task));
         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:  notifying client...\n");
-        GNUNET_SERVER_receive_done (dd->client, GNUNET_OK);
+        GNUNET_SERVER_receive_done (mesh_data->t->client->handle, GNUNET_OK);
       }
-      GNUNET_free (dd->timeout_task);
+      GNUNET_free (mesh_data->task);
     }
-    GNUNET_free (dd->copies);
-    GNUNET_free (dd->data);
+    GNUNET_free (mesh_data->reference_counter);
+    GNUNET_free (mesh_data->data);
+    GNUNET_free (mesh_data);
   }
 }
 
@@ -939,7 +975,7 @@ peer_info_cancel_transmission (struct MeshPeerInfo *peer, unsigned int i)
 {
   if (NULL != peer->core_transmit[i])
   {
-    struct MeshDataDescriptor *dd;
+    struct MeshTransmissionDescriptor *dd;
     struct MeshPathInfo *path_info;
 
 #if MESH_DEBUG
@@ -962,7 +998,7 @@ peer_info_cancel_transmission (struct MeshPeerInfo *peer, unsigned int i)
     case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:    type payload\n");
       dd = peer->infos[i];
-      data_descriptor_decrement_multicast (dd);
+      data_descriptor_decrement_multicast (dd->mesh_data);
       break;
     case GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE:
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:    type create path\n");
@@ -1087,7 +1123,7 @@ peer_info_delete_tunnel (void *cls, const GNUNET_HashCode * key, void *value)
 /**
   * Core callback to write a
   *
-  * @param cls Closure (MeshDataDescriptor with data in "data" member).
+  * @param cls Closure (MeshTransmissionDescriptor with data in "data" member).
   * @param size Number of bytes available in buf.
   * @param buf Where the to write the message.
   *
@@ -1096,13 +1132,13 @@ peer_info_delete_tunnel (void *cls, const GNUNET_HashCode * key, void *value)
 static size_t
 send_core_data_raw (void *cls, size_t size, void *buf)
 {
-  struct MeshDataDescriptor *info = cls;
+  struct MeshTransmissionDescriptor *info = cls;
   struct GNUNET_MessageHeader *msg;
   size_t total_size;
 
   GNUNET_assert (NULL != info);
-  GNUNET_assert (NULL != info->data);
-  msg = (struct GNUNET_MessageHeader *) info->data;
+  GNUNET_assert (NULL != info->mesh_data);
+  msg = (struct GNUNET_MessageHeader *) info->mesh_data->data;
   total_size = ntohs (msg->size);
 
   if (total_size > size)
@@ -1118,7 +1154,7 @@ send_core_data_raw (void *cls, size_t size, void *buf)
   }
   info->peer->core_transmit[info->handler_n] = NULL;
   memcpy (buf, msg, total_size);
-  GNUNET_free (info->data);
+  GNUNET_free (info->mesh_data);
   GNUNET_free (info);
   return total_size;
 }
@@ -1130,12 +1166,14 @@ send_core_data_raw (void *cls, size_t size, void *buf)
  *
  * @param message Message to send. Fucntion makes a copy of it.
  * @param peer Short ID of the neighbor whom to send the message.
+ *
+ * FIXME tunnel?
  */
 static void
 send_message (const struct GNUNET_MessageHeader *message,
               const struct GNUNET_PeerIdentity *peer)
 {
-  struct MeshDataDescriptor *info;
+  struct MeshTransmissionDescriptor *info;
   struct MeshPeerInfo *neighbor;
   struct MeshPeerPath *p;
   unsigned int i;
@@ -1144,9 +1182,11 @@ send_message (const struct GNUNET_MessageHeader *message,
 //   GNUNET_TRANSPORT_try_connect();
 
   size = ntohs (message->size);
-  info = GNUNET_malloc (sizeof (struct MeshDataDescriptor));
-  info->data = GNUNET_malloc (size);
-  memcpy (info->data, message, size);
+  info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor));
+  info->mesh_data = GNUNET_malloc (sizeof (struct MeshData));
+  info->mesh_data->data = GNUNET_malloc (size);
+  memcpy (info->mesh_data->data, message, size);
+  info->mesh_data->data_len = size;
   neighbor = peer_info_get (peer);
   for (p = neighbor->path_head; NULL != p; p = p->next)
   {
@@ -1158,6 +1198,9 @@ send_message (const struct GNUNET_MessageHeader *message,
   if (NULL == p)
   {
     GNUNET_break (0);
+    GNUNET_free (info->mesh_data->data);
+    GNUNET_free (info->mesh_data);
+    GNUNET_free (info);
     return;
   }
   i = peer_info_transmit_slot (neighbor);
@@ -1266,7 +1309,7 @@ send_destroy_path (struct MeshTunnel *t, GNUNET_PEER_Id destination)
     {
       GNUNET_PEER_resolve (p->peers[i], &pi[i]);
     }
-    send_message (&msg->header, path_get_first_hop (t->tree, destination));
+    send_message (&msg->header, tree_get_first_hop (t->tree, destination));
   }
   path_destroy (p);
 }
@@ -1448,6 +1491,8 @@ peer_info_remove_path (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
   for (i = 0; i < peer->ntunnels; i++)
   {
     d = tunnel_notify_connection_broken (peer->tunnels[i], p1, p2);
+    if (0 == d)
+      continue;
     /* TODO
      * Problem: one or more peers have been deleted from the tunnel tree.
      * We don't know who they are to try to add them again.
@@ -1464,7 +1509,7 @@ peer_info_remove_path (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
     aux = NULL;
     for (p = peer_d->path_head; NULL != p; p = p->next)
     {
-      if ((cost = path_get_cost (peer->tunnels[i]->tree, p)) < best)
+      if ((cost = tree_get_path_cost (peer->tunnels[i]->tree, p)) < best)
       {
         best = cost;
         aux = p;
@@ -1472,7 +1517,9 @@ peer_info_remove_path (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
     }
     if (NULL != aux)
     {
-      /* No callback, as peer will be already disconnected */
+      /* No callback, as peer will be already disconnected and a connection
+       * scheduled by tunnel_notify_connection_broken.
+       */
       tree_add_path (peer->tunnels[i]->tree, aux, NULL, NULL);
     }
     else
@@ -1506,6 +1553,12 @@ peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path,
     path_destroy (path);
     return;
   }
+  if (path->peers[path->length - 1] != peer_info->id)
+  {
+    GNUNET_break (0);
+    path_destroy (path);
+    return;
+  }
   if (path->length <= 2 && GNUNET_NO == trusted)
   {
     /* Only allow CORE to tell us about direct paths */
@@ -1518,7 +1571,7 @@ peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path,
     if (path->peers[l] == myid)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: shortening path by %u\n", l);
-      for (l2 = 0; l2 < path->length - l - 1; l2++)
+      for (l2 = 0; l2 < path->length - l; l2++)
       {
         path->peers[l2] = path->peers[l + l2];
       }
@@ -1675,6 +1728,32 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
 }
 
 
+/**
+ * Adds a path to the peer_infos of all the peers in the path
+ *
+ * @param p Path to process.
+ * @param confirmed Whether we know if the path works or not. FIXME use
+ */
+static void
+path_add_to_peers (struct MeshPeerPath *p, int confirmed)
+{
+  unsigned int i;
+
+  /* TODO: invert and add */
+  for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
+  for (i++; i < p->length; i++)
+  {
+    struct MeshPeerInfo *aux;
+    struct MeshPeerPath *copy;
+
+    aux = peer_info_get_short (p->peers[i]);
+    copy = path_duplicate (p);
+    copy->length = i + 1;
+    peer_info_add_path (aux, copy, GNUNET_NO);
+  }
+}
+
+
 /**
  * Send keepalive packets for a peer
  *
@@ -1833,10 +1912,10 @@ tunnel_add_peer (struct MeshTunnel *t, struct MeshPeerInfo *peer)
   if (NULL != (p = peer->path_head))
   {
     best_p = p;
-    best_cost = path_get_cost (t->tree, p);
+    best_cost = tree_get_path_cost (t->tree, p);
     while (NULL != p)
     {
-      if ((cost = path_get_cost (t->tree, p)) < best_cost)
+      if ((cost = tree_get_path_cost (t->tree, p)) < best_cost)
       {
         best_cost = cost;
         best_p = p;
@@ -1850,7 +1929,7 @@ tunnel_add_peer (struct MeshTunnel *t, struct MeshPeerInfo *peer)
   }
   else
   {
-    /* Start a DHT get if necessary */
+    /* Start a DHT get */
     peer_info_connect (peer, t);
   }
 }
@@ -1873,12 +1952,10 @@ tunnel_add_path (struct MeshTunnel *t, struct MeshPeerPath *p,
 
   GNUNET_assert (0 != own_pos);
   tree_add_path (t->tree, p, NULL, NULL);
-  if (tree_get_me (t->tree) == 0)
-    tree_set_me (t->tree, p->peers[own_pos]);
   if (own_pos < p->length - 1)
   {
     GNUNET_PEER_resolve (p->peers[own_pos + 1], &id);
-    tree_update_first_hops (t->tree, tree_get_me (t->tree), &id);
+    tree_update_first_hops (t->tree, myid, &id);
   }
 }
 
@@ -1931,43 +2008,24 @@ tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1,
 }
 
 
-struct MeshMulticastData
-{
-  struct MeshTunnel *t;
-
-  GNUNET_SCHEDULER_TaskIdentifier *task;
-
-  unsigned int *reference_counter;
-
-  size_t data_len;
-
-  void *data;
-};
-
-
 /**
  * Send a multicast packet to a neighbor.
+ *
+ * @param cls Closure (Info about the multicast packet)
+ * @param neighbor_id Short ID of the neighbor to send the packet to.
  */
 static void
 tunnel_send_multicast_iterator (void *cls, GNUNET_PEER_Id neighbor_id)
 {
-  struct MeshMulticastData *mdata = cls;
-  struct MeshDataDescriptor *info;
+  struct MeshData *mdata = cls;
+  struct MeshTransmissionDescriptor *info;
   struct GNUNET_PeerIdentity neighbor;
   unsigned int i;
 
-  info = GNUNET_malloc (sizeof (struct MeshDataDescriptor));
-
-  info->data = mdata->data;
-  info->size = mdata->data_len;
-  info->copies = mdata->reference_counter;
-  (*(mdata->reference_counter))++;
+  info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor));
 
-  if (NULL != mdata->t->client)
-  {
-    info->client = mdata->t->client->handle;
-    info->timeout_task = mdata->task;
-  }
+  info->mesh_data = mdata;
+  (*(mdata->reference_counter)) ++;
   info->destination = neighbor_id;
   GNUNET_PEER_resolve (neighbor_id, &neighbor);
 #if MESH_DEBUG
@@ -1983,7 +2041,7 @@ tunnel_send_multicast_iterator (void *cls, GNUNET_PEER_Id neighbor_id)
   info->peer->core_transmit[i] =
       GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0,
                                          GNUNET_TIME_UNIT_FOREVER_REL,
-                                         &neighbor, info->size,
+                                         &neighbor, info->mesh_data->data_len,
                                          &send_core_data_multicast, info);
 }
 
@@ -1998,25 +2056,41 @@ static void
 tunnel_send_multicast (struct MeshTunnel *t,
                        const struct GNUNET_MessageHeader *msg)
 {
-  struct MeshMulticastData *mdata;
+  struct MeshData *mdata;
 
 #if MESH_DEBUG
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "MESH:  sending a multicast packet...\n");
 #endif
-  GNUNET_assert (tree_get_me (t->tree) != 0);
-  mdata = GNUNET_malloc (sizeof (struct MeshMulticastData));
+  mdata = GNUNET_malloc (sizeof (struct MeshData));
   mdata->data_len = ntohs (msg->size);
   mdata->reference_counter = GNUNET_malloc (sizeof (unsigned int));
-  mdata->data = GNUNET_malloc (mdata->data_len);
   mdata->t = t;
+  mdata->data = GNUNET_malloc (mdata->data_len);
   memcpy (mdata->data, msg, mdata->data_len);
+  if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST)
+  {
+    struct GNUNET_MESH_Multicast *mcast;
+
+    mcast = (struct GNUNET_MESH_Multicast *) mdata->data;
+    mcast->ttl = htonl (ntohl (mcast->ttl) - 1);
+#if MESH_DEBUG
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   data packet, ttl: %u\n",
+                ntohl (mcast->ttl));
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   not a data packet, no ttl\n");
+#endif
+  }
   if (NULL != t->client)
   {
     mdata->task = GNUNET_malloc (sizeof (GNUNET_SCHEDULER_TaskIdentifier));
-    *(mdata->task) =
+    (*(mdata->task)) =
         GNUNET_SCHEDULER_add_delayed (UNACKNOWLEDGED_WAIT, &client_allow_send,
-                                      t->client->handle);
+                                      mdata);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: timeout task %u\n",
+                *(mdata->task));
   }
 
   tree_iterate_children (t->tree, &tunnel_send_multicast_iterator, mdata);
@@ -2026,10 +2100,13 @@ tunnel_send_multicast (struct MeshTunnel *t,
     GNUNET_free (mdata->reference_counter);
     if (NULL != mdata->task)
     {
+      GNUNET_SCHEDULER_cancel(*(mdata->task));
       GNUNET_free (mdata->task);
+      GNUNET_SERVER_receive_done(t->client->handle, GNUNET_OK);
     }
+    // FIXME change order?
+    GNUNET_free (mdata);
   }
-  GNUNET_free (mdata);
 #if MESH_DEBUG
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "MESH:  sending a multicast packet done\n");
@@ -2143,7 +2220,7 @@ tunnel_destroy (struct MeshTunnel *t)
  * The tunnel itself is also destoyed if results in a remote empty tunnel.
  *
  * @param t Tunnel from which to remove the path.
- * @param p Peer which should be removed.
+ * @param peer Short id of the peer which should be removed.
  */
 static void
 tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer)
@@ -2248,7 +2325,7 @@ send_core_create_path (void *cls, size_t size, void *buf)
     info->peer->core_transmit[info->pos] =
         GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0,
                                            GNUNET_TIME_UNIT_FOREVER_REL,
-                                           path_get_first_hop (t->tree,
+                                           tree_get_first_hop (t->tree,
                                                                peer->id),
                                            size_needed, &send_core_create_path,
                                            info);
@@ -2300,13 +2377,13 @@ send_core_create_path (void *cls, size_t size, void *buf)
 static size_t
 send_core_data_multicast (void *cls, size_t size, void *buf)
 {
-  struct MeshDataDescriptor *info = cls;
+  struct MeshTransmissionDescriptor *info = cls;
   size_t total_size;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Multicast callback.\n");
   GNUNET_assert (NULL != info);
   GNUNET_assert (NULL != info->peer);
-  total_size = info->size;
+  total_size = info->mesh_data->data_len;
   GNUNET_assert (total_size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
 
   if (total_size > size)
@@ -2328,7 +2405,7 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
   info->peer->core_transmit[info->handler_n] = NULL;
   info->peer->infos[info->handler_n] = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:  copying data...\n");
-  memcpy (buf, info->data, total_size);
+  memcpy (buf, info->mesh_data->data, total_size);
 #if MESH_DEBUG
   {
     struct GNUNET_MESH_Multicast *mc;
@@ -2351,7 +2428,7 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
     }
   }
 #endif
-  data_descriptor_decrement_multicast (info);
+  data_descriptor_decrement_multicast (info->mesh_data);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: freeing info...\n");
   GNUNET_free (info);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: return %u\n", total_size);
@@ -2365,7 +2442,7 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
  * NULL and "size" zero if the socket was closed for
  * writing in the meantime.
  *
- * @param cls closure (MeshDataDescriptor)
+ * @param cls closure (MeshTransmissionDescriptor)
  * @param size number of bytes available in buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
@@ -2373,7 +2450,7 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
 static size_t
 send_core_path_ack (void *cls, size_t size, void *buf)
 {
-  struct MeshDataDescriptor *info = cls;
+  struct MeshTransmissionDescriptor *info = cls;
   struct GNUNET_MESH_PathACK *msg = buf;
 
   GNUNET_assert (NULL != info);
@@ -2461,9 +2538,9 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
 
   tid = ntohl (msg->tid);
   pi = (struct GNUNET_PeerIdentity *) &msg[1];
-  t = tunnel_get (pi, tid);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "MESH:     path is for tunnel %s [%X].\n", GNUNET_i2s (pi), tid);
+  t = tunnel_get (pi, tid);
   if (NULL == t)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   Creating tunnel\n");
@@ -2539,26 +2616,38 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     /* FIXME error. destroy tunnel? leave for timeout? */
     return 0;
   }
+  path_add_to_peers (path, GNUNET_NO);
   tunnel_add_path (t, path, own_pos);
   if (own_pos == size - 1)
   {
     /* It is for us! Send ack. */
-    struct GNUNET_MESH_TunnelNotification cmsg;
-    struct MeshDataDescriptor *info;
+    struct MeshTransmissionDescriptor *info;
     unsigned int j;
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   It's for us!\n");
     peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_NO);
     if (NULL == t->peers)
+    {
+      /* New tunnel! Notify clients! */
+      struct GNUNET_MESH_TunnelNotification cmsg;
+
+      cmsg.header.size = htons (sizeof (cmsg));
+      cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
+      GNUNET_PEER_resolve (t->id.oid, &cmsg.peer);
+      cmsg.tunnel_id = htonl (t->local_tid);
+      GNUNET_SERVER_notification_context_broadcast (nc, &cmsg.header,
+                                                    GNUNET_NO);
+
       t->peers = GNUNET_CONTAINER_multihashmap_create (4);
+    }
     GNUNET_break (GNUNET_OK ==
                   GNUNET_CONTAINER_multihashmap_put (t->peers,
                                                      &my_full_id.hashPubKey,
                                                      peer_info_get
                                                      (&my_full_id),
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
     /* FIXME use send_message */
-    info = GNUNET_malloc (sizeof (struct MeshDataDescriptor));
+    info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor));
     info->origin = &t->id;
     info->peer = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
     GNUNET_assert (NULL != info->peer);
@@ -2571,11 +2660,6 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
                                            GNUNET_TIME_UNIT_FOREVER_REL, peer,
                                            sizeof (struct GNUNET_MESH_PathACK),
                                            &send_core_path_ack, info);
-    cmsg.header.size = htons (sizeof (cmsg));
-    cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
-    GNUNET_PEER_resolve (t->id.oid, &cmsg.peer);
-    cmsg.tunnel_id = htonl (t->local_tid);
-    GNUNET_SERVER_notification_context_broadcast (nc, &cmsg.header, GNUNET_NO);
   }
   else
   {
@@ -2819,7 +2903,7 @@ handle_mesh_data_unicast (void *cls, const struct GNUNET_PeerIdentity *peer,
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "MESH:   not for us, retransmitting...\n");
-  send_message (message, path_get_first_hop (t->tree, pid));
+  send_message (message, tree_get_first_hop (t->tree, pid));
   return GNUNET_OK;
 }
 
@@ -2865,6 +2949,21 @@ handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer,
     GNUNET_break_op (0);
     return GNUNET_OK;
   }
+  if (t->mid == ntohl (msg->mid))
+  {
+    /* FIXME: already seen this packet, log dropping */
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "MESH:  Already seen mid %u, DROPPING!\n", t->mid);
+    return GNUNET_OK;
+  }
+#if MESH_DEBUG
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "MESH:  mid %u not seen yet, forwarding\n", ntohl (msg->mid));
+  }
+#endif
+  t->mid = ntohl (msg->mid);
   tunnel_reset_timeout (t);
 
   /* Transmit to locally interested clients */
@@ -2873,6 +2972,15 @@ handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer,
   {
     send_subscribed_clients (message, &msg[1].header);
   }
+#if MESH_DEBUG
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:    ttl: %u\n", ntohl (msg->ttl));
+#endif
+  if (ntohl (msg->ttl) == 0)
+  {
+    /* FIXME: ttl is 0, log dropping */
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "MESH:  TTL is 0, DROPPING!\n");
+    return GNUNET_OK;
+  }
   tunnel_send_multicast (t, message);
   return GNUNET_OK;
 }
@@ -2983,6 +3091,7 @@ handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
   struct GNUNET_MESH_PathACK *msg;
   struct GNUNET_PeerIdentity id;
   struct MeshPeerInfo *peer_info;
+  struct MeshPeerPath *p;
   struct MeshTunnel *t;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Received a path ACK msg [%s]\n",
@@ -2995,6 +3104,20 @@ handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
     return GNUNET_OK;
   }
 
+  peer_info = peer_info_get (&msg->peer_id);
+
+  /* Add paths to peers? */
+  p = tree_get_path_to_peer (t->tree, peer_info->id);
+  if (NULL != p)
+  {
+    path_add_to_peers (p, GNUNET_YES);
+    path_destroy (p);
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+
   /* Message for us? */
   if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity)))
   {
@@ -3009,9 +3132,11 @@ handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
       GNUNET_DHT_get_stop (t->dht_get_type);
       t->dht_get_type = NULL;
     }
-    peer_info = peer_info_get (&msg->peer_id);
-    tree_set_status (t->tree, peer_info->id, MESH_PEER_READY);
-    send_client_peer_connected (t, peer_info->id);
+    if (tree_get_status (t->tree, peer_info->id) != MESH_PEER_READY)
+    {
+      tree_set_status (t->tree, peer_info->id, MESH_PEER_READY);
+      send_client_peer_connected (t, peer_info->id);
+    }
     return GNUNET_OK;
   }
 
@@ -3163,6 +3288,10 @@ path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the put_path
  * @param type type of the result
  * @param size number of bytes in data
  * @param data pointer to the result data
@@ -3186,18 +3315,16 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Got results from DHT!\n");
   GNUNET_PEER_resolve (path_info->peer->id, &pi);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   for %s\n", GNUNET_i2s (&pi));
-//   GNUNET_DHT_get_stop(path_info->peer->dhtget);
-//   path_info->peer->dhtget = NULL;
 
   p = path_build_from_dht (get_path, get_path_length, put_path,
                            put_path_length);
-  peer_info_add_path (path_info->peer, p, GNUNET_NO);
+  path_add_to_peers (p, GNUNET_NO);
+  path_destroy(p);
   for (i = 0; i < path_info->peer->ntunnels; i++)
   {
     tunnel_add_peer (path_info->peer->tunnels[i], path_info->peer);
     peer_info_connect (path_info->peer, path_info->t);
   }
-//   GNUNET_free (path_info);
 
   return;
 }
@@ -3211,6 +3338,10 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
  * @param cls closure
  * @param exp when will this value expire
  * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the put_path
  * @param type type of the result
  * @param size number of bytes in data
  * @param data pointer to the result data
@@ -3242,7 +3373,8 @@ dht_get_type_handler (void *cls, struct GNUNET_TIME_Absolute exp,
 
   p = path_build_from_dht (get_path, get_path_length, put_path,
                            put_path_length);
-  peer_info_add_path (peer_info, p, GNUNET_NO);
+  path_add_to_peers (p, GNUNET_NO);
+  path_destroy(p);
   tunnel_add_peer (t, peer_info);
   peer_info_connect (peer_info, t);
 }
@@ -3354,9 +3486,9 @@ handle_local_new_client (void *cls, struct GNUNET_SERVER_Client *client,
   c = GNUNET_malloc (sizeof (struct MeshClient));
 #if MESH_DEBUG
   c->id = next_client_id++;
-#endif
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   CLIENT NEW %u at %p\n", c->id,
               c);
+#endif
   c->handle = client;
   GNUNET_SERVER_client_keep (client);
   a = (GNUNET_MESH_ApplicationType *) &cc_msg[1];
@@ -3504,7 +3636,6 @@ handle_local_tunnel_create (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
   t->tree = tree_new (myid);
-  tree_set_me (t->tree, myid);
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
   return;
@@ -3769,8 +3900,12 @@ handle_local_connect_by_type (void *cls, struct GNUNET_SERVER_Client *client,
       GNUNET_YES)
   {
     /* Yes! Fast forward, add ourselves to the tunnel and send the
-     * good news to the client
+     * good news to the client, and alert the destination client of
+     * an incoming tunnel.
      */
+    struct GNUNET_MESH_TunnelNotification cmsg;
+    struct MeshClient *c;
+
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:  available locally\n");
     GNUNET_CONTAINER_multihashmap_put (t->peers, &my_full_id.hashPubKey,
                                        peer_info_get (&my_full_id),
@@ -3780,6 +3915,20 @@ handle_local_connect_by_type (void *cls, struct GNUNET_SERVER_Client *client,
     send_client_peer_connected (t, myid);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:  Done\n");
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
+
+    /* FIXME implement a proper handling of this case,
+       a client differentiation mechanism */
+    cmsg.header.size = htons (sizeof (cmsg));
+    cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
+    cmsg.peer = my_full_id;
+    t->local_tid_dest = next_local_tid++;
+    cmsg.tunnel_id = htonl (t->local_tid_dest);
+    c = (struct MeshClient *) GNUNET_CONTAINER_multihashmap_get(applications,
+                                                                &hash);
+    GNUNET_SERVER_notification_context_unicast (nc, c->handle, &cmsg.header,
+                                                GNUNET_NO);
+    
+
     return;
   }
   /* Ok, lets find a peer offering the service */
@@ -4038,6 +4187,8 @@ handle_local_multicast (void *cls, struct GNUNET_SERVER_Client *client,
     memcpy (buf, message, ntohs (message->size));
     copy->oid = my_full_id;
     copy->tid = htonl (t->id.tid);
+    copy->ttl = htonl (DEFAULT_TTL);
+    copy->mid = htonl (t->mid + 1);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "MESH:   calling generic handler...\n");
     handle_mesh_data_multicast (client, &my_full_id, &copy->header, NULL, 0);
@@ -4231,7 +4382,7 @@ static void
 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: shutting down\n");
-  /* TODO: destroy tunnels? */
+
   if (core_handle != NULL)
   {
     GNUNET_CORE_disconnect (core_handle);