printing validation information with cli
[oweals/gnunet.git] / src / transport / transport_api_monitoring.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
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.
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      General Public License for more details.
14
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/transport_api_monitoring.c
23  * @brief montoring api for transport peer status and validation entries
24  *
25  * This api provides the ability to query the transport service about
26  * the status of a specific or all peers as well as address validation entries.
27  *
28  * Calls back with information about peer(s) including address used, state and
29  * state timeout for peer requests and address, address lifetime and next revalidation
30  * for validation entries.
31  */
32 #include "platform.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_arm_service.h"
35 #include "gnunet_hello_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_transport_service.h"
38 #include "transport.h"
39
40 /**
41  * Context for iterating validation entries.
42  */
43 struct GNUNET_TRANSPORT_PeerMonitoringContext
44 {
45   /**
46    * Function to call with the binary address.
47    */
48   GNUNET_TRANSPORT_PeerIterateCallback cb;
49
50   /**
51    * Closure for cb.
52    */
53   void *cb_cls;
54
55   /**
56    * Connection to the service.
57    */
58   struct GNUNET_CLIENT_Connection *client;
59
60   /**
61    * Configuration we use.
62    */
63   const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65   /**
66    * When should this operation time out?
67    */
68   struct GNUNET_TIME_Absolute timeout;
69
70   /**
71    * Backoff for reconnect.
72    */
73   struct GNUNET_TIME_Relative backoff;
74
75   /**
76    * Task ID for reconnect.
77    */
78   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
79
80   /**
81    * Identity of the peer to monitor.
82    */
83   struct GNUNET_PeerIdentity peer;
84
85   /**
86    * Was this a one-shot request?
87    */
88   int one_shot;
89 };
90
91
92 /**
93  * Context for the address lookup.
94  */
95 struct GNUNET_TRANSPORT_ValidationMonitoringContext
96 {
97   /**
98    * Function to call with the binary address.
99    */
100   GNUNET_TRANSPORT_ValidationIterateCallback cb;
101
102   /**
103    * Closure for cb.
104    */
105   void *cb_cls;
106
107   /**
108    * Connection to the service.
109    */
110   struct GNUNET_CLIENT_Connection *client;
111
112   /**
113    * Configuration we use.
114    */
115   const struct GNUNET_CONFIGURATION_Handle *cfg;
116
117   /**
118    * When should this operation time out?
119    */
120   struct GNUNET_TIME_Absolute timeout;
121
122   /**
123    * Backoff for reconnect.
124    */
125   struct GNUNET_TIME_Relative backoff;
126
127   /**
128    * Task ID for reconnect.
129    */
130   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
131
132   /**
133    * Identity of the peer to monitor.
134    */
135   struct GNUNET_PeerIdentity peer;
136
137   /**
138    * Was this a one-shot request?
139    */
140   int one_shot;
141 };
142
143 /**
144  * Check if a state is defined as connected
145  *
146  * @param state the state value
147  * @return GNUNET_YES or GNUNET_NO
148  */
149 int
150 GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
151 {
152   switch (state)
153   {
154   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
155   case GNUNET_TRANSPORT_PS_INIT_ATS:
156   case GNUNET_TRANSPORT_PS_INIT_BLACKLIST:
157   case GNUNET_TRANSPORT_PS_CONNECT_SENT:
158   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST_INBOUND:
159   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS:
160   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST:
161   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK:
162     return GNUNET_NO;
163   case GNUNET_TRANSPORT_PS_CONNECTED:
164   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
165   case GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST:
166   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
167   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST:
168   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT:
169     return GNUNET_YES;
170   case GNUNET_TRANSPORT_PS_DISCONNECT:
171   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
172     return GNUNET_NO;
173   default:
174     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
175                 "Unhandled state `%s' \n",
176                 GNUNET_TRANSPORT_ps2s (state));
177     GNUNET_break (0);
178     break;
179   }
180   return GNUNET_SYSERR;
181 }
182
183 /**
184  * Convert peer state to human-readable string.
185  *
186  * @param state the state value
187  * @return corresponding string
188  */
189 const char *
190 GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
191 {
192   switch (state)
193   {
194   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
195     return "S_NOT_CONNECTED";
196   case GNUNET_TRANSPORT_PS_INIT_ATS:
197     return "S_INIT_ATS";
198   case GNUNET_TRANSPORT_PS_INIT_BLACKLIST:
199     return "S_INIT_BLACKLIST";
200   case GNUNET_TRANSPORT_PS_CONNECT_SENT:
201     return "S_CONNECT_SENT";
202   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST_INBOUND:
203     return "S_CONNECT_RECV_BLACKLIST_INBOUND";
204   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS:
205     return "S_CONNECT_RECV_ATS";
206   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST:
207     return "S_CONNECT_RECV_BLACKLIST";
208   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK:
209     return "S_CONNECT_RECV_ACK";
210   case GNUNET_TRANSPORT_PS_CONNECTED:
211     return "S_CONNECTED";
212   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
213     return "S_RECONNECT_ATS";
214   case GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST:
215     return "S_RECONNECT_BLACKLIST";
216   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
217     return "S_RECONNECT_SENT";
218   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST:
219     return "S_CONNECTED_SWITCHING_BLACKLIST";
220   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT:
221     return "S_CONNECTED_SWITCHING_CONNECT_SENT";
222   case GNUNET_TRANSPORT_PS_DISCONNECT:
223     return "S_DISCONNECT";
224   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
225     return "S_DISCONNECT_FINISHED";
226   default:
227     GNUNET_break (0);
228     return "UNDEFINED";
229   }
230 }
231
232 /**
233  * Convert validation state to human-readable string.
234  *
235  * @param state the state value
236  * @return corresponding string
237  */
238 const char *
239 GNUNET_TRANSPORT_vs2s (enum GNUNET_TRANSPORT_ValidationState state)
240 {
241   switch (state)
242   {
243   case GNUNET_TRANSPORT_VS_NEW:
244     return "NEW";
245   case GNUNET_TRANSPORT_VS_REMOVE:
246     return "REMOVE";
247   case GNUNET_TRANSPORT_VS_TIMEOUT:
248     return "TIMEOUT";
249   case GNUNET_TRANSPORT_VS_UPDATE:
250     return "UPDATE";
251   default:
252     GNUNET_break (0);
253     return "UNDEFINED";
254   }
255 }
256
257
258 /**
259  * Function called with responses from the service.
260  *
261  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
262  * @param msg NULL on timeout or error, otherwise presumably a
263  *        message with the human-readable address
264  */
265 static void
266 peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg);
267
268
269 /**
270  * Function called with responses from the service.
271  *
272  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
273  * @param msg NULL on timeout or error, otherwise presumably a
274  *        message with the human-readable address
275  */
276 static void
277 val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg);
278
279 /**
280  * Send our subscription request to the service.
281  *
282  * @param pal_ctx our context
283  */
284 static void
285 send_peer_mon_request (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
286 {
287   struct PeerMonitorMessage msg;
288
289   msg.header.size = htons (sizeof (struct PeerMonitorMessage));
290   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
291   msg.one_shot = htonl (pal_ctx->one_shot);
292   msg.peer = pal_ctx->peer;
293   GNUNET_assert (GNUNET_OK ==
294                  GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client,
295                     &msg.header,
296                     GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout),
297                     GNUNET_YES,
298                     &peer_response_processor,
299                     pal_ctx));
300 }
301
302 /**
303  * Send our subscription request to the service.
304  *
305  * @param pal_ctx our context
306  */
307 static void
308 send_val_mon_request (struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx)
309 {
310   struct ValidationMonitorMessage msg;
311
312   msg.header.size = htons (sizeof (struct PeerMonitorMessage));
313   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST);
314   msg.one_shot = htonl (val_ctx->one_shot);
315   msg.peer = val_ctx->peer;
316   GNUNET_assert (GNUNET_OK ==
317                  GNUNET_CLIENT_transmit_and_get_response (val_ctx->client,
318                     &msg.header,
319                     GNUNET_TIME_absolute_get_remaining (val_ctx->timeout),
320                     GNUNET_YES,
321                     &val_response_processor,
322                     val_ctx));
323 }
324
325
326 /**
327  * Task run to re-establish the connection.
328  *
329  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
330  * @param tc scheduler context, unused
331  */
332 static void
333 do_connect (void *cls,
334             const struct GNUNET_SCHEDULER_TaskContext *tc)
335 {
336   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
337
338   pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
339   pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg);
340   GNUNET_assert (NULL != pal_ctx->client);
341   send_peer_mon_request (pal_ctx);
342 }
343
344
345 /**
346  * Cut the existing connection and reconnect.
347  *
348  * @param pal_ctx our context
349  */
350 static void
351 reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
352 {
353   GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
354   GNUNET_CLIENT_disconnect (pal_ctx->client);
355   pal_ctx->client = NULL;
356   pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
357   pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
358                                                           &do_connect,
359                                                           pal_ctx);
360 }
361
362 /**
363  * Cut the existing connection and reconnect.
364  *
365  * @param pal_ctx our context
366  */
367 static void
368 reconnect_val_ctx (struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx)
369 {
370   GNUNET_assert (GNUNET_NO == val_ctx->one_shot);
371   GNUNET_CLIENT_disconnect (val_ctx->client);
372   val_ctx->client = NULL;
373   val_ctx->backoff = GNUNET_TIME_STD_BACKOFF (val_ctx->backoff);
374   val_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (val_ctx->backoff,
375                                                           &do_connect,
376                                                           val_ctx);
377 }
378
379 /**
380  * Function called with responses from the service.
381  *
382  * @param cls our 'struct GNUNET_TRANSPORT_PeerMonitoringContext*'
383  * @param msg NULL on timeout or error, otherwise presumably a
384  *        message with the human-readable address
385  */
386 static void
387 val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
388 {
389   struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx = cls;
390   struct ValidationIterateResponseMessage *vr_msg;
391   struct GNUNET_HELLO_Address *address;
392   const char *addr;
393   const char *transport_name;
394   size_t size;
395   size_t tlen;
396   size_t alen;
397
398   if (msg == NULL)
399   {
400     GNUNET_break (0);
401     if (val_ctx->one_shot)
402     {
403       /* Disconnect */
404       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
405           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
406           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_TIMEOUT);
407       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
408     }
409     else
410     {
411       reconnect_val_ctx (val_ctx);
412     }
413     return;
414   }
415   size = ntohs (msg->size);
416   GNUNET_break (ntohs (msg->type) ==
417       GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
418   if (size == sizeof (struct GNUNET_MessageHeader))
419   {
420     /* Done! */
421     if (val_ctx->one_shot)
422     {
423       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
424           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
425           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
426       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
427     }
428     else
429     {
430       reconnect_val_ctx (val_ctx);
431     }
432     return;
433   }
434
435   if ((size < sizeof (struct ValidationIterateResponseMessage)) ||
436       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE))
437   {
438     GNUNET_break (0);
439     if (val_ctx->one_shot)
440     {
441       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
442           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
443           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
444       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
445     }
446     else
447     {
448       reconnect_val_ctx (val_ctx);
449     }
450     return;
451   }
452
453   vr_msg = (struct ValidationIterateResponseMessage *) msg;
454   tlen = ntohl (vr_msg->pluginlen);
455   alen = ntohl (vr_msg->addrlen);
456
457   if (size != sizeof (struct ValidationIterateResponseMessage) + tlen + alen)
458   {
459     GNUNET_break (0);
460     if (val_ctx->one_shot)
461     {
462       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
463           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
464           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
465       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
466     }
467     else
468     {
469       reconnect_val_ctx (val_ctx);
470     }
471     return;
472   }
473   if ( (0 == tlen) && (0 == alen) )
474   {
475     GNUNET_break (0);
476     if (val_ctx->one_shot)
477     {
478       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
479           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
480           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
481       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
482     }
483     else
484     {
485       reconnect_val_ctx (val_ctx);
486     }
487     return;
488   }
489   else
490   {
491     if (0 == tlen)
492     {
493       GNUNET_break (0); /* This must not happen: address without plugin */
494       return;
495     }
496     addr = (const char *) &vr_msg[1];
497     transport_name = &addr[alen];
498
499     if (transport_name[tlen - 1] != '\0')
500     {
501       /* Corrupt plugin name */
502       GNUNET_break (0);
503       if (val_ctx->one_shot)
504       {
505         val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
506             GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
507             GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
508         GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
509       }
510       else
511       {
512         reconnect_val_ctx (val_ctx);
513       }
514       return;
515     }
516
517     /* notify client */
518     address = GNUNET_HELLO_address_allocate (&vr_msg->peer,
519         transport_name, addr, alen, ntohl(vr_msg->local_address_info));
520     val_ctx->cb (val_ctx->cb_cls, &vr_msg->peer, address,
521         GNUNET_TIME_absolute_ntoh(vr_msg->last_validation),
522         GNUNET_TIME_absolute_ntoh(vr_msg->valid_until),
523         GNUNET_TIME_absolute_ntoh(vr_msg->next_validation),
524         ntohl(vr_msg->state));
525     GNUNET_HELLO_address_free (address);
526   }
527   /* expect more replies */
528   GNUNET_CLIENT_receive (val_ctx->client, &val_response_processor,
529       val_ctx, GNUNET_TIME_absolute_get_remaining (val_ctx->timeout));
530 }
531
532
533 /**
534  * Function called with responses from the service.
535  *
536  * @param cls our 'struct GNUNET_TRANSPORT_PeerMonitoringContext*'
537  * @param msg NULL on timeout or error, otherwise presumably a
538  *        message with the human-readable address
539  */
540 static void
541 peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
542 {
543   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
544   struct PeerIterateResponseMessage *pir_msg;
545   struct GNUNET_HELLO_Address *address;
546   const char *addr;
547   const char *transport_name;
548   uint16_t size;
549   size_t alen;
550   size_t tlen;
551   GNUNET_break (0);
552   if (msg == NULL)
553   {
554     if (pal_ctx->one_shot)
555     {
556       /* Disconnect */
557       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
558           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
559       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
560     }
561     else
562     {
563       reconnect_peer_ctx (pal_ctx);
564     }
565     return;
566   }
567   size = ntohs (msg->size);
568   GNUNET_break (ntohs (msg->type) ==
569       GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
570   if (size == sizeof (struct GNUNET_MessageHeader))
571   {
572     /* Done! */
573     if (pal_ctx->one_shot)
574     {
575       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
576           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
577       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
578     }
579     else
580     {
581       reconnect_peer_ctx (pal_ctx);
582     }
583     return;
584   }
585
586   if ((size < sizeof (struct PeerIterateResponseMessage)) ||
587       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE))
588   {
589     GNUNET_break (0);
590     if (pal_ctx->one_shot)
591     {
592       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
593           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
594       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
595     }
596     else
597     {
598       reconnect_peer_ctx (pal_ctx);
599     }
600     return;
601   }
602
603   pir_msg = (struct PeerIterateResponseMessage *) msg;
604   tlen = ntohl (pir_msg->pluginlen);
605   alen = ntohl (pir_msg->addrlen);
606
607   if (size != sizeof (struct PeerIterateResponseMessage) + tlen + alen)
608   {
609     GNUNET_break (0);
610     if (pal_ctx->one_shot)
611     {
612       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
613           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
614       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
615     }
616     else
617     {
618       reconnect_peer_ctx (pal_ctx);
619     }
620     return;
621   }
622
623   if ( (0 == tlen) && (0 == alen) )
624   {
625     /* No address available */
626     pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, NULL,
627         ntohl(pir_msg->state),
628         GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
629   }
630   else
631   {
632     if (0 == tlen)
633     {
634       GNUNET_break (0); /* This must not happen: address without plugin */
635       return;
636     }
637     addr = (const char *) &pir_msg[1];
638     transport_name = &addr[alen];
639
640     if (transport_name[tlen - 1] != '\0')
641     {
642       /* Corrupt plugin name */
643       GNUNET_break (0);
644       if (pal_ctx->one_shot)
645       {
646         pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
647             GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
648         GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
649       }
650       else
651       {
652         reconnect_peer_ctx (pal_ctx);
653       }
654       return;
655     }
656
657     /* notify client */
658     address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
659         transport_name, addr, alen, ntohl(pir_msg->local_address_info));
660     pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, address,
661         ntohl(pir_msg->state),
662         GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
663     GNUNET_HELLO_address_free (address);
664
665   }
666
667   /* expect more replies */
668   GNUNET_CLIENT_receive (pal_ctx->client, &peer_response_processor,
669                          pal_ctx,
670                          GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout));
671 }
672
673
674 /**
675  * Return information about a specific peer or all peers currently known to
676  * transport service once or in monitoring mode. To obtain information about
677  * a specific peer, a peer identity can be passed. To obtain information about
678  * all peers currently known to transport service, NULL can be passed as peer
679  * identity.
680  *
681  * For each peer, the callback is called with information about the address used
682  * to communicate with this peer, the state this peer is currently in and the
683  * the current timeout for this state.
684  *
685  * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
686  * more time with 'NULL'. After this, the operation must no longer be
687  * explicitly canceled.
688  *
689  * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
690  * the peer_callback!
691  *
692  * @param cfg configuration to use
693  * @param peer a specific peer identity to obtain information for,
694  *      NULL for all peers
695  * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL),
696  *                 GNUNET_NO to monitor peers continuously
697  * @param timeout how long is the lookup allowed to take at most
698  * @param peer_callback function to call with the results
699  * @param peer_callback_cls closure for peer_address_callback
700  */
701 struct GNUNET_TRANSPORT_PeerMonitoringContext *
702 GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
703     const struct GNUNET_PeerIdentity *peer,
704     int one_shot,
705     struct GNUNET_TIME_Relative timeout,
706     GNUNET_TRANSPORT_PeerIterateCallback peer_callback,
707     void *peer_callback_cls)
708 {
709   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx;
710   struct GNUNET_CLIENT_Connection *client;
711
712   client = GNUNET_CLIENT_connect ("transport", cfg);
713   if (client == NULL)
714     return NULL;
715   if (GNUNET_YES != one_shot)
716     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
717   pal_ctx = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
718   pal_ctx->cb = peer_callback;
719   pal_ctx->cb_cls = peer_callback_cls;
720   pal_ctx->cfg = cfg;
721   pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
722   if (NULL != peer)
723     pal_ctx->peer = *peer;
724   pal_ctx->one_shot = one_shot;
725   pal_ctx->client = client;
726   send_peer_mon_request (pal_ctx);
727
728   return pal_ctx;
729 }
730
731
732 /**
733  * Cancel request to monitor peers
734  *
735  * @param pic handle for the request to cancel
736  */
737 void
738 GNUNET_TRANSPORT_monitor_peers_cancel (struct GNUNET_TRANSPORT_PeerMonitoringContext *pic)
739 {
740   if (NULL != pic->client)
741   {
742     GNUNET_CLIENT_disconnect (pic->client);
743     pic->client = NULL;
744   }
745   if (GNUNET_SCHEDULER_NO_TASK != pic->reconnect_task)
746   {
747     GNUNET_SCHEDULER_cancel (pic->reconnect_task);
748     pic->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
749   }
750   GNUNET_free (pic);
751 }
752
753
754 /**
755  * Return information about pending address validation operations for a specific
756  * or all peers
757  *
758  * @param cfg configuration to use
759  * @param peer a specific peer identity to obtain validation entries for,
760  *      NULL for all peers
761  * @param one_shot GNUNET_YES to return all entries and then end (with NULL+NULL),
762  *                 GNUNET_NO to monitor validation entries continuously
763  * @param timeout how long is the lookup allowed to take at most
764  * @param validation_callback function to call with the results
765  * @param validation_callback_cls closure for peer_address_callback
766  */
767 struct GNUNET_TRANSPORT_ValidationMonitoringContext *
768 GNUNET_TRANSPORT_monitor_validation_entries (const struct
769                                 GNUNET_CONFIGURATION_Handle *cfg,
770                                 const struct GNUNET_PeerIdentity *peer,
771                                 int one_shot,
772                                 struct GNUNET_TIME_Relative timeout,
773                                 GNUNET_TRANSPORT_ValidationIterateCallback validation_callback,
774                                 void *validation_callback_cls)
775 {
776   struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx;
777   struct GNUNET_CLIENT_Connection *client;
778
779   client = GNUNET_CLIENT_connect ("transport", cfg);
780   if (client == NULL)
781     return NULL;
782   if (GNUNET_YES != one_shot)
783     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
784   val_ctx = GNUNET_new (struct GNUNET_TRANSPORT_ValidationMonitoringContext);
785   val_ctx->cb = validation_callback;
786   val_ctx->cb_cls = validation_callback_cls;
787   val_ctx->cfg = cfg;
788   val_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
789   if (NULL != peer)
790     val_ctx->peer = *peer;
791   val_ctx->one_shot = one_shot;
792   val_ctx->client = client;
793   send_val_mon_request (val_ctx);
794
795   return val_ctx;
796 }
797
798
799 /**
800  * Return information about all current pending validation operations
801  *
802  * @param vic handle for the request to cancel
803  */
804 void
805 GNUNET_TRANSPORT_monitor_validation_entries_cancel (struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic)
806 {
807   if (NULL != vic->client)
808   {
809     GNUNET_CLIENT_disconnect (vic->client);
810     vic->client = NULL;
811   }
812   if (GNUNET_SCHEDULER_NO_TASK != vic->reconnect_task)
813   {
814     GNUNET_SCHEDULER_cancel (vic->reconnect_task);
815     vic->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
816   }
817   GNUNET_free (vic);
818 }
819
820
821 /* end of transport_api_monitoring.c */