From 18bc05a535be767b07473e29ac85cebe79ce83cf Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 23 Jul 2013 17:26:35 +0000 Subject: [PATCH] - set iteration --- src/set/gnunet-service-set.c | 28 ++++++++++ src/set/gnunet-service-set.h | 14 +++++ src/set/gnunet-service-set_union.c | 50 ++++++++++++++++- src/set/set.h | 15 ++++++ src/set/set_api.c | 87 ++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 1 deletion(-) diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c index a55c2188e..8445b3799 100644 --- a/src/set/gnunet-service-set.c +++ b/src/set/gnunet-service-set.c @@ -454,6 +454,32 @@ handle_incoming_msg (struct OperationState *op, } +/** + * 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. * @@ -939,6 +965,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, {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)}, diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h index 6ababe92f..c93cc660a 100644 --- a/src/set/gnunet-service-set.h +++ b/src/set/gnunet-service-set.h @@ -169,6 +169,15 @@ typedef void (*CancelImpl) (struct SetState *set, 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 @@ -222,6 +231,11 @@ struct SetVT * its ID. */ CancelImpl cancel; + + /** + * Callback for iterating over all set elements. + */ + IterateImpl iterate; }; diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c index e512761cc..87100bf54 100644 --- a/src/set/gnunet-service-set_union.c +++ b/src/set/gnunet-service-set_union.c @@ -1421,6 +1421,53 @@ union_op_cancel (struct SetState *set_state, uint32_t op_id) } +/** + * 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 () { @@ -1433,7 +1480,8 @@ _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; diff --git a/src/set/set.h b/src/set/set.h index fc29e6696..9f6eb3642 100644 --- a/src/set/set.h +++ b/src/set/set.h @@ -211,6 +211,21 @@ struct GNUNET_SET_CancelMessage 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 diff --git a/src/set/set_api.c b/src/set/set_api.c index 88f334cbc..c2e88e65f 100644 --- a/src/set/set_api.c +++ b/src/set/set_api.c @@ -67,6 +67,17 @@ struct GNUNET_SET_Handle * 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; }; @@ -170,6 +181,47 @@ struct GNUNET_SET_ListenHandle }; +/** + * 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. * @@ -302,6 +354,8 @@ GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, 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 }; @@ -623,3 +677,36 @@ GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh, 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; +} + -- 2.25.1