more work on #5385
[oweals/gnunet.git] / src / cadet / cadet_api_get_tunnel.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_tunnel.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_GetTunnel
38 {
39
40   /**
41    * Monitor callback
42    */
43   GNUNET_CADET_TunnelCB callback;
44
45   /**
46    * Closure for @e callback.
47    */
48   void *callback_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 the `struct GNUNET_CADET_Handle`
82  * @param msg 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_tunnel (void *cls,
88                   const struct GNUNET_CADET_LocalInfoTunnel *msg)
89 {
90   unsigned int ch_n;
91   unsigned int c_n;
92   size_t esize;
93   size_t msize;
94
95   (void) cls;
96   /* Verify message sanity */
97   msize = ntohs (msg->header.size);
98   esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
99   if (esize > msize)
100   {
101     GNUNET_break (0);
102     return GNUNET_SYSERR;
103   }
104   ch_n = ntohl (msg->channels);
105   c_n = ntohl (msg->connections);
106   esize += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
107   esize += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
108   if (msize != esize)
109   {
110     GNUNET_break_op (0);
111     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
112                 "m:%u, e: %u (%u ch, %u conn)\n",
113                 (unsigned int) msize,
114                 (unsigned int) esize,
115                 ch_n,
116                 c_n);
117     return GNUNET_SYSERR;
118   }
119   return GNUNET_OK;
120 }
121
122
123 /**
124  * Process a local tunnel info reply, pass info to the user.
125  *
126  * @param cls a `struct GNUNET_CADET_GetTunnel *`
127  * @param msg Message itself.
128  */
129 static void
130 handle_get_tunnel (void *cls,
131                    const struct GNUNET_CADET_LocalInfoTunnel *msg)
132 {
133   struct GNUNET_CADET_GetTunnel *gt = cls;
134   unsigned int ch_n;
135   unsigned int c_n;
136   const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
137   const struct GNUNET_CADET_ChannelTunnelNumber *chns;
138
139   ch_n = ntohl (msg->channels);
140   c_n = ntohl (msg->connections);
141
142   /* Call Callback with tunnel info. */
143   conns = (const struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
144   chns = (const struct GNUNET_CADET_ChannelTunnelNumber *) &conns[c_n];
145   gt->callback (gt->callback_cls,
146                 &msg->destination,
147                 ch_n,
148                 c_n,
149                 chns,
150                 conns,
151                 ntohs (msg->estate),
152                 ntohs (msg->cstate));
153 }
154
155
156 /**
157  * Reconnect to the service and try again.
158  *
159  * @param cls a `struct GNUNET_CADET_GetTunnel` operation
160  */
161 static void
162 reconnect (void *cls);
163
164
165 /**
166  * Function called on connection trouble.  Reconnects.
167  *
168  * @param cls a `struct GNUNET_CADET_GetTunnel`
169  * @param error error code from MQ
170  */
171 static void
172 error_handler (void *cls,
173                enum GNUNET_MQ_Error error)
174 {
175   struct GNUNET_CADET_GetTunnel *gt = cls;
176
177   GNUNET_MQ_destroy (gt->mq);
178   gt->mq = NULL;
179   gt->backoff = GNUNET_TIME_randomized_backoff (gt->backoff,
180                                                 GNUNET_TIME_UNIT_MINUTES);
181   gt->reconnect_task = GNUNET_SCHEDULER_add_delayed (gt->backoff,
182                                                      &reconnect,
183                                                      gt);
184 }
185
186   
187 /**
188  * Reconnect to the service and try again.
189  *
190  * @param cls a `struct GNUNET_CADET_GetTunnel` operation
191  */
192 static void
193 reconnect (void *cls)
194 {
195   struct GNUNET_CADET_GetTunnel *gt = cls;
196   struct GNUNET_MQ_MessageHandler handlers[] = {
197     GNUNET_MQ_hd_var_size (get_tunnel,
198                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
199                            struct GNUNET_CADET_LocalInfoTunnel,
200                            gt),
201     GNUNET_MQ_handler_end ()
202   };
203   struct GNUNET_MQ_Envelope *env;
204   struct GNUNET_CADET_LocalInfo *msg;
205   
206   gt->reconnect_task = NULL;
207   gt->mq = GNUNET_CLIENT_connect (gt->cfg,
208                                   "cadet",
209                                   handlers,
210                                   &error_handler,
211                                   gt);
212   if (NULL == gt->mq)
213     return;
214   env = GNUNET_MQ_msg (msg,
215                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
216   msg->peer = gt->id;
217   GNUNET_MQ_send (gt->mq,
218                   env);
219 }
220
221 /**
222  * Request information about a tunnel of the running cadet peer.
223  * The callback will be called for the tunnel once.
224  *
225  * @param cfg configuration to use
226  * @param id Peer whose tunnel to examine.
227  * @param callback Function to call with the requested data.
228  * @param callback_cls Closure for @c callback.
229  * @return NULL on error
230  */
231 struct GNUNET_CADET_GetTunnel *
232 GNUNET_CADET_get_tunnel (const struct GNUNET_CONFIGURATION_Handle *cfg,
233                          const struct GNUNET_PeerIdentity *id,
234                          GNUNET_CADET_TunnelCB callback,
235                          void *callback_cls)
236 {
237   struct GNUNET_CADET_GetTunnel *gt;
238
239   if (NULL == callback)
240   {
241     GNUNET_break (0);
242     return NULL;
243   }
244   gt = GNUNET_new (struct GNUNET_CADET_GetTunnel);
245   gt->callback = callback;
246   gt->callback_cls = callback_cls;
247   gt->cfg = cfg;
248   gt->id = *id;
249   reconnect (gt);
250   if (NULL == gt->mq)
251   {
252     GNUNET_free (gt);
253     return NULL;
254   }
255   return gt;
256 }
257
258
259 /**
260  * Cancel a monitor request. The monitor callback will not be called.
261  *
262  * @param lt operation handle
263  * @return Closure given to #GNUNET_CADET_get_tunnel(), if any.
264  */
265 void *
266 GNUNET_CADET_get_tunnel_cancel (struct GNUNET_CADET_GetTunnel *gt)
267 {
268   void *ret = gt->callback_cls;
269
270   if (NULL != gt->mq)
271     GNUNET_MQ_destroy (gt->mq);
272   if (NULL != gt->reconnect_task)
273     GNUNET_SCHEDULER_cancel (gt->reconnect_task);
274   GNUNET_free (gt);
275   return ret;
276 }
277
278 /* end of cadet_api_get_tunnel.c */