gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r36207 - gnunet/src/cadet


From: gnunet
Subject: [GNUnet-SVN] r36207 - gnunet/src/cadet
Date: Tue, 4 Aug 2015 16:00:31 +0200

Author: bartpolot
Date: 2015-08-04 16:00:31 +0200 (Tue, 04 Aug 2015)
New Revision: 36207

Modified:
   gnunet/src/cadet/gnunet-service-cadet_connection.c
Log:
- resolve duplicate connection handling

Modified: gnunet/src/cadet/gnunet-service-cadet_connection.c
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_connection.c  2015-08-04 14:00:30 UTC 
(rev 36206)
+++ gnunet/src/cadet/gnunet-service-cadet_connection.c  2015-08-04 14:00:31 UTC 
(rev 36207)
@@ -251,6 +251,11 @@
    * Counter to do exponential backoff when creating a connection (max 64).
    */
   unsigned short create_retry;
+
+  /**
+   * Task to check if connection has duplicates.
+   */
+  struct GNUNET_SCHEDULER_Task *check_duplicates_task;
 };
 
 
@@ -1622,6 +1627,143 @@
 
 
 /**
+ * Iterator to compare each connection's path with the path of a new 
connection.
+ *
+ * If the connection conincides, the c member of path is set to the connection
+ * and the destroy flag of the connection is set.
+ *
+ * @param cls Closure (new path).
+ * @param c Connection in the tunnel to check.
+ */
+static void
+check_path (void *cls, struct CadetConnection *c)
+{
+  struct CadetConnection *new_conn = cls;
+  struct CadetPeerPath *path = new_conn->path;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  checking %s (%p), length %u\n",
+       GCC_2s (c), c, c->path->length);
+
+  if (c != new_conn
+      && c->destroy == GNUNET_NO
+      && c->state != CADET_CONNECTION_BROKEN
+      && c->state != CADET_CONNECTION_DESTROYED
+      && path_equivalent (path, c->path))
+  {
+    new_conn->destroy = GNUNET_YES;
+    new_conn->path->c = c;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
+  }
+}
+
+
+/**
+ * Finds out if this path is already being used by an existing connection.
+ *
+ * Checks the tunnel towards the destination to see if it contains
+ * any connection with the same path.
+ *
+ * If the existing connection is ready, it is kept.
+ * Otherwise if the sender has a smaller ID that ours, we accept it (and
+ * the peer will eventually reject our attempt).
+ *
+ * @param path Path to check.
+ * @return #GNUNET_YES if the tunnel has a connection with the same path,
+ *         #GNUNET_NO otherwise.
+ */
+static int
+does_connection_exist (struct CadetConnection *conn)
+{
+  struct CadetPeer *p;
+  struct CadetTunnel *t;
+  struct CadetConnection *c;
+
+  p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
+  if (NULL == p)
+    return GNUNET_NO;
+  t = GCP_get_tunnel (p);
+  if (NULL == t)
+    return GNUNET_NO;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n");
+
+  GCT_iterate_connections (t, &check_path, conn);
+
+  if (GNUNET_YES == conn->destroy)
+  {
+    c = conn->path->c;
+    conn->destroy = GNUNET_NO;
+    conn->path->c = conn;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
+    GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
+    if (CADET_CONNECTION_READY == c->state)
+    {
+      /* The other peer confirmed a live connection with this path,
+       * why is it trying to duplicate it. */
+      GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, 
GNUNET_NO);
+      return GNUNET_YES;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not valid, connection unique\n");
+    return GNUNET_NO;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
+    return GNUNET_NO;
+  }
+}
+
+
+/**
+ * @brief Check if the tunnel this connection belongs to has any other
+ * connection with the same path, and destroy one if so.
+ *
+ * @param cls Closure (connection to check).
+ * @param tc Task context.
+ */
+static void
+check_duplicates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct CadetConnection *c = cls;
+
+  c->check_duplicates_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  if (GNUNET_YES == does_connection_exist (c))
+  {
+    GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG);
+    send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES));
+    GCC_destroy (c);
+  }
+}
+
+
+
+/**
+ * Wait for enough time to let any dead connections time out and check for
+ * any remaining duplicates.
+ *
+ * @param c Connection that is a potential duplicate.
+ */
+static void
+schedule_check_duplicates (struct CadetConnection *c)
+{
+  struct GNUNET_TIME_Relative delay;
+
+  if (NULL != c->check_duplicates_task)
+    return;
+
+  delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 5);
+  c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay,
+                                                           &check_duplicates,
+                                                           c);
+}
+
+
+
+/**
  * Add the connection to the list of both neighbors.
  *
  * @param c Connection.
@@ -1727,110 +1869,6 @@
 
 
 /**
- * Iterator to compare each connection's path with the path of a new 
connection.
- *
- * If the connection conincides, the c member of path is set to the connection
- * and the destroy flag of the connection is set.
- *
- * @param cls Closure (new path).
- * @param c Connection in the tunnel to check.
- */
-static void
-check_path (void *cls, struct CadetConnection *c)
-{
-  struct CadetConnection *new_conn = cls;
-  struct CadetPeerPath *path = new_conn->path;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  checking %s (%p), length %u\n",
-       GCC_2s (c), c, c->path->length);
-
-  if (c != new_conn
-      && c->destroy == GNUNET_NO
-      && c->state != CADET_CONNECTION_BROKEN
-      && c->state != CADET_CONNECTION_DESTROYED
-      && path_equivalent (path, c->path))
-  {
-    new_conn->destroy = GNUNET_YES;
-    new_conn->path->c = c;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
-  }
-}
-
-
-/**
- * Finds out if this path is already being used by and existing connection.
- *
- * Checks the tunnel towards the first peer in the path to see if it contains
- * any connection with the same path.
- *
- * If the existing connection is ready, it is kept.
- * Otherwise if the sender has a smaller ID that ours, we accept it (and
- * the peer will eventually reject our attempt).
- *
- * @param path Path to check.
- * @return #GNUNET_YES if the tunnel has a connection with the same path,
- *         #GNUNET_NO otherwise.
- */
-static int
-does_connection_exist (struct CadetConnection *conn)
-{
-  struct CadetPeer *p;
-  struct CadetTunnel *t;
-  struct CadetConnection *c;
-
-  p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
-  if (NULL == p)
-    return GNUNET_NO;
-  t = GCP_get_tunnel (p);
-  if (NULL == t)
-    return GNUNET_NO;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Checking for duplicates\n");
-
-  GCT_iterate_connections (t, &check_path, conn);
-
-  if (GNUNET_YES == conn->destroy)
-  {
-    c = conn->path->c;
-    conn->destroy = GNUNET_NO;
-    conn->path->c = conn;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
-    GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-    if (CADET_CONNECTION_READY == c->state)
-    {
-      /* The other peer confirmed a live connection with this path,
-       * why is it trying to duplicate it. */
-      return GNUNET_YES;
-    }
-
-    if (GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (p)) > 0)
-    {
-      struct CadetPeer *neighbor;
-
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate allowed (killing old)\n");
-      if (GCC_is_origin (c, GNUNET_YES))
-        neighbor = get_next_hop (c);
-      else
-        neighbor = get_prev_hop (c);
-      send_broken_unknown (&c->id, &my_full_id, NULL,
-                           GCP_get_id (neighbor));
-      GCC_destroy (c);
-      return GNUNET_NO;
-    }
-    else
-      return GNUNET_YES;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
-    return GNUNET_NO;
-  }
-}
-
-
-/**
  * Log receipt of message on stderr (INFO level).
  *
  * @param message Message received.
@@ -1982,22 +2020,16 @@
     add_to_peer (c, orig_peer);
     if (GNUNET_YES == does_connection_exist (c))
     {
-      // FIXME Peer created a connection equal to one we think exists
-      //       and is fine. What should we do?
-      // Use explicit duplicate?
-      // Accept new conn and destroy the old? (interruption in higher level)
-      // Keep both and postpone disambiguation?
-      // Keep the one created by peer with higher ID?
-      // For now: reject new connection until current confirmed dead
-      GNUNET_break_op (0);
-      if (NULL != c->t)
-        GCT_debug (c->t, GNUNET_ERROR_TYPE_WARNING);
-      GCC_debug (c, GNUNET_ERROR_TYPE_WARNING);
-      path_destroy (path);
-      GCC_destroy (c);
-      send_broken_unknown (cid, &my_full_id, NULL, peer);
-      GCC_check_connections ();
-      return GNUNET_OK;
+      /* Peer created a connection equal to one we think exists
+       * and is fine.
+       * Solution: Keep both and postpone disambiguation. In the meantime
+       * the connection will time out or peer will inform us it is broken.
+       *
+       * Other options:
+       * - Use explicit duplicate.
+       * - Accept new conn and destroy the old. (interruption in higher level)
+       * - Keep the one with higher ID / created by peer with higher ID. */
+       schedule_check_duplicates (c);
     }
 
     if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t))
@@ -3023,6 +3055,8 @@
   if (NULL != c->t)
     GCT_remove_connection (c->t, c);
 
+  if (NULL != c->check_duplicates_task)
+    GNUNET_SCHEDULER_cancel (c->check_duplicates_task);
   if (NULL != c->fwd_maintenance_task)
     GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
   if (NULL != c->bck_maintenance_task)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]