X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fmesh_tunnel_tree.c;h=c2fe6c3d98776e90c4527d0882f42dd0d6228580;hb=0f6d24a229e9149db26a4e667ed25032d19f533a;hp=cfe6a46a80a222b31a601cfd93ec87b16ac8d48e;hpb=83b19539f4d322b43683f5838b72e9ec2c8e6073;p=oweals%2Fgnunet.git diff --git a/src/mesh/mesh_tunnel_tree.c b/src/mesh/mesh_tunnel_tree.c index cfe6a46a8..c2fe6c3d9 100644 --- a/src/mesh/mesh_tunnel_tree.c +++ b/src/mesh/mesh_tunnel_tree.c @@ -110,7 +110,7 @@ struct MeshTunnelTree /** * Create a new path * - * @param lenght How many hops will the path have. + * @param length How many hops will the path have. * * @return A newly allocated path with a peer array of the specified length. */ @@ -132,7 +132,7 @@ path_new (unsigned int length) /** * Invert the path * - * @param p the path to invert + * @param path the path to invert */ void path_invert (struct MeshPeerPath *path) @@ -152,7 +152,7 @@ path_invert (struct MeshPeerPath *path) /** * Duplicate a path, incrementing short peer's rc. * - * @param p The path to duplicate. + * @param path The path to duplicate. */ struct MeshPeerPath * path_duplicate (struct MeshPeerPath *path) @@ -172,7 +172,7 @@ path_duplicate (struct MeshPeerPath *path) * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. - * @param parent_id Short ID from node form which to start updating. + * @param parent The node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ @@ -181,53 +181,14 @@ tree_node_update_first_hops (struct MeshTunnelTree *tree, struct MeshTunnelTreeNode *parent, struct GNUNET_PeerIdentity *hop); -/** - * Find the first peer whom to send a packet to go down this path - * - * @param t The tunnel tree to use - * @param peer The peerinfo of the peer we are trying to reach - * - * @return peerinfo of the peer who is the first hop in the tunnel - * NULL on error - */ -struct GNUNET_PeerIdentity * -path_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) -{ - struct GNUNET_PeerIdentity id; - struct GNUNET_PeerIdentity *r; - - GNUNET_PEER_resolve (peer, &id); - r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); - if (NULL == r) - { - struct MeshTunnelTreeNode *n; - - n = tree_find_peer (t, peer); - if (NULL != t->me && NULL != n) - { - tree_node_update_first_hops (t, n, NULL); - r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); - GNUNET_assert (NULL != r); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Tree structure inconsistent! me: %p, n: %p", t->me, n); - GNUNET_break (0); - } - } - - return r; -} - /** - * Get the length of a path + * Get the length of a path. * - * @param path The path to measure, with the local peer at any point of it + * @param path The path to measure, with the local peer at any point of it. * - * @return Number of hops to reach destination - * UINT_MAX in case the peer is not in the path + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. */ unsigned int path_get_length (struct MeshPeerPath *path) @@ -238,24 +199,6 @@ path_get_length (struct MeshPeerPath *path) } -/** - * Get the cost of the path relative to the already built tunnel tree - * - * @param t The tunnel tree to which compare - * @param path The individual path to reach a peer - * - * @return Number of hops to reach destination, UINT_MAX in case the peer is not - * in the path - * - * TODO: remove dummy implementation, look into the tunnel tree - */ -unsigned int -path_get_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path) -{ - return path_get_length (path); -} - - /** * Destroy the path and free any allocated resources linked to it * @@ -269,7 +212,7 @@ path_destroy (struct MeshPeerPath *p) if (NULL == p) return GNUNET_OK; GNUNET_PEER_decrement_rcs (p->peers, p->length); - GNUNET_free (p->peers); + GNUNET_free_non_null (p->peers); GNUNET_free (p); return GNUNET_OK; } @@ -306,7 +249,7 @@ tree_node_new (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer) * Recursively find the given peer. * * @param parent Node where to start looking. - * @param peer Peer to find. + * @param peer_id Short ID of the peer to find. * * @return Pointer to the node of the peer. NULL if not found. */ @@ -332,7 +275,7 @@ tree_node_find_peer (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer_id) * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. - * @param parent_id Short ID from node form which to start updating. + * @param parent ID from node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ @@ -360,8 +303,8 @@ tree_node_update_first_hops (struct MeshTunnelTree *tree, while (aux != tree->me) { #if MESH_TREE_DEBUG - GNUNET_PEER_resolve (old->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... its not %s.\n", + GNUNET_PEER_resolve (aux->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n", GNUNET_i2s (&id)); #endif old = aux; @@ -401,25 +344,25 @@ tree_node_debug (struct MeshTunnelTreeNode *n, uint16_t level) uint16_t i; for (i = 0; i < level; i++) - fprintf (stderr, " "); + FPRINTF (stderr, "%s", " "); if (n->status == MESH_PEER_READY) - fprintf (stderr, "#"); + FPRINTF (stderr, "%s", "#"); if (n->status == MESH_PEER_SEARCHING) - fprintf (stderr, "+"); + FPRINTF (stderr, "%s", "+"); if (n->status == MESH_PEER_RELAY) - fprintf (stderr, "-"); + FPRINTF (stderr, "%s", "-"); if (n->status == MESH_PEER_RECONNECTING) - fprintf (stderr, "*"); + FPRINTF (stderr, "%s", "*"); GNUNET_PEER_resolve (n->peer, &id); - fprintf (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); + FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); if (NULL != n->parent) { GNUNET_PEER_resolve (n->parent->peer, &id); - fprintf (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); + FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); } else - fprintf (stderr, "(root)\n"); + FPRINTF (stderr, "%s", "(root)\n"); for (c = n->children_head; NULL != c; c = c->next) tree_node_debug (c, level + 1); } @@ -428,7 +371,7 @@ tree_node_debug (struct MeshTunnelTreeNode *n, uint16_t level) /** * Destroys and frees the node and all children * - * @param n Parent node to be destroyed + * @param parent Parent node to be destroyed */ static void tree_node_destroy (struct MeshTunnelTreeNode *parent) @@ -436,6 +379,8 @@ tree_node_destroy (struct MeshTunnelTreeNode *parent) struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *next; + if (NULL == parent) + return; #if MESH_TREE_DEBUG struct GNUNET_PeerIdentity id; @@ -461,12 +406,11 @@ tree_node_destroy (struct MeshTunnelTreeNode *parent) /** - * Create a new tunnel tree associated to a tunnel + * Create a new tree. * - * @param t Tunnel this tree will represent - * @param peer A short peer id of the root of the tree + * @param peer A short peer id of the root of the tree. * - * @return A newly allocated and initialized tunnel tree + * @return A newly allocated and initialized tunnel tree. */ struct MeshTunnelTree * tree_new (GNUNET_PEER_Id peer) @@ -474,48 +418,25 @@ tree_new (GNUNET_PEER_Id peer) struct MeshTunnelTree *tree; tree = GNUNET_malloc (sizeof (struct MeshTunnelTree)); - tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32); + tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); tree->root = tree_node_new (NULL, peer); tree->root->status = MESH_PEER_ROOT; - return tree; -} - + if (1 == peer) + { + tree->me = tree->root; + } -/** - * Set own identity in the tree - * - * @param tree Tree. - * @param peer A short peer id of local peer. - */ -void -tree_set_me (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer) -{ - tree->me = tree_find_peer (tree, peer); + return tree; } -/** - * Get the id of the local node of the tree. - * - * @param tree Tree whose local id we want to now. - * - * @return Short peer id of local peer. - */ -GNUNET_PEER_Id -tree_get_me (struct MeshTunnelTree *tree) -{ - if (NULL != tree->me) - return tree->me->peer; - else - return (GNUNET_PEER_Id) 0; -} - /** * Set the status of a node. * * @param tree Tree. - * @param peer A short peer id of local peer. + * @param peer A short peer id of the node. + * @param status New status to set. */ void tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, @@ -533,9 +454,10 @@ tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, /** * Get the status of a node. * - * @param tree Tree whose local id we want to now. + * @param tree Tree whose node's status we want to now. + * @param peer A short peer id of the node. * - * @return Short peer id of local peer. + * @return Status of the peer. */ enum MeshPeerState tree_get_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer) @@ -566,11 +488,53 @@ tree_get_predecessor (struct MeshTunnelTree *tree) } +/** + * Find the first peer whom to send a packet to go down this path + * + * @param t The tunnel tree to use + * @param peer The peerinfo of the peer we are trying to reach + * + * @return peerinfo of the peer who is the first hop in the tunnel + * NULL on error + * + * FIXME use PEER_Id + */ +struct GNUNET_PeerIdentity * +tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) +{ + struct GNUNET_PeerIdentity id; + struct GNUNET_PeerIdentity *r; + + GNUNET_PEER_resolve (peer, &id); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + if (NULL == r) + { + struct MeshTunnelTreeNode *n; + + n = tree_find_peer (t, peer); + if (NULL != t->me && NULL != n) + { + tree_node_update_first_hops (t, n, NULL); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + GNUNET_assert (NULL != r); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Tree structure inconsistent! me: %p, n: %p", t->me, n); + GNUNET_break (0); + } + } + + return r; +} + + /** * Find the given peer in the tree. * * @param tree Tree where to look for the peer. - * @param peer Peer to find. + * @param peer_id Short ID of the peer to find. * * @return Pointer to the node of the peer. NULL if not found. */ @@ -587,6 +551,7 @@ tree_find_peer (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer_id) * @param tree Tree this node belongs to * @param parent Node to be clean, potentially with children * @param cb Callback to use to notify about disconnected peers. + * @param cbcls Closure for cb. */ static void tree_mark_peers_disconnected (struct MeshTunnelTree *tree, @@ -622,26 +587,117 @@ tree_mark_peers_disconnected (struct MeshTunnelTree *tree, * * @param tree Tree to use. Must have "me" set. * @param cb Callback to call over each child. - * @param cls Closure. + * @param cb_cls Closure for @c cb. */ void tree_iterate_children (struct MeshTunnelTree *tree, MeshTreeCallback cb, - void *cls) + void *cb_cls) { struct MeshTunnelTreeNode *n; if (NULL == tree->me) - { - GNUNET_break (0); return; - } for (n = tree->me->children_head; NULL != n; n = n->next) { - cb (cls, n->peer); + cb (cb_cls, n->peer); + } +} + + +/** + * Struct to contain a list of pending nodes when iterating a tree. + */ +struct MeshTreePendingNode { + + /** + * DLL next. + */ + struct MeshTreePendingNode *next; + + /** + * DLL prev. + */ + struct MeshTreePendingNode *prev; + + /** + * Pending node. + */ + struct MeshTunnelTreeNode *node; +}; + + +/** + * Iterate over all nodes in the tree. + * + * @param tree Tree to use.. + * @param cb Callback to call over each child. + * @param cb_cls Closure for @c cb. + * + * TODO: recursive implementation? (s/heap/stack/g) + */ +void +tree_iterate_all (struct MeshTunnelTree *tree, + MeshWholeTreeCallback cb, + void *cb_cls) +{ + struct MeshTunnelTreeNode *parent; + struct MeshTunnelTreeNode *n; + struct MeshTreePendingNode *head; + struct MeshTreePendingNode *tail; + struct MeshTreePendingNode *pending; + + cb (cb_cls, tree->root->peer, 0); + pending = GNUNET_malloc (sizeof (struct MeshTreePendingNode)); + pending->node = tree->root; + head = tail = NULL; + GNUNET_CONTAINER_DLL_insert (head, tail, pending); + + while (NULL != head) + { + pending = head; + parent = pending->node; + GNUNET_CONTAINER_DLL_remove (head, tail, pending); + GNUNET_free (pending); + for (n = parent->children_head; NULL != n; n = n->next) + { + cb (cb_cls, n->peer, parent->peer); + pending = GNUNET_malloc (sizeof (struct MeshTreePendingNode)); + pending->node = n; + /* Insert_tail: breadth first, Insert: depth first */ + GNUNET_CONTAINER_DLL_insert (head, tail, pending); + } } } +/** + * Iterator to count the children in a tree. + */ +static void +count_children_cb (void *cls, GNUNET_PEER_Id peer) +{ + unsigned int *i = cls; + + (*i)++; +} + + +/** + * Count how many children does the local node have in the tree. + * + * @param tree Tree to use. Must have "me" set. + */ +unsigned int +tree_count_children (struct MeshTunnelTree *tree) +{ + unsigned int i; + + i = 0; + tree_iterate_children(tree, &count_children_cb, &i); + return i; +} + + /** * Recusively update the info about what is the first hop to reach the node * @@ -664,7 +720,7 @@ tree_update_first_hops (struct MeshTunnelTree *tree, GNUNET_PEER_Id parent_id, * a new path to it or destroy it explicitly, taking care of it's child nodes. * * @param t Tunnel tree where to delete the path from. - * @param peer Destination peer whose path we want to remove. + * @param peer_id Short ID of the destination peer whose path we want to remove. * @param cb Callback to use to notify about disconnected peers. * @param cbcls Closure for cb. * @@ -686,7 +742,7 @@ tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n", GNUNET_i2s (&id)); #endif - if (peer_id == t->root->peer) + if (NULL == t->root || peer_id == t->root->peer) return NULL; for (n = t->disconnected_head; NULL != n; n = n->next) @@ -708,7 +764,8 @@ tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n); n->parent = NULL; - while (MESH_PEER_RELAY == parent->status && NULL == parent->children_head) + while (MESH_PEER_RELAY == parent->status && + NULL == parent->children_head) { #if MESH_TREE_DEBUG GNUNET_PEER_resolve (parent->peer, &id); @@ -716,6 +773,8 @@ tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, GNUNET_i2s (&id)); #endif n = parent->parent; + if (parent == t->me) + t->me = NULL; tree_node_destroy (parent); parent = n; } @@ -735,8 +794,8 @@ tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, * Return a newly allocated individual path to reach a peer from the local peer, * according to the path tree of some tunnel. * - * @param t Tunnel from which to read the path tree - * @param peer_info Destination peer to whom we want a path + * @param t Tunnel from which to read the path tree. + * @param peer Short ID of the destination peer to whom we want a path. * * @return A newly allocated individual path to reach the destination peer. * Path must be destroyed afterwards. @@ -746,24 +805,30 @@ tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) { struct MeshTunnelTreeNode *n; struct MeshPeerPath *p; - GNUNET_PEER_Id myid = t->me->peer; n = tree_find_peer (t, peer); if (NULL == n) + { + GNUNET_break (0); return NULL; + } p = path_new (0); /* Building the path (inverted!) */ - while (n->peer != myid) + while (n->peer != 1) { GNUNET_array_append (p->peers, p->length, n->peer); GNUNET_PEER_change_rc (n->peer, 1); n = n->parent; if (NULL == n) + { + GNUNET_break (0); + path_destroy (p); return NULL; + } } - GNUNET_array_append (p->peers, p->length, myid); - GNUNET_PEER_change_rc (myid, 1); + GNUNET_array_append (p->peers, p->length, 1); + GNUNET_PEER_change_rc (1, 1); path_invert (p); @@ -802,7 +867,6 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *c; struct GNUNET_PeerIdentity id; - GNUNET_PEER_Id myid; int me; unsigned int i; @@ -813,10 +877,6 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, GNUNET_i2s (&id)); #endif - if (NULL != t->me) - myid = t->me->peer; - else - myid = 0; GNUNET_assert (0 != p->length); parent = n = t->root; if (n->peer != p->peers[0]) @@ -833,7 +893,7 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, * - Length of the path is expected to be log N (size of whole network). * - Each level of the tree is expected to have log n children (size of tree). */ - me = t->root->peer == myid ? 0 : -1; + me = t->root->peer == 1 ? 0 : -1; for (i = 1; i < p->length; i++) { #if MESH_TREE_DEBUG @@ -842,7 +902,7 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, GNUNET_i2s (&id)); #endif parent = n; - if (p->peers[i] == myid) + if (p->peers[i] == 1) me = i; for (c = n->children_head; NULL != c; c = c->next) { @@ -875,7 +935,7 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n", GNUNET_i2s (&id)); GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", GNUNET_i2s (&id)); #endif @@ -898,14 +958,19 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, #endif n = tree_node_new (parent, p->peers[i]); n->status = MESH_PEER_RELAY; - if (n->peer == myid) - t->me = n; + } + if (n->peer == 1) + { + t->me = n; + me = i; } i++; parent = n; } n->status = MESH_PEER_SEARCHING; + GNUNET_break (-1 != me); + /* Add info about first hop into hashmap. */ if (-1 != me && me < p->length - 1) { @@ -915,11 +980,19 @@ tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, p->length - 1); #endif GNUNET_PEER_resolve (p->peers[me + 1], &id); - tree_update_first_hops (t, p->peers[p->length - 1], &id); + tree_update_first_hops (t, p->peers[me + 1], &id); } #if MESH_TREE_DEBUG + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MESH: was last in path, not updating first hops (%d/%u)\n", + me, p->length - 1); + } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n"); #endif + if (NULL == t->me) + t->me = tree_find_peer (t, 1); return GNUNET_OK; } @@ -995,7 +1068,6 @@ tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, GNUNET_break (0); return GNUNET_YES; } - GNUNET_break_op (NULL == n->children_head); tree_node_destroy (n); if (NULL == t->root->children_head && t->me != t->root) { @@ -1007,6 +1079,52 @@ tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, } + +/** + * Get the cost of the path relative to the already built tunnel tree. + * + * @param t The tunnel tree to which compare. + * @param path The individual path to reach a peer. It has to start at the + * root of the tree to be comparable. + * + * @return Number of hops to reach destination, UINT_MAX in case the peer is not + * in the path. + * + * TODO: adapt to allow any start / root combination + * TODO: take in account state of the nodes + */ +unsigned int +tree_get_path_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *p; + unsigned int i; + unsigned int l; + + l = path_get_length (path); + p = t->root; + if (t->root->peer != path->peers[0]) + { + GNUNET_break (0); + return UINT_MAX; + } + for (i = 1; i < l; i++) + { + for (n = p->children_head; NULL != n; n = n->next) + { + if (path->peers[i] == n->peer) + { + break; + } + } + if (NULL == n) + return l - i; + p = n; + } + return l - i; +} + + /** * Print the tree on stderr * @@ -1016,6 +1134,8 @@ void tree_debug (struct MeshTunnelTree *t) { tree_node_debug (t->root, 0); + FPRINTF (stderr, "root: %p\n", t->root); + FPRINTF (stderr, "me: %p\n", t->me); } @@ -1029,7 +1149,7 @@ tree_debug (struct MeshTunnelTree *t) * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not. */ static int -iterate_free (void *cls, const GNUNET_HashCode * key, void *value) +iterate_free (void *cls, const struct GNUNET_HashCode * key, void *value) { GNUNET_free (value); return GNUNET_YES;