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