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