new monitoring API
[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_montoring.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
145 /**
146  * Function called with responses from the service.
147  *
148  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
149  * @param msg NULL on timeout or error, otherwise presumably a
150  *        message with the human-readable address
151  */
152 static void
153 peer_address_response_processor (void *cls,
154                                  const struct GNUNET_MessageHeader *msg);
155
156
157 /**
158  * Send our subscription request to the service.
159  *
160  * @param pal_ctx our context
161  */
162 static void
163 send_request (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
164 {
165   struct PeerIterateMessage msg;
166
167   msg.header.size = htons (sizeof (struct PeerIterateMessage));
168   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE);
169   msg.one_shot = htonl (pal_ctx->one_shot);
170   msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout);
171   msg.peer = pal_ctx->peer;
172   GNUNET_assert (GNUNET_OK ==
173                  GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client,
174                                                           &msg.header,
175                                                           GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout),
176                                                           GNUNET_YES,
177                                                           &peer_address_response_processor,
178                                                           pal_ctx));
179 }
180
181 /**
182  * Task run to re-establish the connection.
183  *
184  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
185  * @param tc scheduler context, unused
186  */
187 static void
188 do_connect (void *cls,
189             const struct GNUNET_SCHEDULER_TaskContext *tc)
190 {
191   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
192
193   pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
194   pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg);
195   GNUNET_assert (NULL != pal_ctx->client);
196   send_request (pal_ctx);
197 }
198
199
200 /**
201  * Cut the existing connection and reconnect.
202  *
203  * @param pal_ctx our context
204  */
205 static void
206 reconnect (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
207 {
208   GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
209   GNUNET_CLIENT_disconnect (pal_ctx->client);
210   pal_ctx->client = NULL;
211   pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
212   pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
213                                                           &do_connect,
214                                                           pal_ctx);
215 }
216
217
218 /**
219  * Function called with responses from the service.
220  *
221  * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
222  * @param msg NULL on timeout or error, otherwise presumably a
223  *        message with the human-readable address
224  */
225 static void
226 peer_address_response_processor (void *cls,
227                                  const struct GNUNET_MessageHeader *msg)
228 {
229   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
230   struct PeerIterateResponseMessage *air_msg;
231   struct GNUNET_HELLO_Address *address;
232   const char *addr;
233   const char *transport_name;
234   uint16_t size;
235   size_t alen;
236   size_t tlen;
237
238   if (msg == NULL)
239   {
240     if (pal_ctx->one_shot)
241     {
242       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
243           S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
244       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
245     }
246     else
247     {
248       reconnect (pal_ctx);
249     }
250     return;
251   }
252   size = ntohs (msg->size);
253   GNUNET_break (ntohs (msg->type) ==
254                 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
255   if (size == sizeof (struct GNUNET_MessageHeader))
256   {
257     /* done! */
258     if (pal_ctx->one_shot)
259     {
260       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
261           S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
262       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
263     }
264     else
265     {
266       reconnect (pal_ctx);
267     }
268     return;
269   }
270
271   if ((size < sizeof (struct PeerIterateResponseMessage)) ||
272       (ntohs (msg->type) !=
273        GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE))
274   {
275     GNUNET_break (0);
276     if (pal_ctx->one_shot)
277     {
278       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
279           S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
280       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
281     }
282     else
283     {
284       reconnect (pal_ctx);
285     }
286     return;
287   }
288
289   air_msg = (struct PeerIterateResponseMessage *) msg;
290   tlen = ntohl (air_msg->pluginlen);
291   alen = ntohl (air_msg->addrlen);
292
293   if (size != sizeof (struct PeerIterateResponseMessage) + tlen + alen)
294   {
295     GNUNET_break (0);
296     if (pal_ctx->one_shot)
297     {
298       pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
299           S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
300       GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
301     }
302     else
303     {
304       reconnect (pal_ctx);
305     }
306     return;
307   }
308
309   if (alen == 0 && tlen == 0)
310   {
311     pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL,
312         S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
313   }
314   else
315   {
316     addr = (const char *) &air_msg[1];
317     transport_name = &addr[alen];
318
319     if (transport_name[tlen - 1] != '\0')
320     {
321       GNUNET_break (0);
322       if (pal_ctx->one_shot)    
323       {
324         pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL,
325             S_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS);
326         GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
327       }
328       else
329       {
330         reconnect (pal_ctx);
331       }
332       return;
333     }
334
335     /* notify client */
336     address = GNUNET_HELLO_address_allocate (&air_msg->peer,
337         transport_name, addr, alen);
338     pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address,
339         ntohl(air_msg->state),
340         GNUNET_TIME_absolute_ntoh (air_msg->state_timeout));
341     GNUNET_HELLO_address_free (address);
342   }
343
344   /* expect more replies */
345   GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor,
346                          pal_ctx,
347                          GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout));
348 }
349
350
351 /**
352  * Return all the known addresses for a specific peer or all peers.
353  * Returns continuously all address if one_shot is set to GNUNET_NO
354  *
355  * CHANGE: Returns the address(es) that we are currently using for this
356  * peer.  Upon completion, the 'AddressLookUpCallback' is called one more
357  * time with 'NULL' for the address and the peer.  After this, the operation must no
358  * longer be explicitly canceled.
359  *
360  * @param cfg configuration to use
361  * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers
362  * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL),
363  *                 GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled)
364  * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO)
365  * @param peer_address_callback function to call with the results
366  * @param peer_address_callback_cls closure for peer_address_callback
367  */
368 struct GNUNET_TRANSPORT_PeerMonitoringContext *
369 GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
370     const struct GNUNET_PeerIdentity *peer,
371     int one_shot,
372     struct GNUNET_TIME_Relative timeout,
373     GNUNET_TRANSPORT_PeerIterateCallback peer_address_callback,
374     void *peer_address_callback_cls)
375 {
376   struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx;
377   struct GNUNET_CLIENT_Connection *client;
378
379   client = GNUNET_CLIENT_connect ("transport", cfg);
380   if (client == NULL)
381     return NULL;
382   if (GNUNET_YES != one_shot)
383     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
384   pal_ctx = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
385   pal_ctx->cb = peer_address_callback;
386   pal_ctx->cb_cls = peer_address_callback_cls;
387   pal_ctx->cfg = cfg;
388   pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
389   if (NULL != peer)
390     pal_ctx->peer = *peer;
391   pal_ctx->one_shot = one_shot;
392   pal_ctx->client = client;
393   send_request (pal_ctx);
394
395   return pal_ctx;
396 }
397
398
399 /**
400  * Cancel request for address conversion.
401  *
402  * @param alc handle for the request to cancel
403  */
404 void
405 GNUNET_TRANSPORT_monitor_peers_cancel (
406     struct GNUNET_TRANSPORT_PeerMonitoringContext *alc)
407 {
408   if (NULL != alc->client)
409   {
410     GNUNET_CLIENT_disconnect (alc->client);
411     alc->client = NULL;
412   }
413   if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task)
414   {
415     GNUNET_SCHEDULER_cancel (alc->reconnect_task);
416     alc->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
417   }
418   GNUNET_free (alc);
419 }
420
421
422 /**
423  * Return information about a peer's or all current pending validation operations
424  *
425  * @param cfg configuration to use
426  * @param peer a specific peer identity to obtain validation entries for,
427  *      NULL for all peers
428  * @param one_shot GNUNET_YES to return all entries and then end (with NULL+NULL),
429  *                 GNUNET_NO to monitor validation entries continuously
430  * @param timeout how long is the lookup allowed to take at most
431  * @param peer_address_callback function to call with the results
432  * @param peer_address_callback_cls closure for peer_address_callback
433  */
434 struct GNUNET_TRANSPORT_ValidationMonitoringContext *
435 GNUNET_TRANSPORT_monitor_validation_entries (const struct
436                                 GNUNET_CONFIGURATION_Handle *cfg,
437                                 const struct GNUNET_PeerIdentity *peer,
438                                 int one_shot,
439                                 struct GNUNET_TIME_Relative timeout,
440                                 GNUNET_TRANSPORT_ValidationIterateCallback validation_callback,
441                                 void *validation_callback_cls)
442 {
443   /* Not implemented */
444   return NULL;
445 }
446
447
448 /**
449  * Return information about all current pending validation operations
450  *
451  * @param vic handle for the request to cancel
452  */
453 void
454 GNUNET_TRANSPORT_monitor_validation_entries_cancel (struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic)
455 {
456   /* Not implemented */
457 }
458
459
460 /* end of transport_api_montoring.c */