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