-fix format warning
[oweals/gnunet.git] / src / peerinfo / peerinfo_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001-2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 @e 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 @e 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   struct GNUNET_SCHEDULER_Task *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 @e 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   struct GNUNET_SCHEDULER_Task *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_new (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,
237                 _("aborted due to explicit disconnect request"));
238     GNUNET_free (ac);
239   }
240   if (NULL != h->th)
241   {
242     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
243     h->th = NULL;
244   }
245   if (NULL != h->client)
246   {
247     GNUNET_CLIENT_disconnect (h->client);
248     h->client = NULL;
249   }
250   if (NULL != h->r_task)
251   {
252     GNUNET_SCHEDULER_cancel (h->r_task);
253     h->r_task = NULL;
254   }
255   GNUNET_free (h);
256 }
257
258
259 /**
260  * Check if we have a request pending in the transmission queue and are
261  * able to transmit it right now.  If so, schedule transmission.
262  *
263  * @param h handle to the service
264  */
265 static void
266 trigger_transmit (struct GNUNET_PEERINFO_Handle *h);
267
268
269 /**
270  * Close the existing connection to PEERINFO and reconnect.
271  *
272  * @param h handle to the service
273  */
274 static void
275 reconnect (struct GNUNET_PEERINFO_Handle *h);
276
277
278 /**
279  * Task scheduled to re-try connecting to the peerinfo service.
280  *
281  * @param cls the `struct GNUNET_PEERINFO_Handle *`
282  */
283 static void
284 reconnect_task (void *cls)
285 {
286   struct GNUNET_PEERINFO_Handle *h = cls;
287
288   h->r_task = NULL;
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 (NULL != h->r_task)
302   {
303     GNUNET_SCHEDULER_cancel (h->r_task);
304     h->r_task = NULL;
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,
322                                       &reconnect_task,
323                                       h);
324     return;
325   }
326   trigger_transmit (h);
327 }
328
329
330 /**
331  * Transmit the request at the head of the transmission queue
332  * and trigger continuation (if any).
333  *
334  * @param cls the `struct GNUNET_PEERINFO_Handle *` (with the queue)
335  * @param size size of @a buf (0 on error)
336  * @param buf where to copy the message
337  * @return number of bytes copied to @a buf
338  */
339 static size_t
340 do_transmit (void *cls,
341              size_t size,
342              void *buf)
343 {
344   struct GNUNET_PEERINFO_Handle *h = cls;
345   struct GNUNET_PEERINFO_AddContext *ac = h->ac_head;
346   size_t ret;
347
348   h->th = NULL;
349   if (NULL == ac)
350     return 0; /* request was cancelled in the meantime */
351   if (NULL == buf)
352   {
353     /* peerinfo service died */
354     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
355          "Failed to transmit message to `%s' service.\n",
356          "PEERINFO");
357     GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
358     reconnect (h);
359     if (NULL != ac->cont)
360       ac->cont (ac->cont_cls,
361                 _("failed to transmit request (service down?)"));
362     GNUNET_free (ac);
363     return 0;
364   }
365   ret = ac->size;
366   if (size < ret)
367   {
368     /* change in head of queue (i.e. cancel + add), try again */
369     trigger_transmit (h);
370     return 0;
371   }
372   LOG (GNUNET_ERROR_TYPE_DEBUG,
373        "Transmitting request of size %u to `%s' service.\n",
374        ret,
375        "PEERINFO");
376   memcpy (buf, &ac[1], ret);
377   GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
378   trigger_transmit (h);
379   if (NULL != ac->cont)
380     ac->cont (ac->cont_cls, NULL);
381   GNUNET_free (ac);
382   return ret;
383 }
384
385
386 /**
387  * Check if we have a request pending in the transmission queue and are
388  * able to transmit it right now.  If so, schedule transmission.
389  *
390  * @param h handle to the service
391  */
392 static void
393 trigger_transmit (struct GNUNET_PEERINFO_Handle *h)
394 {
395   struct GNUNET_PEERINFO_AddContext *ac;
396
397   if (NULL == (ac = h->ac_head))
398     return; /* no requests queued */
399   if (NULL != h->th)
400     return; /* request already pending */
401   if (NULL == h->client)
402   {
403     /* disconnected, try to reconnect */
404     reconnect (h);
405     return;
406   }
407   h->th =
408     GNUNET_CLIENT_notify_transmit_ready (h->client,
409                                          ac->size,
410                                          GNUNET_TIME_UNIT_FOREVER_REL,
411                                          GNUNET_YES,
412                                          &do_transmit, h);
413 }
414
415
416 /**
417  * Add a host to the persistent list.  This method operates in
418  * semi-reliable mode: if the transmission is not completed by
419  * the time #GNUNET_PEERINFO_disconnect() is called, it will be
420  * aborted.  Furthermore, if a second HELLO is added for the
421  * same peer before the first one was transmitted, PEERINFO may
422  * merge the two HELLOs prior to transmission to the service.
423  *
424  * @param h handle to the peerinfo service
425  * @param hello the verified (!) HELLO message
426  * @param cont continuation to call when done, NULL is allowed
427  * @param cont_cls closure for @a cont
428  * @return handle to cancel add operation; all pending
429  *         'add' operations will be cancelled automatically
430  *        on disconnect, so it is not necessary to keep this
431  *        handle (unless @a cont is NULL and at some point
432  *        calling @a cont must be prevented)
433  */
434 struct GNUNET_PEERINFO_AddContext *
435 GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
436                           const struct GNUNET_HELLO_Message *hello,
437                           GNUNET_PEERINFO_Continuation cont,
438                           void *cont_cls)
439 {
440   uint16_t hs = GNUNET_HELLO_size (hello);
441   struct GNUNET_PEERINFO_AddContext *ac;
442   struct GNUNET_PeerIdentity peer;
443
444   GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer));
445   LOG (GNUNET_ERROR_TYPE_DEBUG,
446        "Adding peer `%s' to PEERINFO database (%u bytes of HELLO)\n",
447        GNUNET_i2s (&peer),
448        hs);
449   ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs);
450   ac->h = h;
451   ac->size = hs;
452   ac->cont = cont;
453   ac->cont_cls = cont_cls;
454   memcpy (&ac[1], hello, hs);
455   GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac);
456   trigger_transmit (h);
457   return ac;
458 }
459
460
461 /**
462  * Cancel pending 'add' operation.  Must only be called before
463  * either 'cont' or #GNUNET_PEERINFO_disconnect() are invoked.
464  *
465  * @param ac handle for the add operation to cancel
466  */
467 void
468 GNUNET_PEERINFO_add_peer_cancel (struct GNUNET_PEERINFO_AddContext *ac)
469 {
470   struct GNUNET_PEERINFO_Handle *h = ac->h;
471
472   GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
473   GNUNET_free (ac);
474 }
475
476
477 /**
478  * Type of a function to call when we receive a message from the
479  * service.  Call the iterator with the result and (if applicable)
480  * continue to receive more messages or trigger processing the next
481  * event (if applicable).
482  *
483  * @param cls closure
484  * @param msg message received, NULL on timeout or fatal error
485  */
486 static void
487 peerinfo_handler (void *cls,
488                   const struct GNUNET_MessageHeader *msg)
489 {
490   struct GNUNET_PEERINFO_Handle *h = cls;
491   struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
492   const struct InfoMessage *im;
493   const struct GNUNET_HELLO_Message *hello;
494   GNUNET_PEERINFO_Processor cb;
495   struct GNUNET_PeerIdentity id;
496   void *cb_cls;
497   uint16_t ms;
498
499   h->in_receive = GNUNET_NO;
500   if (NULL == msg)
501   {
502     /* peerinfo service died, signal error */
503     if (NULL != ic)
504     {
505       cb = ic->callback;
506       cb_cls = ic->callback_cls;
507       GNUNET_PEERINFO_iterate_cancel (ic);
508     }
509     else
510     {
511       cb = NULL;
512     }
513     reconnect (h);
514     if (NULL != cb)
515       cb (cb_cls, NULL, NULL,
516           _("Failed to receive response from `PEERINFO' service."));
517     return;
518   }
519   if (NULL == ic)
520   {
521     /* didn't expect a response, reconnect */
522     reconnect (h);
523     return;
524   }
525   ic->request_transmitted = GNUNET_NO;
526   cb = ic->callback;
527   cb_cls = ic->callback_cls;
528   if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type))
529   {
530     /* normal end of list of peers, signal end, process next pending request */
531     LOG (GNUNET_ERROR_TYPE_DEBUG,
532          "Received end of list of peers from `%s' service\n",
533          "PEERINFO");
534     GNUNET_PEERINFO_iterate_cancel (ic);
535     trigger_transmit (h);
536     if ( (GNUNET_NO == h->in_receive) &&
537          (NULL != h->ic_head) )
538     {
539       h->in_receive = GNUNET_YES;
540       GNUNET_CLIENT_receive (h->client,
541                              &peerinfo_handler,
542                              h,
543                              GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout));
544     }
545     if (NULL != cb)
546       cb (cb_cls, NULL, NULL, NULL);
547     return;
548   }
549
550   ms = ntohs (msg->size);
551   if ((ms < sizeof (struct InfoMessage)) ||
552       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
553   {
554     /* malformed message */
555     GNUNET_break (0);
556     GNUNET_PEERINFO_iterate_cancel (ic);
557     reconnect (h);
558     if (NULL != cb)
559       cb (cb_cls, NULL, NULL,
560           _("Received invalid message from `PEERINFO' service."));
561     return;
562   }
563   im = (const struct InfoMessage *) msg;
564   GNUNET_break (0 == ntohl (im->reserved));
565   if ( (GNUNET_YES == ic->have_peer) &&
566        (0 != memcmp (&ic->peer,
567                      &im->peer,
568                      sizeof (struct GNUNET_PeerIdentity))) )
569   {
570     /* bogus message (from a different iteration call?); out of sequence! */
571     LOG (GNUNET_ERROR_TYPE_ERROR,
572          "Received HELLO for peer `%s', expected peer `%s'\n",
573          GNUNET_i2s (&im->peer),
574          GNUNET_i2s (&ic->peer));
575
576     GNUNET_break (0);
577     GNUNET_PEERINFO_iterate_cancel (ic);
578     reconnect (h);
579     if (NULL != cb)
580       cb (cb_cls,
581           NULL,
582           NULL,
583           _("Received invalid message from `PEERINFO' service."));
584     return;
585   }
586   hello = NULL;
587   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
588   {
589     hello = (const struct GNUNET_HELLO_Message *) &im[1];
590     if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
591     {
592       /* malformed message */
593       GNUNET_break (0);
594       GNUNET_PEERINFO_iterate_cancel (ic);
595       reconnect (h);
596       if (NULL != cb)
597         cb (cb_cls,
598             NULL,
599             NULL,
600             _("Received invalid message from `PEERINFO' service."));
601       return;
602     }
603     if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id))
604     {
605       /* malformed message */
606       GNUNET_break (0);
607       GNUNET_PEERINFO_iterate_cancel (ic);
608       reconnect (h);
609       if (NULL != cb)
610         cb (cb_cls,
611             NULL,
612             NULL,
613             _("Received invalid message from `PEERINFO' service."));
614       return;
615     }
616     if (0 != memcmp (&im->peer,
617                      &id,
618                      sizeof (struct GNUNET_PeerIdentity)))
619     {
620       /* malformed message */
621       GNUNET_break (0);
622       GNUNET_PEERINFO_iterate_cancel (ic);
623       reconnect (h);
624       if (NULL != cb)
625         cb (cb_cls,
626             NULL,
627             NULL,
628             _("Received invalid message from `PEERINFO' service."));
629       return;
630     }
631   }
632
633   /* normal data message */
634   LOG (GNUNET_ERROR_TYPE_DEBUG,
635        "Received %u bytes of `%s' information about peer `%s' from `%s' service\n",
636        (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello),
637        "HELLO",
638        GNUNET_i2s (&im->peer),
639        "PEERINFO");
640   h->in_receive = GNUNET_YES;
641   GNUNET_CLIENT_receive (h->client,
642                          &peerinfo_handler,
643                          h,
644                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
645   if (NULL != cb)
646     cb (cb_cls,
647         &im->peer,
648         hello,
649         NULL);
650 }
651
652
653 /**
654  * We've transmitted the iteration request.  Now get ready to process
655  * the results (or handle transmission error).
656  *
657  * @param cls the `struct GNUNET_PEERINFO_IteratorContext *`
658  * @param emsg error message, NULL if transmission worked
659  */
660 static void
661 iterator_start_receive (void *cls,
662                         const char *emsg)
663 {
664   struct GNUNET_PEERINFO_IteratorContext *ic = cls;
665   struct GNUNET_PEERINFO_Handle *h = ic->h;
666   GNUNET_PEERINFO_Processor cb;
667   void *cb_cls;
668
669   ic->ac = NULL;
670   if (NULL != emsg)
671   {
672     cb = ic->callback;
673     cb_cls = ic->callback_cls;
674     GNUNET_PEERINFO_iterate_cancel (ic);
675     reconnect (h);
676     if (NULL != cb)
677       cb (cb_cls, NULL, NULL, emsg);
678     return;
679   }
680   LOG (GNUNET_ERROR_TYPE_DEBUG,
681        "Waiting for response from `%s' service.\n",
682        "PEERINFO");
683   ic->request_transmitted = GNUNET_YES;
684   if (GNUNET_NO == h->in_receive)
685   {
686     h->in_receive = GNUNET_YES;
687     GNUNET_CLIENT_receive (h->client,
688                            &peerinfo_handler,
689                            h,
690                            GNUNET_TIME_absolute_get_remaining (ic->timeout));
691   }
692 }
693
694
695 /**
696  * Peerinfo iteration request has timed out.
697  *
698  * @param cls the `struct GNUNET_PEERINFO_IteratorContext *`
699  */
700 static void
701 signal_timeout (void *cls)
702 {
703   struct GNUNET_PEERINFO_IteratorContext *ic = cls;
704   GNUNET_PEERINFO_Processor cb;
705   void *cb_cls;
706
707   ic->timeout_task = NULL;
708   cb = ic->callback;
709   cb_cls = ic->callback_cls;
710   GNUNET_PEERINFO_iterate_cancel (ic);
711   if (NULL != cb)
712     cb (cb_cls,
713         NULL,
714         NULL,
715         _("Timeout transmitting iteration request to `PEERINFO' service."));
716 }
717
718
719 /**
720  * Call a method for each known matching host.  The callback method
721  * will be invoked once for each matching host and then finally once
722  * with a NULL pointer.  After that final invocation, the iterator
723  * context must no longer be used.
724  *
725  * Instead of calling this function with `peer == NULL` it is often
726  * better to use #GNUNET_PEERINFO_notify().
727  *
728  * @param h handle to the peerinfo service
729  * @param include_friend_only include HELLO messages for friends only
730  * @param peer restrict iteration to this peer only (can be NULL)
731  * @param timeout how long to wait until timing out
732  * @param callback the method to call for each peer
733  * @param callback_cls closure for @a callback
734  * @return iterator context
735  */
736 struct GNUNET_PEERINFO_IteratorContext *
737 GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
738                          int include_friend_only,
739                          const struct GNUNET_PeerIdentity *peer,
740                          struct GNUNET_TIME_Relative timeout,
741                          GNUNET_PEERINFO_Processor callback,
742                          void *callback_cls)
743 {
744   struct ListAllPeersMessage *lapm;
745   struct ListPeerMessage *lpm;
746   struct GNUNET_PEERINFO_IteratorContext *ic;
747   struct GNUNET_PEERINFO_AddContext *ac;
748
749   ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
750   if (NULL == peer)
751   {
752     LOG (GNUNET_ERROR_TYPE_DEBUG,
753          "Requesting list of peers from PEERINFO service\n");
754     ac =
755         GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
756                        sizeof (struct ListAllPeersMessage));
757     ac->size = sizeof (struct ListAllPeersMessage);
758     lapm = (struct ListAllPeersMessage *) &ac[1];
759     lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
760     lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
761     lapm->include_friend_only = htonl (include_friend_only);
762   }
763   else
764   {
765     LOG (GNUNET_ERROR_TYPE_DEBUG,
766          "Requesting information on peer `%4s' from PEERINFO service\n",
767          GNUNET_i2s (peer));
768     ac =
769         GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
770                        sizeof (struct ListPeerMessage));
771     ac->size = sizeof (struct ListPeerMessage);
772     lpm = (struct ListPeerMessage *) &ac[1];
773     lpm->header.size = htons (sizeof (struct ListPeerMessage));
774     lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
775     lpm->include_friend_only = htonl (include_friend_only);
776     memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
777     ic->have_peer = GNUNET_YES;
778     ic->peer = *peer;
779   }
780   ic->h = h;
781   ic->ac = ac;
782   ic->callback = callback;
783   ic->callback_cls = callback_cls;
784   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
785   ic->timeout_task =
786       GNUNET_SCHEDULER_add_delayed (timeout, &signal_timeout, ic);
787   ac->cont = &iterator_start_receive;
788   ac->cont_cls = ic;
789   GNUNET_CONTAINER_DLL_insert_tail (h->ac_head,
790                                     h->ac_tail,
791                                     ac);
792   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
793                                     h->ic_tail,
794                                     ic);
795   trigger_transmit (h);
796   return ic;
797 }
798
799
800 /**
801  * Cancel an iteration over peer information.
802  *
803  * @param ic context of the iterator to cancel
804  */
805 void
806 GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
807 {
808   struct GNUNET_PEERINFO_Handle *h;
809
810   h = ic->h;
811   if (NULL != ic->timeout_task)
812   {
813     GNUNET_SCHEDULER_cancel (ic->timeout_task);
814     ic->timeout_task = NULL;
815   }
816   ic->callback = NULL;
817   if (GNUNET_YES == ic->request_transmitted)
818     return;                     /* need to finish processing */
819   GNUNET_CONTAINER_DLL_remove (h->ic_head,
820                                h->ic_tail,
821                                ic);
822   if (NULL != ic->ac)
823   {
824     GNUNET_CONTAINER_DLL_remove (h->ac_head,
825                                  h->ac_tail,
826                                  ic->ac);
827     GNUNET_free (ic->ac);
828   }
829   GNUNET_free (ic);
830 }
831
832
833 /* end of peerinfo_api.c */