Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / cadet / cadet_api_list_peers.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_peers.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_PeersLister
38 {
39
40   /**
41    * Monitor callback
42    */
43   GNUNET_CADET_PeersCB peers_cb;
44
45   /**
46    * Info callback closure for @c info_cb.
47    */
48   void *peers_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  * Process a local reply about info on all tunnels, pass info to the user.
75  *
76  * @param cls a `struct GNUNET_CADET_PeersLister`
77  * @param info Message itself.
78  */
79 static void
80 handle_get_peers (void *cls,
81                   const struct GNUNET_CADET_LocalInfoPeers *info)
82 {
83   struct GNUNET_CADET_PeersLister *pl = cls;
84   struct GNUNET_CADET_PeerListEntry ple;
85
86   ple.peer = info->destination;
87   ple.have_tunnel = (int) ntohs (info->tunnel);
88   ple.n_paths = (unsigned int) ntohs (info->paths);
89   ple.best_path_length = (unsigned int) ntohl (info->best_path_length);
90   pl->peers_cb (pl->peers_cb_cls,
91                 &ple);
92 }
93
94
95 /**
96  * Process a end of list reply about info on all peers.
97  *
98  * @param cls a `struct GNUNET_CADET_PeersLister`
99  * @param msg Message itself.
100  */
101 static void
102 handle_get_peers_end (void *cls,
103                       const struct GNUNET_MessageHeader *msg)
104 {
105   struct GNUNET_CADET_PeersLister *pl = cls;
106   (void) msg;
107
108   pl->peers_cb (pl->peers_cb_cls,
109                 NULL);
110   GNUNET_CADET_list_peers_cancel (pl);
111 }
112
113
114 /**
115  * Reconnect to the service and try again.
116  *
117  * @param cls a `struct GNUNET_CADET_PeersLister` operation
118  */
119 static void
120 reconnect (void *cls);
121
122
123 /**
124  * Function called on connection trouble.  Reconnects.
125  *
126  * @param cls a `struct GNUNET_CADET_PeersLister`
127  * @param error error code from MQ
128  */
129 static void
130 error_handler (void *cls,
131                enum GNUNET_MQ_Error error)
132 {
133   struct GNUNET_CADET_PeersLister *pl = cls;
134
135   GNUNET_MQ_destroy (pl->mq);
136   pl->mq = NULL;
137   pl->backoff = GNUNET_TIME_randomized_backoff (pl->backoff,
138                                                 GNUNET_TIME_UNIT_MINUTES);
139   pl->reconnect_task = GNUNET_SCHEDULER_add_delayed (pl->backoff,
140                                                      &reconnect,
141                                                      pl);
142 }
143
144
145 /**
146  * Reconnect to the service and try again.
147  *
148  * @param cls a `struct GNUNET_CADET_PeersLister` operation
149  */
150 static void
151 reconnect (void *cls)
152 {
153   struct GNUNET_CADET_PeersLister *pl = cls;
154   struct GNUNET_MQ_MessageHandler handlers[] = {
155     GNUNET_MQ_hd_fixed_size (get_peers,
156                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
157                              struct GNUNET_CADET_LocalInfoPeers,
158                              pl),
159     GNUNET_MQ_hd_fixed_size (get_peers_end,
160                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS_END,
161                              struct GNUNET_MessageHeader,
162                              pl),
163     GNUNET_MQ_handler_end ()
164   };
165   struct GNUNET_MessageHeader *msg;
166   struct GNUNET_MQ_Envelope *env;
167
168   pl->reconnect_task = NULL;
169   pl->mq = GNUNET_CLIENT_connect (pl->cfg,
170                                   "cadet",
171                                   handlers,
172                                   &error_handler,
173                                   pl);  
174   if (NULL == pl->mq)
175     return;
176   env = GNUNET_MQ_msg (msg,
177                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_PEERS);
178   GNUNET_MQ_send (pl->mq,
179                   env);
180 }
181
182
183 /**
184  * Request information about peers known to the running cadet service.
185  * The callback will be called for every peer known to the service.
186  * Only one info request (of any kind) can be active at once.
187  *
188  * @param cfg configuration to use
189  * @param callback Function to call with the requested data.
190  * @param callback_cls Closure for @c callback.
191  * @return NULL on error
192  */
193 struct GNUNET_CADET_PeersLister *
194 GNUNET_CADET_list_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
195                          GNUNET_CADET_PeersCB callback,
196                          void *callback_cls)
197 {
198   struct GNUNET_CADET_PeersLister *pl;
199
200   if (NULL == callback)
201   {
202     GNUNET_break (0);
203     return NULL;
204   }
205   pl = GNUNET_new (struct GNUNET_CADET_PeersLister);
206   pl->peers_cb = callback;
207   pl->peers_cb_cls = callback_cls;
208   pl->cfg = cfg;
209   reconnect (pl);
210   if (NULL == pl->mq)
211   {
212     GNUNET_free (pl);
213     return NULL;
214   }
215   return pl;
216 }
217
218
219 /**
220  * Cancel a peer info request. The callback will not be called (anymore).
221  *
222  * @param pl operation handle
223  * @return Closure given to GNUNET_CADET_get_peers().
224  */
225 void *
226 GNUNET_CADET_list_peers_cancel (struct GNUNET_CADET_PeersLister *pl)
227 {
228   void *ret = pl->peers_cb_cls;
229
230   if (NULL != pl->mq)
231     GNUNET_MQ_destroy (pl->mq);
232   if (NULL != pl->reconnect_task)
233     GNUNET_SCHEDULER_cancel (pl->reconnect_task);
234   GNUNET_free (pl);
235   return ret;
236 }
237
238 /* end of cadet_api_list_peers.c */