more work on #5385
[oweals/gnunet.git] / src / cadet / cadet_api_list_tunnels.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011, 2017, 2019 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_list_tunnels.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_ListTunnels
38 {
39
40   /**
41    * Monitor callback
42    */
43   GNUNET_CADET_TunnelsCB tunnels_cb;
44
45   /**
46    * Info callback closure for @c tunnels_cb.
47    */
48   void *tunnels_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
72
73 /**
74  * Check that message received from CADET service is well-formed.
75  *
76  * @param cls the `struct GNUNET_CADET_Handle`
77  * @param message the message we got
78  * @return #GNUNET_OK if the message is well-formed,
79  *         #GNUNET_SYSERR otherwise
80  */
81 static int
82 check_get_tunnels (void *cls,
83                    const struct GNUNET_MessageHeader *message)
84 {
85   size_t esize;
86
87   (void) cls;
88   esize = ntohs (message->size);
89   if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) == esize)
90     return GNUNET_OK;
91   if (sizeof (struct GNUNET_MessageHeader) == esize)
92     return GNUNET_OK;
93   return GNUNET_SYSERR;
94 }
95
96
97 /**
98  * Process a local reply about info on all tunnels, pass info to the user.
99  *
100  * @param cls a `struct GNUNET_CADET_ListTunnels *`
101  * @param message Message itself.
102  */
103 static void
104 handle_get_tunnels (void *cls,
105                     const struct GNUNET_MessageHeader *msg)
106 {
107   struct GNUNET_CADET_ListTunnels *lt = cls;
108   const struct GNUNET_CADET_LocalInfoTunnel *info =
109     (const struct GNUNET_CADET_LocalInfoTunnel *) msg;
110
111   // FIXME: use two message types!
112   if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) == ntohs (msg->size))
113     lt->tunnels_cb (lt->tunnels_cb_cls,
114                     &info->destination,
115                     ntohl (info->channels),
116                     ntohl (info->connections),
117                     ntohs (info->estate),
118                     ntohs (info->cstate));
119   else
120   {
121     lt->tunnels_cb (lt->tunnels_cb_cls,
122                     NULL,
123                     0,
124                     0,
125                     0,
126                     0);
127     GNUNET_CADET_list_tunnels_cancel (lt);
128   }
129 }
130
131
132 /**
133  * Reconnect to the service and try again.
134  *
135  * @param cls a `struct GNUNET_CADET_ListTunnels` operation
136  */
137 static void
138 reconnect (void *cls);
139
140
141 /**
142  * Function called on connection trouble.  Reconnects.
143  *
144  * @param cls a `struct GNUNET_CADET_ListTunnels`
145  * @param error error code from MQ
146  */
147 static void
148 error_handler (void *cls,
149                enum GNUNET_MQ_Error error)
150 {
151   struct GNUNET_CADET_ListTunnels *lt = cls;
152
153   GNUNET_MQ_destroy (lt->mq);
154   lt->mq = NULL;
155   lt->backoff = GNUNET_TIME_randomized_backoff (lt->backoff,
156                                                 GNUNET_TIME_UNIT_MINUTES);
157   lt->reconnect_task = GNUNET_SCHEDULER_add_delayed (lt->backoff,
158                                                      &reconnect,
159                                                      lt);
160 }
161
162
163 /**
164  * Reconnect to the service and try again.
165  *
166  * @param cls a `struct GNUNET_CADET_ListTunnels` operation
167  */
168 static void
169 reconnect (void *cls)
170 {
171   struct GNUNET_CADET_ListTunnels *lt = cls;
172   struct GNUNET_MQ_MessageHandler handlers[] = {
173     GNUNET_MQ_hd_var_size (get_tunnels,
174                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
175                            struct GNUNET_MessageHeader,
176                            lt),
177     GNUNET_MQ_handler_end ()
178   };
179   struct GNUNET_MessageHeader *msg;
180   struct GNUNET_MQ_Envelope *env;
181
182   lt->reconnect_task = NULL;
183   lt->mq = GNUNET_CLIENT_connect (lt->cfg,
184                                   "cadet",
185                                   handlers,
186                                   &error_handler,
187                                   lt);  
188   if (NULL == lt->mq)
189     return;
190   env = GNUNET_MQ_msg (msg,
191                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
192   GNUNET_MQ_send (lt->mq,
193                   env);
194 }
195
196
197 /**
198  * Request information about tunnels of the running cadet peer.
199  * The callback will be called for every tunnel of the service.
200  * Only one info request (of any kind) can be active at once.
201  *
202  * WARNING: unstable API, likely to change in the future!
203  *
204  * @param h Handle to the cadet peer.
205  * @param callback Function to call with the requested data.
206  * @param callback_cls Closure for @c callback.
207  * @return NULL on error
208  */
209 struct GNUNET_CADET_ListTunnels *
210 GNUNET_CADET_list_tunnels (const struct GNUNET_CONFIGURATION_Handle *cfg,
211                            GNUNET_CADET_TunnelsCB callback,
212                            void *callback_cls)
213 {
214   struct GNUNET_CADET_ListTunnels *lt;
215
216   if (NULL == callback)
217   {
218     GNUNET_break (0);
219     return NULL;
220   }
221   lt = GNUNET_new (struct GNUNET_CADET_ListTunnels);
222   lt->tunnels_cb = callback;
223   lt->tunnels_cb_cls = callback_cls;
224   lt->cfg = cfg;
225   reconnect (lt);
226   if (NULL == lt->mq)
227   {
228     GNUNET_free (lt);
229     return NULL;
230   }
231   return lt;
232 }
233
234
235 /**
236  * Cancel a monitor request. The monitor callback will not be called.
237  *
238  * @param lt operation handle
239  * @return Closure given to GNUNET_CADET_list_tunnels().
240  */
241 void *
242 GNUNET_CADET_list_tunnels_cancel (struct GNUNET_CADET_ListTunnels *lt)
243 {
244   void *ret = lt->tunnels_cb_cls;
245
246   if (NULL != lt->mq)
247     GNUNET_MQ_destroy (lt->mq);
248   if (NULL != lt->reconnect_task)
249     GNUNET_SCHEDULER_cancel (lt->reconnect_task);
250   GNUNET_free (lt);
251   return ret;
252 }
253
254
255 /* end of cadet_api_list_tunnels.c */