adding logic to allow GNUNET_SET_iterate_cancel
authorChristian Grothoff <christian@grothoff.org>
Thu, 27 Nov 2014 13:55:23 +0000 (13:55 +0000)
committerChristian Grothoff <christian@grothoff.org>
Thu, 27 Nov 2014 13:55:23 +0000 (13:55 +0000)
src/include/gnunet_set_service.h
src/set/gnunet-service-set.c
src/set/gnunet-service-set.h
src/set/set.h
src/set/set_api.c

index c0e65cb72cd8616efe6fabab11ed369c35a990f2..4106f4bebdd9c7734517c0276d36ce8b4b9463d5 100644 (file)
@@ -283,6 +283,11 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
 
 /**
  * Destroy the set handle, and free all associated resources.
+ * Iterations must have completed (or be explicitly canceled)
+ * before destroying the corresponding set.  Operations may
+ * still be pending when a set is destroyed.
+ *
+ * @param set set to destroy
  */
 void
 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set);
@@ -334,9 +339,8 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
 
 /**
- * Cancel the given listen operation.
- * After calling cancel, the listen callback for this listen handle
- * will not be called again.
+ * Cancel the given listen operation.  After calling cancel, the
+ * listen callback for this listen handle will not be called again.
  *
  * @param lh handle for the listen operation
  */
@@ -404,13 +408,24 @@ GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh);
  * @param iter the iterator to call for each element
  * @param iter_cls closure for @a iter
  * @return #GNUNET_YES if the iteration started successfuly,
- *         #GNUNET_SYSERR if the set  is invalid (e.g. the server crashed, disconnected)
+ *         #GNUNET_NO if another iteration was still active,
+ *         #GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
  */
 int
 GNUNET_SET_iterate (struct GNUNET_SET_Handle *set,
                     GNUNET_SET_ElementIterator iter,
                     void *iter_cls);
 
+/**
+ * Stop iteration over all elements in the given set.  Can only
+ * be called before the iteration has "naturally" completed its
+ * turn.
+ *
+ * @param set the set to stop iterating over
+ */
+void
+GNUNET_SET_iterate_cancel (struct GNUNET_SET_Handle *set);
+
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
index 5e1b89936b6a38643edb2fbb435f28f21e0b24ed..b2c3da7dcb79e7c16636b099af88f3ed4a901a05 100644 (file)
@@ -410,6 +410,7 @@ set_destroy (struct Set *set)
   {
     GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
     set->iter = NULL;
+    set->iteration_id++;
   }
   if (NULL != set->elements)
   {
@@ -667,6 +668,7 @@ send_client_element (struct Set *set)
     ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
     GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
     set->iter = NULL;
+    set->iteration_id++;
   }
   else
   {
@@ -678,6 +680,7 @@ send_client_element (struct Set *set)
             ee->element.data,
             ee->element.size);
     msg->element_type = ee->element.element_type;
+    msg->iteration_id = htons (set->iteration_id);
   }
   GNUNET_MQ_send (set->client_mq, ev);
 }
@@ -1097,6 +1100,7 @@ handle_client_iter_ack (void *cls,
   {
     GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
     set->iter = NULL;
+    set->iteration_id++;
   }
 }
 
index 448ed9478b8da05403cd7ef7776adbd235f1b8c7..ab81558834e8a83e3997c106f20e4b386de23c2d 100644 (file)
@@ -468,6 +468,12 @@ struct Set
    */
   enum GNUNET_SET_OperationType operation;
 
+  /**
+   * Each @e iter is assigned a unique number, so that the client
+   * can distinguish iterations.
+   */
+  uint16_t iteration_id;
+
 };
 
 
index 01c96896dbaa426fdbce636535b2cb903d251c37..944881b630d644390ec99b01d616a9e83f75a794 100644 (file)
 #include "platform.h"
 #include "gnunet_common.h"
 
-/**
- * FIXME
- */
-#define GNUNET_SET_ACK_WINDOW 10
-
-
 GNUNET_NETWORK_STRUCT_BEGIN
 
 /**
@@ -266,6 +260,10 @@ struct GNUNET_SET_CancelMessage
 };
 
 
+/**
+ * Set element transmitted by service to client in response to a set
+ * iteration request.
+ */
 struct GNUNET_SET_IterResponseMessage
 {
   /**
@@ -273,6 +271,12 @@ struct GNUNET_SET_IterResponseMessage
    */
   struct GNUNET_MessageHeader header;
 
+  /**
+   * To which set iteration does this reponse belong to?  First
+   * iteration (per client) has counter zero. Wraps around.
+   */
+  uint16_t iteration_id GNUNET_PACKED;
+
   /**
    * Type of the element attachted to the message,
    * if any.
@@ -282,6 +286,10 @@ struct GNUNET_SET_IterResponseMessage
   /* rest: element */
 };
 
+
+/**
+ * Client acknowledges receiving element in iteration.
+ */
 struct GNUNET_SET_IterAckMessage
 {
   /**
index d6247501309f65a7617a1759a6a08be49ed8f0f6..b919f6e020df8af0814da20c2b9db29963f83141 100644 (file)
@@ -77,6 +77,12 @@ struct GNUNET_SET_Handle
    * Has the set become invalid (e.g. service died)?
    */
   int invalid;
+
+  /**
+   * Both client and service count the number of iterators
+   * created so far to match replies with iterators.
+   */
+  uint16_t iteration_id;
 };
 
 
@@ -210,7 +216,7 @@ struct GNUNET_SET_ListenHandle
  * Handle element for iteration over the set.  Notifies the
  * iterator and sends an acknowledgement to the service.
  *
- * @param cls the set
+ * @param cls the `struct GNUNET_SET_Handle *`
  * @param mh the message
  */
 static void
@@ -231,13 +237,19 @@ handle_iter_element (void *cls,
     /* 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;
+  if (set->iteration_id != ntohs (msg->iteration_id))
+  {
+    /* element from a previous iteration, skip! */
+    iter = NULL;
+  }
   if (NULL != iter)
   {
-    msg = (const struct GNUNET_SET_IterResponseMessage *) mh;
     element.size = msize - sizeof (struct GNUNET_SET_IterResponseMessage);
     element.element_type = htons (msg->element_type);
     element.data = &msg[1];
@@ -268,6 +280,7 @@ handle_iter_done (void *cls,
   if (NULL == iter)
     return;
   set->iterator = NULL;
+  set->iteration_id++;
   iter (set->iterator_cls,
         NULL);
 }
@@ -304,7 +317,7 @@ handle_result (void *cls,
   }
   if (GNUNET_SET_STATUS_OK != result_status)
   {
-    /* status is not STATUS_OK => there's no attached element,
+    /* status is not #GNUNET_SET_STATUS_OK => there's no attached element,
      * and this is the last result message we get */
     GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
     GNUNET_CONTAINER_DLL_remove (set->ops_head,
@@ -608,6 +621,10 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
 void
 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)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -923,4 +940,21 @@ GNUNET_SET_iterate (struct GNUNET_SET_Handle *set,
   return GNUNET_YES;
 }
 
+
+/**
+ * Stop iteration over all elements in the given set.  Can only
+ * be called before the iteration has "naturally" completed its
+ * turn.
+ *
+ * @param set the set to stop iterating over
+ */
+void
+GNUNET_SET_iterate_cancel (struct GNUNET_SET_Handle *set)
+{
+  GNUNET_assert (NULL != set->iterator);
+  set->iterator = NULL;
+  set->iteration_id++;
+}
+
+
 /* end of set_api.c */