allow destruction while iteration is active
[oweals/gnunet.git] / src / set / set_api.c
index af4907deaf1fd9e4415e64aa4a49456f66635a60..04a4e49108f6a7d2661f369d989fb78314f5839c 100644 (file)
@@ -297,9 +297,9 @@ check_iter_element (void *cls,
  * @param cls the `struct GNUNET_SET_Handle *`
  * @param mh the message
  */
- static void
- handle_iter_element (void *cls,
-                      const struct GNUNET_SET_IterResponseMessage *msg)
+static void
+handle_iter_element (void *cls,
+                     const struct GNUNET_SET_IterResponseMessage *msg)
 {
   struct GNUNET_SET_Handle *set = cls;
   GNUNET_SET_ElementIterator iter = set->iterator;
@@ -349,6 +349,9 @@ handle_iter_done (void *cls,
   set->iteration_id++;
   iter (set->iterator_cls,
         NULL);
+
+  if (GNUNET_YES == set->destroy_requested)
+    GNUNET_SET_destroy (set);
 }
 
 
@@ -382,6 +385,7 @@ handle_result (void *cls,
   struct GNUNET_SET_OperationHandle *oh;
   struct GNUNET_SET_Element e;
   enum GNUNET_SET_Status result_status;
+  int destroy_set;
 
   GNUNET_assert (NULL != set->mq);
   result_status = ntohs (msg->result_status);
@@ -422,10 +426,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
@@ -433,8 +443,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;
@@ -448,6 +457,7 @@ do_element:
   if (NULL != oh->result_cb)
     oh->result_cb (oh->result_cls,
                    &e,
+                   GNUNET_ntohll (msg->current_size),
                    result_status);
 }
 
@@ -525,7 +535,7 @@ handle_client_set_error (void *cls,
   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)
@@ -533,21 +543,16 @@ 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 (NULL != iter)
     iter (set->iterator_cls,
           NULL);
-  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);
-  }
 }
 
 
@@ -556,24 +561,24 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                  enum GNUNET_SET_OperationType op,
                  const uint32_t *cookie)
 {
-  GNUNET_MQ_hd_var_size (result,
-                        GNUNET_MESSAGE_TYPE_SET_RESULT,
-                        struct GNUNET_SET_ResultMessage);
-  GNUNET_MQ_hd_var_size (iter_element,
-                        GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT,
-                        struct GNUNET_SET_IterResponseMessage);
-  GNUNET_MQ_hd_fixed_size (iter_done,
-                          GNUNET_MESSAGE_TYPE_SET_ITER_DONE,
-                          struct GNUNET_MessageHeader);
-  GNUNET_MQ_hd_fixed_size (copy_lazy,
-                          GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE,
-                          struct GNUNET_SET_CopyLazyResponseMessage);
   struct GNUNET_SET_Handle *set = GNUNET_new (struct GNUNET_SET_Handle);
   struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    make_result_handler (set),
-    make_iter_element_handler (set),
-    make_iter_done_handler (set),
-    make_copy_lazy_handler (set),
+    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_MQ_Envelope *mqm;
@@ -581,7 +586,7 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
   struct GNUNET_SET_CopyLazyConnectMessage *copy_msg;
 
   set->cfg = cfg;
-  set->mq = GNUNET_CLIENT_connecT (cfg,
+  set->mq = GNUNET_CLIENT_connect (cfg,
                                    "set",
                                    mq_handlers,
                                    &handle_client_set_error,
@@ -655,18 +660,21 @@ 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\n", (unsigned) element->element_type);
+
   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);
@@ -706,9 +714,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);
@@ -728,8 +736,7 @@ 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) )
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Set operations are pending, delaying set destruction\n");
@@ -766,13 +773,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;
@@ -782,6 +794,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;
 
@@ -811,9 +842,12 @@ check_request (void *cls,
 {
   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;
   }
@@ -893,12 +927,12 @@ handle_client_listener_error (void *cls,
 static void
 listen_connect (void *cls)
 {
-  GNUNET_MQ_hd_var_size (request,
-                        GNUNET_MESSAGE_TYPE_SET_REQUEST,
-                        struct GNUNET_SET_RequestMessage);
   struct GNUNET_SET_ListenHandle *lh = cls;
   struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    make_request_handler (lh),
+    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;
@@ -906,7 +940,7 @@ listen_connect (void *cls)
 
   lh->reconnect_task = NULL;
   GNUNET_assert (NULL == lh->mq);
-  lh->mq = GNUNET_CLIENT_connecT (lh->cfg,
+  lh->mq = GNUNET_CLIENT_connect (lh->cfg,
                                   "set",
                                   mq_handlers,
                                   &handle_client_listener_error,
@@ -1000,6 +1034,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,6 +1043,9 @@ 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)\n",
+       result_mode);
   request->accepted = GNUNET_YES;
   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
   msg->accept_reject_id = htonl (request->accept_id);
@@ -1047,14 +1085,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;
@@ -1131,8 +1173,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;
 }