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