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