Implemented workaround for #2071
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh.c
index 14dd5d1fd1450b3584e97e193505ba5593b1b368..63700504860f550761679d45ac7bb822cfb332f4 100644 (file)
 /** 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;
 };
 
 
@@ -265,6 +276,11 @@ 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.
      */
@@ -723,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);
 }
 
 
@@ -769,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
@@ -783,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))
@@ -819,7 +839,11 @@ 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
@@ -911,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);
   }
 }
 
@@ -950,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
@@ -973,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");
@@ -1098,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.
   *
@@ -1107,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)
@@ -1129,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;
 }
@@ -1141,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;
@@ -1155,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)
   {
@@ -1169,6 +1198,8 @@ 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;
   }
@@ -1460,7 +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;
+    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.
@@ -1477,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;
@@ -1521,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 */
@@ -1690,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
  *
@@ -1848,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;
@@ -1865,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);
   }
 }
@@ -1944,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 = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor));
 
-  info->data = mdata->data;
-  info->size = mdata->data_len;
-  info->copies = mdata->reference_counter;
-  (*(mdata->reference_counter))++;
-
-  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
@@ -1996,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);
 }
 
@@ -2011,13 +2056,13 @@ 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
-  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->t = t;
@@ -2030,22 +2075,22 @@ tunnel_send_multicast (struct MeshTunnel *t,
     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",
+    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");
+    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);
@@ -2055,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");
@@ -2172,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)
@@ -2329,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)
@@ -2357,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;
@@ -2380,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);
@@ -2394,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
@@ -2402,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);
@@ -2490,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");
@@ -2568,11 +2616,12 @@ 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 MeshDataDescriptor *info;
+    struct MeshTransmissionDescriptor *info;
     unsigned int j;
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH:   It's for us!\n");
@@ -2598,7 +2647,7 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
                                                      (&my_full_id),
                                                      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);
@@ -2904,16 +2953,14 @@ handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer,
   {
     /* FIXME: already seen this packet, log dropping */
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "MESH:  Already seen mid %u, DROPPING!\n",
-                t->mid);
+                "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));
+                "MESH:  mid %u not seen yet, forwarding\n", ntohl (msg->mid));
   }
 #endif
   t->mid = ntohl (msg->mid);
@@ -2926,15 +2973,12 @@ 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));
+  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");
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "MESH:  TTL is 0, DROPPING!\n");
     return GNUNET_OK;
   }
   tunnel_send_multicast (t, message);
@@ -3047,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",
@@ -3059,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)))
   {
@@ -3073,8 +3132,7 @@ 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);
-    if (tree_get_status(t->tree, peer_info->id) != MESH_PEER_READY)
+    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);
@@ -3230,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
@@ -3253,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;
 }
@@ -3278,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
@@ -3309,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);
 }
@@ -3835,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),
@@ -3846,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 */
@@ -4299,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);