/**
* 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);
/**
- * 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
*/
* @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 */
{
{
GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
set->iter = NULL;
+ set->iteration_id++;
}
if (NULL != set->elements)
{
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
{
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);
}
{
GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
set->iter = NULL;
+ set->iteration_id++;
}
}
*/
enum GNUNET_SET_OperationType operation;
+ /**
+ * Each @e iter is assigned a unique number, so that the client
+ * can distinguish iterations.
+ */
+ uint16_t iteration_id;
+
};
#include "platform.h"
#include "gnunet_common.h"
-/**
- * FIXME
- */
-#define GNUNET_SET_ACK_WINDOW 10
-
-
GNUNET_NETWORK_STRUCT_BEGIN
/**
};
+/**
+ * Set element transmitted by service to client in response to a set
+ * iteration request.
+ */
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.
/* rest: element */
};
+
+/**
+ * Client acknowledges receiving element in iteration.
+ */
struct GNUNET_SET_IterAckMessage
{
/**
* 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;
};
* 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
/* 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];
if (NULL == iter)
return;
set->iterator = NULL;
+ set->iteration_id++;
iter (set->iterator_cls,
NULL);
}
}
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,
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,
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 */