guix-env: some update.
[oweals/gnunet.git] / src / set / set_api.c
index 7721402698580fbcb405401c61a12b9e7fedf3a5..f5c43a9a7c90d056db5dfab775c2fd93a52ba858 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2012-2014 GNUnet e.V.
+     Copyright (C) 2012-2016 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -26,7 +26,6 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
-#include "gnunet_client_lib.h"
 #include "gnunet_set_service.h"
 #include "set.h"
 
@@ -49,11 +48,6 @@ struct SetCopyRequest
  */
 struct GNUNET_SET_Handle
 {
-  /**
-   * Client connected to the set service.
-   */
-  struct GNUNET_CLIENT_Connection *client;
-
   /**
    * Message queue for @e client.
    */
@@ -82,6 +76,8 @@ struct GNUNET_SET_Handle
 
   /**
    * Should the set be destroyed once all operations are gone?
+   * #GNUNET_SYSERR if #GNUNET_SET_destroy() must raise this flag,
+   * #GNUNET_YES if #GNUNET_SET_destroy() did raise this flag.
    */
   int destroy_requested;
 
@@ -189,10 +185,6 @@ struct GNUNET_SET_OperationHandle
  */
 struct GNUNET_SET_ListenHandle
 {
-  /**
-   * Connection to the service.
-   */
-  struct GNUNET_CLIENT_Connection *client;
 
   /**
    * Message queue for the client.
@@ -230,7 +222,7 @@ struct GNUNET_SET_ListenHandle
   /**
    * Task for reconnecting when the listener fails.
    */
-  struct GNUNET_SCHEDULER_Task * reconnect_task;
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
 
   /**
    * Operation we listen for.
@@ -243,7 +235,7 @@ struct GNUNET_SET_ListenHandle
 static struct GNUNET_SET_Handle *
 create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                  enum GNUNET_SET_OperationType op,
-                 uint32_t *cookie);
+                 const uint32_t *cookie);
 
 
 /**
@@ -251,21 +243,17 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
  * iterator and sends an acknowledgement to the service.
  *
  * @param cls the `struct GNUNET_SET_Handle *`
- * @param mh the message
+ * @param msg the message
  */
 static void
 handle_copy_lazy (void *cls,
-                  const struct GNUNET_MessageHeader *mh)
+                  const struct GNUNET_SET_CopyLazyResponseMessage *msg)
 {
-  struct GNUNET_SET_CopyLazyResponseMessage *msg;
   struct GNUNET_SET_Handle *set = cls;
   struct SetCopyRequest *req;
   struct GNUNET_SET_Handle *new_set;
 
-  msg = (struct GNUNET_SET_CopyLazyResponseMessage *) mh;
-
   req = set->copy_req_head;
-
   if (NULL == req)
   {
     /* Service sent us unsolicited lazy copy response */
@@ -275,22 +263,35 @@ handle_copy_lazy (void *cls,
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Handling response to lazy copy\n");
-
   GNUNET_CONTAINER_DLL_remove (set->copy_req_head,
                                set->copy_req_tail,
                                req);
-
-
   // We pass none as operation here, since it doesn't matter when
   // cloning.
-  new_set = create_internal (set->cfg, GNUNET_SET_OPERATION_NONE, &msg->cookie);
-
+  new_set = create_internal (set->cfg,
+                            GNUNET_SET_OPERATION_NONE,
+                            &msg->cookie);
   req->cb (req->cls, new_set);
-
   GNUNET_free (req);
 }
 
 
+/**
+ * Check that the given @a msg is well-formed.
+ *
+ * @param cls closure
+ * @param msg message to check
+ * @return #GNUNET_OK if message is well-formed
+ */
+static int
+check_iter_element (void *cls,
+                   const struct GNUNET_SET_IterResponseMessage *msg)
+{
+  /* minimum size was already checked, everything else is OK! */
+  return GNUNET_OK;
+}
+
+
 /**
  * Handle element for iteration over the set.  Notifies the
  * iterator and sends an acknowledgement to the service.
@@ -300,28 +301,18 @@ handle_copy_lazy (void *cls,
  */
 static void
 handle_iter_element (void *cls,
-                     const struct GNUNET_MessageHeader *mh)
+                     const struct GNUNET_SET_IterResponseMessage *msg)
 {
   struct GNUNET_SET_Handle *set = cls;
   GNUNET_SET_ElementIterator iter = set->iterator;
   struct GNUNET_SET_Element element;
-  const struct GNUNET_SET_IterResponseMessage *msg;
   struct GNUNET_SET_IterAckMessage *ack_msg;
   struct GNUNET_MQ_Envelope *ev;
   uint16_t msize;
 
-  msize = ntohs (mh->size);
-  if (msize < sizeof (sizeof (struct GNUNET_SET_IterResponseMessage)))
-  {
-    /* message malformed */
-    GNUNET_break (0);
-    set->iterator = NULL;
-    set->iteration_id++;
-    iter (set->iterator_cls,
-          NULL);
-    iter = NULL;
-  }
-  msg = (const struct GNUNET_SET_IterResponseMessage *) mh;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received element in set iteration\n");
+  msize = ntohs (msg->header.size);
   if (set->iteration_id != ntohs (msg->iteration_id))
   {
     /* element from a previous iteration, skip! */
@@ -357,11 +348,40 @@ handle_iter_done (void *cls,
   GNUNET_SET_ElementIterator iter = set->iterator;
 
   if (NULL == iter)
+  {
+    /* FIXME: if this is true, could cancel+start a fresh one
+       cause elements to go to the wrong iteration? */
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Service completed set iteration that was already cancelled\n");
     return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Set iteration completed\n");
+  set->destroy_requested = GNUNET_SYSERR;
   set->iterator = NULL;
   set->iteration_id++;
   iter (set->iterator_cls,
         NULL);
+  if (GNUNET_SYSERR == set->destroy_requested)
+    set->destroy_requested = GNUNET_NO;
+  if (GNUNET_YES == set->destroy_requested)
+    GNUNET_SET_destroy (set);
+}
+
+
+/**
+ * Check that the given @a msg is well-formed.
+ *
+ * @param cls closure
+ * @param msg message to check
+ * @return #GNUNET_OK if message is well-formed
+ */
+static int
+check_result (void *cls,
+             const struct GNUNET_SET_ResultMessage *msg)
+{
+  /* minimum size was already checked, everything else is OK! */
+  return GNUNET_OK;
 }
 
 
@@ -373,17 +393,16 @@ handle_iter_done (void *cls,
  */
 static void
 handle_result (void *cls,
-               const struct GNUNET_MessageHeader *mh)
+               const struct GNUNET_SET_ResultMessage *msg)
 {
   struct GNUNET_SET_Handle *set = cls;
-  const struct GNUNET_SET_ResultMessage *msg;
   struct GNUNET_SET_OperationHandle *oh;
   struct GNUNET_SET_Element e;
   enum GNUNET_SET_Status result_status;
+  int destroy_set;
 
-  msg = (const struct GNUNET_SET_ResultMessage *) mh;
   GNUNET_assert (NULL != set->mq);
-  result_status = ntohs (msg->result_status);
+  result_status = (enum GNUNET_SET_Status) ntohs (msg->result_status);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Got result message with status %d\n",
        result_status);
@@ -421,10 +440,16 @@ do_final:
   GNUNET_CONTAINER_DLL_remove (set->ops_head,
                                set->ops_tail,
                                oh);
+  /* Need to do this calculation _before_ the result callback,
+     as IF the application still has a valid set handle, it
+     may trigger destruction of the set during the callback. */
+  destroy_set = (GNUNET_YES == set->destroy_requested) &&
+                (NULL == set->ops_head);
   if (NULL != oh->result_cb)
   {
     oh->result_cb (oh->result_cls,
                    NULL,
+                   GNUNET_ntohll (msg->current_size),
                    result_status);
   }
   else
@@ -432,8 +457,7 @@ do_final:
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "No callback for final status\n");
   }
-  if ( (GNUNET_YES == set->destroy_requested) &&
-       (NULL == set->ops_head) )
+  if (destroy_set)
     GNUNET_SET_destroy (set);
   GNUNET_free (oh);
   return;
@@ -442,11 +466,12 @@ do_element:
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Treating result as element\n");
   e.data = &msg[1];
-  e.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ResultMessage);
+  e.size = ntohs (msg->header.size) - sizeof (struct GNUNET_SET_ResultMessage);
   e.element_type = ntohs (msg->element_type);
   if (NULL != oh->result_cb)
     oh->result_cb (oh->result_cls,
                    &e,
+                   GNUNET_ntohll (msg->current_size),
                    result_status);
 }
 
@@ -492,6 +517,8 @@ GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
   struct GNUNET_SET_CancelMessage *m;
   struct GNUNET_MQ_Envelope *mqm;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Cancelling SET operation\n");
   if (NULL != set)
   {
     mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL);
@@ -522,8 +549,9 @@ handle_client_set_error (void *cls,
                          enum GNUNET_MQ_Error error)
 {
   struct GNUNET_SET_Handle *set = cls;
+  GNUNET_SET_ElementIterator iter = set->iterator;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_ERROR,
        "Handling client set error %d\n",
        error);
   while (NULL != set->ops_head)
@@ -531,58 +559,62 @@ handle_client_set_error (void *cls,
     if (NULL != set->ops_head->result_cb)
       set->ops_head->result_cb (set->ops_head->result_cls,
                                 NULL,
+                                0,
                                 GNUNET_SET_STATUS_FAILURE);
     set_operation_destroy (set->ops_head);
   }
+  set->iterator = NULL;
+  set->iteration_id++;
   set->invalid = GNUNET_YES;
-  if (GNUNET_YES == set->destroy_requested)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Destroying set after operation failure\n");
-    GNUNET_SET_destroy (set);
-  }
+  if (NULL != iter)
+    iter (set->iterator_cls,
+          NULL);
 }
 
 
+/**
+ * FIXME.
+ */
 static struct GNUNET_SET_Handle *
 create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                  enum GNUNET_SET_OperationType op,
-                 uint32_t *cookie)
+                 const uint32_t *cookie)
 {
-  static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    { &handle_result,
-      GNUNET_MESSAGE_TYPE_SET_RESULT,
-      0 },
-    { &handle_iter_element,
-      GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT,
-      0 },
-    { &handle_iter_done,
-      GNUNET_MESSAGE_TYPE_SET_ITER_DONE,
-      sizeof (struct GNUNET_MessageHeader) },
-    { &handle_copy_lazy,
-      GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE,
-      sizeof (struct GNUNET_SET_CopyLazyResponseMessage) },
-    GNUNET_MQ_HANDLERS_END
+  struct GNUNET_SET_Handle *set = GNUNET_new (struct GNUNET_SET_Handle);
+  struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+    GNUNET_MQ_hd_var_size (result,
+                           GNUNET_MESSAGE_TYPE_SET_RESULT,
+                           struct GNUNET_SET_ResultMessage,
+                           set),
+    GNUNET_MQ_hd_var_size (iter_element,
+                           GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT,
+                           struct GNUNET_SET_IterResponseMessage,
+                           set),
+    GNUNET_MQ_hd_fixed_size (iter_done,
+                             GNUNET_MESSAGE_TYPE_SET_ITER_DONE,
+                             struct GNUNET_MessageHeader,
+                             set),
+    GNUNET_MQ_hd_fixed_size (copy_lazy,
+                             GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE,
+                             struct GNUNET_SET_CopyLazyResponseMessage,
+                             set),
+    GNUNET_MQ_handler_end ()
   };
-  struct GNUNET_SET_Handle *set;
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_CreateMessage *create_msg;
   struct GNUNET_SET_CopyLazyConnectMessage *copy_msg;
 
-  set = GNUNET_new (struct GNUNET_SET_Handle);
-  set->client = GNUNET_CLIENT_connect ("set", cfg);
   set->cfg = cfg;
-  if (NULL == set->client)
+  set->mq = GNUNET_CLIENT_connect (cfg,
+                                   "set",
+                                   mq_handlers,
+                                   &handle_client_set_error,
+                                   set);
+  if (NULL == set->mq)
   {
     GNUNET_free (set);
     return NULL;
   }
-  set->mq = GNUNET_MQ_queue_for_connection_client (set->client,
-                                                   mq_handlers,
-                                                   &handle_client_set_error,
-                                                   set);
-  GNUNET_assert (NULL != set->mq);
-
   if (NULL == cookie)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -601,7 +633,8 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                          GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT);
     copy_msg->cookie = *cookie;
   }
-  GNUNET_MQ_send (set->mq, mqm);
+  GNUNET_MQ_send (set->mq,
+                  mqm);
   return set;
 }
 
@@ -621,7 +654,16 @@ struct GNUNET_SET_Handle *
 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
                    enum GNUNET_SET_OperationType op)
 {
-  return create_internal (cfg, op, NULL);
+  struct GNUNET_SET_Handle *set;
+
+  set = create_internal (cfg,
+                          op,
+                          NULL);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating set %p for operation %d\n",
+       set,
+       op);
+  return set;
 }
 
 
@@ -647,18 +689,23 @@ GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_ElementMessage *msg;
 
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "adding element of type %u to set %p\n",
+       (unsigned int) element->element_type,
+       set);
   if (GNUNET_YES == set->invalid)
   {
     if (NULL != cont)
       cont (cont_cls);
     return GNUNET_SYSERR;
   }
-  mqm = GNUNET_MQ_msg_extra (msg, element->size,
+  mqm = GNUNET_MQ_msg_extra (msg,
+                             element->size,
                              GNUNET_MESSAGE_TYPE_SET_ADD);
   msg->element_type = htons (element->element_type);
-  memcpy (&msg[1],
-          element->data,
-          element->size);
+  GNUNET_memcpy (&msg[1],
+                 element->data,
+                 element->size);
   GNUNET_MQ_notify_sent (mqm,
                          cont, cont_cls);
   GNUNET_MQ_send (set->mq, mqm);
@@ -688,6 +735,9 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_ElementMessage *msg;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing element from set %p\n",
+       set);
   if (GNUNET_YES == set->invalid)
   {
     if (NULL != cont)
@@ -698,9 +748,9 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
                              element->size,
                              GNUNET_MESSAGE_TYPE_SET_REMOVE);
   msg->element_type = htons (element->element_type);
-  memcpy (&msg[1],
-          element->data,
-          element->size);
+  GNUNET_memcpy (&msg[1],
+                 element->data,
+                 element->size);
   GNUNET_MQ_notify_sent (mqm,
                          cont, cont_cls);
   GNUNET_MQ_send (set->mq, mqm);
@@ -720,8 +770,9 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
   /* destroying set while iterator is active is currently
      not supported; we should expand the API to allow
      clients to explicitly cancel the iteration! */
-  GNUNET_assert (NULL == set->iterator);
-  if (NULL != set->ops_head)
+  if ( (NULL != set->ops_head) ||
+       (NULL != set->iterator) ||
+       (GNUNET_SYSERR == set->destroy_requested) )
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Set operations are pending, delaying set destruction\n");
@@ -730,11 +781,6 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Really destroying set\n");
-  if (NULL != set->client)
-  {
-    GNUNET_CLIENT_disconnect (set->client);
-    set->client = NULL;
-  }
   if (NULL != set->mq)
   {
     GNUNET_MQ_destroy (set->mq);
@@ -763,13 +809,18 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
                     const struct GNUNET_HashCode *app_id,
                     const struct GNUNET_MessageHeader *context_msg,
                     enum GNUNET_SET_ResultMode result_mode,
+                    struct GNUNET_SET_Option options[],
                     GNUNET_SET_ResultIterator result_cb,
                     void *result_cls)
 {
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_OperationHandle *oh;
   struct GNUNET_SET_EvaluateMessage *msg;
+  struct GNUNET_SET_Option *opt;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Client prepares set operation (%d)\n",
+       result_mode);
   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
   oh->result_cb = result_cb;
   oh->result_cls = result_cls;
@@ -779,6 +830,25 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
   msg->app_id = *app_id;
   msg->result_mode = htonl (result_mode);
   msg->target_peer = *other_peer;
+  for (opt = options; opt->type != 0; opt++)
+  {
+    switch (opt->type)
+    {
+      case GNUNET_SET_OPTION_BYZANTINE:
+        msg->byzantine = GNUNET_YES;
+        msg->byzantine_lower_bound = opt->v.num;
+        break;
+      case GNUNET_SET_OPTION_FORCE_FULL:
+        msg->force_full = GNUNET_YES;
+        break;
+      case GNUNET_SET_OPTION_FORCE_DELTA:
+        msg->force_delta = GNUNET_YES;
+        break;
+      default:
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             "Option with type %d not recognized\n", (int) opt->type);
+    }
+  }
   oh->conclude_mqm = mqm;
   oh->request_id_addr = &msg->request_id;
 
@@ -795,42 +865,53 @@ static void
 listen_connect (void *cls);
 
 
+/**
+ * Check validity of request message for a listen operation
+ *
+ * @param cls the listen handle
+ * @param msg the message
+ * @return #GNUNET_OK if the message is well-formed
+ */
+static int
+check_request (void *cls,
+              const struct GNUNET_SET_RequestMessage *msg)
+{
+  const struct GNUNET_MessageHeader *context_msg;
+
+  if (ntohs (msg->header.size) == sizeof (*msg))
+    return GNUNET_OK; /* no context message is OK */
+  context_msg = GNUNET_MQ_extract_nested_mh (msg);
+  if (NULL == context_msg)
+  {
+    /* malformed context message is NOT ok */
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
 /**
  * Handle request message for a listen operation
  *
  * @param cls the listen handle
- * @param mh the message
+ * @param msg the message
  */
 static void
 handle_request (void *cls,
-                const struct GNUNET_MessageHeader *mh)
+                const struct GNUNET_SET_RequestMessage *msg)
 {
   struct GNUNET_SET_ListenHandle *lh = cls;
-  const struct GNUNET_SET_RequestMessage *msg;
   struct GNUNET_SET_Request req;
   const struct GNUNET_MessageHeader *context_msg;
-  uint16_t msize;
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_RejectMessage *rmsg;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Processing incoming operation request\n");
-  msize = ntohs (mh->size);
-  if (msize < sizeof (struct GNUNET_SET_RequestMessage))
-  {
-    GNUNET_break (0);
-    GNUNET_CLIENT_disconnect (lh->client);
-    lh->client = NULL;
-    GNUNET_MQ_destroy (lh->mq);
-    lh->mq = NULL;
-    lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
-                                                       &listen_connect, lh);
-    lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
-    return;
-  }
+       "Processing incoming operation request with id %u\n",
+       ntohl (msg->accept_id));
   /* we got another valid request => reset the backoff */
   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
-  msg = (const struct GNUNET_SET_RequestMessage *) mh;
   req.accept_id = ntohl (msg->accept_id);
   req.accepted = GNUNET_NO;
   context_msg = GNUNET_MQ_extract_nested_mh (msg);
@@ -842,7 +923,8 @@ handle_request (void *cls,
   if (GNUNET_YES == req.accepted)
     return; /* the accept-case is handled in #GNUNET_SET_accept() */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Rejecting request\n");
+       "Rejected request %u\n",
+       ntohl (msg->accept_id));
   mqm = GNUNET_MQ_msg (rmsg,
                        GNUNET_MESSAGE_TYPE_SET_REJECT);
   rmsg->accept_reject_id = msg->accept_id;
@@ -866,12 +948,11 @@ handle_client_listener_error (void *cls,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Listener broke down (%d), re-connecting\n",
        (int) error);
-  GNUNET_CLIENT_disconnect (lh->client);
-  lh->client = NULL;
   GNUNET_MQ_destroy (lh->mq);
   lh->mq = NULL;
   lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
-                                                     &listen_connect, lh);
+                                                     &listen_connect,
+                                                    lh);
   lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
 }
 
@@ -884,35 +965,31 @@ handle_client_listener_error (void *cls,
 static void
 listen_connect (void *cls)
 {
-  static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    { &handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST },
-    GNUNET_MQ_HANDLERS_END
-  };
   struct GNUNET_SET_ListenHandle *lh = cls;
+  struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+    GNUNET_MQ_hd_var_size (request,
+                           GNUNET_MESSAGE_TYPE_SET_REQUEST,
+                           struct GNUNET_SET_RequestMessage,
+                           lh),
+    GNUNET_MQ_handler_end ()
+  };
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_ListenMessage *msg;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
 
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Listener not reconnecting due to shutdown\n");
-    return;
-  }
   lh->reconnect_task = NULL;
-  GNUNET_assert (NULL == lh->client);
-  lh->client = GNUNET_CLIENT_connect ("set", lh->cfg);
-  if (NULL == lh->client)
-    return;
   GNUNET_assert (NULL == lh->mq);
-  lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client,
-                                                  mq_handlers,
-                                                  &handle_client_listener_error, lh);
+  lh->mq = GNUNET_CLIENT_connect (lh->cfg,
+                                  "set",
+                                  mq_handlers,
+                                  &handle_client_listener_error,
+                                  lh);
+  if (NULL == lh->mq)
+    return;
   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
   msg->operation = htonl (lh->operation);
   msg->app_id = lh->app_id;
-  GNUNET_MQ_send (lh->mq, mqm);
+  GNUNET_MQ_send (lh->mq,
+                  mqm);
 }
 
 
@@ -937,6 +1014,9 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
 {
   struct GNUNET_SET_ListenHandle *lh;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting listener for app %s\n",
+       GNUNET_h2s (app_id));
   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
   lh->listen_cb = listen_cb;
   lh->listen_cls = listen_cls;
@@ -945,7 +1025,7 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
   lh->app_id = *app_id;
   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
   listen_connect (lh);
-  if (NULL == lh->client)
+  if (NULL == lh->mq)
   {
     GNUNET_free (lh);
     return NULL;
@@ -963,17 +1043,13 @@ void
 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
 {
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Canceling listener\n");
+       "Canceling listener %s\n",
+       GNUNET_h2s (&lh->app_id));
   if (NULL != lh->mq)
   {
     GNUNET_MQ_destroy (lh->mq);
     lh->mq = NULL;
   }
-  if (NULL != lh->client)
-  {
-    GNUNET_CLIENT_disconnect (lh->client);
-    lh->client = NULL;
-  }
   if (NULL != lh->reconnect_task)
   {
     GNUNET_SCHEDULER_cancel (lh->reconnect_task);
@@ -1000,6 +1076,7 @@ GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
 struct GNUNET_SET_OperationHandle *
 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
                    enum GNUNET_SET_ResultMode result_mode,
+                   struct GNUNET_SET_Option options[],
                    GNUNET_SET_ResultIterator result_cb,
                    void *result_cls)
 {
@@ -1008,8 +1085,13 @@ GNUNET_SET_accept (struct GNUNET_SET_Request *request,
   struct GNUNET_SET_AcceptMessage *msg;
 
   GNUNET_assert (GNUNET_NO == request->accepted);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Client accepts set operation (%d) with id %u\n",
+       result_mode,
+       request->accept_id);
   request->accepted = GNUNET_YES;
-  mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
+  mqm = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_SET_ACCEPT);
   msg->accept_reject_id = htonl (request->accept_id);
   msg->result_mode = htonl (result_mode);
   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
@@ -1047,14 +1129,18 @@ GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
   }
   if (GNUNET_YES == set->invalid)
     return GNUNET_SYSERR;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Client commits to SET\n");
   GNUNET_assert (NULL != oh->conclude_mqm);
   oh->set = set;
   GNUNET_CONTAINER_DLL_insert (set->ops_head,
                                set->ops_tail,
                                oh);
-  oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
+  oh->request_id = GNUNET_MQ_assoc_add (set->mq,
+                                        oh);
   *oh->request_id_addr = htonl (oh->request_id);
-  GNUNET_MQ_send (set->mq, oh->conclude_mqm);
+  GNUNET_MQ_send (set->mq,
+                  oh->conclude_mqm);
   oh->conclude_mqm = NULL;
   oh->request_id_addr = NULL;
   return GNUNET_OK;
@@ -1103,6 +1189,8 @@ GNUNET_SET_copy_lazy (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *ev;
   struct SetCopyRequest *req;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating lazy copy of set\n");
   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE);
   GNUNET_MQ_send (set->mq, ev);
 
@@ -1131,8 +1219,9 @@ GNUNET_SET_element_dup (const struct GNUNET_SET_Element *element)
   copy->size = element->size;
   copy->element_type = element->element_type;
   copy->data = &copy[1];
-  memcpy ((void *) copy->data, element->data, copy->size);
-
+  GNUNET_memcpy (&copy[1],
+                 element->data,
+                 copy->size);
   return copy;
 }
 
@@ -1141,11 +1230,12 @@ GNUNET_SET_element_dup (const struct GNUNET_SET_Element *element)
  * Hash a set element.
  *
  * @param element the element that should be hashed
- * @param ret_hash a pointer to where the hash of @a element
+ * @param[out] ret_hash a pointer to where the hash of @a element
  *        should be stored
  */
 void
-GNUNET_SET_element_hash (const struct GNUNET_SET_Element *element, struct GNUNET_HashCode *ret_hash)
+GNUNET_SET_element_hash (const struct GNUNET_SET_Element *element,
+                        struct GNUNET_HashCode *ret_hash)
 {
   struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start ();