fad77a194de544e3991dac6ac5b672d009ecb1c9
[oweals/gnunet.git] / src / peerinfo / peerinfo_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010, 2012 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 peerinfo/peerinfo_api.c
23  * @brief API to access peerinfo service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "peerinfo.h"
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "peerinfo-api",__VA_ARGS__)
32
33
34 /**
35  * Entry in the transmission queue to PEERINFO service.  We use
36  * the same structure for queueing 'iteration' requests and
37  * actual 'add' messages.
38  */
39 struct GNUNET_PEERINFO_AddContext
40 {
41   /**
42    * This is a linked list.
43    */
44   struct GNUNET_PEERINFO_AddContext *next;
45
46   /**
47    * This is a linked list.
48    */
49   struct GNUNET_PEERINFO_AddContext *prev;
50
51   /**
52    * Handle to the PEERINFO service.
53    */
54   struct GNUNET_PEERINFO_Handle *h;
55
56   /**
57    * Function to call after request has been transmitted, or NULL.
58    */
59   GNUNET_PEERINFO_Continuation cont;
60
61   /**
62    * Closure for 'cont'.
63    */
64   void *cont_cls;
65
66   /**
67    * Number of bytes of the request message (follows after this struct).
68    */
69   size_t size;
70
71 };
72
73
74 /**
75  * Context for an iteration request.
76  */
77 struct GNUNET_PEERINFO_IteratorContext
78 {
79
80   /**
81    * Kept in a DLL.
82    */
83   struct GNUNET_PEERINFO_IteratorContext *next;
84
85   /**
86    * Kept in a DLL.
87    */
88   struct GNUNET_PEERINFO_IteratorContext *prev;
89
90   /**
91    * Handle to the PEERINFO service.
92    */
93   struct GNUNET_PEERINFO_Handle *h;
94
95   /**
96    * Function to call with the results.
97    */
98   GNUNET_PEERINFO_Processor callback;
99
100   /**
101    * Closure for 'callback'.
102    */
103   void *callback_cls;
104
105   /**
106    * Our entry in the transmission queue.
107    */
108   struct GNUNET_PEERINFO_AddContext *ac;
109
110   /**
111    * Task responsible for timeout.
112    */
113   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
114
115   /**
116    * Timeout for the operation.
117    */
118   struct GNUNET_TIME_Absolute timeout;
119
120   /**
121    * Peer we are interested in (only valid if iteration was restricted to one peer).
122    */
123   struct GNUNET_PeerIdentity peer;
124
125   /**
126    * Is 'peer' set?
127    */
128   int have_peer;
129
130   /**
131    * Set to GNUNET_YES if we are currently receiving replies from the
132    * service.
133    */
134   int request_transmitted;
135
136 };
137
138
139 /**
140  * Handle to the peerinfo service.
141  */
142 struct GNUNET_PEERINFO_Handle
143 {
144   /**
145    * Our configuration.
146    */
147   const struct GNUNET_CONFIGURATION_Handle *cfg;
148
149   /**
150    * Connection to the service.
151    */
152   struct GNUNET_CLIENT_Connection *client;
153
154   /**
155    * Head of transmission queue.
156    */
157   struct GNUNET_PEERINFO_AddContext *ac_head;
158
159   /**
160    * Tail of transmission queue.
161    */
162   struct GNUNET_PEERINFO_AddContext *ac_tail;
163
164   /**
165    * Handle for the current transmission request, or NULL if none is pending.
166    */
167   struct GNUNET_CLIENT_TransmitHandle *th;
168
169   /**
170    * Head of iterator DLL.
171    */
172   struct GNUNET_PEERINFO_IteratorContext *ic_head;
173
174   /**
175    * Tail of iterator DLL.
176    */
177   struct GNUNET_PEERINFO_IteratorContext *ic_tail;
178
179   /**
180    * ID for a reconnect task.
181    */
182   GNUNET_SCHEDULER_TaskIdentifier r_task;
183
184   /**
185    * Are we now receiving?
186    */
187   int in_receive;
188
189 };
190
191
192 /**
193  * Connect to the peerinfo service.
194  *
195  * @param cfg configuration to use
196  * @return NULL on error (configuration related, actual connection
197  *         establishment may happen asynchronously).
198  */
199 struct GNUNET_PEERINFO_Handle *
200 GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
201 {
202   struct GNUNET_PEERINFO_Handle *h;
203
204   h = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_Handle));
205   h->client = GNUNET_CLIENT_connect ("peerinfo", cfg);
206   h->cfg = cfg;
207   return h;
208 }
209
210
211 /**
212  * Disconnect from the peerinfo service.  Note that all iterators must
213  * have completed or have been cancelled by the time this function is
214  * called (otherwise, calling this function is a serious error).
215  * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still
216  * pending, they will be cancelled silently on disconnect.
217  *
218  * @param h handle to disconnect
219  */
220 void
221 GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
222 {
223   struct GNUNET_PEERINFO_AddContext *ac;
224   struct GNUNET_PEERINFO_IteratorContext *ic;
225
226   while (NULL != (ic = h->ic_head))
227   {
228     GNUNET_break (GNUNET_YES == ic->request_transmitted);
229     ic->request_transmitted = GNUNET_NO;
230     GNUNET_PEERINFO_iterate_cancel (ic);
231   }
232   while (NULL != (ac = h->ac_head))
233   {
234     GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
235     if (NULL != ac->cont)
236       ac->cont (ac->cont_cls, _("aborted due to explicit disconnect request"));
237     GNUNET_free (ac);
238   }
239   if (NULL != h->th)
240   {
241     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
242     h->th = NULL;
243   }
244   if (NULL != h->client)
245   {
246     GNUNET_CLIENT_disconnect (h->client);
247     h->client = NULL;
248   }
249   if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
250   {
251     GNUNET_SCHEDULER_cancel (h->r_task);
252     h->r_task = GNUNET_SCHEDULER_NO_TASK;
253   }
254   GNUNET_free (h);
255 }
256
257
258 /**
259  * Check if we have a request pending in the transmission queue and are
260  * able to transmit it right now.  If so, schedule transmission.
261  *
262  * @param h handle to the service
263  */
264 static void
265 trigger_transmit (struct GNUNET_PEERINFO_Handle *h);
266
267
268 /**
269  * Close the existing connection to PEERINFO and reconnect.
270  *
271  * @param h handle to the service
272  */
273 static void
274 reconnect (struct GNUNET_PEERINFO_Handle *h);
275
276
277 /**
278  * Task scheduled to re-try connecting to the peerinfo service.
279  *
280  * @param cls the 'struct GNUNET_PEERINFO_Handle'
281  * @param tc scheduler context
282  */
283 static void
284 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
285 {
286   struct GNUNET_PEERINFO_Handle *h = cls;
287
288   h->r_task = GNUNET_SCHEDULER_NO_TASK;
289   reconnect (h);
290 }
291
292
293 /**
294  * Close the existing connection to PEERINFO and reconnect.
295  *
296  * @param h handle to the service
297  */
298 static void
299 reconnect (struct GNUNET_PEERINFO_Handle *h)
300 {
301   if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
302   {
303     GNUNET_SCHEDULER_cancel (h->r_task);
304     h->r_task = GNUNET_SCHEDULER_NO_TASK;
305   }
306   if (NULL != h->th)
307   {
308     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
309     h->th = NULL;
310   }
311   if (NULL != h->client)
312   {
313     GNUNET_CLIENT_disconnect (h->client);
314     h->client = NULL;
315   }
316   h->in_receive = GNUNET_NO;
317   h->client = GNUNET_CLIENT_connect ("peerinfo", h->cfg);
318   if (NULL == h->client)
319   {
320     h->r_task =
321         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
322                                       h);
323     return;
324   }
325   trigger_transmit (h);
326 }
327
328
329 /**
330  * Transmit the request at the head of the transmission queue
331  * and trigger continuation (if any).
332  *
333  * @param cls the 'struct GNUNET_PEERINFO_Handle' (with the queue)
334  * @param size size of the buffer (0 on error)
335  * @param buf where to copy the message
336  * @return number of bytes copied to buf
337  */
338 static size_t
339 do_transmit (void *cls, size_t size, void *buf)
340 {
341   struct GNUNET_PEERINFO_Handle *h = cls;
342   struct GNUNET_PEERINFO_AddContext *ac = h->ac_head;
343   size_t ret;
344
345   h->th = NULL;
346   if (NULL == ac)
347     return 0; /* request was cancelled in the meantime */
348   if (NULL == buf)
349   {
350     /* peerinfo service died */
351     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
352          "Failed to transmit message to `%s' service.\n", "PEERINFO");
353     GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
354     reconnect (h);
355     if (NULL != ac->cont)
356       ac->cont (ac->cont_cls, _("failed to transmit request (service down?)"));
357     GNUNET_free (ac);
358     return 0;
359   }
360   ret = ac->size;
361   if (size < ret)
362   {
363     /* change in head of queue (i.e. cancel + add), try again */
364     trigger_transmit (h);
365     return 0;
366   }
367   LOG (GNUNET_ERROR_TYPE_DEBUG,
368        "Transmitting request of size %u to `%s' service.\n", ret, "PEERINFO");
369   memcpy (buf, &ac[1], ret);
370   GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
371   trigger_transmit (h);
372   if (NULL != ac->cont)
373     ac->cont (ac->cont_cls, NULL);
374   GNUNET_free (ac);
375   return ret;
376 }
377
378
379 /**
380  * Check if we have a request pending in the transmission queue and are
381  * able to transmit it right now.  If so, schedule transmission.
382  *
383  * @param h handle to the service
384  */
385 static void
386 trigger_transmit (struct GNUNET_PEERINFO_Handle *h)
387 {
388   struct GNUNET_PEERINFO_AddContext *ac;
389
390   if (NULL == (ac = h->ac_head))
391     return; /* no requests queued */
392   if (NULL != h->th)
393     return; /* request already pending */
394   if (NULL == h->client)
395   {
396     /* disconnected, try to reconnect */
397     reconnect (h);
398     return;
399   }
400   h->th =
401     GNUNET_CLIENT_notify_transmit_ready (h->client, ac->size,
402                                          GNUNET_TIME_UNIT_FOREVER_REL,
403                                          GNUNET_YES,
404                                          &do_transmit, h);
405 }
406
407
408 /**
409  * Add a host to the persistent list.  This method operates in
410  * semi-reliable mode: if the transmission is not completed by
411  * the time 'GNUNET_PEERINFO_disconnect' is called, it will be
412  * aborted.  Furthermore, if a second HELLO is added for the
413  * same peer before the first one was transmitted, PEERINFO may
414  * merge the two HELLOs prior to transmission to the service.
415  *
416  * @param h handle to the peerinfo service
417  * @param hello the verified (!) HELLO message
418  * @param cont continuation to call when done, NULL is allowed
419  * @param cont_cls closure for 'cont'
420  * @return handle to cancel add operation; all pending
421  *         'add' operations will be cancelled automatically
422  *        on disconnect, so it is not necessary to keep this
423  *        handle (unless 'cont' is NULL and at some point
424  *        calling 'cont' must be prevented)
425  */
426 struct GNUNET_PEERINFO_AddContext *
427 GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
428                           const struct GNUNET_HELLO_Message *hello,
429                           GNUNET_PEERINFO_Continuation cont,
430                           void *cont_cls)
431 {
432   uint16_t hs = GNUNET_HELLO_size (hello);
433   struct GNUNET_PEERINFO_AddContext *ac;
434   struct GNUNET_PeerIdentity peer;
435
436   GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer));
437   LOG (GNUNET_ERROR_TYPE_DEBUG,
438        "Adding peer `%s' to PEERINFO database (%u bytes of `%s')\n",
439        GNUNET_i2s (&peer), hs, "HELLO");
440   ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs);
441   ac->h = h;
442   ac->size = hs;
443   ac->cont = cont;
444   ac->cont_cls = cont_cls;
445   memcpy (&ac[1], hello, hs);
446   GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac);
447   trigger_transmit (h);
448   return ac;
449 }
450
451
452 /**
453  * Cancel pending 'add' operation.  Must only be called before
454  * either 'cont' or 'GNUNET_PEERINFO_disconnect' are invoked.
455  *
456  * @param ac handle for the add operation to cancel
457  */
458 void 
459 GNUNET_PEERINFO_add_peer_cancel (struct GNUNET_PEERINFO_AddContext *ac)
460 {
461   struct GNUNET_PEERINFO_Handle *h = ac->h;
462
463   GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
464   GNUNET_free (ac);
465 }
466
467
468 /**
469  * Type of a function to call when we receive a message from the
470  * service.  Call the iterator with the result and (if applicable)
471  * continue to receive more messages or trigger processing the next
472  * event (if applicable).
473  *
474  * @param cls closure
475  * @param msg message received, NULL on timeout or fatal error
476  */
477 static void
478 peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
479 {
480   struct GNUNET_PEERINFO_Handle *h = cls;
481   struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
482   const struct InfoMessage *im;
483   const struct GNUNET_HELLO_Message *hello;
484   GNUNET_PEERINFO_Processor cb;
485   struct GNUNET_PeerIdentity id;
486   void *cb_cls;
487   uint16_t ms;
488
489   h->in_receive = GNUNET_NO;
490   if (NULL == msg)
491   {
492     /* peerinfo service died, signal error */
493     if (NULL != ic)
494     {
495       cb = ic->callback;
496       cb_cls = ic->callback_cls;
497       GNUNET_PEERINFO_iterate_cancel (ic);
498     }
499     else
500     {
501       cb = NULL;
502     }
503     reconnect (h);
504     if (NULL != cb)
505       cb (cb_cls, NULL, NULL,
506           _("Failed to receive response from `PEERINFO' service."));
507     return;
508   }
509   if (NULL == ic)
510   {
511     /* didn't expect a response, reconnect */
512     reconnect (h);
513     return;
514   }
515   ic->request_transmitted = GNUNET_NO;
516   cb = ic->callback;
517   cb_cls = ic->callback_cls;
518   if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type))
519   {
520     /* normal end of list of peers, signal end, process next pending request */
521     LOG (GNUNET_ERROR_TYPE_DEBUG,
522          "Received end of list of peers from `%s' service\n", "PEERINFO");
523     GNUNET_PEERINFO_iterate_cancel (ic);
524     trigger_transmit (h);
525     if ( (GNUNET_NO == h->in_receive) &&
526          (NULL != h->ic_head) )
527     {
528       h->in_receive = GNUNET_YES;
529       GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h,
530                              GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout));
531     }    
532     if (NULL != cb)
533       cb (cb_cls, NULL, NULL, NULL);
534     return;
535   }
536
537   ms = ntohs (msg->size);
538   if ((ms < sizeof (struct InfoMessage)) ||
539       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
540   {
541     /* malformed message */
542     GNUNET_break (0);
543     GNUNET_PEERINFO_iterate_cancel (ic);
544     reconnect (h);
545     if (NULL != cb)
546       cb (cb_cls, NULL, NULL,
547           _("Received invalid message from `PEERINFO' service."));
548     return;
549   }
550   im = (const struct InfoMessage *) msg;
551   GNUNET_break (0 == ntohl (im->reserved));
552   if ( (GNUNET_YES == ic->have_peer) &&
553        (0 != memcmp (&ic->peer, &im->peer, sizeof (struct GNUNET_PeerIdentity))) )
554   {
555     /* bogus message (from a different iteration call?); out of sequence! */
556     LOG (GNUNET_ERROR_TYPE_ERROR,
557          "Received HELLO for peer `%s', expected peer `%s'\n",
558          GNUNET_i2s (&im->peer),
559          GNUNET_i2s (&ic->peer));
560     
561     GNUNET_break (0);
562     GNUNET_PEERINFO_iterate_cancel (ic);
563     reconnect (h);
564     if (NULL != cb)      
565       cb (cb_cls, NULL, NULL,
566           _("Received invalid message from `PEERINFO' service."));
567     return;
568   }
569   hello = NULL;
570   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
571   {
572     hello = (const struct GNUNET_HELLO_Message *) &im[1];
573     if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
574     {
575       /* malformed message */
576       GNUNET_break (0);
577       GNUNET_PEERINFO_iterate_cancel (ic);
578       reconnect (h);
579       if (NULL != cb)      
580         cb (cb_cls, NULL, NULL,
581             _("Received invalid message from `PEERINFO' service."));
582       return;
583     }
584     if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id))
585     {
586       /* malformed message */
587       GNUNET_break (0);
588       GNUNET_PEERINFO_iterate_cancel (ic);
589       reconnect (h);
590       if (NULL != cb)      
591         cb (cb_cls, NULL, NULL,
592             _("Received invalid message from `PEERINFO' service."));
593       return;
594     }
595     if (0 != memcmp (&im->peer, &id, sizeof (struct GNUNET_PeerIdentity)))
596     {
597       /* malformed message */
598       GNUNET_break (0);
599       GNUNET_PEERINFO_iterate_cancel (ic);
600       reconnect (h);
601       if (NULL != cb)      
602         cb (cb_cls, NULL, NULL,
603             _("Received invalid message from `PEERINFO' service."));
604       return;
605     }
606   }
607
608   /* normal data message */
609   LOG (GNUNET_ERROR_TYPE_DEBUG,
610        "Received %u bytes of `%s' information about peer `%s' from `%s' service\n",
611        (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), "HELLO",
612        GNUNET_i2s (&im->peer), "PEERINFO");
613   h->in_receive = GNUNET_YES;
614   GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h,
615                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
616   if (NULL != cb)
617     cb (cb_cls, &im->peer, hello, NULL);
618 }
619
620
621 /**
622  * We've transmitted the iteration request.  Now get ready to process
623  * the results (or handle transmission error).
624  *
625  * @param cls the 'struct GNUNET_PEERINFO_IteratorContext'
626  * @param emsg error message, NULL if transmission worked
627  */
628 static void
629 iterator_start_receive (void *cls, const char *emsg)
630 {
631   struct GNUNET_PEERINFO_IteratorContext *ic = cls;
632   struct GNUNET_PEERINFO_Handle *h = ic->h;
633   GNUNET_PEERINFO_Processor cb;
634   void *cb_cls;
635
636   ic->ac = NULL;
637   if (NULL != emsg)
638   {
639     cb = ic->callback;
640     cb_cls = ic->callback_cls;
641     GNUNET_PEERINFO_iterate_cancel (ic);
642     reconnect (h);
643     if (NULL != cb)
644       cb (cb_cls, NULL, NULL, emsg);
645     return;
646   }
647   LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
648        "PEERINFO");
649   ic->request_transmitted = GNUNET_YES;
650   if (GNUNET_NO == h->in_receive)
651   {
652     h->in_receive = GNUNET_YES;
653     GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h,
654                            GNUNET_TIME_absolute_get_remaining (ic->timeout));
655   }
656 }
657
658
659 /**
660  * Peerinfo iteration request has timed out.
661  *
662  * @param cls the 'struct GNUNET_PEERINFO_IteratorContext*'
663  * @param tc scheduler context
664  */
665 static void
666 signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
667 {
668   struct GNUNET_PEERINFO_IteratorContext *ic = cls;
669   GNUNET_PEERINFO_Processor cb;
670   void *cb_cls;
671
672   ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
673   cb = ic->callback;
674   cb_cls = ic->callback_cls;
675   GNUNET_PEERINFO_iterate_cancel (ic);
676   if (NULL != cb)
677     cb (cb_cls, NULL, NULL,
678         _("Timeout transmitting iteration request to `PEERINFO' service."));
679 }
680
681
682 /**
683  * Call a method for each known matching host.  The callback method
684  * will be invoked once for each matching host and then finally once
685  * with a NULL pointer.  After that final invocation, the iterator
686  * context must no longer be used.
687  *
688  * Instead of calling this function with 'peer == NULL' it is often
689  * better to use 'GNUNET_PEERINFO_notify'.
690  *
691  * @param h handle to the peerinfo service
692  * @param include_friend_only include HELLO messages for friends only
693  * @param peer restrict iteration to this peer only (can be NULL)
694  * @param timeout how long to wait until timing out
695  * @param callback the method to call for each peer
696  * @param callback_cls closure for callback
697  * @return iterator context
698  */
699 struct GNUNET_PEERINFO_IteratorContext *
700 GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
701                                                                                                  int include_friend_only,
702                          const struct GNUNET_PeerIdentity *peer,
703                          struct GNUNET_TIME_Relative timeout,
704                          GNUNET_PEERINFO_Processor callback, void *callback_cls)
705 {
706   struct ListAllPeersMessage *lapm;
707   struct ListPeerMessage *lpm;
708   struct GNUNET_PEERINFO_IteratorContext *ic;
709   struct GNUNET_PEERINFO_AddContext *ac;
710
711   ic = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext));
712   if (NULL == peer)
713   {
714     LOG (GNUNET_ERROR_TYPE_DEBUG,
715          "Requesting list of peers from PEERINFO service\n");
716     ac =
717         GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
718                        sizeof (struct ListAllPeersMessage));
719     ac->size = sizeof (struct ListAllPeersMessage);
720     lapm = (struct ListAllPeersMessage *) &ac[1];
721     lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
722     lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
723     lapm->include_friend_only = htonl (include_friend_only);
724   }
725   else
726   {
727     LOG (GNUNET_ERROR_TYPE_DEBUG,
728          "Requesting information on peer `%4s' from PEERINFO service\n",
729          GNUNET_i2s (peer));
730     ac =
731         GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
732                        sizeof (struct ListPeerMessage));
733     ac->size = sizeof (struct ListPeerMessage);
734     lpm = (struct ListPeerMessage *) &ac[1];
735     lpm->header.size = htons (sizeof (struct ListPeerMessage));
736     lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
737     lpm->include_friend_only = htonl (include_friend_only);
738     memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
739     ic->have_peer = GNUNET_YES;
740     ic->peer = *peer;
741   }
742   ic->h = h;
743   ic->ac = ac;
744   ic->callback = callback;
745   ic->callback_cls = callback_cls;
746   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
747   ic->timeout_task =
748       GNUNET_SCHEDULER_add_delayed (timeout, &signal_timeout, ic);
749   ac->cont = &iterator_start_receive;
750   ac->cont_cls = ic;
751   GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac);
752   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
753                                     h->ic_tail,
754                                     ic);
755   trigger_transmit (h);
756   return ic;
757 }
758
759
760 /**
761  * Cancel an iteration over peer information.
762  *
763  * @param ic context of the iterator to cancel
764  */
765 void
766 GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
767 {
768   struct GNUNET_PEERINFO_Handle *h;
769
770   h = ic->h;
771   if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
772   {
773     GNUNET_SCHEDULER_cancel (ic->timeout_task);
774     ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
775   }
776   ic->callback = NULL;
777   if (GNUNET_YES == ic->request_transmitted)
778     return;                     /* need to finish processing */
779   GNUNET_CONTAINER_DLL_remove (h->ic_head,
780                                h->ic_tail,
781                                ic);
782   if (NULL != ic->ac)
783   {
784     GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ic->ac);
785     GNUNET_free (ic->ac);
786   }
787   GNUNET_free (ic);
788 }
789
790
791 /* end of peerinfo_api.c */