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