Added new api in the tree module to handle core or remote disconnections
authorBart Polot <bart@net.in.tum.de>
Mon, 26 Sep 2011 12:24:41 +0000 (12:24 +0000)
committerBart Polot <bart@net.in.tum.de>
Mon, 26 Sep 2011 12:24:41 +0000 (12:24 +0000)
Added reconnecting mechanism to find new paths in case of peer disconnection

src/mesh/gnunet-service-mesh.c
src/mesh/mesh_tunnel_tree.c
src/mesh/mesh_tunnel_tree.h

index 1222803698d5e184633e4a99b9f0064ef12e55d1..79f9182f0bf878543cfa0b2786f7206dba84a8d1 100644 (file)
@@ -601,6 +601,32 @@ announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 }
 
 
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param get_path NULL-terminated array of pointers
+ *                 to the peers on reverse GET path (or NULL if not recorded)
+ * @param put_path NULL-terminated array of pointers
+ *                 to the peers on the PUT path (or NULL if not recorded)
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ *
+ * FIXME path
+ */
+static void
+dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
+                    const GNUNET_HashCode * key,
+                    const struct GNUNET_PeerIdentity *const *get_path,
+                    const struct GNUNET_PeerIdentity *const *put_path,
+                    enum GNUNET_BLOCK_Type type, size_t size, const void *data);
+
+
 /******************************************************************************/
 /******************      GENERAL HELPER FUNCTIONS      ************************/
 /******************************************************************************/
@@ -661,33 +687,43 @@ peer_info_destroy (struct MeshPeerInfo *pi)
  * Notify a tunnel that a connection has broken that affects at least
  * some of its peers.
  *
- * @param t Tunnel affected
- * @param peer Peer that (at least) has been affected by the disconnection
- * @param p1 Peer that got disconnected from p2
- * @param p2 Peer that got disconnected from p1
+ * @param t Tunnel affected.
+ * @param peer Peer that (at least) has been affected by the disconnection.
+ * @param p1 Peer that got disconnected from p2.
+ * @param p2 Peer that got disconnected from p1.
+ *
+ * @return Short ID of the peer disconnected (either p1 or p2).
+ *         0 if the tunnel remained unaffected.
  */
-static void
+static GNUNET_PEER_Id
 tunnel_notify_connection_broken (struct MeshTunnel *t,
                                  struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
                                  GNUNET_PEER_Id p2);
 
-
 /**
  * Remove all paths that rely on a direct connection between p1 and p2
  * from the peer itself and notify all tunnels about it.
  *
- * @param pi PeerInfo of affected peer
+ * @param peer PeerInfo of affected peer.
  * @param p1 GNUNET_PEER_Id of one peer.
  * @param p2 GNUNET_PEER_Id of another peer that was connected to the first and
  *           no longer is.
+ *
+ * TODO: optimize (see below)
  */
 static void
-path_remove_from_peer (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
+path_remove_from_peer (struct MeshPeerInfo *peer,
+                       GNUNET_PEER_Id p1,
                        GNUNET_PEER_Id p2)
 {
+  struct GNUNET_PeerIdentity id;
   struct MeshPeerPath *p;
   struct MeshPeerPath *aux;
+  struct MeshPeerInfo *peer_d;
+  GNUNET_PEER_Id d;
   unsigned int destroyed;
+  unsigned int best;
+  unsigned int cost;
   unsigned int i;
 
   destroyed = 0;
@@ -712,7 +748,56 @@ path_remove_from_peer (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
 
   for (i = 0; i < peer->ntunnels; i++)
   {
-    tunnel_notify_connection_broken (peer->tunnels[i], peer, p1, p2);
+    d = tunnel_notify_connection_broken (peer->tunnels[i], peer, p1, p2);
+    /* 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.
+     * We need to try to find a new path for each of the disconnected peers.
+     * Some of them might already have a path to reach them that does not
+     * involve p1 and p2. Adding all anew might render in a better tree than
+     * the trivial immediate fix.
+     * 
+     * Trivial immiediate fix: try to reconnect to the disconnected node. All
+     * its children will be reachable trough him.
+     */
+    GNUNET_PEER_resolve(d, &id);
+    peer_d = peer_info_get(&id);
+    best = UINT_MAX;
+    aux = NULL;
+    for (p = peer_d->path_head; NULL != p; p = p->next)
+    {
+      if ((cost = path_get_cost(peer->tunnels[i]->tree, p)) < best)
+      {
+        best = cost;
+        aux = p;
+      }
+    }
+    if (NULL != aux)
+    {
+      /* No callback, as peer will be already disconnected */
+      tree_add_path(peer->tunnels[i]->tree, aux, NULL);
+    }
+    else
+    {
+      struct MeshPathInfo *path_info;
+
+      path_info = GNUNET_malloc(sizeof(struct MeshPathInfo));
+      path_info->path = p;
+      path_info->peer = peer_d;
+      path_info->t = peer->tunnels[i];
+      peer_d->dhtget = GNUNET_DHT_get_start(dht_handle,       /* handle */
+                                            GNUNET_TIME_UNIT_FOREVER_REL,     /* timeout */
+                                            GNUNET_BLOCK_TYPE_TEST,   /* type */
+                                            &id.hashPubKey,   /*key to search */
+                                            4,        /* replication level */
+                                            GNUNET_DHT_RO_RECORD_ROUTE,
+                                            NULL,     /* bloom filter */
+                                            0,        /* mutator */
+                                            NULL,     /* xquery */
+                                            0,        /* xquery bits */
+                                            dht_get_id_handler,
+                                            (void *) path_info);
+    }
   }
 }
 
@@ -1051,18 +1136,24 @@ tunnel_add_peer (struct MeshTunnel *t, struct MeshPeerInfo *peer)
  * Notify a tunnel that a connection has broken that affects at least
  * some of its peers.
  *
- * @param t Tunnel affected
- * @param peer Peer that (at least) has been affected by the disconnection
- * @param p1 Peer that got disconnected from p2
- * @param p2 Peer that got disconnected from p1
- * 
- * FIXME path
+ * @param t Tunnel affected.
+ * @param peer Peer that (at least) has been affected by the disconnection.
+ * @param p1 Peer that got disconnected from p2.
+ * @param p2 Peer that got disconnected from p1.
+ *
+ * @return Short ID of the peer disconnected (either p1 or p2).
+ *         0 if the tunnel remained unaffected.
+ *
+ * FIXME working on it
  */
-static void
+static GNUNET_PEER_Id
 tunnel_notify_connection_broken (struct MeshTunnel *t,
-                                 struct MeshPeerInfo *peer, GNUNET_PEER_Id p1,
+                                 struct MeshPeerInfo *peer,
+                                 GNUNET_PEER_Id p1,
                                  GNUNET_PEER_Id p2)
 {
+  return tree_notify_connection_broken (t->tree, p1, p2,
+                                        &notify_peer_disconnected);
 }
 
 
index 748683a34e7679dcbdfc98a0c680eebdc8f40fdb..9c8d5e97d64059c8891c50adb5a20697fac02f61 100644 (file)
@@ -386,9 +386,22 @@ tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id,
   struct MeshTunnelTreeNode *node;
   struct MeshTunnelTreeNode *n;
 
-  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   Deleting path to %u.\n", peer_id);
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+             "tree:   Deleting path to %u.\n", peer_id);
   if (peer_id == t->root->peer)
     return NULL;
+
+  for (n = t->disconnected_head; NULL != n; n = n->next)
+  {
+    if (n->peer == peer_id)
+    {
+      /* Was already pathless, waiting for reconnection */
+      GNUNET_CONTAINER_DLL_remove (t->disconnected_head,
+                                   t->disconnected_tail,
+                                   n);
+      return n;
+    }
+  }
   n = tree_find_peer (t->me, peer_id);
   if (NULL == n)
     return NULL;
@@ -470,8 +483,9 @@ tree_get_path_to_peer(struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
  * - do not disconnect peers until new path is created & connected
  */
 int
-tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p,
-                 MeshNodeDisconnectCB cb)
+tree_add_path (struct MeshTunnelTree *t,
+               const struct MeshPeerPath *p,
+               MeshNodeDisconnectCB cb)
 {
   struct MeshTunnelTreeNode *parent;
   struct MeshTunnelTreeNode *oldnode;
@@ -588,6 +602,95 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p,
 }
 
 
+/**
+ * Notifies a tree that a connection it might be using is broken.
+ * Marks all peers down the paths as disconnected and notifies the client.
+ *
+ * @param t Tree to use.
+ * @param p1 Short id of one of the peers (order unimportant)
+ * @param p2 Short id of one of the peers (order unimportant)
+ * @param cb Function to call for every peer that is marked as disconnected.
+ *
+ * @return Short ID of the first disconnected peer in the tree.
+ */
+GNUNET_PEER_Id
+tree_notify_connection_broken (struct MeshTunnelTree *t,
+                               GNUNET_PEER_Id p1,
+                               GNUNET_PEER_Id p2,
+                               MeshNodeDisconnectCB cb)
+{
+  struct MeshTunnelTreeNode *n;
+  struct MeshTunnelTreeNode *c;
+
+  n = tree_find_peer(t->me, p1);
+  if (NULL == n)
+    return 0;
+  if (NULL != n->parent && n->parent->peer == p2)
+  {
+    tree_mark_peers_disconnected(t, n, cb);
+    GNUNET_CONTAINER_DLL_remove(n->parent->children_head,
+                                n->parent->children_tail,
+                                n);
+    GNUNET_CONTAINER_DLL_insert(t->disconnected_head,
+                                t->disconnected_tail,
+                                n);
+    return p1;
+  }
+  for (c = n->children_head; NULL != c; c = c->next)
+  {
+    if (c->peer == p2)
+    {
+      tree_mark_peers_disconnected(t, c, cb);
+      GNUNET_CONTAINER_DLL_remove(n->children_head,
+                                  n->children_tail,
+                                  c);
+      GNUNET_CONTAINER_DLL_insert(t->disconnected_head,
+                                  t->disconnected_tail,
+                                  c);
+      return p2;
+    }
+  }
+  return 0;
+}
+
+
+/**
+ * Deletes a peer from a tunnel, marking its children as disconnected.
+ *
+ * @param t Tunnel tree to use.
+ * @param peer Short ID of the peer to remove from the tunnel tree.
+ * @param cb Callback to notify client of disconnected peers.
+ *
+ * @return GNUNET_OK or GNUNET_SYSERR
+ */
+int
+tree_del_peer (struct MeshTunnelTree *t,
+               GNUNET_PEER_Id peer,
+               MeshNodeDisconnectCB cb)
+{
+  struct MeshTunnelTreeNode *n;
+  struct MeshTunnelTreeNode *c;
+  struct MeshTunnelTreeNode *aux;
+
+  n = tree_del_path(t, peer, cb);
+  c = n->children_head;
+  while (NULL != c)
+  {
+    aux = c->next;
+    GNUNET_CONTAINER_DLL_remove(n->children_head,
+                                n->children_tail,
+                                c);
+    GNUNET_CONTAINER_DLL_insert(t->disconnected_head,
+                                t->disconnected_tail,
+                                c);
+    cb (c);
+    c = aux;
+  }
+  tree_node_destroy(n);
+  return GNUNET_OK;
+}
+
+
 /**
  * Print the tree on stderr
  *
index 2529295498b1161e849d3a8cffce13567a8c2ec0..f187e7957227136a41bb7234ebe22f5fad0bad4f 100644 (file)
@@ -127,6 +127,16 @@ struct MeshTunnelTree
    */
   struct MeshTunnelTreeNode *me;
 
+  /**
+   * DLL of disconneted nodes
+   */
+  struct MeshTunnelTreeNode *disconnected_head;
+
+  /**
+   * DLL of disconneted nodes
+   */
+  struct MeshTunnelTreeNode *disconnected_tail;
+
   /**
    * Cache of all peers and the first hop to them.
    * Indexed by PeerIdentity, contains a pointer to the PeerIdentity
@@ -297,6 +307,24 @@ tree_add_path (struct MeshTunnelTree *t,
                MeshNodeDisconnectCB cb);
 
 
+/**
+ * Notifies a tree that a connection it might be using is broken.
+ * Marks all peers down the paths as disconnected and notifies the client.
+ *
+ * @param t Tree to use.
+ * @param p1 Short id of one of the peers (order unimportant)
+ * @param p2 Short id of one of the peers (order unimportant)
+ * @param cb Function to call for every peer that is marked as disconnected.
+ *
+ * @return Short ID of the first disconnected peer in the tree.
+ */
+GNUNET_PEER_Id
+tree_notify_connection_broken (struct MeshTunnelTree *t,
+                               GNUNET_PEER_Id p1,
+                               GNUNET_PEER_Id p2,
+                               MeshNodeDisconnectCB cb);
+
+
 /**
  * Print the tree on stderr
  *