Fixed a memory leak when receiving a second create path for the same tunnel
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh.c
index 59c5174ac326fe741ab89a1fc5856396b3fccc64..9d3784567842a9832f81a28a154b59061c3e334b 100644 (file)
@@ -1130,7 +1130,7 @@ send_core_data_raw (void *cls, size_t size, void *buf)
  * Sends an already built message to a peer, properly registrating
  * all used resources.
  *
- * @param message Message to send.
+ * @param message Message to send. Fucntion makes a copy of it.
  * @param peer Short ID of the neighbor whom to send the message.
  */
 static void
@@ -1236,10 +1236,7 @@ send_create_path (struct MeshPeerInfo *peer,
 static void
 send_destroy_path (struct MeshTunnel *t, GNUNET_PEER_Id destination)
 {
-  struct GNUNET_MESH_ManipulatePath *msg;
-  struct GNUNET_PeerIdentity *pi;
   struct MeshPeerPath *p;
-  unsigned int i;
   size_t size;
 
   p = tree_get_path_to_peer(t->tree, destination);
@@ -1250,16 +1247,23 @@ send_destroy_path (struct MeshTunnel *t, GNUNET_PEER_Id destination)
   }
   size = sizeof (struct GNUNET_MESH_ManipulatePath);
   size += p->length * sizeof (struct GNUNET_PeerIdentity);
-  msg = GNUNET_malloc (size);
-  msg->header.size = htons (size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY);
-  msg->tid = htonl (t->id.tid);
-  pi = (struct GNUNET_PeerIdentity *) &msg[1];
-  for (i = 0; i < p->length; i++)
   {
-    GNUNET_PEER_resolve(p->peers[i], &pi[i]);
+    struct GNUNET_MESH_ManipulatePath *msg;
+    struct GNUNET_PeerIdentity *pi;
+    char cbuf[size];
+    unsigned int i;
+
+    msg = (struct GNUNET_MESH_ManipulatePath *) cbuf;
+    msg->header.size = htons (size);
+    msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY);
+    msg->tid = htonl (t->id.tid);
+    pi = (struct GNUNET_PeerIdentity *) &msg[1];
+    for (i = 0; i < p->length; i++)
+    {
+      GNUNET_PEER_resolve(p->peers[i], &pi[i]);
+    }
+    send_message (&msg->header, path_get_first_hop(t->tree, destination));
   }
-  send_message (&msg->header, path_get_first_hop(t->tree, destination));
   path_destroy (p);
 }
 
@@ -1282,6 +1286,12 @@ peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t)
   if (NULL != peer->path_head)
   {
     p = tree_get_path_to_peer(t->tree, peer->id);
+    if (NULL == p)
+    {
+      GNUNET_break (0);
+      return;
+    }
+
     if (p->length > 1)
     {
       send_create_path(peer, p, t);
@@ -1321,6 +1331,28 @@ peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t)
 }
 
 
+/**
+ * Task to delay the connection of a peer
+ *
+ * @param cls Closure (path info with tunnel and peer to connect).
+ *            Will be free'd on exection.
+ * @param tc TaskContext
+ */
+static void
+peer_info_connect_task (void *cls,
+                        const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct MeshPathInfo *path_info = cls;
+
+  if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason)
+  {
+    GNUNET_free (cls);
+  }
+  peer_info_connect (path_info->peer, path_info->t);
+  GNUNET_free (cls);
+}
+
+
 /**
  * Destroy the peer_info and free any allocated resources linked to it
  * 
@@ -1714,6 +1746,7 @@ void
 notify_peer_disconnected (const struct MeshTunnelTreeNode *n)
 {
   struct MeshPeerInfo *peer;
+  struct MeshPathInfo *path_info;
 
   if (NULL != n->t->client && NULL != nc)
   {
@@ -1726,7 +1759,10 @@ notify_peer_disconnected (const struct MeshTunnelTreeNode *n)
                                                 &msg.header, GNUNET_NO);
   }
   peer = peer_info_get_short(n->peer);
-  peer_info_connect(peer, n->t);
+  path_info = GNUNET_malloc (sizeof (struct MeshPathInfo));
+  path_info->peer = peer;
+  path_info->t = n->t;
+  GNUNET_SCHEDULER_add_now(&peer_info_connect_task, path_info);
 }
 
 
@@ -2494,7 +2530,8 @@ handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "MESH:   It's for us!\n");
     path_add_to_origin (orig_peer_info, path);
-    t->peers = GNUNET_CONTAINER_multihashmap_create(4);
+    if (NULL == t->peers)
+      t->peers = GNUNET_CONTAINER_multihashmap_create(4);
     GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (
         t->peers,
         &my_full_id.hashPubKey,
@@ -2618,6 +2655,7 @@ handle_mesh_path_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
   if (own_pos < path->length - 1)
     send_message (message, &pi[own_pos + 1]);
   tunnel_delete_peer (t, path->peers[path->length - 1]);
+  path_destroy (path);
   return GNUNET_OK;
 }