remove unsued INIT_BLACKLIST state: blacklist check is done before switching
[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_CONNECT_SENT:
157   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST_INBOUND:
158   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS:
159   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST:
160   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK:
161     return GNUNET_NO;
162   case GNUNET_TRANSPORT_PS_CONNECTED:
163   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
164   case GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST:
165   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
166   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST:
167   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT:
168     return GNUNET_YES;
169   case GNUNET_TRANSPORT_PS_DISCONNECT:
170   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
171     return GNUNET_NO;
172   default:
173     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174                 "Unhandled state `%s' \n",
175                 GNUNET_TRANSPORT_ps2s (state));
176     GNUNET_break (0);
177     break;
178   }
179   return GNUNET_SYSERR;
180 }
181
182 /**
183  * Convert peer state to human-readable string.
184  *
185  * @param state the state value
186  * @return corresponding string
187  */
188 const char *
189 GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
190 {
191   switch (state)
192   {
193   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
194     return "S_NOT_CONNECTED";
195   case GNUNET_TRANSPORT_PS_INIT_ATS:
196     return "S_INIT_ATS";
197   case GNUNET_TRANSPORT_PS_CONNECT_SENT:
198     return "S_CONNECT_SENT";
199   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST_INBOUND:
200     return "S_CONNECT_RECV_BLACKLIST_INBOUND";
201   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS:
202     return "S_CONNECT_RECV_ATS";
203   case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST:
204     return "S_CONNECT_RECV_BLACKLIST";
205   case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK:
206     return "S_CONNECT_RECV_ACK";
207   case GNUNET_TRANSPORT_PS_CONNECTED:
208     return "S_CONNECTED";
209   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
210     return "S_RECONNECT_ATS";
211   case GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST:
212     return "S_RECONNECT_BLACKLIST";
213   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
214     return "S_RECONNECT_SENT";
215   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST:
216     return "S_CONNECTED_SWITCHING_BLACKLIST";
217   case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT:
218     return "S_CONNECTED_SWITCHING_CONNECT_SENT";
219   case GNUNET_TRANSPORT_PS_DISCONNECT:
220     return "S_DISCONNECT";
221   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
222     return "S_DISCONNECT_FINISHED";
223   default:
224     GNUNET_break (0);
225     return "UNDEFINED";
226   }
227 }
228
229 /**
230  * Convert validation state to human-readable string.
231  *
232  * @param state the state value
233  * @return corresponding string
234  */
235 const char *
236 GNUNET_TRANSPORT_vs2s (enum GNUNET_TRANSPORT_ValidationState state)
237 {
238   switch (state)
239   {
240   case GNUNET_TRANSPORT_VS_NONE:
241     return "NONE";
242   case GNUNET_TRANSPORT_VS_NEW:
243     return "NEW";
244   case GNUNET_TRANSPORT_VS_REMOVE:
245     return "REMOVE";
246   case GNUNET_TRANSPORT_VS_TIMEOUT:
247     return "TIMEOUT";
248   case GNUNET_TRANSPORT_VS_UPDATE:
249     return "UPDATE";
250   default:
251     GNUNET_break (0);
252     return "UNDEFINED";
253   }
254 }
255
256
257 /**
258  * Function called with responses from the service.
259  *
260  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
261  * @param msg NULL on timeout or error, otherwise presumably a
262  *        message with the human-readable address
263  */
264 static void
265 peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg);
266
267
268 /**
269  * Function called with responses from the service.
270  *
271  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
272  * @param msg NULL on timeout or error, otherwise presumably a
273  *        message with the human-readable address
274  */
275 static void
276 val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg);
277
278 /**
279  * Send our subscription request to the service.
280  *
281  * @param pal_ctx our context
282  */
283 static void
284 send_peer_mon_request (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
285 {
286   struct PeerMonitorMessage msg;
287
288   msg.header.size = htons (sizeof (struct PeerMonitorMessage));
289   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
290   msg.one_shot = htonl (pal_ctx->one_shot);
291   msg.peer = pal_ctx->peer;
292   GNUNET_assert (GNUNET_OK ==
293                  GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client,
294                     &msg.header,
295                     GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout),
296                     GNUNET_YES,
297                     &peer_response_processor,
298                     pal_ctx));
299 }
300
301 /**
302  * Send our subscription request to the service.
303  *
304  * @param val_ctx our context
305  */
306 static void
307 send_val_mon_request (struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx)
308 {
309   struct ValidationMonitorMessage msg;
310
311   msg.header.size = htons (sizeof (struct ValidationMonitorMessage));
312   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST);
313   msg.one_shot = htonl (val_ctx->one_shot);
314   msg.peer = val_ctx->peer;
315   GNUNET_assert (GNUNET_OK ==
316                  GNUNET_CLIENT_transmit_and_get_response (val_ctx->client,
317                     &msg.header,
318                     GNUNET_TIME_absolute_get_remaining (val_ctx->timeout),
319                     GNUNET_YES,
320                     &val_response_processor,
321                     val_ctx));
322 }
323
324 /**
325  * Task run to re-establish the connection.
326  *
327  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
328  * @param tc scheduler context, unused
329  */
330 static void
331 do_peer_connect (void *cls,
332            const struct GNUNET_SCHEDULER_TaskContext *tc)
333 {
334   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
335
336   pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
337   pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg);
338   GNUNET_assert (NULL != pal_ctx->client);
339   send_peer_mon_request (pal_ctx);
340 }
341
342
343 /**
344  * Cut the existing connection and reconnect.
345  *
346  * @param pal_ctx our context
347  */
348 static void
349 reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
350 {
351   GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
352   GNUNET_CLIENT_disconnect (pal_ctx->client);
353   pal_ctx->client = NULL;
354   pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
355   pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
356                                                           &do_peer_connect,
357                                                           pal_ctx);
358 }
359
360
361 /**
362  * Task run to re-establish the connection.
363  *
364  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
365  * @param tc scheduler context, unused
366  */
367 static void
368 do_val_connect (void *cls,
369            const struct GNUNET_SCHEDULER_TaskContext *tc)
370 {
371   struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx = cls;
372
373   val_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
374   val_ctx->client = GNUNET_CLIENT_connect ("transport", val_ctx->cfg);
375   GNUNET_assert (NULL != val_ctx->client);
376   send_val_mon_request (val_ctx);
377 }
378
379 /**
380  * Cut the existing connection and reconnect.
381  *
382  * @param val_ctx our context
383  */
384 static void
385 reconnect_val_ctx (struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx)
386 {
387   GNUNET_assert (GNUNET_NO == val_ctx->one_shot);
388   GNUNET_CLIENT_disconnect (val_ctx->client);
389   val_ctx->client = NULL;
390   val_ctx->backoff = GNUNET_TIME_STD_BACKOFF (val_ctx->backoff);
391   val_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (val_ctx->backoff,
392                                                           &do_val_connect,
393                                                           val_ctx);
394 }
395
396 /**
397  * Function called with responses from the service.
398  *
399  * @param cls our 'struct GNUNET_TRANSPORT_PeerMonitoringContext*'
400  * @param msg NULL on timeout or error, otherwise presumably a
401  *        message with the human-readable address
402  */
403 static void
404 val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
405 {
406   struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx = cls;
407   struct ValidationIterateResponseMessage *vr_msg;
408   struct GNUNET_HELLO_Address *address;
409   const char *addr;
410   const char *transport_name;
411   size_t size;
412   size_t tlen;
413   size_t alen;
414
415   if (msg == NULL)
416   {
417     if (val_ctx->one_shot)
418     {
419       /* Disconnect */
420       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
421           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
422           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_TIMEOUT);
423       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
424     }
425     else
426     {
427       reconnect_val_ctx (val_ctx);
428     }
429     return;
430   }
431   size = ntohs (msg->size);
432   GNUNET_break (ntohs (msg->type) ==
433       GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
434
435   if (size == sizeof (struct GNUNET_MessageHeader))
436   {
437     /* Done! */
438     if (val_ctx->one_shot)
439     {
440       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
441           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
442           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
443       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
444     }
445     else
446     {
447       reconnect_val_ctx (val_ctx);
448     }
449     return;
450   }
451
452   if ((size < sizeof (struct ValidationIterateResponseMessage)) ||
453       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE))
454   {
455     GNUNET_break (0);
456     if (val_ctx->one_shot)
457     {
458       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
459           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
460           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
461       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
462     }
463     else
464     {
465       reconnect_val_ctx (val_ctx);
466     }
467     return;
468   }
469
470   vr_msg = (struct ValidationIterateResponseMessage *) msg;
471   tlen = ntohl (vr_msg->pluginlen);
472   alen = ntohl (vr_msg->addrlen);
473
474   if (size != sizeof (struct ValidationIterateResponseMessage) + tlen + alen)
475   {
476     GNUNET_break (0);
477     if (val_ctx->one_shot)
478     {
479       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
480           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
481           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
482       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
483     }
484     else
485     {
486       reconnect_val_ctx (val_ctx);
487     }
488     return;
489   }
490   if ( (0 == tlen) && (0 == alen) )
491   {
492     GNUNET_break (0);
493     if (val_ctx->one_shot)
494     {
495       val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
496           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
497           GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
498       GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
499     }
500     else
501     {
502       reconnect_val_ctx (val_ctx);
503     }
504     return;
505   }
506   else
507   {
508     if (0 == tlen)
509     {
510       GNUNET_break (0); /* This must not happen: address without plugin */
511       return;
512     }
513     addr = (const char *) &vr_msg[1];
514     transport_name = &addr[alen];
515
516     if (transport_name[tlen - 1] != '\0')
517     {
518       /* Corrupt plugin name */
519       GNUNET_break (0);
520       if (val_ctx->one_shot)
521       {
522         val_ctx->cb (val_ctx->cb_cls, NULL, NULL,
523             GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS,
524             GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_NONE);
525         GNUNET_TRANSPORT_monitor_validation_entries_cancel (val_ctx);
526       }
527       else
528       {
529         reconnect_val_ctx (val_ctx);
530       }
531       return;
532     }
533
534     /* notify client */
535     address = GNUNET_HELLO_address_allocate (&vr_msg->peer,
536         transport_name, addr, alen, ntohl(vr_msg->local_address_info));
537     val_ctx->cb (val_ctx->cb_cls, &vr_msg->peer, address,
538         GNUNET_TIME_absolute_ntoh(vr_msg->last_validation),
539         GNUNET_TIME_absolute_ntoh(vr_msg->valid_until),
540         GNUNET_TIME_absolute_ntoh(vr_msg->next_validation),
541         ntohl(vr_msg->state));
542     GNUNET_HELLO_address_free (address);
543   }
544   /* expect more replies */
545   GNUNET_CLIENT_receive (val_ctx->client, &val_response_processor,
546       val_ctx, GNUNET_TIME_absolute_get_remaining (val_ctx->timeout));
547 }
548
549
550 /**
551  * Function called with responses from the service.
552  *
553  * @param cls our 'struct GNUNET_TRANSPORT_PeerMonitoringContext*'
554  * @param msg NULL on timeout or error, otherwise presumably a
555  *        message with the human-readable address
556  */
557 static void
558 peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
559 {
560   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
561   struct PeerIterateResponseMessage *pir_msg;
562   struct GNUNET_HELLO_Address *address;
563   const char *addr;
564   const char *transport_name;
565   uint16_t size;
566   size_t alen;
567   size_t tlen;
568
569   if (msg == NULL)
570   {
571     if (pal_ctx->one_shot)
572     {
573       /* Disconnect */
574       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
575           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
576       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
577     }
578     else
579     {
580       reconnect_peer_ctx (pal_ctx);
581     }
582     return;
583   }
584   size = ntohs (msg->size);
585   GNUNET_break (ntohs (msg->type) ==
586       GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
587   if (size == sizeof (struct GNUNET_MessageHeader))
588   {
589     /* Done! */
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   if ((size < sizeof (struct PeerIterateResponseMessage)) ||
604       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE))
605   {
606     GNUNET_break (0);
607     if (pal_ctx->one_shot)
608     {
609       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
610           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
611       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
612     }
613     else
614     {
615       reconnect_peer_ctx (pal_ctx);
616     }
617     return;
618   }
619
620   pir_msg = (struct PeerIterateResponseMessage *) msg;
621   tlen = ntohl (pir_msg->pluginlen);
622   alen = ntohl (pir_msg->addrlen);
623
624   if (size != sizeof (struct PeerIterateResponseMessage) + tlen + alen)
625   {
626     GNUNET_break (0);
627     if (pal_ctx->one_shot)
628     {
629       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
630           GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
631       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
632     }
633     else
634     {
635       reconnect_peer_ctx (pal_ctx);
636     }
637     return;
638   }
639
640   if ( (0 == tlen) && (0 == alen) )
641   {
642     /* No address available */
643     pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, NULL,
644         ntohl(pir_msg->state),
645         GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
646   }
647   else
648   {
649     if (0 == tlen)
650     {
651       GNUNET_break (0); /* This must not happen: address without plugin */
652       return;
653     }
654     addr = (const char *) &pir_msg[1];
655     transport_name = &addr[alen];
656
657     if (transport_name[tlen - 1] != '\0')
658     {
659       /* Corrupt plugin name */
660       GNUNET_break (0);
661       if (pal_ctx->one_shot)
662       {
663         pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
664             GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
665         GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
666       }
667       else
668       {
669         reconnect_peer_ctx (pal_ctx);
670       }
671       return;
672     }
673
674     /* notify client */
675     address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
676         transport_name, addr, alen, ntohl(pir_msg->local_address_info));
677     pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, address,
678         ntohl(pir_msg->state),
679         GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
680     GNUNET_HELLO_address_free (address);
681
682   }
683
684   /* expect more replies */
685   GNUNET_CLIENT_receive (pal_ctx->client, &peer_response_processor,
686                          pal_ctx,
687                          GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout));
688 }
689
690
691 /**
692  * Return information about a specific peer or all peers currently known to
693  * transport service once or in monitoring mode. To obtain information about
694  * a specific peer, a peer identity can be passed. To obtain information about
695  * all peers currently known to transport service, NULL can be passed as peer
696  * identity.
697  *
698  * For each peer, the callback is called with information about the address used
699  * to communicate with this peer, the state this peer is currently in and the
700  * the current timeout for this state.
701  *
702  * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
703  * more time with 'NULL'. After this, the operation must no longer be
704  * explicitly canceled.
705  *
706  * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
707  * the peer_callback!
708  *
709  * @param cfg configuration to use
710  * @param peer a specific peer identity to obtain information for,
711  *      NULL for all peers
712  * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL),
713  *                 GNUNET_NO to monitor peers continuously
714  * @param timeout how long is the lookup allowed to take at most
715  * @param peer_callback function to call with the results
716  * @param peer_callback_cls closure for peer_address_callback
717  */
718 struct GNUNET_TRANSPORT_PeerMonitoringContext *
719 GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
720     const struct GNUNET_PeerIdentity *peer,
721     int one_shot,
722     struct GNUNET_TIME_Relative timeout,
723     GNUNET_TRANSPORT_PeerIterateCallback peer_callback,
724     void *peer_callback_cls)
725 {
726   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx;
727   struct GNUNET_CLIENT_Connection *client;
728
729   client = GNUNET_CLIENT_connect ("transport", cfg);
730   if (client == NULL)
731     return NULL;
732   if (GNUNET_YES != one_shot)
733     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
734   pal_ctx = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
735   pal_ctx->cb = peer_callback;
736   pal_ctx->cb_cls = peer_callback_cls;
737   pal_ctx->cfg = cfg;
738   pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
739   if (NULL != peer)
740     pal_ctx->peer = *peer;
741   pal_ctx->one_shot = one_shot;
742   pal_ctx->client = client;
743   send_peer_mon_request (pal_ctx);
744
745   return pal_ctx;
746 }
747
748
749 /**
750  * Cancel request to monitor peers
751  *
752  * @param pic handle for the request to cancel
753  */
754 void
755 GNUNET_TRANSPORT_monitor_peers_cancel (struct GNUNET_TRANSPORT_PeerMonitoringContext *pic)
756 {
757   if (NULL != pic->client)
758   {
759     GNUNET_CLIENT_disconnect (pic->client);
760     pic->client = NULL;
761   }
762   if (GNUNET_SCHEDULER_NO_TASK != pic->reconnect_task)
763   {
764     GNUNET_SCHEDULER_cancel (pic->reconnect_task);
765     pic->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
766   }
767   GNUNET_free (pic);
768 }
769
770
771 /**
772  * Return information about pending address validation operations for a specific
773  * or all peers
774  *
775  * @param cfg configuration to use
776  * @param peer a specific peer identity to obtain validation entries for,
777  *      NULL for all peers
778  * @param one_shot GNUNET_YES to return all entries and then end (with NULL+NULL),
779  *                 GNUNET_NO to monitor validation entries continuously
780  * @param timeout how long is the lookup allowed to take at most
781  * @param validation_callback function to call with the results
782  * @param validation_callback_cls closure for peer_address_callback
783  */
784 struct GNUNET_TRANSPORT_ValidationMonitoringContext *
785 GNUNET_TRANSPORT_monitor_validation_entries (const struct
786                                 GNUNET_CONFIGURATION_Handle *cfg,
787                                 const struct GNUNET_PeerIdentity *peer,
788                                 int one_shot,
789                                 struct GNUNET_TIME_Relative timeout,
790                                 GNUNET_TRANSPORT_ValidationIterateCallback validation_callback,
791                                 void *validation_callback_cls)
792 {
793   struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx;
794   struct GNUNET_CLIENT_Connection *client;
795
796   client = GNUNET_CLIENT_connect ("transport", cfg);
797   if (client == NULL)
798     return NULL;
799   if (GNUNET_YES != one_shot)
800     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
801   val_ctx = GNUNET_new (struct GNUNET_TRANSPORT_ValidationMonitoringContext);
802   val_ctx->cb = validation_callback;
803   val_ctx->cb_cls = validation_callback_cls;
804   val_ctx->cfg = cfg;
805   val_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
806   if (NULL != peer)
807     val_ctx->peer = *peer;
808   val_ctx->one_shot = one_shot;
809   val_ctx->client = client;
810   send_val_mon_request (val_ctx);
811
812   return val_ctx;
813 }
814
815
816 /**
817  * Return information about all current pending validation operations
818  *
819  * @param vic handle for the request to cancel
820  */
821 void
822 GNUNET_TRANSPORT_monitor_validation_entries_cancel (struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic)
823 {
824   if (NULL != vic->client)
825   {
826     GNUNET_CLIENT_disconnect (vic->client);
827     vic->client = NULL;
828   }
829   if (GNUNET_SCHEDULER_NO_TASK != vic->reconnect_task)
830   {
831     GNUNET_SCHEDULER_cancel (vic->reconnect_task);
832     vic->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
833   }
834   GNUNET_free (vic);
835 }
836
837
838 /* end of transport_api_monitoring.c */