}
+/**
+ * Called when a client wants to iterate the elements of a set.
+ *
+ * @param cls unused
+ * @param client client that sent the message
+ * @param m message sent by the client
+ */
+static void
+handle_client_iterate (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
+{
+ struct Set *set;
+
+ set = set_get (client);
+ if (NULL == set)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+
+ set->vt->iterate (set);
+}
+
+
/**
* Called when a client wants to create a new set.
*
{handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
{handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE,
sizeof (struct GNUNET_SET_CreateMessage)},
+ {handle_client_iterate, NULL, GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST,
+ sizeof (struct GNUNET_MessageHeader)},
{handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
{handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN,
sizeof (struct GNUNET_SET_ListenMessage)},
uint32_t request_id);
+/**
+ * Signature of functions that implement sending all the set's
+ * elements to the client.
+ *
+ * @param set set that should be iterated over
+ */
+typedef void (*IterateImpl) (struct Set *set);
+
+
/**
* Dispatch table for a specific set operation.
* Every set operation has to implement the callback
* its ID.
*/
CancelImpl cancel;
+
+ /**
+ * Callback for iterating over all set elements.
+ */
+ IterateImpl iterate;
};
}
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+send_iter_element_iter (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct ElementEntry *ee = value;
+ struct Set *set = cls;
+ struct GNUNET_SET_IterResponseMessage *m;
+ struct GNUNET_MQ_Envelope *ev;
+
+ ev = GNUNET_MQ_msg_extra (m, ee->element.size,
+ GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
+
+ m->element_type = ee->element.type;
+ memcpy (&m[1], ee->element.data, ee->element.size);
+ GNUNET_MQ_send (set->client_mq, ev);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Send all elements of the union set to the client.
+ *
+ * @param set set to iterate over
+ */
+static void
+union_iterate (struct Set *set)
+{
+ struct GNUNET_MQ_Envelope *ev;
+
+ GNUNET_CONTAINER_multihashmap_iterate (set->state->elements, send_iter_element_iter, set);
+ ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
+ GNUNET_MQ_send (set->client_mq, ev);
+}
+
+
const struct SetVT *
_GSS_union_vt ()
{
.evaluate = &union_evaluate,
.accept = &union_accept,
.peer_disconnect = &union_peer_disconnect,
- .cancel = &union_op_cancel
+ .cancel = &union_op_cancel,
+ .iterate = &union_iterate
};
return &union_vt;
uint32_t request_id GNUNET_PACKED;
};
+struct GNUNET_SET_IterResponseMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_SET_ITER_RESPONSE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Type of the element attachted to the message,
+ * if any.
+ */
+ uint16_t element_type GNUNET_PACKED;
+
+ /* rest: element */
+};
GNUNET_NETWORK_STRUCT_END
* Has the set become invalid (e.g. service died)?
*/
int invalid;
+
+ /**
+ * Callback for the current iteration over the set,
+ * NULL if no iterator is active.
+ */
+ GNUNET_SET_ElementIterator iterator;
+
+ /**
+ * Closure for 'iterator'
+ */
+ void *iterator_cls;
};
};
+/**
+ * Handle element for iteration over the set.
+ *
+ * @param cls the set
+ * @param mh the message
+ */
+static void
+handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh)
+{
+ struct GNUNET_SET_Handle *set = cls;
+ struct GNUNET_SET_Element element;
+ const struct GNUNET_SET_IterResponseMessage *msg =
+ (const struct GNUNET_SET_IterResponseMessage *) mh;
+
+ if (NULL == set->iterator)
+ return;
+
+ element.type = htons (mh->type);
+ element.data = &msg[1];
+ set->iterator (set->iterator_cls, &element);
+}
+
+
+/**
+ * Handle element for iteration over the set.
+ *
+ * @param cls the set
+ * @param mh the message
+ */
+static void
+handle_iter_done (void *cls, const struct GNUNET_MessageHeader *mh)
+{
+ struct GNUNET_SET_Handle *set = cls;
+
+ if (NULL == set->iterator)
+ return;
+
+ set->iterator (set->iterator_cls, NULL);
+}
+
+
/**
* Handle result message for a set operation.
*
struct GNUNET_SET_CreateMessage *msg;
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, 0},
GNUNET_MQ_HANDLERS_END
};
return GNUNET_OK;
}
+
+
+/**
+ * Iterate over all elements in the given set.
+ * Note that this operation involves transferring every element of the set
+ * from the service to the client, and is thus costly.
+ *
+ * @param set the set to iterate over
+ * @param iter the iterator to call for each element
+ * @param cls closure for 'iter'
+ * @return GNUNET_YES if the iteration started successfuly,
+ * GNUNET_NO if another iteration is 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 *cls)
+{
+ struct GNUNET_MQ_Envelope *ev;
+
+ GNUNET_assert (NULL != iter);
+
+ if (GNUNET_YES == set->invalid)
+ return GNUNET_SYSERR;
+ if (NULL != set->iterator)
+ return GNUNET_NO;
+
+ set->iterator = iter;
+ set->iterator_cls = cls;
+ ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
+ GNUNET_MQ_send (set->mq, ev);
+ return GNUNET_YES;
+}
+