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