avoid failing hard if 'gnunetcheck' db does not exist
[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   /**
41    * Monitor callback
42    */
43   GNUNET_CADET_PathCB path_cb;
44
45   /**
46    * Closure for @c path_cb.
47    */
48   void *path_cb_cls;
49
50   /**
51    * Message queue to talk to CADET service.
52    */
53   struct GNUNET_MQ_Handle *mq;
54
55   /**
56    * Configuration we use.
57    */
58   const struct GNUNET_CONFIGURATION_Handle *cfg;
59
60   /**
61    * Task to reconnect.
62    */
63   struct GNUNET_SCHEDULER_Task *reconnect_task;
64
65   /**
66    * Backoff for reconnect attempts.
67    */
68   struct GNUNET_TIME_Relative backoff;
69
70   /**
71    * Peer we want information about.
72    */
73   struct GNUNET_PeerIdentity id;
74
75 };
76
77
78 /**
79  * Check that message received from CADET service is well-formed.
80  *
81  * @param cls unused
82  * @param message the message we got
83  * @return #GNUNET_OK if the message is well-formed,
84  *         #GNUNET_SYSERR otherwise
85  */
86 static int
87 check_get_path (void *cls,
88                 const struct GNUNET_CADET_LocalInfoPath *message)
89 {
90   size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPath);
91   size_t esize;
92
93   (void) cls;
94   esize = ntohs (message->header.size);
95   if (esize < msize)
96   {
97     GNUNET_break (0);
98     return GNUNET_SYSERR;
99   }
100   if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
101   {
102     GNUNET_break (0);
103     return GNUNET_SYSERR;
104   }
105   return GNUNET_OK;
106 }
107
108
109 /**
110  * Process a local peer info reply, pass info to the user.
111  *
112  * @param cls Closure
113  * @param message Message itself.
114  */
115 static void
116 handle_get_path (void *cls,
117                  const struct GNUNET_CADET_LocalInfoPath *message)
118 {
119   struct GNUNET_CADET_GetPath *gp = cls;
120   struct GNUNET_CADET_PeerPathDetail ppd;
121
122   ppd.peer = gp->id;
123   ppd.path = (const struct GNUNET_PeerIdentity *) &message[1];
124   ppd.target_offset = ntohl (message->off);
125   ppd.path_length = (ntohs (message->header.size) - sizeof (*message))
126     / sizeof (struct GNUNET_PeerIdentity);
127   gp->path_cb (gp->path_cb_cls,
128                &ppd);
129 }
130
131
132 /**
133  * Process a local peer info reply, pass info to the user.
134  *
135  * @param cls Closure
136  * @param message Message itself.
137  */
138 static void
139 handle_get_path_end (void *cls,
140                      const struct GNUNET_MessageHeader *message)
141 {
142   struct GNUNET_CADET_GetPath *gp = cls;
143
144   (void) message;
145   gp->path_cb (gp->path_cb_cls,
146                NULL);
147   GNUNET_CADET_get_path_cancel (gp);
148 }
149
150
151 /**
152  * Reconnect to the service and try again.
153  *
154  * @param cls a `struct GNUNET_CADET_GetPath` operation
155  */
156 static void
157 reconnect (void *cls);
158
159
160 /**
161  * Function called on connection trouble.  Reconnects.
162  *
163  * @param cls a `struct GNUNET_CADET_GetPath`
164  * @param error error code from MQ
165  */
166 static void
167 error_handler (void *cls,
168                enum GNUNET_MQ_Error error)
169 {
170   struct GNUNET_CADET_GetPath *gp = cls;
171
172   GNUNET_MQ_destroy (gp->mq);
173   gp->mq = NULL;
174   gp->backoff = GNUNET_TIME_randomized_backoff (gp->backoff,
175                                                 GNUNET_TIME_UNIT_MINUTES);
176   gp->reconnect_task = GNUNET_SCHEDULER_add_delayed (gp->backoff,
177                                                      &reconnect,
178                                                      gp);
179 }
180
181
182 /**
183  * Reconnect to the service and try again.
184  *
185  * @param cls a `struct GNUNET_CADET_GetPath` operation
186  */
187 static void
188 reconnect (void *cls)
189 {
190   struct GNUNET_CADET_GetPath *gp = cls;
191   struct GNUNET_MQ_MessageHandler handlers[] = {
192     GNUNET_MQ_hd_var_size (get_path,
193                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PATH,
194                            struct GNUNET_CADET_LocalInfoPath,
195                            gp),
196     GNUNET_MQ_hd_fixed_size (get_path_end,
197                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PATH_END,
198                              struct GNUNET_MessageHeader,
199                              gp),
200     GNUNET_MQ_handler_end ()
201   };
202   struct GNUNET_CADET_RequestPathInfoMessage *msg;
203   struct GNUNET_MQ_Envelope *env;
204
205   gp->reconnect_task = NULL;
206   gp->mq = GNUNET_CLIENT_connect (gp->cfg,
207                                   "cadet",
208                                   handlers,
209                                   &error_handler,
210                                   gp);
211   if (NULL == gp->mq)
212     return;
213   env = GNUNET_MQ_msg (msg,
214                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_PATH);
215   msg->peer = gp->id;
216   GNUNET_MQ_send (gp->mq,
217                   env);
218 }
219
220
221 /**
222  * Request information about paths known to the running cadet peer.
223  *
224  * @param cfg configuration to use
225  * @param id Peer whose paths to examine.
226  * @param callback Function to call with the requested data.
227  * @param callback_cls Closure for @c callback.
228  * @return NULL on error
229  */
230 struct GNUNET_CADET_GetPath *
231 GNUNET_CADET_get_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
232                        const struct GNUNET_PeerIdentity *id,
233                        GNUNET_CADET_PathCB callback,
234                        void *callback_cls)
235 {
236   struct GNUNET_CADET_GetPath *gp;
237
238   if (NULL == callback)
239   {
240     GNUNET_break (0);
241     return NULL;
242   }
243   gp = GNUNET_new (struct GNUNET_CADET_GetPath);
244   gp->path_cb = callback;
245   gp->path_cb_cls = callback_cls;
246   gp->cfg = cfg;
247   gp->id = *id;
248   reconnect (gp);
249   if (NULL == gp->mq)
250   {
251     GNUNET_free (gp);
252     return NULL;
253   }
254   return gp;
255 }
256
257
258 /**
259  * Cancel @a gp operation.
260  *
261  * @param gp operation to cancel
262  * @return closure from #GNUNET_CADET_get_path().
263  */
264 void *
265 GNUNET_CADET_get_path_cancel (struct GNUNET_CADET_GetPath *gp)
266 {
267   void *ret = gp->path_cb_cls;
268
269   if (NULL != gp->mq)
270     GNUNET_MQ_destroy (gp->mq);
271   if (NULL != gp->reconnect_task)
272     GNUNET_SCHEDULER_cancel (gp->reconnect_task);
273   GNUNET_free (gp);
274   return ret;
275 }
276
277
278 /* end of cadet_api_get_path.c */