766960dd4ad4f42659735b91d9cfc6a06eb94da3
[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
31 static void
32 debug_node(struct MeshTunnelTreeNode *n, uint16_t level)
33 {
34   struct MeshTunnelTreeNode *c;
35   uint16_t i;
36
37   for (i = 0; i < level; i++)
38     fprintf(stderr, "  ");
39   if (n->status == MESH_PEER_READY)
40     fprintf(stderr, "#");
41   if (n->status == MESH_PEER_SEARCHING)
42     fprintf(stderr, "+");
43   if (n->status == MESH_PEER_RELAY)
44     fprintf(stderr, "-");
45   if (n->status == MESH_PEER_RECONNECTING)
46     fprintf(stderr, "*");
47  
48   fprintf(stderr, "%u [%p] ", n->peer, n);
49   if (NULL != n->parent)
50     fprintf(stderr, "(-> %u)\n", n->parent->peer);
51   else
52     fprintf(stderr, "(root)\n");
53   for (c = n->children_head; NULL != c; c = c->next)
54     debug_node(c, level + 1);
55 }
56
57
58
59 void
60 tree_debug(struct MeshTunnelTree *t)
61 {
62   debug_node(t->root, 0);
63 }
64
65
66
67 /**
68  * Invert the path
69  *
70  * @param p the path to invert
71  */
72 void
73 path_invert (struct MeshPeerPath *path)
74 {
75   GNUNET_PEER_Id aux;
76   unsigned int i;
77
78   for (i = 0; i < path->length / 2; i++)
79   {
80     aux = path->peers[i];
81     path->peers[i] = path->peers[path->length - i - 1];
82     path->peers[path->length - i - 1] = aux;
83   }
84 }
85
86
87 /**
88  * Destroy the path and free any allocated resources linked to it
89  *
90  * @param p the path to destroy
91  *
92  * @return GNUNET_OK on success
93  */
94 int
95 path_destroy (struct MeshPeerPath *p)
96 {
97   GNUNET_PEER_decrement_rcs (p->peers, p->length);
98   GNUNET_free (p->peers);
99   GNUNET_free (p);
100   return GNUNET_OK;
101 }
102
103
104 /**
105  * Find the first peer whom to send a packet to go down this path
106  *
107  * @param t The tunnel tree to use
108  * @param peer The peerinfo of the peer we are trying to reach
109  *
110  * @return peerinfo of the peer who is the first hop in the tunnel
111  *         NULL on error
112  */
113 struct GNUNET_PeerIdentity *
114 path_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
115 {
116   struct GNUNET_PeerIdentity id;
117
118   GNUNET_PEER_resolve (peer, &id);
119   return GNUNET_CONTAINER_multihashmap_get (t->first_hops,
120                                             &id.hashPubKey);
121 }
122
123
124 /**
125  * Get the length of a path
126  *
127  * @param path The path to measure, with the local peer at any point of it
128  *
129  * @return Number of hops to reach destination
130  *         UINT_MAX in case the peer is not in the path
131  */
132 unsigned int
133 path_get_length (struct MeshPeerPath *path)
134 {
135   if (NULL == path)
136     return UINT_MAX;
137   return path->length;
138 }
139
140
141 /**
142  * Get the cost of the path relative to the already built tunnel tree
143  *
144  * @param t The tunnel tree to which compare
145  * @param path The individual path to reach a peer
146  *
147  * @return Number of hops to reach destination, UINT_MAX in case the peer is not
148  * in the path
149  *
150  * TODO: remove dummy implementation, look into the tunnel tree
151  */
152 unsigned int
153 path_get_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path)
154 {
155   return path_get_length (path);
156 }
157
158
159 /**
160  * Recursively find the given peer in the tree.
161  *
162  * @param t Tunnel where to look for the peer.
163  * @param peer Peer to find
164  *
165  * @return Pointer to the node of the peer. NULL if not found.
166  */
167 struct MeshTunnelTreeNode *
168 tree_find_peer (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer_id)
169 {
170   struct MeshTunnelTreeNode *n;
171   struct MeshTunnelTreeNode *r;
172
173   if (parent->peer == peer_id)
174     return parent;
175   for (n = parent->children_head; NULL != n; n = n->next)
176   {
177     r = tree_find_peer (n, peer_id);
178     if (NULL != r)
179       return r;
180   }
181   return NULL;
182 }
183
184
185 /**
186  * Recusively mark peer and children as disconnected, notify client
187  *
188  * @param tree Tree this node belongs to
189  * @param parent Node to be clean, potentially with children
190  * @param cb Callback to use to notify about disconnected peers.
191  */
192 void
193 tree_mark_peers_disconnected (struct MeshTunnelTree *tree,
194                               struct MeshTunnelTreeNode *parent,
195                               MeshNodeDisconnectCB cb)
196 {
197   struct GNUNET_PeerIdentity *pi;
198   struct GNUNET_PeerIdentity id;
199   struct MeshTunnelTreeNode *n;
200
201   for (n = parent->children_head; NULL != n; n = n->next)
202   {
203     tree_mark_peers_disconnected (tree, n, cb);
204   }
205   if (MESH_PEER_READY == parent->status)
206   {
207     cb (parent);
208   }
209   parent->status = MESH_PEER_RECONNECTING;
210
211   /* Remove and free info about first hop */
212   GNUNET_PEER_resolve(parent->peer, &id);
213   pi = GNUNET_CONTAINER_multihashmap_get(tree->first_hops, &id.hashPubKey);
214   GNUNET_CONTAINER_multihashmap_remove_all(tree->first_hops, &id.hashPubKey);
215   if (NULL != pi)
216     GNUNET_free(pi);
217 }
218
219
220 /**
221  * Recusively update the info about what is the first hop to reach the node
222  *
223  * @param tree Tree this nodes belongs to
224  * @param parent Node to be start updating
225  * @param hop If known, ID of the first hop.
226  *            If not known, NULL to find out and pass on children.
227  */
228 void
229 tree_update_first_hops (struct MeshTunnelTree *tree,
230                         struct MeshTunnelTreeNode *parent,
231                         struct GNUNET_PeerIdentity *hop)
232 {
233   struct GNUNET_PeerIdentity pi;
234   struct GNUNET_PeerIdentity *copy;
235   struct GNUNET_PeerIdentity id;
236   struct MeshTunnelTreeNode *n;
237
238   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
239              "tree:   Finding first hop for %u.\n",
240              parent->peer);
241   if (NULL == hop)
242   {
243     struct MeshTunnelTreeNode *aux;
244     struct MeshTunnelTreeNode *old;
245
246     old = parent;
247     aux = old->parent;
248     while (aux != tree->me)
249     {
250       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
251              "tree:   ... its not %u.\n",
252              old->peer);
253       old = aux;
254       aux = aux->parent;
255       GNUNET_assert(NULL != aux);
256     }
257     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
258              "tree:   It's %u!!\n",
259              old->peer);
260     hop = &pi;
261     GNUNET_PEER_resolve(old->peer, hop);
262   }
263   copy = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
264   *copy = *hop;
265   GNUNET_PEER_resolve(parent->peer, &id);
266   GNUNET_CONTAINER_multihashmap_put(tree->first_hops, &id.hashPubKey, copy,
267                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
268
269   for (n = parent->children_head; NULL != n; n = n->next)
270   {
271     tree_update_first_hops (tree, n, hop);
272   }
273 }
274
275
276 /**
277  * Delete the current path to the peer, including all now unused relays.
278  * The destination peer is NOT destroyed, it is returned in order to either set
279  * a new path to it or destroy it explicitly, taking care of it's child nodes.
280  *
281  * @param t Tunnel tree where to delete the path from.
282  * @param peer Destination peer whose path we want to remove.
283  * @param cb Callback to use to notify about disconnected peers.
284  *
285  * @return pointer to the pathless node.
286  *         NULL when not found
287  */
288 struct MeshTunnelTreeNode *
289 tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id,
290                  MeshNodeDisconnectCB cb)
291 {
292   struct MeshTunnelTreeNode *parent;
293   struct MeshTunnelTreeNode *node;
294   struct MeshTunnelTreeNode *n;
295
296   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   Deleting path to %u.\n", peer_id);
297   if (peer_id == t->root->peer)
298     return NULL;
299   n = tree_find_peer (t->me, peer_id);
300   if (NULL == n)
301     return NULL;
302   node = n;
303
304   parent = n->parent;
305   GNUNET_CONTAINER_DLL_remove(parent->children_head, parent->children_tail, n);
306   n->parent = NULL;
307
308   while (t->root != parent && MESH_PEER_RELAY == parent->status &&
309          NULL == parent->children_head)
310   {
311     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
312                "tree:   Deleting node %u.\n",
313                parent->peer);
314     n = parent->parent;
315     tree_node_destroy(parent);
316     parent = n;
317   }
318   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
319              "tree:   Not deleted peer %u.\n",
320              parent->peer);
321
322   tree_mark_peers_disconnected (t, node, cb);
323
324   return node;
325 }
326
327
328 /**
329  * Return a newly allocated individual path to reach a peer from the local peer,
330  * according to the path tree of some tunnel.
331  *
332  * @param t Tunnel from which to read the path tree
333  * @param peer_info Destination peer to whom we want a path
334  *
335  * @return A newly allocated individual path to reach the destination peer.
336  *         Path must be destroyed afterwards.
337  */
338 struct MeshPeerPath *
339 tree_get_path_to_peer(struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
340 {
341   struct MeshTunnelTreeNode *n;
342   struct MeshPeerPath *p;
343   GNUNET_PEER_Id myid = t->me->peer;
344
345   n = tree_find_peer(t->me, peer);
346   p = GNUNET_malloc(sizeof(struct MeshPeerPath));
347
348   /* Building the path (inverted!) */
349   while (n->peer != myid)
350   {
351     GNUNET_array_append(p->peers, p->length, n->peer);
352     GNUNET_PEER_change_rc(n->peer, 1);
353     n = n->parent;
354     GNUNET_assert(NULL != n);
355   }
356   GNUNET_array_append(p->peers, p->length, myid);
357   GNUNET_PEER_change_rc(myid, 1);
358
359   path_invert(p);
360
361   return p;
362 }
363
364
365 /**
366  * Integrate a stand alone path into the tunnel tree.
367  *
368  * @param t Tunnel where to add the new path.
369  * @param p Path to be integrated.
370  * @param cb Callback to use to notify about peers temporarily disconnecting
371  *
372  * @return GNUNET_OK in case of success.
373  *         GNUNET_SYSERR in case of error.
374  *
375  * TODO: optimize
376  * - go backwards on path looking for each peer in the present tree
377  * - do not disconnect peers until new path is created & connected
378  */
379 int
380 tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p,
381                  MeshNodeDisconnectCB cb)
382 {
383   struct MeshTunnelTreeNode *parent;
384   struct MeshTunnelTreeNode *oldnode;
385   struct MeshTunnelTreeNode *n;
386   struct MeshTunnelTreeNode *c;
387   struct GNUNET_PeerIdentity id;
388   struct GNUNET_PeerIdentity *hop;
389   GNUNET_PEER_Id myid = t->me->peer;
390   int me;
391   unsigned int i;
392
393   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
394              "tree:   Adding path [%u] towards peer %u to peer %u.\n",
395              p->length,
396              p->peers[p->length - 1],
397              t->me->peer);
398   GNUNET_assert(0 != p->length);
399   parent = n = t->root;
400   if (n->peer != p->peers[0])
401   {
402     GNUNET_break (0);
403     return GNUNET_SYSERR;
404   }
405   if (1 == p->length)
406     return GNUNET_OK;
407   oldnode = tree_del_path (t, p->peers[p->length - 1], cb);
408   /* Look for the first node that is not already present in the tree
409    *
410    * Assuming that the tree is somewhat balanced, O(log n * log N).
411    * - Length of the path is expected to be log N (size of whole network).
412    * - Each level of the tree is expected to have log n children (size of tree).
413    */
414   me = t->root->peer == myid ? 0 : -1;
415   for (i = 1; i < p->length; i++)
416   {
417     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
418              "tree:   Looking for peer %u.\n",
419              p->peers[i]);
420     parent = n;
421     if (p->peers[i] == myid)
422       me = i;
423     for (c = n->children_head; NULL != c; c = c->next)
424     {
425       if (c->peer == p->peers[i])
426       {
427         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
428              "tree:   Found in children of %u.\n",
429              parent->peer);
430         n = c;
431         break;
432       }
433     }
434     /*  If we couldn't find a child equal to path[i], we have reached the end
435      * of the common path. */
436     if (parent == n)
437       break;
438   }
439   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
440              "tree:   All childen visited.\n");
441   if (-1 == me)
442   {
443     /* New path deviates from tree before reaching us. What happened? */
444     GNUNET_break (0);
445     return GNUNET_SYSERR;
446   }
447   /* Add the rest of the path as a branch from parent. */
448   while (i < p->length)
449   {
450     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
451                "tree:   Adding  peer %u, to %u.\n",
452                p->peers[i],
453                parent->peer);
454
455     if (i == p->length - 1 && NULL != oldnode)
456     {
457       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   Putting old node into place.\n");
458       oldnode->parent = parent;
459       GNUNET_CONTAINER_DLL_insert(parent->children_head,
460                                   parent->children_tail,
461                                   oldnode);
462       tree_update_first_hops (t, oldnode, NULL);
463       n = oldnode;
464     }
465     else
466     {
467       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   Creating new node.\n");
468       n = tree_node_new(parent, p->peers[i]);
469       n->t = t->t;
470       n->status = MESH_PEER_RELAY;
471     }
472     i++;
473     parent = n;
474   }
475   n->status = MESH_PEER_SEARCHING;
476
477   /* Add info about first hop into hashmap. */
478   if (me < p->length - 1)
479   {
480     GNUNET_PEER_resolve (p->peers[p->length - 1], &id);
481     hop = GNUNET_CONTAINER_multihashmap_get(t->first_hops, &id.hashPubKey);
482     if (NULL != hop)
483     {
484       GNUNET_CONTAINER_multihashmap_remove_all(t->first_hops, &id.hashPubKey);
485       GNUNET_free(hop);
486     }
487     hop = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
488     GNUNET_PEER_resolve (p->peers[me + 1], hop);
489     GNUNET_CONTAINER_multihashmap_put (t->first_hops, &id.hashPubKey,
490                                        hop,
491                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
492   }
493   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "tree:   New node added.\n");
494   return GNUNET_OK;
495 }
496
497
498 /**
499  * Allocates and initializes a new node.
500  * Sets ID and parent of the new node and inserts it in the DLL of the parent
501  *
502  * @param parent Node that will be the parent from the new node, NULL for root
503  * @param id Short Id of the new node
504  *
505  * @return Newly allocated node
506  */
507 struct MeshTunnelTreeNode *
508 tree_node_new(struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id id)
509 {
510   struct MeshTunnelTreeNode *node;
511
512   node = GNUNET_malloc(sizeof(struct MeshTunnelTreeNode));
513   node->peer = id;
514   GNUNET_PEER_change_rc(id, 1);
515   node->parent = parent;
516   if (NULL != parent)
517     GNUNET_CONTAINER_DLL_insert(parent->children_head,
518                                 parent->children_tail,
519                                 node);
520
521   return node;
522 }
523
524
525 /**
526  * Destroys and frees the node and all children
527  * 
528  * @param n Parent node to be destroyed
529  */
530 void
531 tree_node_destroy (struct MeshTunnelTreeNode *parent)
532 {
533   struct MeshTunnelTreeNode *n;
534   struct MeshTunnelTreeNode *next;
535
536   n = parent->children_head;
537   while (NULL != n)
538   {
539     next = n->next;
540     tree_node_destroy(n);
541     n = next;
542   }
543   GNUNET_PEER_change_rc(parent->peer, -1);
544   if (NULL != parent->parent)
545     GNUNET_CONTAINER_DLL_remove(parent->parent->children_head,
546                                 parent->parent->children_tail,
547                                 parent);
548   GNUNET_free(parent);
549 }
550
551
552 /**
553  * Iterator over hash map peer entries and frees all data in it.
554  * Used prior to destroying a hashmap. Makes you miss anonymous functions in C.
555  *
556  * @param cls closure
557  * @param key current key code (will no longer contain valid data!!)
558  * @param value value in the hash map (treated as void *)
559  * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not.
560  */
561 static int
562 iterate_free (void *cls, const GNUNET_HashCode * key, void *value)
563 {
564   GNUNET_free(value);
565   return GNUNET_YES;
566 }
567
568
569 /**
570  * Destroy the whole tree and free all used memory and Peer_Ids
571  * 
572  * @param t Tree to be destroyed
573  */
574 void
575 tree_destroy (struct MeshTunnelTree *t)
576 {
577   tree_node_destroy(t->root);
578   GNUNET_CONTAINER_multihashmap_iterate(t->first_hops, &iterate_free, NULL);
579   GNUNET_CONTAINER_multihashmap_destroy(t->first_hops);
580   GNUNET_free(t);
581 }