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