Fix cleanup issues and some leak
authorChristian Grothoff <christian@grothoff.org>
Fri, 17 Feb 2017 20:26:37 +0000 (21:26 +0100)
committerChristian Grothoff <christian@grothoff.org>
Fri, 17 Feb 2017 20:26:37 +0000 (21:26 +0100)
src/cadet/cadet.conf.in
src/cadet/gnunet-service-cadet-new.c
src/cadet/gnunet-service-cadet-new_channel.c

index 86ba2e535d0a2b6e839c2ccd52a8a4b027822930..296a648e28db224fbb50e33d551de3d5055662ce 100644 (file)
@@ -4,7 +4,7 @@ AUTOSTART = @AUTOSTART@
 @JAVAPORT@PORT = 2096
 HOSTNAME = localhost
 BINARY = gnunet-service-cadet-new
-PREFIX = valgrind --leak-check=yes
+PREFIX = valgrind --leak-check=yes
 ACCEPT_FROM = 127.0.0.1;
 ACCEPT_FROM6 = ::1;
 UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-cadet.sock
index 1f28745e118a88008e30156fe18635ff5ced5378..b16767fbb3aaee5a5c7e22849283cfa3d1939767 100644 (file)
@@ -1238,14 +1238,14 @@ channel_destroy_iterator (void *cls,
        "Destroying %s, due to %s disconnecting.\n",
        GCCH_2s (ch),
        GSC_2s (c));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         key,
-                                                         ch));
   ccn.channel_of_client = htonl (key);
   GCCH_channel_local_destroy (ch,
                               c,
                               ccn);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         key,
+                                                         ch));
   return GNUNET_OK;
 }
 
@@ -1304,6 +1304,7 @@ client_disconnect_cb (void *cls,
     GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
                                              &channel_destroy_iterator,
                                              c);
+    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
     GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
   }
   if (NULL != c->ports)
index 828c3daa7bf51270f02dd59ccfa2c0b45670c8de..9f565a7f46586e1cb2e5ea1ceec8f8ed374a7963 100644 (file)
@@ -661,11 +661,8 @@ GCCH_channel_local_new (struct CadetClient *owner,
     }
     else
     {
-      ch->dest = GNUNET_new (struct CadetChannelClient);
-      ch->dest->c = c;
-      ch->dest->client_ready = GNUNET_YES;
       GCCH_bind (ch,
-                 ch->dest->c);
+                 c);
     }
   }
   else
@@ -962,6 +959,7 @@ GCCH_bind (struct CadetChannel *ch,
   if (ch->out_of_order)
     options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
   cccd = GNUNET_new (struct CadetChannelClient);
+  GNUNET_assert (NULL == ch->dest);
   ch->dest = cccd;
   cccd->c = c;
   cccd->client_ready = GNUNET_YES;
@@ -999,6 +997,28 @@ GCCH_bind (struct CadetChannel *ch,
 }
 
 
+/**
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
+ *
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
+ */
+static void
+signal_remote_destroy_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct CadetChannelClient *ccc;
+
+  /* Find which end is left... */
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  GSC_handle_remote_channel_destroy (ccc->c,
+                                     ccc->ccn,
+                                     ch);
+  channel_destroy (ch);
+}
+
+
 /**
  * Destroy locally created channel.  Called by the local client, so no
  * need to tell the client.
@@ -1052,32 +1072,34 @@ GCCH_channel_local_destroy (struct CadetChannel *ch,
     ch->destroy = GNUNET_YES;
     return;
   }
-  if (GNUNET_YES == ch->is_loopback)
+  if ( (GNUNET_YES == ch->is_loopback) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
   {
-    struct CadetChannelClient *ccc;
-
-    /* Find which end is left... */
-    ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-    GSC_handle_remote_channel_destroy (ccc->c,
-                                       ccc->ccn,
-                                       ch);
-    channel_destroy (ch);
+    if (NULL != ch->retry_control_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+                                  ch);
     return;
   }
-  /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
-  switch (ch->state)
+  if (GNUNET_NO == ch->is_loopback)
   {
-  case CADET_CHANNEL_NEW:
-    /* We gave up on a channel that we created as a client to a remote
-       target, but that never went anywhere. Nothing to do here. */
-    break;
-  case CADET_CHANNEL_LOOSE:
-    GSC_drop_loose_channel (&ch->port,
-                            ch);
-    break;
-  default:
-    GCT_send_channel_destroy (ch->t,
-                              ch->ctn);
+    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+    switch (ch->state)
+    {
+    case CADET_CHANNEL_NEW:
+      /* We gave up on a channel that we created as a client to a remote
+         target, but that never went anywhere. Nothing to do here. */
+      break;
+    case CADET_CHANNEL_LOOSE:
+      GSC_drop_loose_channel (&ch->port,
+                              ch);
+      break;
+    default:
+      GCT_send_channel_destroy (ch->t,
+                                ch->ctn);
+    }
   }
   /* Nothing left to do, just finish destruction */
   channel_destroy (ch);