2 This file is part of GNUnet.
3 (C) 2012-2014 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @brief api for the set service
23 * @author Florian Dold
26 #include "gnunet_util_lib.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_client_lib.h"
29 #include "gnunet_set_service.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "set-api",__VA_ARGS__)
36 * Opaque handle to a set.
38 struct GNUNET_SET_Handle
41 * Client connected to the set service.
43 struct GNUNET_CLIENT_Connection *client;
46 * Message queue for @e client.
48 struct GNUNET_MQ_Handle *mq;
51 * Linked list of operations on the set.
53 struct GNUNET_SET_OperationHandle *ops_head;
56 * Linked list of operations on the set.
58 struct GNUNET_SET_OperationHandle *ops_tail;
61 * Callback for the current iteration over the set,
62 * NULL if no iterator is active.
64 GNUNET_SET_ElementIterator iterator;
67 * Closure for @e iterator
72 * Should the set be destroyed once all operations are gone?
74 int destroy_requested;
77 * Has the set become invalid (e.g. service died)?
82 * Both client and service count the number of iterators
83 * created so far to match replies with iterators.
85 uint16_t iteration_id;
90 * Handle for a set operation request from another peer.
92 struct GNUNET_SET_Request
95 * Id of the request, used to identify the request when
96 * accepting/rejecting it.
101 * Has the request been accepted already?
102 * #GNUNET_YES/#GNUNET_NO
109 * Handle to an operation. Only known to the service after committing
110 * the handle with a set.
112 struct GNUNET_SET_OperationHandle
115 * Function to be called when we have a result,
118 GNUNET_SET_ResultIterator result_cb;
121 * Closure for @e result_cb.
126 * Local set used for the operation,
127 * NULL if no set has been provided by conclude yet.
129 struct GNUNET_SET_Handle *set;
132 * Message sent to the server on calling conclude,
133 * NULL if conclude has been called.
135 struct GNUNET_MQ_Envelope *conclude_mqm;
138 * Address of the request if in the conclude message,
139 * used to patch the request id into the message when the set is known.
141 uint32_t *request_id_addr;
144 * Handles are kept in a linked list.
146 struct GNUNET_SET_OperationHandle *prev;
149 * Handles are kept in a linked list.
151 struct GNUNET_SET_OperationHandle *next;
154 * Request ID to identify the operation within the set.
161 * Opaque handle to a listen operation.
163 struct GNUNET_SET_ListenHandle
166 * Connection to the service.
168 struct GNUNET_CLIENT_Connection *client;
171 * Message queue for the client.
173 struct GNUNET_MQ_Handle* mq;
176 * Configuration handle for the listener, stored
177 * here to be able to reconnect transparently on
178 * connection failure.
180 const struct GNUNET_CONFIGURATION_Handle *cfg;
183 * Function to call on a new incoming request,
186 GNUNET_SET_ListenCallback listen_cb;
189 * Closure for @e listen_cb.
194 * Application ID we listen for.
196 struct GNUNET_HashCode app_id;
199 * Time to wait until we try to reconnect on failure.
201 struct GNUNET_TIME_Relative reconnect_backoff;
204 * Task for reconnecting when the listener fails.
206 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
209 * Operation we listen for.
211 enum GNUNET_SET_OperationType operation;
216 * Handle element for iteration over the set. Notifies the
217 * iterator and sends an acknowledgement to the service.
219 * @param cls the `struct GNUNET_SET_Handle *`
220 * @param mh the message
223 handle_iter_element (void *cls,
224 const struct GNUNET_MessageHeader *mh)
226 struct GNUNET_SET_Handle *set = cls;
227 GNUNET_SET_ElementIterator iter = set->iterator;
228 struct GNUNET_SET_Element element;
229 const struct GNUNET_SET_IterResponseMessage *msg;
230 struct GNUNET_SET_IterAckMessage *ack_msg;
231 struct GNUNET_MQ_Envelope *ev;
234 msize = ntohs (mh->size);
235 if (msize < sizeof (sizeof (struct GNUNET_SET_IterResponseMessage)))
237 /* message malformed */
239 set->iterator = NULL;
241 iter (set->iterator_cls,
245 msg = (const struct GNUNET_SET_IterResponseMessage *) mh;
246 if (set->iteration_id != ntohs (msg->iteration_id))
248 /* element from a previous iteration, skip! */
253 element.size = msize - sizeof (struct GNUNET_SET_IterResponseMessage);
254 element.element_type = htons (msg->element_type);
255 element.data = &msg[1];
256 iter (set->iterator_cls,
259 ev = GNUNET_MQ_msg (ack_msg,
260 GNUNET_MESSAGE_TYPE_SET_ITER_ACK);
261 ack_msg->send_more = htonl ((NULL != iter));
262 GNUNET_MQ_send (set->mq, ev);
267 * Handle message signalling conclusion of iteration over the set.
268 * Notifies the iterator that we are done.
271 * @param mh the message
274 handle_iter_done (void *cls,
275 const struct GNUNET_MessageHeader *mh)
277 struct GNUNET_SET_Handle *set = cls;
278 GNUNET_SET_ElementIterator iter = set->iterator;
282 set->iterator = NULL;
284 iter (set->iterator_cls,
290 * Handle result message for a set operation.
293 * @param mh the message
296 handle_result (void *cls,
297 const struct GNUNET_MessageHeader *mh)
299 struct GNUNET_SET_Handle *set = cls;
300 const struct GNUNET_SET_ResultMessage *msg;
301 struct GNUNET_SET_OperationHandle *oh;
302 struct GNUNET_SET_Element e;
303 enum GNUNET_SET_Status result_status;
305 msg = (const struct GNUNET_SET_ResultMessage *) mh;
306 GNUNET_assert (NULL != set->mq);
307 result_status = ntohs (msg->result_status);
308 oh = GNUNET_MQ_assoc_get (set->mq,
309 ntohl (msg->request_id));
312 /* 'oh' can be NULL if we canceled the operation, but the service
313 did not get the cancel message yet. */
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Ignoring result from canceled operation\n");
318 if (GNUNET_SET_STATUS_OK != result_status)
320 /* status is not #GNUNET_SET_STATUS_OK => there's no attached element,
321 * and this is the last result message we get */
322 GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
323 GNUNET_CONTAINER_DLL_remove (set->ops_head,
326 if ( (GNUNET_YES == set->destroy_requested) &&
327 (NULL == set->ops_head) )
328 GNUNET_SET_destroy (set);
329 if (NULL != oh->result_cb)
330 oh->result_cb (oh->result_cls,
337 e.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ResultMessage);
338 e.element_type = msg->element_type;
339 if (NULL != oh->result_cb)
340 oh->result_cb (oh->result_cls,
347 * Handle request message for a listen operation
349 * @param cls the listen handle
350 * @param mh the message
353 handle_request (void *cls,
354 const struct GNUNET_MessageHeader *mh)
356 const struct GNUNET_SET_RequestMessage *msg = (const struct GNUNET_SET_RequestMessage *) mh;
357 struct GNUNET_SET_ListenHandle *lh = cls;
358 struct GNUNET_SET_Request *req;
359 const struct GNUNET_MessageHeader *context_msg;
361 LOG (GNUNET_ERROR_TYPE_DEBUG,
362 "processing operation request\n");
363 req = GNUNET_new (struct GNUNET_SET_Request);
364 req->accept_id = ntohl (msg->accept_id);
365 context_msg = GNUNET_MQ_extract_nested_mh (msg);
366 /* calling #GNUNET_SET_accept() in the listen cb will set req->accepted */
367 lh->listen_cb (lh->listen_cls, &msg->peer_id, context_msg, req);
369 /* we got another request => reset the backoff */
370 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
372 if (GNUNET_NO == req->accepted)
374 struct GNUNET_MQ_Envelope *mqm;
375 struct GNUNET_SET_RejectMessage *rmsg;
377 mqm = GNUNET_MQ_msg (rmsg,
378 GNUNET_MESSAGE_TYPE_SET_REJECT);
379 rmsg->accept_reject_id = msg->accept_id;
380 GNUNET_MQ_send (lh->mq, mqm);
381 LOG (GNUNET_ERROR_TYPE_DEBUG,
382 "rejecting request\n");
386 LOG (GNUNET_ERROR_TYPE_DEBUG,
387 "processed op request from service\n");
389 /* the accept-case is handled in GNUNET_SET_accept,
390 * as we have the accept message available there */
395 * Destroy the given set operation.
397 * @param oh set operation to destroy
400 set_operation_destroy (struct GNUNET_SET_OperationHandle *oh)
402 struct GNUNET_SET_Handle *set = oh->set;
403 struct GNUNET_SET_OperationHandle *h_assoc;
405 if (NULL != oh->conclude_mqm)
406 GNUNET_MQ_discard (oh->conclude_mqm);
407 /* is the operation already commited? */
410 GNUNET_CONTAINER_DLL_remove (set->ops_head,
413 h_assoc = GNUNET_MQ_assoc_remove (set->mq,
415 GNUNET_assert ((NULL == h_assoc) || (h_assoc == oh));
422 * Cancel the given set operation. We need to send an explicit cancel
423 * message, as all operations one one set communicate using one
426 * @param oh set operation to cancel
429 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
431 struct GNUNET_SET_Handle *set = oh->set;
432 struct GNUNET_SET_CancelMessage *m;
433 struct GNUNET_MQ_Envelope *mqm;
437 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL);
438 m->request_id = htonl (oh->request_id);
439 GNUNET_MQ_send (set->mq, mqm);
441 set_operation_destroy (oh);
442 if ( (NULL != set) &&
443 (GNUNET_YES == set->destroy_requested) &&
444 (NULL == set->ops_head) )
446 LOG (GNUNET_ERROR_TYPE_DEBUG,
447 "Destroying set after operation cancel\n");
448 GNUNET_SET_destroy (set);
454 * We encountered an error communicating with the set service while
455 * performing a set operation. Report to the application.
457 * @param cls the `struct GNUNET_SET_Handle`
458 * @param error error code
461 handle_client_set_error (void *cls,
462 enum GNUNET_MQ_Error error)
464 struct GNUNET_SET_Handle *set = cls;
466 LOG (GNUNET_ERROR_TYPE_DEBUG,
467 "Handling client set error\n");
468 while (NULL != set->ops_head)
470 if (NULL != set->ops_head->result_cb)
471 set->ops_head->result_cb (set->ops_head->result_cls,
473 GNUNET_SET_STATUS_FAILURE);
474 set_operation_destroy (set->ops_head);
476 set->invalid = GNUNET_YES;
477 if (GNUNET_YES == set->destroy_requested)
479 LOG (GNUNET_ERROR_TYPE_DEBUG,
480 "Destroying set after operation failure\n");
481 GNUNET_SET_destroy (set);
487 * Create an empty set, supporting the specified operation.
489 * @param cfg configuration to use for connecting to the
491 * @param op operation supported by the set
492 * Note that the operation has to be specified
493 * beforehand, as certain set operations need to maintain
494 * data structures spefific to the operation
495 * @return a handle to the set
497 struct GNUNET_SET_Handle *
498 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
499 enum GNUNET_SET_OperationType op)
501 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
502 { &handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
503 { &handle_iter_element, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT, 0},
505 GNUNET_MESSAGE_TYPE_SET_ITER_DONE,
506 sizeof (struct GNUNET_MessageHeader) },
507 GNUNET_MQ_HANDLERS_END
509 struct GNUNET_SET_Handle *set;
510 struct GNUNET_MQ_Envelope *mqm;
511 struct GNUNET_SET_CreateMessage *msg;
513 set = GNUNET_new (struct GNUNET_SET_Handle);
514 set->client = GNUNET_CLIENT_connect ("set", cfg);
515 if (NULL == set->client)
520 set->mq = GNUNET_MQ_queue_for_connection_client (set->client,
522 &handle_client_set_error, set);
523 GNUNET_assert (NULL != set->mq);
524 mqm = GNUNET_MQ_msg (msg,
525 GNUNET_MESSAGE_TYPE_SET_CREATE);
526 msg->operation = htonl (op);
527 GNUNET_MQ_send (set->mq, mqm);
533 * Add an element to the given set. After the element has been added
534 * (in the sense of being transmitted to the set service), @a cont
535 * will be called. Multiple calls to GNUNET_SET_add_element() can be
538 * @param set set to add element to
539 * @param element element to add to the set
540 * @param cont continuation called after the element has been added
541 * @param cont_cls closure for @a cont
542 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
543 * set is invalid (e.g. the set service crashed)
546 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
547 const struct GNUNET_SET_Element *element,
548 GNUNET_SET_Continuation cont,
551 struct GNUNET_MQ_Envelope *mqm;
552 struct GNUNET_SET_ElementMessage *msg;
554 if (GNUNET_YES == set->invalid)
558 return GNUNET_SYSERR;
560 mqm = GNUNET_MQ_msg_extra (msg, element->size,
561 GNUNET_MESSAGE_TYPE_SET_ADD);
562 msg->element_type = element->element_type;
566 GNUNET_MQ_notify_sent (mqm,
568 GNUNET_MQ_send (set->mq, mqm);
574 * Remove an element to the given set. After the element has been
575 * removed (in the sense of the request being transmitted to the set
576 * service), @a cont will be called. Multiple calls to
577 * GNUNET_SET_remove_element() can be queued
579 * @param set set to remove element from
580 * @param element element to remove from the set
581 * @param cont continuation called after the element has been removed
582 * @param cont_cls closure for @a cont
583 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
584 * set is invalid (e.g. the set service crashed)
587 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
588 const struct GNUNET_SET_Element *element,
589 GNUNET_SET_Continuation cont,
592 struct GNUNET_MQ_Envelope *mqm;
593 struct GNUNET_SET_ElementMessage *msg;
595 if (GNUNET_YES == set->invalid)
599 return GNUNET_SYSERR;
601 mqm = GNUNET_MQ_msg_extra (msg,
603 GNUNET_MESSAGE_TYPE_SET_REMOVE);
604 msg->element_type = element->element_type;
608 GNUNET_MQ_notify_sent (mqm,
610 GNUNET_MQ_send (set->mq, mqm);
616 * Destroy the set handle if no operations are left, mark the set
617 * for destruction otherwise.
619 * @param set set handle to destroy
622 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
624 /* destroying set while iterator is active is currently
625 not supported; we should expand the API to allow
626 clients to explicitly cancel the iteration! */
627 GNUNET_assert (NULL == set->iterator);
628 if (NULL != set->ops_head)
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "Set operations are pending, delaying set destruction\n");
632 set->destroy_requested = GNUNET_YES;
635 LOG (GNUNET_ERROR_TYPE_DEBUG,
636 "Really destroying set\n");
637 if (NULL != set->client)
639 GNUNET_CLIENT_disconnect (set->client);
644 GNUNET_MQ_destroy (set->mq);
652 * Prepare a set operation to be evaluated with another peer.
653 * The evaluation will not start until the client provides
654 * a local set with #GNUNET_SET_commit().
656 * @param other_peer peer with the other set
657 * @param app_id hash for the application using the set
658 * @param context_msg additional information for the request
659 * @param result_mode specified how results will be returned,
660 * see `enum GNUNET_SET_ResultMode`.
661 * @param result_cb called on error or success
662 * @param result_cls closure for @e result_cb
663 * @return a handle to cancel the operation
665 struct GNUNET_SET_OperationHandle *
666 GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
667 const struct GNUNET_HashCode *app_id,
668 const struct GNUNET_MessageHeader *context_msg,
669 enum GNUNET_SET_ResultMode result_mode,
670 GNUNET_SET_ResultIterator result_cb,
673 struct GNUNET_MQ_Envelope *mqm;
674 struct GNUNET_SET_OperationHandle *oh;
675 struct GNUNET_SET_EvaluateMessage *msg;
677 oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
678 oh->result_cb = result_cb;
679 oh->result_cls = result_cls;
680 mqm = GNUNET_MQ_msg_nested_mh (msg,
681 GNUNET_MESSAGE_TYPE_SET_EVALUATE,
683 msg->app_id = *app_id;
684 msg->result_mode = htonl (result_mode);
685 msg->target_peer = *other_peer;
686 oh->conclude_mqm = mqm;
687 oh->request_id_addr = &msg->request_id;
694 * Connect to the set service in order to listen for requests.
696 * @param cls the `struct GNUNET_SET_ListenHandle *` to connect
697 * @param tc task context if invoked as a task, NULL otherwise
700 listen_connect (void *cls,
701 const struct GNUNET_SCHEDULER_TaskContext *tc);
705 * Our connection with the set service encountered an error,
706 * re-initialize with exponential back-off.
708 * @param cls the `struct GNUNET_SET_ListenHandle *`
709 * @param error reason for the disconnect
712 handle_client_listener_error (void *cls,
713 enum GNUNET_MQ_Error error)
715 struct GNUNET_SET_ListenHandle *lh = cls;
717 LOG (GNUNET_ERROR_TYPE_DEBUG,
718 "Listener broke down (%d), re-connecting\n",
720 GNUNET_CLIENT_disconnect (lh->client);
722 GNUNET_MQ_destroy (lh->mq);
724 lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
725 &listen_connect, lh);
726 lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
731 * Connect to the set service in order to listen for requests.
733 * @param cls the `struct GNUNET_SET_ListenHandle *` to connect
734 * @param tc task context if invoked as a task, NULL otherwise
737 listen_connect (void *cls,
738 const struct GNUNET_SCHEDULER_TaskContext *tc)
740 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
741 { &handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST },
742 GNUNET_MQ_HANDLERS_END
744 struct GNUNET_SET_ListenHandle *lh = cls;
745 struct GNUNET_MQ_Envelope *mqm;
746 struct GNUNET_SET_ListenMessage *msg;
749 (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
751 LOG (GNUNET_ERROR_TYPE_DEBUG,
752 "Listener not reconnecting due to shutdown\n");
755 lh->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
757 GNUNET_assert (NULL == lh->client);
758 lh->client = GNUNET_CLIENT_connect ("set", lh->cfg);
759 if (NULL == lh->client)
761 GNUNET_assert (NULL == lh->mq);
762 lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers,
763 &handle_client_listener_error, lh);
764 mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
765 msg->operation = htonl (lh->operation);
766 msg->app_id = lh->app_id;
767 GNUNET_MQ_send (lh->mq, mqm);
772 * Wait for set operation requests for the given application id
774 * @param cfg configuration to use for connecting to
775 * the set service, needs to be valid for the lifetime of the listen handle
776 * @param operation operation we want to listen for
777 * @param app_id id of the application that handles set operation requests
778 * @param listen_cb called for each incoming request matching the operation
780 * @param listen_cls handle for @a listen_cb
781 * @return a handle that can be used to cancel the listen operation
783 struct GNUNET_SET_ListenHandle *
784 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
785 enum GNUNET_SET_OperationType operation,
786 const struct GNUNET_HashCode *app_id,
787 GNUNET_SET_ListenCallback listen_cb,
790 struct GNUNET_SET_ListenHandle *lh;
792 lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
793 lh->listen_cb = listen_cb;
794 lh->listen_cls = listen_cls;
796 lh->operation = operation;
797 lh->app_id = *app_id;
798 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
799 listen_connect (lh, NULL);
800 if (NULL == lh->client)
810 * Cancel the given listen operation.
812 * @param lh handle for the listen operation
815 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
817 LOG (GNUNET_ERROR_TYPE_DEBUG,
818 "Canceling listener\n");
821 GNUNET_MQ_destroy (lh->mq);
824 if (NULL != lh->client)
826 GNUNET_CLIENT_disconnect (lh->client);
829 if (GNUNET_SCHEDULER_NO_TASK != lh->reconnect_task)
831 GNUNET_SCHEDULER_cancel (lh->reconnect_task);
832 lh->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
839 * Accept a request we got via #GNUNET_SET_listen. Must be called during
840 * #GNUNET_SET_listen, as the 'struct GNUNET_SET_Request' becomes invalid
842 * Call #GNUNET_SET_commit to provide the local set to use for the operation,
843 * and to begin the exchange with the remote peer.
845 * @param request request to accept
846 * @param result_mode specified how results will be returned,
847 * see `enum GNUNET_SET_ResultMode`.
848 * @param result_cb callback for the results
849 * @param result_cls closure for @a result_cb
850 * @return a handle to cancel the operation
852 struct GNUNET_SET_OperationHandle *
853 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
854 enum GNUNET_SET_ResultMode result_mode,
855 GNUNET_SET_ResultIterator result_cb,
858 struct GNUNET_MQ_Envelope *mqm;
859 struct GNUNET_SET_OperationHandle *oh;
860 struct GNUNET_SET_AcceptMessage *msg;
862 GNUNET_assert (GNUNET_NO == request->accepted);
863 request->accepted = GNUNET_YES;
864 mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
865 msg->accept_reject_id = htonl (request->accept_id);
866 msg->result_mode = htonl (result_mode);
867 oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
868 oh->result_cb = result_cb;
869 oh->result_cls = result_cls;
870 oh->conclude_mqm = mqm;
871 oh->request_id_addr = &msg->request_id;
877 * Commit a set to be used with a set operation.
878 * This function is called once we have fully constructed
879 * the set that we want to use for the operation. At this
880 * time, the P2P protocol can then begin to exchange the
881 * set information and call the result callback with the
882 * result information.
884 * @param oh handle to the set operation
885 * @param set the set to use for the operation
886 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
887 * set is invalid (e.g. the set service crashed)
890 GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
891 struct GNUNET_SET_Handle *set)
893 GNUNET_assert (NULL == oh->set);
894 if (GNUNET_YES == set->invalid)
895 return GNUNET_SYSERR;
896 GNUNET_assert (NULL != oh->conclude_mqm);
898 GNUNET_CONTAINER_DLL_insert (set->ops_head,
901 oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
902 *oh->request_id_addr = htonl (oh->request_id);
903 GNUNET_MQ_send (set->mq, oh->conclude_mqm);
904 oh->conclude_mqm = NULL;
905 oh->request_id_addr = NULL;
911 * Iterate over all elements in the given set. Note that this
912 * operation involves transferring every element of the set from the
913 * service to the client, and is thus costly.
915 * @param set the set to iterate over
916 * @param iter the iterator to call for each element
917 * @param iter_cls closure for @a iter
918 * @return #GNUNET_YES if the iteration started successfuly,
919 * #GNUNET_NO if another iteration is active
920 * #GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
923 GNUNET_SET_iterate (struct GNUNET_SET_Handle *set,
924 GNUNET_SET_ElementIterator iter,
927 struct GNUNET_MQ_Envelope *ev;
929 GNUNET_assert (NULL != iter);
930 if (GNUNET_YES == set->invalid)
931 return GNUNET_SYSERR;
932 if (NULL != set->iterator)
934 LOG (GNUNET_ERROR_TYPE_DEBUG,
935 "Iterating over set\n");
936 set->iterator = iter;
937 set->iterator_cls = iter_cls;
938 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
939 GNUNET_MQ_send (set->mq, ev);
945 * Stop iteration over all elements in the given set. Can only
946 * be called before the iteration has "naturally" completed its
949 * @param set the set to stop iterating over
952 GNUNET_SET_iterate_cancel (struct GNUNET_SET_Handle *set)
954 GNUNET_assert (NULL != set->iterator);
955 set->iterator = NULL;
960 /* end of set_api.c */