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 it
6 under the terms of the GNU 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.
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.
17 * @file transport/transport_api_monitor_peers.c
18 * @brief montoring api for transport peer status
20 * This api provides the ability to query the transport service about
21 * the connection status of a specific or all peers.
23 * Calls back with information about peer(s) including address used, state and
24 * state timeout for peer requests.
27 #include "gnunet_util_lib.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_transport_service.h"
32 #include "transport.h"
35 * Context for iterating validation entries.
37 struct GNUNET_TRANSPORT_PeerMonitoringContext
40 * Function to call with the binary address.
42 GNUNET_TRANSPORT_PeerIterateCallback cb;
50 * Connection to the service.
52 struct GNUNET_MQ_Handle *mq;
55 * Configuration we use.
57 const struct GNUNET_CONFIGURATION_Handle *cfg;
60 * Backoff for reconnect.
62 struct GNUNET_TIME_Relative backoff;
65 * Task ID for reconnect.
67 struct GNUNET_SCHEDULER_Task *reconnect_task;
70 * Identity of the peer to monitor.
72 struct GNUNET_PeerIdentity peer;
75 * Was this a one-shot request?
82 * Check if a state is defined as connected
84 * @param state the state value
85 * @return #GNUNET_YES or #GNUNET_NO
88 GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
92 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
93 case GNUNET_TRANSPORT_PS_INIT_ATS:
94 case GNUNET_TRANSPORT_PS_SYN_SENT:
95 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
96 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
98 case GNUNET_TRANSPORT_PS_CONNECTED:
99 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
100 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
101 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
103 case GNUNET_TRANSPORT_PS_DISCONNECT:
104 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
107 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
108 "Unhandled state `%s'\n",
109 GNUNET_TRANSPORT_ps2s (state));
113 return GNUNET_SYSERR;
118 * Convert peer state to human-readable string.
120 * @param state the state value
121 * @return corresponding string
124 GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
128 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
129 return "S_NOT_CONNECTED";
130 case GNUNET_TRANSPORT_PS_INIT_ATS:
132 case GNUNET_TRANSPORT_PS_SYN_SENT:
134 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
135 return "S_SYN_RECV_ATS";
136 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
137 return "S_SYN_RECV_ACK";
138 case GNUNET_TRANSPORT_PS_CONNECTED:
139 return "S_CONNECTED";
140 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
141 return "S_RECONNECT_ATS";
142 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
143 return "S_RECONNECT_SENT";
144 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
145 return "S_SWITCH_SYN_SENT";
146 case GNUNET_TRANSPORT_PS_DISCONNECT:
147 return "S_DISCONNECT";
148 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
149 return "S_DISCONNECT_FINISHED";
158 * Task run to re-establish the connection.
160 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
163 do_peer_connect (void *cls);
167 * Cut the existing connection and reconnect.
169 * @param pal_ctx our context
172 reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
174 GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
175 GNUNET_MQ_destroy (pal_ctx->mq);
177 pal_ctx->cb (pal_ctx->cb_cls,
180 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
181 GNUNET_TIME_UNIT_ZERO_ABS);
182 pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
183 pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
190 * Function called with responses from the service.
192 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
193 * @param msg message from service
196 handle_response_end (void *cls,
197 const struct GNUNET_MessageHeader *msg)
199 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
201 if (pal_ctx->one_shot)
203 /* iteration finished */
204 pal_ctx->cb (pal_ctx->cb_cls,
207 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
208 GNUNET_TIME_UNIT_ZERO_ABS);
209 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
212 /* not quite what we expected, reconnect */
214 reconnect_peer_ctx (pal_ctx);
219 * Function called to check responses from the service.
221 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
222 * @param pir_msg message with the human-readable address
223 * @return #GNUNET_OK if @a pir_msg is well-formed
226 check_response (void *cls,
227 const struct PeerIterateResponseMessage *pir_msg)
229 uint16_t size = ntohs (pir_msg->header.size) - sizeof (*pir_msg);
230 size_t alen = ntohl (pir_msg->addrlen);
231 size_t tlen = ntohl (pir_msg->pluginlen);
233 const char *transport_name;
235 if (size != tlen + alen)
238 return GNUNET_SYSERR;
240 if ( (0 == tlen) && (0 == alen) )
244 GNUNET_break (0); /* This must not happen: address without plugin */
245 return GNUNET_SYSERR;
247 addr = (const char *) &pir_msg[1];
248 transport_name = &addr[alen];
249 if (transport_name[tlen - 1] != '\0')
252 return GNUNET_SYSERR;
259 * Function called with responses from the service.
261 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
262 * @param msg message with the human-readable address
265 handle_response (void *cls,
266 const struct PeerIterateResponseMessage *pir_msg)
268 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
269 struct GNUNET_HELLO_Address *address;
270 size_t alen = ntohl (pir_msg->addrlen);
271 size_t tlen = ntohl (pir_msg->pluginlen);
273 const char *transport_name;
278 /* No address available */
279 pal_ctx->cb (pal_ctx->cb_cls,
282 ntohl(pir_msg->state),
283 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
286 addr = (const char *) &pir_msg[1];
287 transport_name = &addr[alen];
290 address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
294 ntohl (pir_msg->local_address_info));
295 pal_ctx->cb (pal_ctx->cb_cls,
298 ntohl (pir_msg->state),
299 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
300 GNUNET_HELLO_address_free (address);
306 * Generic error handler, called with the appropriate error code and
307 * the same closure specified at the creation of the message queue.
308 * Not every message queue implementation supports an error handler.
310 * @param cls closure with the `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
311 * @param error error code
314 mq_error_handler (void *cls,
315 enum GNUNET_MQ_Error error)
317 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
319 if (pal_ctx->one_shot)
322 pal_ctx->cb (pal_ctx->cb_cls,
325 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
326 GNUNET_TIME_UNIT_ZERO_ABS);
327 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
330 reconnect_peer_ctx (pal_ctx);
335 * Task run to re-establish the connection.
337 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
340 do_peer_connect (void *cls)
342 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
343 struct GNUNET_MQ_MessageHandler handlers[] = {
344 GNUNET_MQ_hd_var_size (response,
345 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE,
346 struct PeerIterateResponseMessage,
348 GNUNET_MQ_hd_fixed_size (response_end,
349 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END,
350 struct GNUNET_MessageHeader,
352 GNUNET_MQ_handler_end ()
354 struct PeerMonitorMessage *msg;
355 struct GNUNET_MQ_Envelope *env;
357 pal_ctx->reconnect_task = NULL;
358 pal_ctx->mq = GNUNET_CLIENT_connect (pal_ctx->cfg,
363 if (NULL == pal_ctx->mq)
365 env = GNUNET_MQ_msg (msg,
366 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
367 msg->one_shot = htonl (pal_ctx->one_shot);
368 msg->peer = pal_ctx->peer;
369 GNUNET_MQ_send (pal_ctx->mq,
375 * Return information about a specific peer or all peers currently known to
376 * transport service once or in monitoring mode. To obtain information about
377 * a specific peer, a peer identity can be passed. To obtain information about
378 * all peers currently known to transport service, NULL can be passed as peer
381 * For each peer, the callback is called with information about the address used
382 * to communicate with this peer, the state this peer is currently in and the
383 * the current timeout for this state.
385 * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
386 * more time with 'NULL'. After this, the operation must no longer be
387 * explicitly canceled.
389 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
392 * @param cfg configuration to use
393 * @param peer a specific peer identity to obtain information for,
395 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
396 * #GNUNET_NO to monitor peers continuously
397 * @param peer_callback function to call with the results
398 * @param peer_callback_cls closure for @a peer_address_callback
400 struct GNUNET_TRANSPORT_PeerMonitoringContext *
401 GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
402 const struct GNUNET_PeerIdentity *peer,
404 GNUNET_TRANSPORT_PeerIterateCallback peer_callback,
405 void *peer_callback_cls)
407 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
408 = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
410 pal_ctx->cb = peer_callback;
411 pal_ctx->cb_cls = peer_callback_cls;
414 pal_ctx->peer = *peer;
415 pal_ctx->one_shot = one_shot;
416 do_peer_connect (pal_ctx);
417 if (NULL == pal_ctx->mq)
419 GNUNET_free (pal_ctx);
427 * Cancel request to monitor peers
429 * @param pic handle for the request to cancel
432 GNUNET_TRANSPORT_monitor_peers_cancel (struct GNUNET_TRANSPORT_PeerMonitoringContext *pic)
436 GNUNET_MQ_destroy (pic->mq);
439 if (NULL != pic->reconnect_task)
441 GNUNET_SCHEDULER_cancel (pic->reconnect_task);
442 pic->reconnect_task = NULL;
448 /* end of transport_api_monitor_peers.c */