f3b19beedb92bb40e602d9dcdc4fccb96ae70912
[oweals/gnunet.git] / src / mesh / mesh_tunnel_tree.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file mesh/mesh_tunnel_tree.c
23  * @brief Tunnel tree handling functions
24  * @author Bartlomiej Polot
25  */
26
27 #include "mesh.h"
28 #include "mesh_tunnel_tree.h"
29
30 #define MESH_TREE_DEBUG GNUNET_YES
31
32
33 /**
34  * Create a new path
35  *
36  * @param lenght How many hops will the path have.
37  *
38  * @return A newly allocated path with a peer array of the specified length.
39  */
40 struct MeshPeerPath *
41 path_new (unsigned int length)
42 {
43   struct MeshPeerPath *p;
44
45   p = GNUNET_malloc (sizeof(struct MeshPeerPath));
46   if (length > 0)
47   {
48     p->length = length;
49     p->peers = GNUNET_malloc (length * sizeof(GNUNET_PEER_Id));
50   }
51   return p;
52 }
53
54
55 /**
56  * Invert the path
57  *
58  * @param p the path to invert
59  */
60 void
61 path_invert (struct MeshPeerPath *path)
62 {
63   GNUNET_PEER_Id aux;
64   unsigned int i;
65
66   for (i = 0; i < path->length / 2; i++)
67   {
68     aux = path->peers[i];
69     path->peers[i] = path->peers[path->length - i - 1];
70     path->peers[path->length - i - 1] = aux;
71   }
72 }
73
74
75 /**
76  * Duplicate a path, incrementing short peer's rc.
77  *
78  * @param p The path to duplicate.
79  */
80 struct MeshPeerPath *
81 path_duplicate (struct MeshPeerPath *path)
82 {
83   struct MeshPeerPath *aux;
84   unsigned int i;
85
86   aux = path_new(path->length);
87   memcpy (aux->peers, path->peers, path->length * sizeof(GNUNET_PEER_Id));
88   for (i = 0; i < path->length; i++)
89     GNUNET_PEER_change_rc(path->peers[i], 1);
90   return aux;
91 }
92
93
94 /**
95  * Find the first peer whom to send a packet to go down this path
96  *
97  * @param t The tunnel tree to use
98  * @param peer The peerinfo of the peer we are trying to reach
99  *
100  * @return peerinfo of the peer who is the first hop in the tunnel
101  *         NULL on error
102  */
103 struct GNUNET_PeerIdentity *
104 path_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
105 {
106   struct GNUNET_PeerIdentity id;
107   struct GNUNET_PeerIdentity *r;
108
109   GNUNET_PEER_resolve (peer, &id);
110   r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
111   GNUNET_break (NULL != r);
112
113   return r;
114 }
115
116
117 /**
118  * Get the length of a path
119  *
120  * @param path The path to measure, with the local peer at any point of it
121  *
122  * @return Number of hops to reach destination
123  *         UINT_MAX in case the peer is not in the path
124  */
125 unsigned int
126 path_get_length (struct MeshPeerPath *path)
127 {
128   if (NULL == path)
129     return UINT_MAX;
130   return path->length;
131 }
132
133
134 /**
135  * Get the cost of the path relative to the already built tunnel tree
136  *
137  * @param t The tunnel tree to which compare
138  * @param path The individual path to reach a peer
139  *
140  * @return Number of hops to reach destination, UINT_MAX in case the peer is not
141  * in the path
142  *
143  * TODO: remove dummy implementation, look into the tunnel tree
144  */
145 unsigned int
146 path_get_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path)
147 {
148   return path_get_length (path);
149 }
150
151
152 /**
153  * Destroy the path and free any allocated resources linked to it
154  *
155  * @param p the path to destroy
156  *
157  * @return GNUNET_OK on success
158  */
159 int
160 path_destroy (struct MeshPeerPath *p)
161 {
162   GNUNET_PEER_decrement_rcs (p->peers, p->length);
163   GNUNET_free (p->peers);
164   GNUNET_free (p);
165   return GNUNET_OK;
166 }
167
168
169
170 /**
171  * Allocates and initializes a new node.
172  * Sets ID and parent of the new node and inserts it in the DLL of the parent
173  *
174  * @param parent Node that will be the parent from the new node, NULL for root
175  * @param peer Short Id of the new node
176  *
177  * @return Newly allocated node
178  */
179 static struct MeshTunnelTreeNode *
180 tree_node_new(struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer)
181 {
182   struct MeshTunnelTreeNode *node;
183
184   node = GNUNET_malloc(sizeof(struct MeshTunnelTreeNode));
185   node->peer = peer;
186   GNUNET_PEER_change_rc(peer, 1);
187   node->parent = parent;
188   if (NULL != parent)
189     GNUNET_CONTAINER_DLL_insert(parent->children_head,
190                                 parent->children_tail,
191                                 node);
192
193   return node;
194 }
195
196
197 static void
198 tree_node_debug(struct MeshTunnelTreeNode *n, uint16_t level)
199 {
200   struct MeshTunnelTreeNode *c;
201   uint16_t i;
202
203   for (i = 0; i < level; i++)
204     fprintf(stderr, "  ");
205   if (n->status == MESH_PEER_READY)
206     fprintf(stderr, "#");
207   if (n->status == MESH_PEER_SEARCHING)
208     fprintf(stderr, "+");
209   if (n->status == MESH_PEER_RELAY)
210     fprintf(stderr, "-");
211   if (n->status == MESH_PEER_RECONNECTING)
212     fprintf(stderr, "*");
213
214   fprintf(stderr, "%u [%p] ", n->peer, n);
215   if (NULL != n->parent)
216     fprintf(stderr, "(-> %u)\n", n->parent->peer);
217   else
218     fprintf(stderr, "(root)\n");
219   for (c = n->children_head; NULL != c; c = c->next)
220     tree_node_debug(c, level + 1);
221 }
222
223
224 /**
225  * Destroys and frees the node and all children
226  *
227  * @param n Parent node to be destroyed
228  */
229 static void
230 tree_node_destroy (struct MeshTunnelTreeNode *parent)
231 {
232   struct MeshTunnelTreeNode *n;
233   struct MeshTunnelTreeNode *next;
234
235   n = parent->children_head;
236   while (NULL != n)
237   {
238     next = n->next;
239     tree_node_destroy(n);
240     n = next;
241   }
242   GNUNET_PEER_change_rc(parent->peer, -1);
243   if (NULL != parent->parent)
244     GNUNET_CONTAINER_DLL_remove(parent->parent->children_head,
245                                 parent->parent->children_tail,
246                                 parent);
247   GNUNET_free(parent);
248 }
249
250
251
252 /**
253  * Create a new tunnel tree associated to a tunnel
254  *
255  * @param t Tunnel this tree will represent
256  * @param peer A short peer id of the root of the tree
257  *
258  * @return A newly allocated and initialized tunnel tree
259  */
260 struct MeshTunnelTree *
261 tree_new (struct MeshTunnel *t, GNUNET_PEER_Id peer)
262 {
263   struct MeshTunnelTree *tree;
264
265   tree = GNUNET_malloc(sizeof (struct MeshTunnelTree));
266   tree->first_hops = GNUNET_CONTAINER_multihashmap_create(32);
267   tree->root = tree_node_new(NULL, peer);
268   tree->root->status = MESH_PEER_ROOT;
269   tree->t = t;
270   tree->root->t = t;
271
272   return tree;
273 }
274
275
276 /**
277  * Recursively find the given peer in the tree.
278  *
279  * @param t Tunnel where to look for the peer.
280  * @param peer Peer to find
281  *
282  * @return Pointer to the node of the peer. NULL if not found.
283  */
284 struct MeshTunnelTreeNode *
285 tree_find_peer (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer_id)
286 {
287   struct MeshTunnelTreeNode *n;
288   struct MeshTunnelTreeNode *r;
289
290   if (parent->peer == peer_id)
291     return parent;
292   for (n = parent->children_head; NULL != n; n = n->next)
293   {
294     r = tree_find_peer (n, peer_id);
295     if (NULL != r)
296       return r;
297   }
298   return NULL;
299 }
300
301
302 /**
303  * Recusively mark peer and children as disconnected, notify client
304  *
305  * @param tree Tree this node belongs to
306  * @param parent Node to be clean, potentially with children
307  * @param cb Callback to use to notify about disconnected peers.
308  */
309 static void
310 tree_mark_peers_disconnected (struct MeshTunnelTree *tree,
311                               struct MeshTunnelTreeNode *parent,
312                               MeshNodeDisconnectCB cb)
313 {
314   struct GNUNET_PeerIdentity *pi;
315   struct GNUNET_PeerIdentity id;
316   struct MeshTunnelTreeNode *n;
317
318   for (n = parent->children_head; NULL != n; n = n->next)
319   {
320     tree_mark_peers_disconnected (tree, n, cb);
321   }
322   if (MESH_PEER_READY == parent->status && NULL != cb)
323   {
324     cb (parent);
325   }
326   parent->status = MESH_PEER_RECONNECTING;
327
328   /* Remove and free info about first hop */
329   GNUNET_PEER_resolve(parent->peer, &id);
330   pi = GNUNET_CONTAINER_multihashmap_get(tree->first_hops, &id.hashPubKey);
331   GNUNET_CONTAINER_multihashmap_remove_all(tree->first_hops, &id.hashPubKey);
332   if (NULL != pi)
333     GNUNET_free(pi);
334 }
335
336
337 /**
338  * Recusively update the info about what is the first hop to reach the node
339  *
340  * @param tree Tree this nodes belongs to
341  * @param parent Node to be start updating
342  * @param hop If known, ID of the first hop.
343  *            If not known, NULL to find out and pass on children.
344  */
345 void
346 tree_update_first_hops (struct MeshTunnelTree *tree,
347                         struct MeshTunnelTreeNode *parent,
348                         struct GNUNET_PeerIdentity *hop)
349 {
350   struct GNUNET_PeerIdentity pi;
351   struct GNUNET_PeerIdentity *copy;
352   struct GNUNET_PeerIdentity id;
353   struct MeshTunnelTreeNode *n;
354
355 #if MESH_TREE_DEBUG
356   GNUNET_PEER_resolve(parent->peer, &id);
357   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
358           "tree:   Finding first hop for %s.\n",
359           GNUNET_i2s (&id));
360 #endif
361   if (NULL == hop)
362   {
363     struct MeshTunnelTreeNode *aux;
364     struct MeshTunnelTreeNode *old;
365
366     aux = old = parent;
367     while (aux != tree->me)
368     {
369 #if MESH_TREE_DEBUG
370       GNUNET_PEER_resolve(old->peer, &id);
371       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
372              "tree:   ... its not %s.\n",
373              GNUNET_i2s (&id));
374 #endif
375       old = aux;
376       aux = aux->parent;
377       GNUNET_assert(NULL != aux);
378     }
379 #if MESH_TREE_DEBUG
380     GNUNET_PEER_resolve(old->peer, &id);
381     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
382                "tree:   It's %s!\n",
383                GNUNET_i2s (&id));
384 #endif
385     hop = &pi;
386     GNUNET_PEER_resolve(old->peer, hop);
387   }
388   copy = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
389   *copy = *hop;
390   GNUNET_PEER_resolve(parent->peer, &id);
391   GNUNET_CONTAINER_multihashmap_put(
392     tree->first_hops,
393     &id.hashPubKey,
394     copy,
395     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
396
397   for (n = parent->children_head; NULL != n; n = n->next)
398   {
399     tree_update_first_hops (tree, n, hop);
400   }
401 }
402
403
404 /**
405  * Delete the current path to the peer, including all now unused relays.
406  * The destination peer is NOT destroyed, it is returned in order to either set
407  * a new path to it or destroy it explicitly, taking care of it's child nodes.
408  *
409  * @param t Tunnel tree where to delete the path from.
410  * @param peer Destination peer whose path we want to remove.
411  * @param cb Callback to use to notify about disconnected peers.
412  *
413  * @return pointer to the pathless node.
414  *         NULL when not found
415  */
416 struct MeshTunnelTreeNode *
417 tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id,
418                  MeshNodeDisconnectCB cb)
419 {
420   struct MeshTunnelTreeNode *parent;
421   struct MeshTunnelTreeNode *node;
422   struct MeshTunnelTreeNode *n;
423
424 #if MESH_TREE_DEBUG
425   struct GNUNET_PeerIdentity id;
426   GNUNET_PEER_resolve(peer_id, &id);
427   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
428           "tree:   Deleting path to %s.\n",
429           GNUNET_i2s (&id));
430 #endif
431   if (peer_id == t->root->peer)
432     return NULL;
433
434   for (n = t->disconnected_head; NULL != n; n = n->next)
435   {
436     if (n->peer == peer_id)
437     {
438       /* Was already pathless, waiting for reconnection */
439       GNUNET_CONTAINER_DLL_remove (t->disconnected_head,
440                                    t->disconnected_tail,
441                                    n);
442       return n;
443     }
444   }
445   n = tree_find_peer (t->root, peer_id);
446   if (NULL == n)
447     return NULL;
448   node = n;
449
450   parent = n->parent;
451   GNUNET_CONTAINER_DLL_remove(parent->children_head, parent->children_tail, n);
452   n->parent = NULL;
453
454   while (MESH_PEER_RELAY == parent->status && NULL == parent->children_head)
455   {
456 #if MESH_TREE_DEBUG
457     GNUNET_PEER_resolve(parent->peer, &id);
458     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
459               "tree:   Deleting node %s.\n",
460               GNUNET_i2s (&id));
461 #endif
462     n = parent->parent;
463     tree_node_destroy(parent);
464     parent = n;
465   }
466 #if MESH_TREE_DEBUG
467   GNUNET_PEER_resolve(parent->peer, &id);
468   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
469              "tree:   Not deleted peer %s.\n",
470              GNUNET_i2s (&id));
471 #endif
472
473   tree_mark_peers_disconnected (t, node, cb);
474
475   return node;
476 }
477
478
479 /**
480  * Return a newly allocated individual path to reach a peer from the local peer,
481  * according to the path tree of some tunnel.
482  *
483  * @param t Tunnel from which to read the path tree
484  * @param peer_info Destination peer to whom we want a path
485  *
486  * @return A newly allocated individual path to reach the destination peer.
487  *         Path must be destroyed afterwards.
488  */
489 struct MeshPeerPath *
490 tree_get_path_to_peer(struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
491 {
492   struct MeshTunnelTreeNode *n;
493   struct MeshPeerPath *p;
494   GNUNET_PEER_Id myid = t->me->peer;
495
496   n = tree_find_peer(t->me, peer);
497   p = path_new(0);
498
499   /* Building the path (inverted!) */
500   while (n->peer != myid)
501   {
502     GNUNET_array_append(p->peers, p->length, n->peer);
503     GNUNET_PEER_change_rc(n->peer, 1);
504     n = n->parent;
505     GNUNET_assert(NULL != n);
506   }
507   GNUNET_array_append(p->peers, p->length, myid);
508   GNUNET_PEER_change_rc(myid, 1);
509
510   path_invert(p);
511
512   return p;
513 }
514
515
516
517 /**
518  * Integrate a stand alone path into the tunnel tree.
519  * If the peer toward which the new path is already in the tree, the peer
520  * and its children will be maked as disconnected and the callback
521  * will be called on each one of them. They will be maked as online only after
522  * receiving a PATH ACK for the new path for each one of them, so the caller
523  * should take care of sending a new CREATE PATH message for each disconnected
524  * peer.
525  *
526  * @param t Tunnel where to add the new path.
527  * @param p Path to be integrated.
528  * @param cb Callback to use to notify about peers temporarily disconnecting
529  *
530  * @return GNUNET_OK in case of success.
531  *         GNUNET_SYSERR in case of error.
532  *
533  * TODO: optimize
534  * - go backwards on path looking for each peer in the present tree
535  * - do not disconnect peers until new path is created & connected
536  */
537 int
538 tree_add_path (struct MeshTunnelTree *t,
539                const struct MeshPeerPath *p,
540                MeshNodeDisconnectCB cb)
541 {
542   struct MeshTunnelTreeNode *parent;
543   struct MeshTunnelTreeNode *oldnode;
544   struct MeshTunnelTreeNode *n;
545   struct MeshTunnelTreeNode *c;
546   struct GNUNET_PeerIdentity id;
547   GNUNET_PEER_Id myid;
548   int me;
549 //   int oldnode_is_me;
550   unsigned int i;
551
552 #if MESH_TREE_DEBUG
553   GNUNET_PEER_resolve(p->peers[p->length - 1], &id);
554   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
555              "tree:   Adding path [%u] towards peer %s.\n",
556             p->length,
557             GNUNET_i2s (&id));
558 #endif
559
560   if (NULL != t->me)
561     myid = t->me->peer;
562   else
563     myid = 0;
564   GNUNET_assert(0 != p->length);
565   parent = n = t->root;
566   if (n->peer != p->peers[0])
567   {
568     GNUNET_break (0);
569     return GNUNET_SYSERR;
570   }
571   if (1 == p->length)
572     return GNUNET_OK;
573   oldnode = tree_del_path (t, p->peers[p->length - 1], cb);
574   /* Look for the first node that is not already present in the tree
575    *
576    * Assuming that the tree is somewhat balanced, O(log n * log N).
577    * - Length of the path is expected to be log N (size of whole network).
578    * - Each level of the tree is expected to have log n children (size of tree).
579    */
580   me = t->root->peer == myid ? 0 : -1;
581   for (i = 1; i < p->length; i++)
582   {
583 #if MESH_TREE_DEBUG
584     GNUNET_PEER_resolve(p->peers[i], &id);
585     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
586                "tree:   Looking for peer %s.\n",
587                GNUNET_i2s (&id));
588 #endif
589     parent = n;
590     if (p->peers[i] == myid)
591       me = i;
592     for (c = n->children_head; NULL != c; c = c->next)
593     {
594       if (c->peer == p->peers[i])
595       {
596 #if MESH_TREE_DEBUG
597         GNUNET_PEER_resolve(parent->peer, &id);
598         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
599                    "tree:   Found in children of %s.\n",
600                    GNUNET_i2s (&id));
601 #endif
602         n = c;
603         break;
604       }
605     }
606     /*  If we couldn't find a child equal to path[i], we have reached the end
607      * of the common path. */
608     if (parent == n)
609       break;
610   }
611 #if MESH_TREE_DEBUG
612   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
613              "tree:   All childen visited.\n");
614 #endif
615   /* Add the rest of the path as a branch from parent. */
616   while (i < p->length)
617   {
618 #if MESH_TREE_DEBUG
619     GNUNET_PEER_resolve(p->peers[i], &id);
620     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
621                "tree:   Adding  peer %s.\n",
622                GNUNET_i2s (&id));
623     GNUNET_PEER_resolve(parent->peer, &id);
624     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
625                "tree:     to %s.\n",
626                GNUNET_i2s (&id));
627 #endif
628
629     if (i == p->length - 1 && NULL != oldnode)
630     {
631 #if MESH_TREE_DEBUG
632       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
633                  "tree:   Putting old node into place.\n");
634 #endif
635       oldnode->parent = parent;
636       GNUNET_CONTAINER_DLL_insert(parent->children_head,
637                                   parent->children_tail,
638                                   oldnode);
639       tree_update_first_hops (t, oldnode, NULL);
640       n = oldnode;
641     }
642     else
643     {
644 #if MESH_TREE_DEBUG
645       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   Creating new node.\n");
646 #endif
647       n = tree_node_new(parent, p->peers[i]);
648       n->t = t->t;
649       n->status = MESH_PEER_RELAY;
650     }
651     i++;
652     parent = n;
653   }
654   n->status = MESH_PEER_SEARCHING;
655
656   /* Add info about first hop into hashmap. */
657   if (-1 != me && me < p->length - 1)
658   {
659 #if MESH_TREE_DEBUG
660     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661                 "MESH:   finding first hop (own pos %d/%u)\n",
662                 me, p->length - 1);
663 #endif
664     GNUNET_PEER_resolve (p->peers[me + 1], &id);
665     tree_update_first_hops(t,
666                            tree_find_peer(t->root, p->peers[p->length - 1]),
667                            &id);
668   }
669 #if MESH_TREE_DEBUG
670   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   New node added.\n");
671 #endif
672   return GNUNET_OK;
673 }
674
675
676 /**
677  * Notifies a tree that a connection it might be using is broken.
678  * Marks all peers down the paths as disconnected and notifies the client.
679  *
680  * @param t Tree to use.
681  * @param p1 Short id of one of the peers (order unimportant)
682  * @param p2 Short id of one of the peers (order unimportant)
683  * @param cb Function to call for every peer that is marked as disconnected.
684  *
685  * @return Short ID of the first disconnected peer in the tree.
686  */
687 GNUNET_PEER_Id
688 tree_notify_connection_broken (struct MeshTunnelTree *t,
689                                GNUNET_PEER_Id p1,
690                                GNUNET_PEER_Id p2,
691                                MeshNodeDisconnectCB cb)
692 {
693   struct MeshTunnelTreeNode *n;
694   struct MeshTunnelTreeNode *c;
695
696   n = tree_find_peer(t->me, p1);
697   if (NULL == n)
698     return 0;
699   if (NULL != n->parent && n->parent->peer == p2)
700   {
701     tree_mark_peers_disconnected(t, n, cb);
702     GNUNET_CONTAINER_DLL_remove(n->parent->children_head,
703                                 n->parent->children_tail,
704                                 n);
705     GNUNET_CONTAINER_DLL_insert(t->disconnected_head,
706                                 t->disconnected_tail,
707                                 n);
708     return p1;
709   }
710   for (c = n->children_head; NULL != c; c = c->next)
711   {
712     if (c->peer == p2)
713     {
714       tree_mark_peers_disconnected(t, c, cb);
715       GNUNET_CONTAINER_DLL_remove(n->children_head,
716                                   n->children_tail,
717                                   c);
718       GNUNET_CONTAINER_DLL_insert(t->disconnected_head,
719                                   t->disconnected_tail,
720                                   c);
721       return p2;
722     }
723   }
724   return 0;
725 }
726
727
728 /**
729  * Deletes a peer from a tunnel, liberating all unused resources on the path to
730  * it. It shouldn't have children, if it has they will be destroyed as well.
731  * If the tree is not local and no longer has any paths, the root node will be
732  * destroyed and marked as NULL.
733  *
734  * @param t Tunnel tree to use.
735  * @param peer Short ID of the peer to remove from the tunnel tree.
736  * @param cb Callback to notify client of disconnected peers.
737  *
738  * @return GNUNET_OK or GNUNET_SYSERR
739  */
740 int
741 tree_del_peer (struct MeshTunnelTree *t,
742                GNUNET_PEER_Id peer,
743                MeshNodeDisconnectCB cb)
744 {
745   struct MeshTunnelTreeNode *n;
746
747   n = tree_del_path(t, peer, cb);
748   if (NULL == n)
749     return GNUNET_SYSERR;
750   GNUNET_break_op (NULL == n->children_head);
751   tree_node_destroy(n);
752   if (NULL == t->root->children_head && t->me != t->root)
753   {
754     tree_node_destroy (t->root);
755     t->root = NULL;
756   }
757   return GNUNET_OK;
758 }
759
760
761 /**
762  * Print the tree on stderr
763  *
764  * @param t The tree
765  */
766 void
767 tree_debug(struct MeshTunnelTree *t)
768 {
769   tree_node_debug(t->root, 0);
770 }
771
772
773 /**
774  * Iterator over hash map peer entries and frees all data in it.
775  * Used prior to destroying a hashmap. Makes you miss anonymous functions in C.
776  *
777  * @param cls closure
778  * @param key current key code (will no longer contain valid data!!)
779  * @param value value in the hash map (treated as void *)
780  * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not.
781  */
782 static int
783 iterate_free (void *cls, const GNUNET_HashCode * key, void *value)
784 {
785   GNUNET_free(value);
786   return GNUNET_YES;
787 }
788
789
790 /**
791  * Destroy the whole tree and free all used memory and Peer_Ids
792  * 
793  * @param t Tree to be destroyed
794  */
795 void
796 tree_destroy (struct MeshTunnelTree *t)
797 {
798   tree_node_destroy(t->root);
799   GNUNET_CONTAINER_multihashmap_iterate(t->first_hops, &iterate_free, NULL);
800   GNUNET_CONTAINER_multihashmap_destroy(t->first_hops);
801   GNUNET_free(t);
802 }