}
+/**
+ * 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 ************************/
/******************************************************************************/
* 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;
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);
+ }
}
}
* 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);
}
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;
* - 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;
}
+/**
+ * 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
*