0d972de25f36f112bad9875efb4aa3844b1f9537
[oweals/gnunet.git] / src / cadet / cadet_path.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001 - 2013 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 cadet/cadet_path.c
23  * @brief Path handling functions
24  * @author Bartlomiej Polot
25  */
26
27 #include "cadet.h"
28 #include "cadet_path.h"
29 #include "gnunet-service-cadet_peer.h"
30
31 #define LOG(level, ...) GNUNET_log_from (level,"cadet-pth",__VA_ARGS__)
32
33
34 /**
35  * @brief Destroy a path after some time has past.
36  *
37  * If the path is returned from DHT again after a while, try again.
38  *
39  * Removes the path from the peer (except for direct paths).
40  *
41  * @param cls Closure (path to destroy).
42  * @param tc Task context.
43  */
44 static void
45 path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
46 {
47   struct CadetPeerPath *path = cls;
48   struct CadetPeer *peer;
49
50   LOG (GNUNET_ERROR_TYPE_INFO, "Destroy delayed %p (%u)\n", path, path->length);
51   path->path_delete = NULL;
52
53   if (2 < path->length && (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) == 0)
54   {
55     /* During shutdown, the peers peermap might not exist anymore. */
56     peer = GCP_get_short (path->peers[path->length - 1]);
57     GCP_remove_path (peer, path);
58   }
59   else
60     path_destroy (path);
61 }
62
63
64 /**
65  * Create a new path
66  *
67  * @param length How many hops will the path have.
68  *
69  * @return A newly allocated path with a peer array of the specified length.
70  */
71 struct CadetPeerPath *
72 path_new (unsigned int length)
73 {
74   struct CadetPeerPath *p;
75
76   p = GNUNET_new (struct CadetPeerPath);
77   if (length > 0)
78   {
79     p->length = length;
80     p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
81   }
82   LOG (GNUNET_ERROR_TYPE_INFO, "New path %p (%u)\n", p, p->length);
83   return p;
84 }
85
86
87 /**
88  * Invert the path
89  *
90  * @param path the path to invert
91  */
92 void
93 path_invert (struct CadetPeerPath *path)
94 {
95   GNUNET_PEER_Id aux;
96   unsigned int i;
97
98   for (i = 0; i < path->length / 2; i++)
99   {
100     aux = path->peers[i];
101     path->peers[i] = path->peers[path->length - i - 1];
102     path->peers[path->length - i - 1] = aux;
103   }
104 }
105
106
107 /**
108  * Duplicate a path, incrementing short peer's rc.
109  *
110  * @param path The path to duplicate.
111  */
112 struct CadetPeerPath *
113 path_duplicate (const struct CadetPeerPath *path)
114 {
115   struct CadetPeerPath *aux;
116   unsigned int i;
117
118   aux = path_new (path->length);
119   memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
120   for (i = 0; i < aux->length; i++)
121     GNUNET_PEER_change_rc (aux->peers[i], 1);
122   return aux;
123 }
124
125
126 /**
127  * Get the length of a path.
128  *
129  * @param path The path to measure, with the local peer at any point of it.
130  *
131  * @return Number of hops to reach destination.
132  *         UINT_MAX in case the peer is not in the path.
133  */
134 unsigned int
135 path_get_length (struct CadetPeerPath *path)
136 {
137   if (NULL == path)
138     return UINT_MAX;
139   return path->length;
140 }
141
142
143
144 /**
145  * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
146  *
147  * Never invalidates a two-hop (direct) path, only a core handler can do that.
148  *
149  * Rationale: DHT_get sometimes returns bad cached results, for instance,
150  * on a locally cached result where the PUT followed a path that is no longer
151  * current. The path must remain "known and marked as invalid" for a while.
152  *
153  * @param p Path to invalidate.
154  */
155 void
156 path_invalidate (struct CadetPeerPath *p)
157 {
158   if (NULL != p->path_delete)
159     return;
160
161   LOG (GNUNET_ERROR_TYPE_INFO, "Invalidating path %p (%u)\n", p, p->length);
162   p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
163                                                  &path_destroy_delayed, p);
164 }
165
166
167 /**
168  * Builds a path from a PeerIdentity array.
169  *
170  * @param peers PeerIdentity array.
171  * @param size Size of the @c peers array.
172  * @param myid ID of local peer, to find @c own_pos.
173  * @param own_pos Output parameter: own position in the path.
174  *
175  * @return Fixed and shortened path.
176  */
177 struct CadetPeerPath *
178 path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
179                           unsigned int size,
180                           GNUNET_PEER_Id myid,
181                           unsigned int *own_pos)
182 {
183   struct CadetPeerPath *path;
184   GNUNET_PEER_Id shortid;
185   unsigned int i;
186   unsigned int j;
187   unsigned int offset;
188
189   /* Create path */
190   LOG (GNUNET_ERROR_TYPE_DEBUG, "  Creating path...\n");
191   path = path_new (size);
192   *own_pos = 0;
193   offset = 0;
194   for (i = 0; i < size; i++)
195   {
196     LOG (GNUNET_ERROR_TYPE_DEBUG, "  - %u: taking %s\n",
197          i, GNUNET_i2s (&peers[i]));
198     shortid = GNUNET_PEER_intern (&peers[i]);
199
200     /* Check for loops / duplicates */
201     for (j = 0; j < i - offset; j++)
202     {
203       if (path->peers[j] == shortid)
204       {
205         LOG (GNUNET_ERROR_TYPE_DEBUG, "    already exists at pos %u\n", j);
206         offset = i - j;
207         LOG (GNUNET_ERROR_TYPE_DEBUG, "    offset now %u\n", offset);
208         GNUNET_PEER_change_rc (shortid, -1);
209       }
210     }
211     LOG (GNUNET_ERROR_TYPE_DEBUG, "    storing at %u\n", i - offset);
212     path->peers[i - offset] = shortid;
213     if (path->peers[i - offset] == myid)
214       *own_pos = i - offset;
215   }
216   path->length -= offset;
217
218   if (path->peers[*own_pos] != myid)
219   {
220     /* create path: self not found in path through self */
221     GNUNET_break_op (0);
222     path_destroy (path);
223     return NULL;
224   }
225
226   return path;
227 }
228
229
230 /**
231  * Test if two paths are equivalent (equal or revese of each other).
232  *
233  * @param p1 First path
234  * @param p2 Second path
235  *
236  * @return GNUNET_YES if both paths are equivalent
237  *         GNUNET_NO otherwise
238  */
239 int
240 path_equivalent (const struct CadetPeerPath *p1,
241                  const struct CadetPeerPath *p2)
242 {
243   unsigned int i;
244   unsigned int l;
245   unsigned int half;
246
247   if (NULL == p1 || NULL == p2)
248     return GNUNET_NO;
249
250   if (p1->length != p2->length)
251     return GNUNET_NO;
252
253   l = p1->length;
254   if (0 == memcmp (p1->peers, p2->peers, sizeof (p1->peers[0]) * l))
255     return GNUNET_YES;
256
257   half = l / 2;
258   l = l - 1;
259   for (i = 0; i <= half; i++)
260     if (p1->peers[i] != p2->peers[l - i])
261       return GNUNET_NO;
262
263   return GNUNET_YES;
264 }
265
266
267 /**
268  * Test if a path is valid (or at least not known to be invalid).
269  *
270  * @param path Path to test.
271  *
272  * @return #GNUNET_YES If the path is valid or unknown,
273  *         #GNUNET_NO If the path is known to be invalid.
274  */
275 int
276 path_is_valid (const struct CadetPeerPath *path)
277 {
278   return (NULL == path->path_delete);
279 }
280
281
282 /**
283  * Destroy the path and free any allocated resources linked to it
284  *
285  * @param p the path to destroy
286  *
287  * @return GNUNET_OK on success
288  */
289 int
290 path_destroy (struct CadetPeerPath *p)
291 {
292   if (NULL == p)
293     return GNUNET_OK;
294
295   LOG (GNUNET_ERROR_TYPE_INFO, "destroying path %p (%u)\n", p, p->length);
296   GNUNET_PEER_decrement_rcs (p->peers, p->length);
297   GNUNET_free_non_null (p->peers);
298   if (NULL != p->path_delete)
299     GNUNET_SCHEDULER_cancel (p->path_delete);
300   GNUNET_free (p);
301   return GNUNET_OK;
302 }
303
304
305 /**
306  * Compare two paths.
307  *
308  * @param p1 First path.
309  * @param p2 Second path.
310  *
311  * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
312  *         < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
313  *         0 if they are identical.
314  */
315 int
316 path_cmp (const struct CadetPeerPath *p1, const struct CadetPeerPath *p2)
317 {
318   if (p1->length > p2->length)
319     return 1;
320
321   if (p1->length < p2->length)
322     return -1;
323
324   return memcmp (p1->peers, p2->peers, sizeof (GNUNET_PEER_Id) * p1->length);
325 }
326
327
328 char *
329 path_2s (struct CadetPeerPath *p)
330 {
331   char *s;
332   char *old;
333   unsigned int i;
334
335   old = GNUNET_strdup ("");
336   for (i = 0; i < p->length; i++)
337   {
338     GNUNET_asprintf (&s, "%s %s",
339                      old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
340     GNUNET_free_non_null (old);
341     old = s;
342   }
343   return old;
344 }
345
346
347 void
348 path_debug (struct CadetPeerPath *p)
349 {
350   unsigned int i;
351
352   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
353   for (i = 0; i < p->length; i++)
354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
355                 GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
356   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
357 }