use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / transport / transport_api2_monitor.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2018 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 /**
22  * @file transport/transport_api2_monitor.c
23  * @brief implementation of the gnunet_transport_monitor_service.h API
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_transport_monitor_service.h"
30 #include "transport.h"
31
32
33 /**
34  * Opaque handle to the transport service for monitors.
35  */
36 struct GNUNET_TRANSPORT_MonitorContext
37 {
38   /**
39    * Our configuration.
40    */
41   const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43   /**
44    * Queue to talk to the transport service.
45    */
46   struct GNUNET_MQ_Handle *mq;
47
48   /**
49    * Peer we monitor, all zeros for "all"
50    */
51   struct GNUNET_PeerIdentity peer;
52
53   /**
54    * #GNUNET_YES to return the current state and then end.
55    */
56   int one_shot;
57
58   /**
59    * Function to call with monitor data.
60    */
61   GNUNET_TRANSPORT_MonitorCallback cb;
62
63   /**
64    * Closure for @e cb.
65    */
66   void *cb_cls;
67 };
68
69
70 /**
71  * (re)connect our monitor to the transport service
72  *
73  * @param mc handle to reconnect
74  */
75 static void
76 reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc);
77
78
79 /**
80  * Send message to the transport service about our montoring
81  * desire.
82  *
83  * @param ai address to delete
84  */
85 static void
86 send_start_monitor (struct GNUNET_TRANSPORT_MonitorContext *mc)
87 {
88   struct GNUNET_MQ_Envelope *env;
89   struct GNUNET_TRANSPORT_MonitorStart *smm;
90
91   if (NULL == mc->mq)
92     return;
93   env = GNUNET_MQ_msg (smm, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START);
94   smm->one_shot = htonl ((uint32_t) mc->one_shot);
95   smm->peer = mc->peer;
96   GNUNET_MQ_send (mc->mq, env);
97 }
98
99
100 /**
101  * Disconnect from the transport service.
102  *
103  * @param mc service to disconnect from
104  */
105 static void
106 disconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
107 {
108   if (NULL == mc->mq)
109     return;
110   GNUNET_MQ_destroy (mc->mq);
111   mc->mq = NULL;
112 }
113
114
115 /**
116  * Function called on MQ errors. Reconnects to the service.
117  *
118  * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
119  * @param error what error happened?
120  */
121 static void
122 error_handler (void *cls, enum GNUNET_MQ_Error error)
123 {
124   struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
125
126   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
127               "MQ failure %d, reconnecting to transport service.\n",
128               error);
129   disconnect (mc);
130   /* TODO: maybe do this with exponential backoff/delay */
131   reconnect (mc);
132 }
133
134
135 /**
136  * Transport service sends us information about what is going on.
137  * Check if @a md is well-formed.
138  *
139  * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
140  * @param md the monitor data we got
141  * @return #GNUNET_OK if @a smt is well-formed
142  */
143 static int
144 check_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
145 {
146   (void) cls;
147   GNUNET_MQ_check_zero_termination (md);
148   return GNUNET_OK;
149 }
150
151
152 /**
153  * Transport service sends us information about what is going on.
154  *
155  * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
156  * @param md monitor data
157  */
158 static void
159 handle_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
160 {
161   struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
162   struct GNUNET_TRANSPORT_MonitorInformation mi;
163
164   mi.address = (const char *) &md[1];
165   mi.nt = (enum GNUNET_NetworkType) ntohl (md->nt);
166   mi.cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (md->cs);
167   mi.num_msg_pending = ntohl (md->num_msg_pending);
168   mi.num_bytes_pending = ntohl (md->num_bytes_pending);
169   mi.last_validation = GNUNET_TIME_absolute_ntoh (md->last_validation);
170   mi.valid_until = GNUNET_TIME_absolute_ntoh (md->valid_until);
171   mi.next_validation = GNUNET_TIME_absolute_ntoh (md->next_validation);
172   mi.rtt = GNUNET_TIME_relative_ntoh (md->rtt);
173   mc->cb (mc->cb_cls, &md->peer, &mi);
174 }
175
176
177 /**
178  * One shot was requested, and transport service is done.
179  *
180  * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
181  * @param me end message
182  */
183 static void
184 handle_monitor_end (void *cls, const struct GNUNET_MessageHeader *me)
185 {
186   struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
187
188   if (GNUNET_YES != mc->one_shot)
189   {
190     GNUNET_break (0);
191     disconnect (mc);
192     reconnect (mc);
193     return;
194   }
195   mc->cb (mc->cb_cls, NULL, NULL);
196   GNUNET_TRANSPORT_monitor_cancel (mc);
197 }
198
199
200 /**
201  * (re)connect our monitor to the transport service
202  *
203  * @param mc handle to reconnect
204  */
205 static void
206 reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
207 {
208   struct GNUNET_MQ_MessageHandler handlers[] =
209   { GNUNET_MQ_hd_var_size (monitor_data,
210                            GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA,
211                            struct GNUNET_TRANSPORT_MonitorData,
212                            mc),
213     GNUNET_MQ_hd_fixed_size (monitor_end,
214                              GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_END,
215                              struct GNUNET_MessageHeader,
216                              mc),
217     GNUNET_MQ_handler_end () };
218
219   mc->mq =
220     GNUNET_CLIENT_connect (mc->cfg, "transport", handlers, &error_handler, mc);
221   if (NULL == mc->mq)
222     return;
223   send_start_monitor (mc);
224 }
225
226
227 /**
228  * Return information about a specific peer or all peers currently known to
229  * transport service once or in monitoring mode. To obtain information about
230  * a specific peer, a peer identity can be passed. To obtain information about
231  * all peers currently known to transport service, NULL can be passed as peer
232  * identity.
233  *
234  * For each peer, the callback is called with information about the address used
235  * to communicate with this peer, the state this peer is currently in and the
236  * the current timeout for this state.
237  *
238  * Upon completion, the #GNUNET_TRANSPORT_PeerIterateCallback is called one
239  * more time with `NULL`. After this, the operation must no longer be
240  * explicitly canceled.
241  *
242  * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
243  * the peer_callback!
244  *
245  * @param cfg configuration to use
246  * @param peer a specific peer identity to obtain information for,
247  *      NULL for all peers
248  * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
249  *                 #GNUNET_NO to monitor peers continuously
250  * @param cb function to call with the results
251  * @param cb_cls closure for @a mc
252  */
253 struct GNUNET_TRANSPORT_MonitorContext *
254 GNUNET_TRANSPORT_monitor (const struct GNUNET_CONFIGURATION_Handle *cfg,
255                           const struct GNUNET_PeerIdentity *peer,
256                           int one_shot,
257                           GNUNET_TRANSPORT_MonitorCallback cb,
258                           void *cb_cls)
259 {
260   struct GNUNET_TRANSPORT_MonitorContext *mc;
261
262   mc = GNUNET_new (struct GNUNET_TRANSPORT_MonitorContext);
263   mc->cfg = cfg;
264   if (NULL != peer)
265     mc->peer = *peer;
266   mc->one_shot = one_shot;
267   mc->cb = cb;
268   mc->cb_cls = cb_cls;
269   reconnect (mc);
270   if (NULL == mc->mq)
271   {
272     GNUNET_free (mc);
273     return NULL;
274   }
275   return mc;
276 }
277
278
279 /**
280  * Cancel request to monitor peers
281  *
282  * @param pmc handle for the request to cancel
283  */
284 void
285 GNUNET_TRANSPORT_monitor_cancel (struct GNUNET_TRANSPORT_MonitorContext *mc)
286 {
287   disconnect (mc);
288   GNUNET_free (mc);
289 }
290
291
292 /* end of transport_api2_monitor.c */