2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file transport/transport_api_monitor_peers.c
23 * @brief montoring api for transport peer status
25 * This api provides the ability to query the transport service about
26 * the connection status of a specific or all peers.
28 * Calls back with information about peer(s) including address used, state and
29 * state timeout for peer requests.
32 #include "gnunet_util_lib.h"
33 #include "gnunet_arm_service.h"
34 #include "gnunet_hello_lib.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_transport_service.h"
37 #include "transport.h"
40 * Context for iterating validation entries.
42 struct GNUNET_TRANSPORT_PeerMonitoringContext
45 * Function to call with the binary address.
47 GNUNET_TRANSPORT_PeerIterateCallback cb;
55 * Connection to the service.
57 struct GNUNET_MQ_Handle *mq;
60 * Configuration we use.
62 const struct GNUNET_CONFIGURATION_Handle *cfg;
65 * Backoff for reconnect.
67 struct GNUNET_TIME_Relative backoff;
70 * Task ID for reconnect.
72 struct GNUNET_SCHEDULER_Task *reconnect_task;
75 * Identity of the peer to monitor.
77 struct GNUNET_PeerIdentity peer;
80 * Was this a one-shot request?
87 * Check if a state is defined as connected
89 * @param state the state value
90 * @return #GNUNET_YES or #GNUNET_NO
93 GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
97 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
98 case GNUNET_TRANSPORT_PS_INIT_ATS:
99 case GNUNET_TRANSPORT_PS_SYN_SENT:
100 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
101 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
103 case GNUNET_TRANSPORT_PS_CONNECTED:
104 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
105 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
106 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
108 case GNUNET_TRANSPORT_PS_DISCONNECT:
109 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
113 "Unhandled state `%s'\n",
114 GNUNET_TRANSPORT_ps2s (state));
118 return GNUNET_SYSERR;
123 * Convert peer state to human-readable string.
125 * @param state the state value
126 * @return corresponding string
129 GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
133 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
134 return "S_NOT_CONNECTED";
135 case GNUNET_TRANSPORT_PS_INIT_ATS:
137 case GNUNET_TRANSPORT_PS_SYN_SENT:
139 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
140 return "S_SYN_RECV_ATS";
141 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
142 return "S_SYN_RECV_ACK";
143 case GNUNET_TRANSPORT_PS_CONNECTED:
144 return "S_CONNECTED";
145 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
146 return "S_RECONNECT_ATS";
147 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
148 return "S_RECONNECT_SENT";
149 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
150 return "S_SWITCH_SYN_SENT";
151 case GNUNET_TRANSPORT_PS_DISCONNECT:
152 return "S_DISCONNECT";
153 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
154 return "S_DISCONNECT_FINISHED";
163 * Task run to re-establish the connection.
165 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
168 do_peer_connect (void *cls);
172 * Cut the existing connection and reconnect.
174 * @param pal_ctx our context
177 reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
179 GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
180 GNUNET_MQ_destroy (pal_ctx->mq);
182 pal_ctx->cb (pal_ctx->cb_cls,
185 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
186 GNUNET_TIME_UNIT_ZERO_ABS);
187 pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
188 pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
195 * Function called with responses from the service.
197 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
198 * @param msg message from service
201 handle_response_end (void *cls,
202 const struct GNUNET_MessageHeader *msg)
204 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
206 if (pal_ctx->one_shot)
208 /* iteration finished */
209 pal_ctx->cb (pal_ctx->cb_cls,
212 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
213 GNUNET_TIME_UNIT_ZERO_ABS);
214 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
217 /* not quite what we expected, reconnect */
219 reconnect_peer_ctx (pal_ctx);
224 * Function called to check responses from the service.
226 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
227 * @param pir_msg message with the human-readable address
228 * @return #GNUNET_OK if @a pir_msg is well-formed
231 check_response (void *cls,
232 const struct PeerIterateResponseMessage *pir_msg)
234 uint16_t size = ntohs (pir_msg->header.size) - sizeof (*pir_msg);
235 size_t alen = ntohl (pir_msg->addrlen);
236 size_t tlen = ntohl (pir_msg->pluginlen);
238 const char *transport_name;
240 if (size != tlen + alen)
243 return GNUNET_SYSERR;
245 if ( (0 == tlen) && (0 == alen) )
249 GNUNET_break (0); /* This must not happen: address without plugin */
250 return GNUNET_SYSERR;
252 addr = (const char *) &pir_msg[1];
253 transport_name = &addr[alen];
254 if (transport_name[tlen - 1] != '\0')
257 return GNUNET_SYSERR;
264 * Function called with responses from the service.
266 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
267 * @param msg message with the human-readable address
270 handle_response (void *cls,
271 const struct PeerIterateResponseMessage *pir_msg)
273 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
274 struct GNUNET_HELLO_Address *address;
275 size_t alen = ntohl (pir_msg->addrlen);
276 size_t tlen = ntohl (pir_msg->pluginlen);
278 const char *transport_name;
283 /* No address available */
284 pal_ctx->cb (pal_ctx->cb_cls,
287 ntohl(pir_msg->state),
288 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
291 addr = (const char *) &pir_msg[1];
292 transport_name = &addr[alen];
295 address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
299 ntohl (pir_msg->local_address_info));
300 pal_ctx->cb (pal_ctx->cb_cls,
303 ntohl (pir_msg->state),
304 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
305 GNUNET_HELLO_address_free (address);
311 * Generic error handler, called with the appropriate error code and
312 * the same closure specified at the creation of the message queue.
313 * Not every message queue implementation supports an error handler.
315 * @param cls closure with the `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
316 * @param error error code
319 mq_error_handler (void *cls,
320 enum GNUNET_MQ_Error error)
322 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
324 if (pal_ctx->one_shot)
327 pal_ctx->cb (pal_ctx->cb_cls,
330 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
331 GNUNET_TIME_UNIT_ZERO_ABS);
332 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
335 reconnect_peer_ctx (pal_ctx);
340 * Task run to re-establish the connection.
342 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
345 do_peer_connect (void *cls)
347 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
348 struct GNUNET_MQ_MessageHandler handlers[] = {
349 GNUNET_MQ_hd_var_size (response,
350 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE,
351 struct PeerIterateResponseMessage,
353 GNUNET_MQ_hd_fixed_size (response_end,
354 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END,
355 struct GNUNET_MessageHeader,
357 GNUNET_MQ_handler_end ()
359 struct PeerMonitorMessage *msg;
360 struct GNUNET_MQ_Envelope *env;
362 pal_ctx->reconnect_task = NULL;
363 pal_ctx->mq = GNUNET_CLIENT_connecT (pal_ctx->cfg,
368 if (NULL == pal_ctx->mq)
370 env = GNUNET_MQ_msg (msg,
371 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
372 msg->one_shot = htonl (pal_ctx->one_shot);
373 msg->peer = pal_ctx->peer;
374 GNUNET_MQ_send (pal_ctx->mq,
380 * Return information about a specific peer or all peers currently known to
381 * transport service once or in monitoring mode. To obtain information about
382 * a specific peer, a peer identity can be passed. To obtain information about
383 * all peers currently known to transport service, NULL can be passed as peer
386 * For each peer, the callback is called with information about the address used
387 * to communicate with this peer, the state this peer is currently in and the
388 * the current timeout for this state.
390 * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
391 * more time with 'NULL'. After this, the operation must no longer be
392 * explicitly canceled.
394 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
397 * @param cfg configuration to use
398 * @param peer a specific peer identity to obtain information for,
400 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
401 * #GNUNET_NO to monitor peers continuously
402 * @param peer_callback function to call with the results
403 * @param peer_callback_cls closure for @a peer_address_callback
405 struct GNUNET_TRANSPORT_PeerMonitoringContext *
406 GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
407 const struct GNUNET_PeerIdentity *peer,
409 GNUNET_TRANSPORT_PeerIterateCallback peer_callback,
410 void *peer_callback_cls)
412 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
413 = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
415 pal_ctx->cb = peer_callback;
416 pal_ctx->cb_cls = peer_callback_cls;
419 pal_ctx->peer = *peer;
420 pal_ctx->one_shot = one_shot;
421 do_peer_connect (pal_ctx);
422 if (NULL == pal_ctx->mq)
424 GNUNET_free (pal_ctx);
432 * Cancel request to monitor peers
434 * @param pic handle for the request to cancel
437 GNUNET_TRANSPORT_monitor_peers_cancel (struct GNUNET_TRANSPORT_PeerMonitoringContext *pic)
441 GNUNET_MQ_destroy (pic->mq);
444 if (NULL != pic->reconnect_task)
446 GNUNET_SCHEDULER_cancel (pic->reconnect_task);
447 pic->reconnect_task = NULL;
453 /* end of transport_api_monitor_peers.c */