-remove debug message
[oweals/gnunet.git] / src / cadet / cadet_api_get_path.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011, 2017 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file cadet/cadet_api_get_path.c
22  * @brief cadet api: client implementation of cadet service
23  * @author Bartlomiej Polot
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_cadet_service.h"
30 #include "cadet.h"
31 #include "cadet_protocol.h"
32
33
34 /**
35  * Operation handle.
36  */
37 struct GNUNET_CADET_GetPath
38 {
39   /**
40    * Monitor callback
41    */
42   GNUNET_CADET_PathCB path_cb;
43
44   /**
45    * Closure for @c path_cb.
46    */
47   void *path_cb_cls;
48
49   /**
50    * Message queue to talk to CADET service.
51    */
52   struct GNUNET_MQ_Handle *mq;
53
54   /**
55    * Configuration we use.
56    */
57   const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59   /**
60    * Task to reconnect.
61    */
62   struct GNUNET_SCHEDULER_Task *reconnect_task;
63
64   /**
65    * Backoff for reconnect attempts.
66    */
67   struct GNUNET_TIME_Relative backoff;
68
69   /**
70    * Peer we want information about.
71    */
72   struct GNUNET_PeerIdentity id;
73 };
74
75
76 /**
77  * Check that message received from CADET service is well-formed.
78  *
79  * @param cls unused
80  * @param message the message we got
81  * @return #GNUNET_OK if the message is well-formed,
82  *         #GNUNET_SYSERR otherwise
83  */
84 static int
85 check_get_path (void *cls,
86                 const struct GNUNET_CADET_LocalInfoPath *message)
87 {
88   size_t msize = sizeof(struct GNUNET_CADET_LocalInfoPath);
89   size_t esize;
90
91   (void) cls;
92   esize = ntohs (message->header.size);
93   if (esize < msize)
94   {
95     GNUNET_break (0);
96     return GNUNET_SYSERR;
97   }
98   if (0 != ((esize - msize) % sizeof(struct GNUNET_PeerIdentity)))
99   {
100     GNUNET_break (0);
101     return GNUNET_SYSERR;
102   }
103   return GNUNET_OK;
104 }
105
106
107 /**
108  * Process a local peer info reply, pass info to the user.
109  *
110  * @param cls Closure
111  * @param message Message itself.
112  */
113 static void
114 handle_get_path (void *cls,
115                  const struct GNUNET_CADET_LocalInfoPath *message)
116 {
117   struct GNUNET_CADET_GetPath *gp = cls;
118   struct GNUNET_CADET_PeerPathDetail ppd;
119
120   ppd.peer = gp->id;
121   ppd.path = (const struct GNUNET_PeerIdentity *) &message[1];
122   ppd.target_offset = ntohl (message->off);
123   ppd.path_length = (ntohs (message->header.size) - sizeof(*message))
124                     / sizeof(struct GNUNET_PeerIdentity);
125   gp->path_cb (gp->path_cb_cls,
126                &ppd);
127 }
128
129
130 /**
131  * Process a local peer info reply, pass info to the user.
132  *
133  * @param cls Closure
134  * @param message Message itself.
135  */
136 static void
137 handle_get_path_end (void *cls,
138                      const struct GNUNET_MessageHeader *message)
139 {
140   struct GNUNET_CADET_GetPath *gp = cls;
141
142   (void) message;
143   gp->path_cb (gp->path_cb_cls,
144                NULL);
145   GNUNET_CADET_get_path_cancel (gp);
146 }
147
148
149 /**
150  * Reconnect to the service and try again.
151  *
152  * @param cls a `struct GNUNET_CADET_GetPath` operation
153  */
154 static void
155 reconnect (void *cls);
156
157
158 /**
159  * Function called on connection trouble.  Reconnects.
160  *
161  * @param cls a `struct GNUNET_CADET_GetPath`
162  * @param error error code from MQ
163  */
164 static void
165 error_handler (void *cls,
166                enum GNUNET_MQ_Error error)
167 {
168   struct GNUNET_CADET_GetPath *gp = cls;
169
170   GNUNET_MQ_destroy (gp->mq);
171   gp->mq = NULL;
172   gp->backoff = GNUNET_TIME_randomized_backoff (gp->backoff,
173                                                 GNUNET_TIME_UNIT_MINUTES);
174   gp->reconnect_task = GNUNET_SCHEDULER_add_delayed (gp->backoff,
175                                                      &reconnect,
176                                                      gp);
177 }
178
179
180 /**
181  * Reconnect to the service and try again.
182  *
183  * @param cls a `struct GNUNET_CADET_GetPath` operation
184  */
185 static void
186 reconnect (void *cls)
187 {
188   struct GNUNET_CADET_GetPath *gp = cls;
189   struct GNUNET_MQ_MessageHandler handlers[] = {
190     GNUNET_MQ_hd_var_size (get_path,
191                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PATH,
192                            struct GNUNET_CADET_LocalInfoPath,
193                            gp),
194     GNUNET_MQ_hd_fixed_size (get_path_end,
195                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PATH_END,
196                              struct GNUNET_MessageHeader,
197                              gp),
198     GNUNET_MQ_handler_end ()
199   };
200   struct GNUNET_CADET_RequestPathInfoMessage *msg;
201   struct GNUNET_MQ_Envelope *env;
202
203   gp->reconnect_task = NULL;
204   gp->mq = GNUNET_CLIENT_connect (gp->cfg,
205                                   "cadet",
206                                   handlers,
207                                   &error_handler,
208                                   gp);
209   if (NULL == gp->mq)
210     return;
211   env = GNUNET_MQ_msg (msg,
212                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_PATH);
213   msg->peer = gp->id;
214   GNUNET_MQ_send (gp->mq,
215                   env);
216 }
217
218
219 /**
220  * Request information about paths known to the running cadet peer.
221  *
222  * @param cfg configuration to use
223  * @param id Peer whose paths to examine.
224  * @param callback Function to call with the requested data.
225  * @param callback_cls Closure for @c callback.
226  * @return NULL on error
227  */
228 struct GNUNET_CADET_GetPath *
229 GNUNET_CADET_get_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
230                        const struct GNUNET_PeerIdentity *id,
231                        GNUNET_CADET_PathCB callback,
232                        void *callback_cls)
233 {
234   struct GNUNET_CADET_GetPath *gp;
235
236   if (NULL == callback)
237   {
238     GNUNET_break (0);
239     return NULL;
240   }
241   gp = GNUNET_new (struct GNUNET_CADET_GetPath);
242   gp->path_cb = callback;
243   gp->path_cb_cls = callback_cls;
244   gp->cfg = cfg;
245   gp->id = *id;
246   reconnect (gp);
247   if (NULL == gp->mq)
248   {
249     GNUNET_free (gp);
250     return NULL;
251   }
252   return gp;
253 }
254
255
256 /**
257  * Cancel @a gp operation.
258  *
259  * @param gp operation to cancel
260  * @return closure from #GNUNET_CADET_get_path().
261  */
262 void *
263 GNUNET_CADET_get_path_cancel (struct GNUNET_CADET_GetPath *gp)
264 {
265   void *ret = gp->path_cb_cls;
266
267   if (NULL != gp->mq)
268     GNUNET_MQ_destroy (gp->mq);
269   if (NULL != gp->reconnect_task)
270     GNUNET_SCHEDULER_cancel (gp->reconnect_task);
271   GNUNET_free (gp);
272   return ret;
273 }
274
275
276 /* end of cadet_api_get_path.c */