Merge branch 'master' of gnunet.org:gnunet
[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
40   /**
41    * Channel callback.
42    */
43   GNUNET_CADET_ChannelCB channel_cb;
44
45   /**
46    * Info callback closure for @c channel_cb.
47    */
48   void *channel_cb_cls;
49
50   /**
51    * Configuration we use.
52    */
53   const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55   /**
56    * Message queue to talk to CADET service.
57    */
58   struct GNUNET_MQ_Handle *mq;
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 peer;
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_channel_info (void *cls,
88                     const struct GNUNET_CADET_ChannelInfoMessage *message)
89 {
90   (void) cls;
91   
92   return GNUNET_OK;
93 }
94
95
96 /**
97  * Process a local peer info reply, pass info to the user.
98  *
99  * @param cls Closure 
100  * @param message Message itself.
101  */
102 static void
103 handle_channel_info (void *cls,
104                      const struct GNUNET_CADET_ChannelInfoMessage *message)
105 {
106   struct GNUNET_CADET_ChannelMonitor *cm = cls;
107   struct GNUNET_CADET_ChannelInternals ci;
108
109   ci.root = message->root;
110   ci.dest = message->dest;
111   cm->channel_cb (cm->channel_cb_cls,
112                   &ci);
113   GNUNET_CADET_get_channel_cancel (cm);
114 }
115
116
117 /**
118  * Process a local peer info reply, pass info to the user.
119  *
120  * @param cls Closure 
121  * @param message Message itself.
122  */
123 static void
124 handle_channel_info_end (void *cls,
125                          const struct GNUNET_MessageHeader *message)
126 {
127   struct GNUNET_CADET_ChannelMonitor *cm = cls;
128
129   cm->channel_cb (cm->channel_cb_cls,
130                   NULL);
131   GNUNET_CADET_get_channel_cancel (cm);
132 }
133
134
135 /**
136  * Reconnect to the service and try again.
137  *
138  * @param cls a `struct GNUNET_CADET_ChannelMonitor` operation
139  */
140 static void
141 reconnect (void *cls);
142
143
144 /**
145  * Function called on connection trouble.  Reconnects.
146  *
147  * @param cls a `struct GNUNET_CADET_ChannelMonitor``
148  * @param error error code from MQ
149  */
150 static void
151 error_handler (void *cls,
152                enum GNUNET_MQ_Error error)
153 {
154   struct GNUNET_CADET_ChannelMonitor *cm = cls;
155
156   GNUNET_MQ_destroy (cm->mq);
157   cm->mq = NULL;
158   cm->backoff = GNUNET_TIME_randomized_backoff (cm->backoff,
159                                                 GNUNET_TIME_UNIT_MINUTES);
160   cm->reconnect_task = GNUNET_SCHEDULER_add_delayed (cm->backoff,
161                                                      &reconnect,
162                                                      cm);
163 }
164
165
166 /**
167  * Reconnect to the service and try again.
168  *
169  * @param cls a `struct GNUNET_CADET_ChannelMonitor` operation
170  */
171 static void
172 reconnect (void *cls)
173 {
174   struct GNUNET_CADET_ChannelMonitor *cm = cls;
175   struct GNUNET_MQ_MessageHandler handlers[] = {
176     GNUNET_MQ_hd_fixed_size (channel_info_end,
177                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL_END,
178                              struct GNUNET_MessageHeader,
179                              cm),
180     GNUNET_MQ_hd_var_size (channel_info,
181                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL,
182                            struct GNUNET_CADET_ChannelInfoMessage,
183                            cm),
184     GNUNET_MQ_handler_end ()
185   };
186   struct GNUNET_CADET_RequestChannelInfoMessage *msg;
187   struct GNUNET_MQ_Envelope *env;
188  
189   cm->reconnect_task = NULL;
190   cm->mq = GNUNET_CLIENT_connect (cm->cfg,
191                                   "cadet",
192                                   handlers,
193                                   &error_handler,
194                                   cm);
195   if (NULL == cm->mq)
196     return;                      
197   env = GNUNET_MQ_msg (msg,
198                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_CHANNEL);
199   msg->target = cm->peer;
200   GNUNET_MQ_send (cm->mq,
201                   env);
202 }
203
204
205 /**
206  * Request information about a specific channel of the running cadet peer.
207  *
208  * @param cfg configuration to use
209  * @param peer ID of the other end of the channel.
210  * @param callback Function to call with the requested data.
211  * @param callback_cls Closure for @c callback.
212  * @return NULL on error
213  */
214 struct GNUNET_CADET_ChannelMonitor *
215 GNUNET_CADET_get_channel (const struct GNUNET_CONFIGURATION_Handle *cfg,
216                           struct GNUNET_PeerIdentity *peer,
217                           GNUNET_CADET_ChannelCB callback,
218                           void *callback_cls)
219 {
220   struct GNUNET_CADET_ChannelMonitor *cm;
221
222   if (NULL == callback)
223   {
224     GNUNET_break (0);
225     return NULL;
226   }
227   cm = GNUNET_new (struct GNUNET_CADET_ChannelMonitor);
228   cm->channel_cb = callback;
229   cm->channel_cb_cls = callback_cls;
230   cm->cfg = cfg;
231   cm->peer = *peer;
232   reconnect (cm);
233   if (NULL == cm->mq)
234   {
235     GNUNET_free (cm);
236     return NULL;
237   }
238   return cm;
239 }
240
241
242 /**
243  * Cancel a channel monitor request. The callback will not be called (anymore).
244  *
245  * @param h Cadet handle.
246  * @return Closure that was given to #GNUNET_CADET_get_channel().
247  */
248 void *
249 GNUNET_CADET_get_channel_cancel (struct GNUNET_CADET_ChannelMonitor *cm)
250 {
251   void *ret = cm->channel_cb_cls;
252
253   if (NULL != cm->mq)
254     GNUNET_MQ_destroy (cm->mq);
255   if (NULL != cm->reconnect_task)
256     GNUNET_SCHEDULER_cancel (cm->reconnect_task);
257   GNUNET_free (cm);
258   return ret;
259 }
260
261 /* end of cadet_api_get_channel.c */