- moved timeout handling responsibility from for nat tests from caller to the library
[oweals/gnunet.git] / src / cadet / cadet_path.c
1 /*
2      This file is part of GNUnet.
3      (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 /**
32  * @brief Destroy a path after some time has past.
33  *
34  * If the path is returned from DHT again after a while, try again.
35  *
36  * @param cls Closure (path to destroy).
37  * @param tc Task context.
38  */
39 static void
40 path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
41 {
42   struct CadetPeerPath *path = cls;
43   struct CadetPeer *peer;
44
45   path->path_delete = GNUNET_SCHEDULER_NO_TASK;
46   peer = GCP_get_short (path->peers[path->length - 1]);
47   GCP_remove_path (peer, path);
48 }
49
50
51 /**
52  * Create a new path
53  *
54  * @param length How many hops will the path have.
55  *
56  * @return A newly allocated path with a peer array of the specified length.
57  */
58 struct CadetPeerPath *
59 path_new (unsigned int length)
60 {
61   struct CadetPeerPath *p;
62
63   p = GNUNET_new (struct CadetPeerPath);
64   if (length > 0)
65   {
66     p->length = length;
67     p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
68   }
69   return p;
70 }
71
72
73 /**
74  * Invert the path
75  *
76  * @param path the path to invert
77  */
78 void
79 path_invert (struct CadetPeerPath *path)
80 {
81   GNUNET_PEER_Id aux;
82   unsigned int i;
83
84   for (i = 0; i < path->length / 2; i++)
85   {
86     aux = path->peers[i];
87     path->peers[i] = path->peers[path->length - i - 1];
88     path->peers[path->length - i - 1] = aux;
89   }
90 }
91
92
93 /**
94  * Duplicate a path, incrementing short peer's rc.
95  *
96  * @param path The path to duplicate.
97  */
98 struct CadetPeerPath *
99 path_duplicate (const struct CadetPeerPath *path)
100 {
101   struct CadetPeerPath *aux;
102   unsigned int i;
103
104   aux = path_new (path->length);
105   memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
106   for (i = 0; i < aux->length; i++)
107     GNUNET_PEER_change_rc (aux->peers[i], 1);
108   return aux;
109 }
110
111
112 /**
113  * Get the length of a path.
114  *
115  * @param path The path to measure, with the local peer at any point of it.
116  *
117  * @return Number of hops to reach destination.
118  *         UINT_MAX in case the peer is not in the path.
119  */
120 unsigned int
121 path_get_length (struct CadetPeerPath *path)
122 {
123   if (NULL == path)
124     return UINT_MAX;
125   return path->length;
126 }
127
128
129
130 /**
131  * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
132  *
133  * DHT_get sometimes returns bad cached results, for instance, on a locally
134  * cached result where the PUT followed a path that is no longer current.
135  *
136  * @param p Path to invalidate.
137  */
138 void
139 path_invalidate (struct CadetPeerPath *p)
140 {
141   if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
142     return;
143
144   p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
145                                                  &path_destroy_delayed, p);
146 }
147
148
149 /**
150  * Test if a path is valid (or at least not known to be invalid).
151  *
152  * @param path Path to test.
153  *
154  * @return #GNUNET_YES If the path is valid or unknown,
155  *         #GNUNET_NO If the path is known to be invalid.
156  */
157 int
158 path_is_valid (const struct CadetPeerPath *path)
159 {
160   return (GNUNET_SCHEDULER_NO_TASK == path->path_delete);
161 }
162
163
164 /**
165  * Destroy the path and free any allocated resources linked to it
166  *
167  * @param p the path to destroy
168  *
169  * @return GNUNET_OK on success
170  */
171 int
172 path_destroy (struct CadetPeerPath *p)
173 {
174   if (NULL == p)
175     return GNUNET_OK;
176
177   GNUNET_PEER_decrement_rcs (p->peers, p->length);
178   GNUNET_free_non_null (p->peers);
179   if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
180     GNUNET_SCHEDULER_cancel (p->path_delete);
181   GNUNET_free (p);
182   return GNUNET_OK;
183 }
184
185 char *
186 path_2s (struct CadetPeerPath *p)
187 {
188   char *s;
189   char *old;
190   unsigned int i;
191
192   old = GNUNET_strdup ("");
193   for (i = 0; i < p->length; i++)
194   {
195     GNUNET_asprintf (&s, "%s %s",
196                      old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
197     GNUNET_free_non_null (old);
198     old = s;
199   }
200   return s;
201 }
202
203 void
204 path_debug (struct CadetPeerPath *p)
205 {
206   unsigned int i;
207
208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
209   for (i = 0; i < p->length; i++)
210     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
211                 GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
213 }