uncrustify as demanded.
[oweals/gnunet.git] / src / cadet / cadet_api_get_channel.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_get_channel.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_ChannelMonitor {
38   /**
39    * Channel callback.
40    */
41   GNUNET_CADET_ChannelCB channel_cb;
42
43   /**
44    * Info callback closure for @c channel_cb.
45    */
46   void *channel_cb_cls;
47
48   /**
49    * Configuration we use.
50    */
51   const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53   /**
54    * Message queue to talk to CADET service.
55    */
56   struct GNUNET_MQ_Handle *mq;
57
58   /**
59    * Task to reconnect.
60    */
61   struct GNUNET_SCHEDULER_Task *reconnect_task;
62
63   /**
64    * Backoff for reconnect attempts.
65    */
66   struct GNUNET_TIME_Relative backoff;
67
68   /**
69    * Peer we want information about.
70    */
71   struct GNUNET_PeerIdentity peer;
72 };
73
74
75 /**
76  * Check that message received from CADET service is well-formed.
77  *
78  * @param cls unused
79  * @param message the message we got
80  * @return #GNUNET_OK if the message is well-formed,
81  *         #GNUNET_SYSERR otherwise
82  */
83 static int
84 check_channel_info(void *cls,
85                    const struct GNUNET_CADET_ChannelInfoMessage *message)
86 {
87   (void)cls;
88
89   return GNUNET_OK;
90 }
91
92
93 /**
94  * Process a local peer info reply, pass info to the user.
95  *
96  * @param cls Closure
97  * @param message Message itself.
98  */
99 static void
100 handle_channel_info(void *cls,
101                     const struct GNUNET_CADET_ChannelInfoMessage *message)
102 {
103   struct GNUNET_CADET_ChannelMonitor *cm = cls;
104   struct GNUNET_CADET_ChannelInternals ci;
105
106   ci.root = message->root;
107   ci.dest = message->dest;
108   cm->channel_cb(cm->channel_cb_cls,
109                  &ci);
110   GNUNET_CADET_get_channel_cancel(cm);
111 }
112
113
114 /**
115  * Process a local peer info reply, pass info to the user.
116  *
117  * @param cls Closure
118  * @param message Message itself.
119  */
120 static void
121 handle_channel_info_end(void *cls,
122                         const struct GNUNET_MessageHeader *message)
123 {
124   struct GNUNET_CADET_ChannelMonitor *cm = cls;
125
126   cm->channel_cb(cm->channel_cb_cls,
127                  NULL);
128   GNUNET_CADET_get_channel_cancel(cm);
129 }
130
131
132 /**
133  * Reconnect to the service and try again.
134  *
135  * @param cls a `struct GNUNET_CADET_ChannelMonitor` 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_ChannelMonitor``
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_ChannelMonitor *cm = cls;
152
153   GNUNET_MQ_destroy(cm->mq);
154   cm->mq = NULL;
155   cm->backoff = GNUNET_TIME_randomized_backoff(cm->backoff,
156                                                GNUNET_TIME_UNIT_MINUTES);
157   cm->reconnect_task = GNUNET_SCHEDULER_add_delayed(cm->backoff,
158                                                     &reconnect,
159                                                     cm);
160 }
161
162
163 /**
164  * Reconnect to the service and try again.
165  *
166  * @param cls a `struct GNUNET_CADET_ChannelMonitor` operation
167  */
168 static void
169 reconnect(void *cls)
170 {
171   struct GNUNET_CADET_ChannelMonitor *cm = cls;
172   struct GNUNET_MQ_MessageHandler handlers[] = {
173     GNUNET_MQ_hd_fixed_size(channel_info_end,
174                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL_END,
175                             struct GNUNET_MessageHeader,
176                             cm),
177     GNUNET_MQ_hd_var_size(channel_info,
178                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL,
179                           struct GNUNET_CADET_ChannelInfoMessage,
180                           cm),
181     GNUNET_MQ_handler_end()
182   };
183   struct GNUNET_CADET_RequestChannelInfoMessage *msg;
184   struct GNUNET_MQ_Envelope *env;
185
186   cm->reconnect_task = NULL;
187   cm->mq = GNUNET_CLIENT_connect(cm->cfg,
188                                  "cadet",
189                                  handlers,
190                                  &error_handler,
191                                  cm);
192   if (NULL == cm->mq)
193     return;
194   env = GNUNET_MQ_msg(msg,
195                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_CHANNEL);
196   msg->target = cm->peer;
197   GNUNET_MQ_send(cm->mq,
198                  env);
199 }
200
201
202 /**
203  * Request information about a specific channel of the running cadet peer.
204  *
205  * @param cfg configuration to use
206  * @param peer ID of the other end of the channel.
207  * @param callback Function to call with the requested data.
208  * @param callback_cls Closure for @c callback.
209  * @return NULL on error
210  */
211 struct GNUNET_CADET_ChannelMonitor *
212 GNUNET_CADET_get_channel(const struct GNUNET_CONFIGURATION_Handle *cfg,
213                          struct GNUNET_PeerIdentity *peer,
214                          GNUNET_CADET_ChannelCB callback,
215                          void *callback_cls)
216 {
217   struct GNUNET_CADET_ChannelMonitor *cm;
218
219   if (NULL == callback)
220     {
221       GNUNET_break(0);
222       return NULL;
223     }
224   cm = GNUNET_new(struct GNUNET_CADET_ChannelMonitor);
225   cm->channel_cb = callback;
226   cm->channel_cb_cls = callback_cls;
227   cm->cfg = cfg;
228   cm->peer = *peer;
229   reconnect(cm);
230   if (NULL == cm->mq)
231     {
232       GNUNET_free(cm);
233       return NULL;
234     }
235   return cm;
236 }
237
238
239 /**
240  * Cancel a channel monitor request. The callback will not be called (anymore).
241  *
242  * @param h Cadet handle.
243  * @return Closure that was given to #GNUNET_CADET_get_channel().
244  */
245 void *
246 GNUNET_CADET_get_channel_cancel(struct GNUNET_CADET_ChannelMonitor *cm)
247 {
248   void *ret = cm->channel_cb_cls;
249
250   if (NULL != cm->mq)
251     GNUNET_MQ_destroy(cm->mq);
252   if (NULL != cm->reconnect_task)
253     GNUNET_SCHEDULER_cancel(cm->reconnect_task);
254   GNUNET_free(cm);
255   return ret;
256 }
257
258 /* end of cadet_api_get_channel.c */