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