Fixed failing test and discrepancy between documentation and implemented functionality:
[oweals/gnunet.git] / src / peerinfo / peerinfo_api.c
index aac83f71b7085acec073534e8acee2b05ed19082..a0cb5c5c4a94323aba029ffcdb1d79393d0e6006 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2004, 2005, 2007, 2009 Christian Grothoff (and other contributing authors)
+     (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @file peerinfo/peerinfo_api.c
  * @brief API to access peerinfo service
  * @author Christian Grothoff
  * @file peerinfo/peerinfo_api.c
  * @brief API to access peerinfo service
  * @author Christian Grothoff
- *
- * TODO:
- * - document NEW API implementation
- * - add timeout for iteration
- * - implement cancellation of iteration
  */
 #include "platform.h"
 #include "gnunet_client_lib.h"
  */
 #include "platform.h"
 #include "gnunet_client_lib.h"
 #include "peerinfo.h"
 
 /**
 #include "peerinfo.h"
 
 /**
- *
+ * Function to call after transmission has succeeded.
+ * 
+ * @param cls closure
+ * @param success GNUNET_OK if transmission worked, GNUNET_SYSERR on error
  */
 typedef void (*TransmissionContinuation)(void *cls,
                                         int success);
 
 
 /**
  */
 typedef void (*TransmissionContinuation)(void *cls,
                                         int success);
 
 
 /**
- *
+ * Entry in the transmission queue to PEERINFO service.
  */
 struct TransmissionQueueEntry
 {
   /**
  */
 struct TransmissionQueueEntry
 {
   /**
-   *
+   * This is a linked list.
    */
   struct TransmissionQueueEntry *next;
   
   /**
    */
   struct TransmissionQueueEntry *next;
   
   /**
-   *
+   * This is a linked list.
    */
   struct TransmissionQueueEntry *prev;
 
   /**
    */
   struct TransmissionQueueEntry *prev;
 
   /**
-   *
+   * Function to call after request has been transmitted, or NULL (in which
+   * case we must consider sending the next entry immediately).
    */
   TransmissionContinuation cont;
   
   /**
    */
   TransmissionContinuation cont;
   
   /**
-   *
+   * Closure for 'cont'.
    */
   void *cont_cls;
 
   /**
    */
   void *cont_cls;
 
   /**
-   *
+   * Timeout for the operation.
    */
   struct GNUNET_TIME_Absolute timeout;
 
   /**
    */
   struct GNUNET_TIME_Absolute timeout;
 
   /**
-   *
+   * Number of bytes of the request message (follows after this struct).
    */
   size_t size;
 
    */
   size_t size;
 
@@ -91,30 +90,32 @@ struct GNUNET_PEERINFO_Handle
    */
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
    */
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
-  /**
-   * Our scheduler.
-   */
-  struct GNUNET_SCHEDULER_Handle *sched;
-
   /**
    * Connection to the service.
    */
   struct GNUNET_CLIENT_Connection *client;
 
   /**
   /**
    * Connection to the service.
    */
   struct GNUNET_CLIENT_Connection *client;
 
   /**
-   *
+   * Head of transmission queue.
    */
   struct TransmissionQueueEntry *tq_head;
 
   /**
    */
   struct TransmissionQueueEntry *tq_head;
 
   /**
-   *
+   * Tail of transmission queue.
    */
   struct TransmissionQueueEntry *tq_tail;
 
   /**
    */
   struct TransmissionQueueEntry *tq_tail;
 
   /**
-   *
+   * Handle for the current transmission request, or NULL if none is pending.
    */
   struct GNUNET_CLIENT_TransmitHandle *th;
    */
   struct GNUNET_CLIENT_TransmitHandle *th;
+
+  /**
+   * Set to GNUNET_YES if we are currently receiving replies from the
+   * service.
+   */
+  int in_receive;
+
 };
 
 
 };
 
 
@@ -122,24 +123,21 @@ struct GNUNET_PEERINFO_Handle
  * Connect to the peerinfo service.
  *
  * @param cfg configuration to use
  * Connect to the peerinfo service.
  *
  * @param cfg configuration to use
- * @param sched scheduler to use
  * @return NULL on error (configuration related, actual connection
  * @return NULL on error (configuration related, actual connection
- *         etablishment may happen asynchronously).
+ *         establishment may happen asynchronously).
  */
 struct GNUNET_PEERINFO_Handle *
  */
 struct GNUNET_PEERINFO_Handle *
-GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                        struct GNUNET_SCHEDULER_Handle *sched)
+GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct GNUNET_CLIENT_Connection *client;
   struct GNUNET_PEERINFO_Handle *ret;
 
 {
   struct GNUNET_CLIENT_Connection *client;
   struct GNUNET_PEERINFO_Handle *ret;
 
-  client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
+  client = GNUNET_CLIENT_connect ("peerinfo", cfg);
   if (client == NULL)
     return NULL;
   ret = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_Handle));
   ret->client = client;
   ret->cfg = cfg;
   if (client == NULL)
     return NULL;
   ret = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_Handle));
   ret->client = client;
   ret->cfg = cfg;
-  ret->sched = sched;
   return ret;
 }
 
   return ret;
 }
 
@@ -167,32 +165,49 @@ GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
        tqe->cont (tqe->cont_cls, GNUNET_SYSERR);
       GNUNET_free (tqe);
     }
        tqe->cont (tqe->cont_cls, GNUNET_SYSERR);
       GNUNET_free (tqe);
     }
+  if (h->th != NULL)
+    {
+      GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+      h->th = NULL;
+    }
   GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
   GNUNET_free (h);
 }
 
 
 /**
   GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
   GNUNET_free (h);
 }
 
 
 /**
+ * Check if we have a request pending in the transmission queue and are
+ * able to transmit it right now.  If so, schedule transmission.
  *
  *
+ * @param h handle to the service
  */
 static void
 trigger_transmit (struct GNUNET_PEERINFO_Handle *h);
 
 
 /**
  */
 static void
 trigger_transmit (struct GNUNET_PEERINFO_Handle *h);
 
 
 /**
+ * Close the existing connection to PEERINFO and reconnect.
  *
  *
+ * @param h handle to the service
  */
 static void
 reconnect (struct GNUNET_PEERINFO_Handle *h)
 {
   GNUNET_CLIENT_disconnect (h->client, GNUNET_SYSERR);
  */
 static void
 reconnect (struct GNUNET_PEERINFO_Handle *h)
 {
   GNUNET_CLIENT_disconnect (h->client, GNUNET_SYSERR);
-  h->client = GNUNET_CLIENT_connect (h->sched, "client", h->cfg);
+  h->th = NULL;
+  h->client = GNUNET_CLIENT_connect ("peerinfo", h->cfg);
   GNUNET_assert (h->client != NULL);
 }
 
 
 /**
   GNUNET_assert (h->client != NULL);
 }
 
 
 /**
+ * Transmit the request at the head of the transmission queue
+ * and trigger continuation (if any).
  *
  *
+ * @param cls the 'struct GNUNET_PEERINFO_Handle' (with the queue)
+ * @param size size of the buffer (0 on error)
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
  */
 static size_t
 do_transmit (void *cls, size_t size, void *buf)
  */
 static size_t
 do_transmit (void *cls, size_t size, void *buf)
@@ -204,26 +219,37 @@ do_transmit (void *cls, size_t size, void *buf)
   h->th = NULL;
   if (buf == NULL)
     {
   h->th = NULL;
   if (buf == NULL)
     {
-#if DEBUG_PEERINFO
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _
-                  ("Failed to transmit message of type %u to `%s' service.\n"),
-                  ntohs (msg->type), "peerinfo");
-#endif
-      GNUNET_CONTAINER_DLL_remove (h->tq_head,
-                                  h->tq_tail,
-                                  tqe);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+                  _("Failed to transmit message to `%s' service.\n"),
+                 "PEERINFO");
+      if (tqe != NULL)
+       GNUNET_CONTAINER_DLL_remove (h->tq_head,
+                                    h->tq_tail,
+                                    tqe);
       reconnect (h);
       trigger_transmit (h);
       reconnect (h);
       trigger_transmit (h);
-      if (tqe->cont != NULL)
-       tqe->cont (tqe->cont_cls, GNUNET_SYSERR);
-      GNUNET_free (tqe);
+      if (tqe != NULL)
+       {
+         if (tqe->cont != NULL)
+           tqe->cont (tqe->cont_cls, GNUNET_SYSERR);
+         GNUNET_free (tqe);
+       }
       return 0;
     }
       return 0;
     }
+  /* If it can be NULL above, it can be NULL here to... */
+  if (tqe == NULL)
+    return 0;
+
   ret = tqe->size;
   GNUNET_assert (size >= ret);
   memcpy (buf, &tqe[1], ret);
   ret = tqe->size;
   GNUNET_assert (size >= ret);
   memcpy (buf, &tqe[1], ret);
-  GNUNET_CONTAINER_DLL_remove (h->tq_head,
+#if DEBUG_PEERINFO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Transmitting request of size %u to `%s' service.\n",
+             ret, 
+             "PEERINFO");
+#endif
+   GNUNET_CONTAINER_DLL_remove (h->tq_head,
                               h->tq_tail,
                               tqe);
   if (tqe->cont != NULL)
                               h->tq_tail,
                               tqe);
   if (tqe->cont != NULL)
@@ -235,15 +261,23 @@ do_transmit (void *cls, size_t size, void *buf)
 }
 
 
 }
 
 
+/**
+ * Check if we have a request pending in the transmission queue and are
+ * able to transmit it right now.  If so, schedule transmission.
+ *
+ * @param h handle to the service
+ */
 static void
 trigger_transmit (struct GNUNET_PEERINFO_Handle *h)
 {
   struct TransmissionQueueEntry *tqe;
 
   if (NULL == (tqe = h->tq_head))
 static void
 trigger_transmit (struct GNUNET_PEERINFO_Handle *h)
 {
   struct TransmissionQueueEntry *tqe;
 
   if (NULL == (tqe = h->tq_head))
-    return;
+    return NULL;
   if (h->th != NULL)
   if (h->th != NULL)
-    return;
+    return NULL;
+  if (h->in_receive == GNUNET_YES)
+    return NULL;
   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
                                               tqe->size,
                                               GNUNET_TIME_absolute_get_remaining (tqe->timeout),
   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
                                               tqe->size,
                                               GNUNET_TIME_absolute_get_remaining (tqe->timeout),
@@ -261,12 +295,11 @@ trigger_transmit (struct GNUNET_PEERINFO_Handle *h)
  * merge the two HELLOs prior to transmission to the service.
  *
  * @param h handle to the peerinfo service
  * merge the two HELLOs prior to transmission to the service.
  *
  * @param h handle to the peerinfo service
- * @param peer identity of the peer
  * @param hello the verified (!) HELLO message
  */
 void
  * @param hello the verified (!) HELLO message
  */
 void
-GNUNET_PEERINFO_add_peer_new (struct GNUNET_PEERINFO_Handle *h,
-                             const struct GNUNET_HELLO_Message *hello)
+GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
+                         const struct GNUNET_HELLO_Message *hello)
 {
   uint16_t hs = GNUNET_HELLO_size (hello);
   struct TransmissionQueueEntry *tqe;
 {
   uint16_t hs = GNUNET_HELLO_size (hello);
   struct TransmissionQueueEntry *tqe;
@@ -292,33 +325,46 @@ GNUNET_PEERINFO_add_peer_new (struct GNUNET_PEERINFO_Handle *h,
 }
 
 
 }
 
 
-
 /**
 /**
- *
+ * Context for an iteration request.
  */
  */
-struct GNUNET_PEERINFO_NewIteratorContext
+struct GNUNET_PEERINFO_IteratorContext
 {
   /**
 {
   /**
-   *
+   * Handle to the PEERINFO service.
    */
   struct GNUNET_PEERINFO_Handle *h;
 
   /**
    */
   struct GNUNET_PEERINFO_Handle *h;
 
   /**
-   *
+   * Function to call with the results.
    */
   GNUNET_PEERINFO_Processor callback;
 
   /**
    */
   GNUNET_PEERINFO_Processor callback;
 
   /**
-   *
+   * Closure for 'callback'.
    */
   void *callback_cls;
 
   /**
    */
   void *callback_cls;
 
   /**
-   *
+   * Our entry in the transmission queue.
+   */
+  struct TransmissionQueueEntry *tqe;
+
+  /**
+   * Task responsible for timeout.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+  /**
+   * Timeout for the operation.
    */
   struct GNUNET_TIME_Absolute timeout;
    */
   struct GNUNET_TIME_Absolute timeout;
-};
 
 
+  /**
+   * Are we now receiving?
+   */
+  int in_receive;
+};
 
 
 /**
 
 
 /**
@@ -331,19 +377,23 @@ struct GNUNET_PEERINFO_NewIteratorContext
 static void
 peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 {
 static void
 peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 {
-  struct GNUNET_PEERINFO_NewIteratorContext *ic = cls;
+  struct GNUNET_PEERINFO_IteratorContext *ic = cls;
   const struct InfoMessage *im;
   const struct GNUNET_HELLO_Message *hello;
   uint16_t ms;
 
   const struct InfoMessage *im;
   const struct GNUNET_HELLO_Message *hello;
   uint16_t ms;
 
+  ic->h->in_receive = GNUNET_NO;
   if (msg == NULL)
     {
   if (msg == NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   _("Failed to receive response from `%s' service.\n"),
                   _("Failed to receive response from `%s' service.\n"),
-                  "peerinfo");
+                  "PEERINFO");
       reconnect (ic->h);
       trigger_transmit (ic->h);
       reconnect (ic->h);
       trigger_transmit (ic->h);
-      ic->callback (ic->callback_cls, NULL, NULL, 1);
+      if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+       GNUNET_SCHEDULER_cancel (ic->timeout_task);
+      if (ic->callback != NULL)
+       ic->callback (ic->callback_cls, NULL, NULL);
       GNUNET_free (ic);
       return;
     }
       GNUNET_free (ic);
       return;
     }
@@ -351,10 +401,14 @@ peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
     {
 #if DEBUG_PEERINFO
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     {
 #if DEBUG_PEERINFO
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Received end of list of peers from peerinfo database\n");
+                 "Received end of list of peers from `%s' service\n",
+                 "PEERINFO");
 #endif
       trigger_transmit (ic->h);
 #endif
       trigger_transmit (ic->h);
-      ic->callback (ic->callback_cls, NULL, NULL, 0);
+      if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+       GNUNET_SCHEDULER_cancel (ic->timeout_task);
+      if (ic->callback != NULL)
+       ic->callback (ic->callback_cls, NULL, NULL);
       GNUNET_free (ic);
       return;
     }
       GNUNET_free (ic);
       return;
     }
@@ -365,11 +419,15 @@ peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
       GNUNET_break (0);
       reconnect (ic->h);
       trigger_transmit (ic->h);
       GNUNET_break (0);
       reconnect (ic->h);
       trigger_transmit (ic->h);
-      ic->callback (ic->callback_cls, NULL, NULL, 2);
+      if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+       GNUNET_SCHEDULER_cancel (ic->timeout_task);
+      if (ic->callback != NULL)
+       ic->callback (ic->callback_cls, NULL, NULL);
       GNUNET_free (ic);
       return;
     }
   im = (const struct InfoMessage *) msg;
       GNUNET_free (ic);
       return;
     }
   im = (const struct InfoMessage *) msg;
+  GNUNET_break (0 == ntohl (im->reserved));
   hello = NULL;
   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
     {
   hello = NULL;
   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
     {
@@ -379,19 +437,25 @@ peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
          GNUNET_break (0);
          reconnect (ic->h);
          trigger_transmit (ic->h);
          GNUNET_break (0);
          reconnect (ic->h);
          trigger_transmit (ic->h);
-         ic->callback (ic->callback_cls, NULL, NULL, 2);
+         if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+           GNUNET_SCHEDULER_cancel (ic->timeout_task);
+         if (ic->callback != NULL)
+           ic->callback (ic->callback_cls, NULL, NULL);
          GNUNET_free (ic);
           return;
         }
     }
 #if DEBUG_PEERINFO
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
          GNUNET_free (ic);
           return;
         }
     }
 #if DEBUG_PEERINFO
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received %u bytes of `%s' information about peer `%s' from PEERINFO database\n",
+             "Received %u bytes of `%s' information about peer `%s' from `%s' service\n",
              (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello),
              "HELLO",
              (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello),
              "HELLO",
-             GNUNET_i2s (&im->peer));
+             GNUNET_i2s (&im->peer),
+             "PEERINFO");
 #endif
 #endif
-  ic->callback (ic->callback_cls, &im->peer, hello, ntohl (im->trust));
+  ic->h->in_receive = GNUNET_YES;
+  if (ic->callback != NULL)
+    ic->callback (ic->callback_cls, &im->peer, hello);
   GNUNET_CLIENT_receive (ic->h->client,
                          &peerinfo_handler,
                          ic,
   GNUNET_CLIENT_receive (ic->h->client,
                          &peerinfo_handler,
                          ic,
@@ -400,22 +464,44 @@ peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 
 
 /**
 
 
 /**
+ * We've transmitted the iteration request.  Now get ready to process
+ * the results (or handle transmission error).
  *
  *
+ * @param cls the 'struct GNUNET_PEERINFO_IteratorContext'
+ * @param transmit_success GNUNET_OK if transmission worked
  */
 static void
 iterator_start_receive (void *cls,
                        int transmit_success)
 {
  */
 static void
 iterator_start_receive (void *cls,
                        int transmit_success)
 {
-  struct GNUNET_PEERINFO_NewIteratorContext *ic = cls;
+  struct GNUNET_PEERINFO_IteratorContext *ic = cls;
 
   if (GNUNET_OK != transmit_success)
     {
 
   if (GNUNET_OK != transmit_success)
     {
-      ic->callback (ic->callback_cls, NULL, NULL, 2);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                 _("Failed to transmit iteration request to `%s' service (%d).\n"),
+                 "PEERINFO",
+                 transmit_success);
+      if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+       {
+         GNUNET_SCHEDULER_cancel (ic->timeout_task);
+         ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+       }
       reconnect (ic->h);
       trigger_transmit (ic->h);
       reconnect (ic->h);
       trigger_transmit (ic->h);
+      if (ic->callback != NULL)
+       ic->callback (ic->callback_cls, NULL, NULL);
       GNUNET_free (ic);
       return;
     }  
       GNUNET_free (ic);
       return;
     }  
+#if DEBUG_PEERINFO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Waiting for response from `%s' service.\n",
+             "PEERINFO");
+#endif
+  ic->h->in_receive = GNUNET_YES;
+  ic->in_receive = GNUNET_YES;
+  ic->tqe = NULL;
   GNUNET_CLIENT_receive (ic->h->client,
                          &peerinfo_handler,
                          ic,
   GNUNET_CLIENT_receive (ic->h->client,
                          &peerinfo_handler,
                          ic,
@@ -423,75 +509,103 @@ iterator_start_receive (void *cls,
 }
 
 
 }
 
 
+/**
+ * Peerinfo iteration request has timed out.  
+ *
+ * @param cls the 'struct GNUNET_PEERINFO_IteratorContext*'
+ * @param tc scheduler context
+ */
+static void
+signal_timeout (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_PEERINFO_IteratorContext *ic = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+             _("Timeout transmitting iteration request to `%s' service.\n"),
+             "PEERINFO");
+  ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  if (! ic->in_receive)
+    GNUNET_CONTAINER_DLL_remove (ic->h->tq_head,
+                                ic->h->tq_tail,
+                                ic->tqe);
+  reconnect (ic->h);
+  ic->callback (ic->callback_cls, NULL, NULL);
+  ic->callback = NULL;
+  GNUNET_free_non_null (ic->tqe);
+  GNUNET_free (ic);
+}
+
+
 /**
  * Call a method for each known matching host and change its trust
  * value.  The callback method will be invoked once for each matching
  * host and then finally once with a NULL pointer.  After that final
  * invocation, the iterator context must no longer be used.
  *
 /**
  * Call a method for each known matching host and change its trust
  * value.  The callback method will be invoked once for each matching
  * host and then finally once with a NULL pointer.  After that final
  * invocation, the iterator context must no longer be used.
  *
- * Note that the last call can be triggered by timeout or by simply
- * being done; however, the trust argument will be set to zero if we
- * are done, 1 if we timed out and 2 for fatal error.
- *
- * Instead of calling this function with 'peer == NULL' and 'trust ==
- * 0', it is often better to use 'GNUNET_PEERINFO_notify'.
+ * Instead of calling this function with 'peer == NULL' it is often
+ * better to use 'GNUNET_PEERINFO_notify'.
  * 
  * @param h handle to the peerinfo service
  * @param peer restrict iteration to this peer only (can be NULL)
  * 
  * @param h handle to the peerinfo service
  * @param peer restrict iteration to this peer only (can be NULL)
- * @param trust_delta how much to change the trust in all matching peers
  * @param timeout how long to wait until timing out
  * @param callback the method to call for each peer
  * @param callback_cls closure for callback
  * @param timeout how long to wait until timing out
  * @param callback the method to call for each peer
  * @param callback_cls closure for callback
- * @return NULL on error (in this case, 'callback' is never called!), 
- *         otherwise an iterator context
+ * @return iterator context
  */
  */
-struct GNUNET_PEERINFO_NewIteratorContext *
-GNUNET_PEERINFO_iterate_new (struct GNUNET_PEERINFO_Handle *h,
-                            const struct GNUNET_PeerIdentity *peer,
-                            int trust_delta,
-                            struct GNUNET_TIME_Relative timeout,
-                            GNUNET_PEERINFO_Processor callback,
-                            void *callback_cls)
+struct GNUNET_PEERINFO_IteratorContext *
+GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
+                        const struct GNUNET_PeerIdentity *peer,
+                        struct GNUNET_TIME_Relative timeout,
+                        GNUNET_PEERINFO_Processor callback,
+                        void *callback_cls)
 {
 {
-  struct ListAllPeersMessage *lapm;
+  struct GNUNET_MessageHeader *lapm;
   struct ListPeerMessage *lpm;
   struct ListPeerMessage *lpm;
-  struct GNUNET_PEERINFO_NewIteratorContext *ic;
+  struct GNUNET_PEERINFO_IteratorContext *ic;
   struct TransmissionQueueEntry *tqe;
 
   struct TransmissionQueueEntry *tqe;
 
-#if DEBUG_PEERINFO
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Requesting list of peers from peerinfo database\n");
-#endif
   if (peer == NULL)
     {
   if (peer == NULL)
     {
+#if DEBUG_PEERINFO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Requesting list of peers from PEERINFO service\n");
+#endif
       tqe = GNUNET_malloc (sizeof (struct TransmissionQueueEntry) +
       tqe = GNUNET_malloc (sizeof (struct TransmissionQueueEntry) +
-                          sizeof (struct ListAllPeersMessage));
-      tqe->size = sizeof (struct ListAllPeersMessage);
-      lapm = (struct ListAllPeersMessage *) &tqe[1];
-      lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
-      lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
-      lapm->trust_change = htonl (trust_delta);
+                          sizeof (struct GNUNET_MessageHeader));
+      tqe->size = sizeof (struct GNUNET_MessageHeader);
+      lapm = (struct GNUNET_MessageHeader *) &tqe[1];
+      lapm->size = htons (sizeof (struct GNUNET_MessageHeader));
+      lapm->type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
     }
   else
     {
     }
   else
     {
+#if DEBUG_PEERINFO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Requesting information on peer `%4s' from PEERINFO service\n",
+                 GNUNET_i2s (peer));
+#endif
       tqe = GNUNET_malloc (sizeof (struct TransmissionQueueEntry) +
                           sizeof (struct ListPeerMessage));
       tqe->size = sizeof (struct ListPeerMessage);
       lpm = (struct ListPeerMessage *) &tqe[1];
       lpm->header.size = htons (sizeof (struct ListPeerMessage));
       lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
       tqe = GNUNET_malloc (sizeof (struct TransmissionQueueEntry) +
                           sizeof (struct ListPeerMessage));
       tqe->size = sizeof (struct ListPeerMessage);
       lpm = (struct ListPeerMessage *) &tqe[1];
       lpm->header.size = htons (sizeof (struct ListPeerMessage));
       lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
-      lpm->trust_change = htonl (trust_delta);
       memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
     }
       memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
     }
-  ic = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_NewIteratorContext));
+  ic = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext));
+  ic->h = h;
+  ic->tqe = tqe;
   ic->callback = callback;
   ic->callback_cls = callback_cls;
   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   ic->callback = callback;
   ic->callback_cls = callback_cls;
   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+  ic->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout,
+                                                  &signal_timeout,
+                                                  ic);
   tqe->timeout = ic->timeout;
   tqe->cont = &iterator_start_receive;
   tqe->cont_cls = ic;
   tqe->timeout = ic->timeout;
   tqe->cont = &iterator_start_receive;
   tqe->cont_cls = ic;
-  /* FIXME: sort DLL by timeout? */
-  /* FIXME: add timeout task!? */
+  tqe->timeout = ic->timeout;
   GNUNET_CONTAINER_DLL_insert_after (h->tq_head,
                                     h->tq_tail,
                                     h->tq_tail,
   GNUNET_CONTAINER_DLL_insert_after (h->tq_head,
                                     h->tq_tail,
                                     h->tq_tail,
@@ -508,311 +622,20 @@ GNUNET_PEERINFO_iterate_new (struct GNUNET_PEERINFO_Handle *h,
  * @param ic context of the iterator to cancel
  */
 void
  * @param ic context of the iterator to cancel
  */
 void
-GNUNET_PEERINFO_iterate_cancel_new (struct GNUNET_PEERINFO_NewIteratorContext *ic)
-{
-  GNUNET_assert (0); 
-  // FIXME: not implemented
-}
-
-
-
-
-
-/* ***************************** OLD API ****************************** */
-
-
-
-
-#define ADD_PEER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
-
-
-struct CAFContext
-{
-  struct GNUNET_CLIENT_Connection *client;
-  struct GNUNET_MessageHeader *msg;
-};
-
-
-static size_t
-copy_and_free (void *cls, size_t size, void *buf)
-{
-  struct CAFContext *cc = cls;
-  struct GNUNET_MessageHeader *msg = cc->msg;
-  uint16_t msize;
-
-  if (buf == NULL)
-    {
-#if DEBUG_PEERINFO
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _
-                  ("Failed to transmit message of type %u to `%s' service.\n"),
-                  ntohs (msg->type), "peerinfo");
-#endif
-      GNUNET_free (msg);
-      GNUNET_CLIENT_disconnect (cc->client, GNUNET_NO);
-      GNUNET_free (cc);
-      return 0;
-    }
-  msize = ntohs (msg->size);
-  GNUNET_assert (size >= msize);
-  memcpy (buf, msg, msize);
-  GNUNET_free (msg);
-  GNUNET_CLIENT_disconnect (cc->client, GNUNET_YES);
-  GNUNET_free (cc);
-  return msize;
-}
-
-
-
-/**
- * Add a host to the persistent list.
- *
- * @param cfg configuration to use
- * @param sched scheduler to use
- * @param peer identity of the peer
- * @param hello the verified (!) HELLO message
- */
-void
-GNUNET_PEERINFO_add_peer (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                          struct GNUNET_SCHEDULER_Handle *sched,
-                          const struct GNUNET_PeerIdentity *peer,
-                          const struct GNUNET_HELLO_Message *hello)
-{
-  struct GNUNET_CLIENT_Connection *client;
-  struct PeerAddMessage *pam;
-  uint16_t hs;
-  struct CAFContext *cc;
-
-#if DEBUG_PEERINFO
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Adding peer `%s' to peerinfo database\n",
-             GNUNET_i2s(peer));
-#endif
-  client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
-  if (client == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Could not connect to `%s' service.\n"), "peerinfo");
-      return;
-    }
-  hs = GNUNET_HELLO_size (hello);
-#if DEBUG_PEERINFO
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Size of `%s' is %u bytes\n",
-             "HELLO",
-             (unsigned int) GNUNET_HELLO_size (hello));
-#endif  
-  pam = GNUNET_malloc (sizeof (struct PeerAddMessage) + hs);
-  pam->header.size = htons (hs + sizeof (struct PeerAddMessage));
-  pam->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_ADD);
-  memcpy (&pam->peer, peer, sizeof (struct GNUNET_PeerIdentity));
-  memcpy (&pam[1], hello, hs);
-  cc = GNUNET_malloc (sizeof (struct CAFContext));
-  cc->client = client;
-  cc->msg = &pam->header;
-  GNUNET_CLIENT_notify_transmit_ready (client,
-                                       ntohs (pam->header.size),
-                                       ADD_PEER_TIMEOUT, 
-                                      GNUNET_NO,
-                                      &copy_and_free, cc);
-}
-
-
-/**
- * Context for the info handler.
- */
-struct GNUNET_PEERINFO_IteratorContext
-{
-
-  /**
-   * Our connection to the PEERINFO service.
-   */
-  struct GNUNET_CLIENT_Connection *client;
-
-  /**
-   * Function to call with information.
-   */
-  GNUNET_PEERINFO_Processor callback;
-
-  /**
-   * Closure for callback.
-   */
-  void *callback_cls;
-
-  /**
-   * When should we time out?
-   */
-  struct GNUNET_TIME_Absolute timeout;
-
-};
-
-
-/**
- * Type of a function to call when we receive a message
- * from the service.
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-info_handler (void *cls, const struct GNUNET_MessageHeader *msg)
-{
-  struct GNUNET_PEERINFO_IteratorContext *ic = cls;
-  const struct InfoMessage *im;
-  const struct GNUNET_HELLO_Message *hello;
-  uint16_t ms;
-
-  if (msg == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Failed to receive response from `%s' service.\n"),
-                  "peerinfo");
-      ic->callback (ic->callback_cls, NULL, NULL, 1);
-      GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
-      GNUNET_free (ic);
-      return;
-    }
-  if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END)
-    {
-#if DEBUG_PEERINFO
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Received end of list of peers from peerinfo database\n");
-#endif
-      ic->callback (ic->callback_cls, NULL, NULL, 0);
-      GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
-      GNUNET_free (ic);
-      return;
-    }
-  ms = ntohs (msg->size);
-  if ((ms < sizeof (struct InfoMessage)) ||
-      (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
-    {
-      GNUNET_break (0);
-      ic->callback (ic->callback_cls, NULL, NULL, 2);
-      GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
-      GNUNET_free (ic);
-      return;
-    }
-  im = (const struct InfoMessage *) msg;
-  hello = NULL;
-  if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
-    {
-      hello = (const struct GNUNET_HELLO_Message *) &im[1];
-      if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
-        {
-          GNUNET_break (0);
-          ic->callback (ic->callback_cls, NULL, NULL, 2);
-          GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
-          GNUNET_free (ic);
-          return;
-        }
-    }
-#if DEBUG_PEERINFO
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received %u bytes of `%s' information about peer `%s' from PEERINFO database\n",
-             (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello),
-             "HELLO",
-             GNUNET_i2s (&im->peer));
-#endif
-  ic->callback (ic->callback_cls, &im->peer, hello, ntohl (im->trust));
-  GNUNET_CLIENT_receive (ic->client,
-                         &info_handler,
-                         ic,
-                         GNUNET_TIME_absolute_get_remaining (ic->timeout));
-}
-
-
-/**
- * Call a method for each known matching host and change
- * its trust value.  The method will be invoked once for
- * each host and then finally once with a NULL pointer.
- * Note that the last call can be triggered by timeout or
- * by simply being done; however, the trust argument will
- * be set to zero if we are done and to 1 if we timed out.
- *
- * @param cfg configuration to use
- * @param sched scheduler to use
- * @param peer restrict iteration to this peer only (can be NULL)
- * @param trust_delta how much to change the trust in all matching peers
- * @param timeout how long to wait until timing out
- * @param callback the method to call for each peer
- * @param callback_cls closure for callback
- * @return NULL on error, otherwise an iterator context
- */
-struct GNUNET_PEERINFO_IteratorContext *
-GNUNET_PEERINFO_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                         struct GNUNET_SCHEDULER_Handle *sched,
-                         const struct GNUNET_PeerIdentity *peer,
-                         int trust_delta,
-                         struct GNUNET_TIME_Relative timeout,
-                         GNUNET_PEERINFO_Processor callback,
-                         void *callback_cls)
+GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
 {
 {
-  struct GNUNET_CLIENT_Connection *client;
-  struct ListAllPeersMessage *lapm;
-  struct ListPeerMessage *lpm;
-  struct GNUNET_PEERINFO_IteratorContext *ihc;
-
-  client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
-  if (client == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Could not connect to `%s' service.\n"), "peerinfo");
-      return NULL;
-    }
-#if DEBUG_PEERINFO
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Requesting list of peers from peerinfo database\n");
-#endif
-  if (peer == NULL)
-    {
-      ihc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext) +
-                          sizeof (struct ListAllPeersMessage));
-      lapm = (struct ListAllPeersMessage *) &ihc[1];
-      lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
-      lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
-      lapm->trust_change = htonl (trust_delta);
-    }
-  else
-    {
-      ihc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext) +
-                          sizeof (struct ListPeerMessage));
-      lpm = (struct ListPeerMessage *) &ihc[1];
-      lpm->header.size = htons (sizeof (struct ListPeerMessage));
-      lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
-      lpm->trust_change = htonl (trust_delta);
-      memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
-    }
-  ihc->client = client;
-  ihc->callback = callback;
-  ihc->callback_cls = callback_cls;
-  ihc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  if (GNUNET_OK != 
-      GNUNET_CLIENT_transmit_and_get_response (client,
-                                              (const struct GNUNET_MessageHeader*) &ihc[1],
-                                              timeout,
-                                              GNUNET_YES,
-                                              &info_handler,
-                                              ihc))
+  if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK)
     {
     {
-      GNUNET_break (0);
-      GNUNET_CLIENT_disconnect (ihc->client, GNUNET_NO);
-      GNUNET_free (ihc);
-      return NULL;
+      GNUNET_SCHEDULER_cancel (ic->timeout_task);
+      ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
     }
     }
-  return ihc;
-}
-
-
-/**
- * Cancel an iteration over peer information.
- *
- * @param ic context of the iterator to cancel
- */
-void
-GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
-{
-  GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
+  ic->callback = NULL;
+  if (ic->in_receive)
+    return; /* need to finish processing */
+  GNUNET_CONTAINER_DLL_remove (ic->h->tq_head,
+                              ic->h->tq_tail,
+                              ic->tqe);
+  GNUNET_free (ic->tqe);
   GNUNET_free (ic);
 }
 
   GNUNET_free (ic);
 }