From 535d51c21e7ed8b8e1f9bec144c54f177de6b2f5 Mon Sep 17 00:00:00 2001 From: Bart Polot Date: Mon, 26 Sep 2011 12:24:41 +0000 Subject: [PATCH] Added new api in the tree module to handle core or remote disconnections Added reconnecting mechanism to find new paths in case of peer disconnection --- src/mesh/gnunet-service-mesh.c | 125 ++++++++++++++++++++++++++++----- src/mesh/mesh_tunnel_tree.c | 109 +++++++++++++++++++++++++++- src/mesh/mesh_tunnel_tree.h | 28 ++++++++ 3 files changed, 242 insertions(+), 20 deletions(-) diff --git a/src/mesh/gnunet-service-mesh.c b/src/mesh/gnunet-service-mesh.c index 122280369..79f9182f0 100644 --- a/src/mesh/gnunet-service-mesh.c +++ b/src/mesh/gnunet-service-mesh.c @@ -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, + ¬ify_peer_disconnected); } diff --git a/src/mesh/mesh_tunnel_tree.c b/src/mesh/mesh_tunnel_tree.c index 748683a34..9c8d5e97d 100644 --- a/src/mesh/mesh_tunnel_tree.c +++ b/src/mesh/mesh_tunnel_tree.c @@ -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 * diff --git a/src/mesh/mesh_tunnel_tree.h b/src/mesh/mesh_tunnel_tree.h index 252929549..f187e7957 100644 --- a/src/mesh/mesh_tunnel_tree.h +++ b/src/mesh/mesh_tunnel_tree.h @@ -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 * -- 2.25.1