3b287d5a4d7257c0793446eddc4c51adb83e54e9
[oweals/gnunet.git] / src / set / set_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file set/set_api.c
23  * @brief api for the set service
24  * @author Florian Dold
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_client_lib.h"
30 #include "gnunet_set_service.h"
31 #include "set.h"
32
33
34 #define LOG(kind,...) GNUNET_log_from (kind, "set-api",__VA_ARGS__)
35
36 /**
37  * Opaque handle to a set.
38  */
39 struct GNUNET_SET_Handle
40 {
41   /**
42    * Client connected to the set service.
43    */
44   struct GNUNET_CLIENT_Connection *client;
45
46   /**
47    * Message queue for 'client'.
48    */
49   struct GNUNET_MQ_Handle *mq;
50
51   /**
52    * Linked list of operations on the set.
53    */
54   struct GNUNET_SET_OperationHandle *ops_head;
55
56   /**
57    * Linked list of operations on the set.
58    */
59   struct GNUNET_SET_OperationHandle *ops_tail;
60
61   /**
62    * Should the set be destroyed once all operations are gone?
63    */
64   int destroy_requested;
65
66   /**
67    * Has the set become invalid (e.g. service died)?
68    */
69   int invalid;
70
71   /**
72    * Callback for the current iteration over the set,
73    * NULL if no iterator is active.
74    */
75   GNUNET_SET_ElementIterator iterator;
76
77   /**
78    * Closure for 'iterator'
79    */
80   void *iterator_cls;
81 };
82
83
84 /**
85  * Opaque handle to a set operation request from another peer.
86  */
87 struct GNUNET_SET_Request
88 {
89   /**
90    * Id of the request, used to identify the request when
91    * accepting/rejecting it.
92    */
93   uint32_t accept_id;
94
95   /**
96    * Has the request been accepted already?
97    * GNUNET_YES/GNUNET_NO
98    */
99   int accepted;
100 };
101
102
103 /**
104  * Handle to an operation.
105  * Only known to the service after commiting
106  * the handle with a set.
107  */
108 struct GNUNET_SET_OperationHandle
109 {
110   /**
111    * Function to be called when we have a result,
112    * or an error.
113    */
114   GNUNET_SET_ResultIterator result_cb;
115
116   /**
117    * Closure for result_cb.
118    */
119   void *result_cls;
120
121   /**
122    * Local set used for the operation,
123    * NULL if no set has been provided by conclude yet.
124    */
125   struct GNUNET_SET_Handle *set;
126
127   /**
128    * Request ID to identify the operation within the set.
129    */
130   uint32_t request_id;
131
132   /**
133    * Message sent to the server on calling conclude,
134    * NULL if conclude has been called.
135    */
136   struct GNUNET_MQ_Envelope *conclude_mqm;
137
138   /**
139    * Address of the request if in the conclude message,
140    * used to patch the request id into the message when the set is known.
141    */
142   uint32_t *request_id_addr;
143
144   /**
145    * Handles are kept in a linked list.
146    */
147   struct GNUNET_SET_OperationHandle *prev;
148
149   /**
150    * Handles are kept in a linked list.
151    */
152   struct GNUNET_SET_OperationHandle *next;
153 };
154
155
156 /**
157  * Opaque handle to a listen operation.
158  */
159 struct GNUNET_SET_ListenHandle
160 {
161   /**
162    * Connection to the service.
163    */
164   struct GNUNET_CLIENT_Connection *client;
165
166   /**
167    * Message queue for the client.
168    */
169   struct GNUNET_MQ_Handle* mq;
170
171   /**
172    * Configuration handle for the listener, stored
173    * here to be able to reconnect transparently on
174    * connection failure.
175    */
176   const struct GNUNET_CONFIGURATION_Handle *cfg;
177
178   /**
179    * Function to call on a new incoming request,
180    * or on error.
181    */
182   GNUNET_SET_ListenCallback listen_cb;
183
184   /**
185    * Closure for listen_cb.
186    */
187   void *listen_cls;
188
189   /**
190    * Operation we listen for.
191    */
192   enum GNUNET_SET_OperationType operation;
193
194   /**
195    * Application ID we listen for.
196    */
197   struct GNUNET_HashCode app_id;
198
199   /**
200    * Time to wait until we try to reconnect on failure.
201    */
202   struct GNUNET_TIME_Relative reconnect_backoff;
203 };
204
205
206 /* forward declaration */
207 static void
208 listen_connect (void *cls,
209                 const struct GNUNET_SCHEDULER_TaskContext *tc);
210
211
212 /**
213  * Handle element for iteration over the set.
214  *
215  * @param cls the set
216  * @param mh the message
217  */
218 static void
219 handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh)
220 {
221   struct GNUNET_SET_Handle *set = cls;
222   struct GNUNET_SET_Element element;
223   const struct GNUNET_SET_IterResponseMessage *msg =
224     (const struct GNUNET_SET_IterResponseMessage *) mh;
225   struct GNUNET_SET_IterAckMessage *ack_msg;
226   struct GNUNET_MQ_Envelope *ev;
227
228   if (NULL == set->iterator)
229     return;
230
231   element.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_IterResponseMessage);
232   element.type = htons (msg->element_type);
233   element.data = &msg[1];
234   set->iterator (set->iterator_cls, &element);
235   ev = GNUNET_MQ_msg (ack_msg, GNUNET_MESSAGE_TYPE_SET_ITER_ACK);
236   ack_msg->send_more = htonl (1);
237   GNUNET_MQ_send (set->mq, ev);
238 }
239
240
241 /**
242  * Handle element for iteration over the set.
243  *
244  * @param cls the set
245  * @param mh the message
246  */
247 static void
248 handle_iter_done (void *cls, const struct GNUNET_MessageHeader *mh)
249 {
250   struct GNUNET_SET_Handle *set = cls;
251
252   if (NULL == set->iterator)
253     return;
254
255   set->iterator (set->iterator_cls, NULL);
256 }
257
258
259 /**
260  * Handle result message for a set operation.
261  *
262  * @param cls the set
263  * @param mh the message
264  */
265 static void
266 handle_result (void *cls, const struct GNUNET_MessageHeader *mh)
267 {
268   const struct GNUNET_SET_ResultMessage *msg;
269   struct GNUNET_SET_Handle *set = cls;
270   struct GNUNET_SET_OperationHandle *oh;
271   struct GNUNET_SET_Element e;
272   enum GNUNET_SET_Status result_status;
273
274   msg = (const struct GNUNET_SET_ResultMessage *) mh;
275   GNUNET_assert (NULL != set);
276   GNUNET_assert (NULL != set->mq);
277
278   result_status = ntohs (msg->result_status);
279
280   oh = GNUNET_MQ_assoc_get (set->mq, ntohl (msg->request_id));
281   GNUNET_assert (NULL != oh);
282   /* status is not STATUS_OK => there's no attached element,
283    * and this is the last result message we get */
284   if (GNUNET_SET_STATUS_OK != result_status)
285   {
286     GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
287     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
288     if (GNUNET_YES == oh->set->destroy_requested)
289       GNUNET_SET_destroy (oh->set);
290     if (NULL != oh->result_cb)
291       oh->result_cb (oh->result_cls, NULL, result_status);
292     GNUNET_free (oh);
293     return;
294   }
295
296   e.data = &msg[1];
297   e.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ResultMessage);
298   e.type = msg->element_type;
299   if (NULL != oh->result_cb)
300     oh->result_cb (oh->result_cls, &e, result_status);
301 }
302
303
304 /**
305  * Handle request message for a listen operation
306  *
307  * @param cls the listen handle
308  * @param mh the message
309  */
310 static void
311 handle_request (void *cls, const struct GNUNET_MessageHeader *mh)
312 {
313   struct GNUNET_SET_RequestMessage *msg = (struct GNUNET_SET_RequestMessage *) mh;
314   struct GNUNET_SET_ListenHandle *lh = cls;
315   struct GNUNET_SET_Request *req;
316   struct GNUNET_MessageHeader *context_msg;
317
318   LOG (GNUNET_ERROR_TYPE_DEBUG, "processing operation request\n");
319   req = GNUNET_new (struct GNUNET_SET_Request);
320   req->accept_id = ntohl (msg->accept_id);
321   context_msg = GNUNET_MQ_extract_nested_mh (msg);
322   /* calling GNUNET_SET_accept in the listen cb will set req->accepted */
323   lh->listen_cb (lh->listen_cls, &msg->peer_id, context_msg, req);
324
325   if (GNUNET_NO == req->accepted)
326   {
327     struct GNUNET_MQ_Envelope *mqm;
328     struct GNUNET_SET_AcceptRejectMessage *amsg;
329
330     mqm = GNUNET_MQ_msg (amsg, GNUNET_MESSAGE_TYPE_SET_REJECT);
331     /* no request id, as we refused */
332     amsg->request_id = htonl (0);
333     amsg->accept_reject_id = msg->accept_id;
334     GNUNET_MQ_send (lh->mq, mqm);
335     LOG (GNUNET_ERROR_TYPE_DEBUG, "rejecting request\n");
336   }
337   GNUNET_free (req);
338
339   LOG (GNUNET_ERROR_TYPE_DEBUG, "processed op request from service\n");
340
341   /* the accept-case is handled in GNUNET_SET_accept,
342    * as we have the accept message available there */
343 }
344
345
346 static void
347 handle_client_listener_error (void *cls, enum GNUNET_MQ_Error error)
348 {
349   struct GNUNET_SET_ListenHandle *lh = cls;
350
351   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "listener broke down, re-connecting\n");
352   GNUNET_CLIENT_disconnect (lh->client);
353   lh->client = NULL;
354   GNUNET_MQ_destroy (lh->mq);
355   lh->mq = NULL;
356
357   GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff, listen_connect, lh);
358   lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
359 }
360
361
362 static void
363 handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
364 {
365   struct GNUNET_SET_Handle *set = cls;
366
367   while (NULL != set->ops_head)
368   {
369     if (NULL != set->ops_head->result_cb)
370       set->ops_head->result_cb (set->ops_head->result_cls, NULL,
371                                 GNUNET_SET_STATUS_FAILURE);
372     GNUNET_SET_operation_cancel (set->ops_head);
373   }
374
375   set->invalid = GNUNET_YES;
376 }
377
378
379 /**
380  * Create an empty set, supporting the specified operation.
381  *
382  * @param cfg configuration to use for connecting to the
383  *        set service
384  * @param op operation supported by the set
385  *        Note that the operation has to be specified
386  *        beforehand, as certain set operations need to maintain
387  *        data structures spefific to the operation
388  * @return a handle to the set
389  */
390 struct GNUNET_SET_Handle *
391 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
392                    enum GNUNET_SET_OperationType op)
393 {
394   struct GNUNET_SET_Handle *set;
395   struct GNUNET_MQ_Envelope *mqm;
396   struct GNUNET_SET_CreateMessage *msg;
397   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
398     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
399     {handle_iter_element, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT, 0},
400     {handle_iter_done, GNUNET_MESSAGE_TYPE_SET_ITER_DONE, 0},
401     GNUNET_MQ_HANDLERS_END
402   };
403
404   set = GNUNET_new (struct GNUNET_SET_Handle);
405   set->client = GNUNET_CLIENT_connect ("set", cfg);
406   LOG (GNUNET_ERROR_TYPE_DEBUG, "set client created\n");
407   GNUNET_assert (NULL != set->client);
408   set->mq = GNUNET_MQ_queue_for_connection_client (set->client, mq_handlers,
409                                                    handle_client_set_error, set);
410   GNUNET_assert (NULL != set->mq);
411   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_CREATE);
412   msg->operation = htons (op);
413   GNUNET_MQ_send (set->mq, mqm);
414   return set;
415 }
416
417
418 /**
419  * Add an element to the given set.
420  * After the element has been added (in the sense of being
421  * transmitted to the set service), cont will be called.
422  * Calls to add_element can be queued
423  *
424  * @param set set to add element to
425  * @param element element to add to the set
426  * @param cont continuation called after the element has been added
427  * @param cont_cls closure for cont
428  * @return GNUNET_OK on success, GNUNET_SYSERR if the
429  *         set is invalid (e.g. the set service crashed)
430  */
431 int
432 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
433                         const struct GNUNET_SET_Element *element,
434                         GNUNET_SET_Continuation cont,
435                         void *cont_cls)
436 {
437   struct GNUNET_MQ_Envelope *mqm;
438   struct GNUNET_SET_ElementMessage *msg;
439
440   if (GNUNET_YES == set->invalid)
441   {
442     if (NULL != cont)
443       cont (cont_cls);
444     return GNUNET_SYSERR;
445   }
446
447   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_ADD);
448   msg->element_type = element->type;
449   memcpy (&msg[1], element->data, element->size);
450   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
451   GNUNET_MQ_send (set->mq, mqm);
452   return GNUNET_OK;
453 }
454
455
456 /**
457  * Remove an element to the given set.
458  * After the element has been removed (in the sense of the
459  * request being transmitted to the set service), cont will be called.
460  * Calls to remove_element can be queued
461  *
462  * @param set set to remove element from
463  * @param element element to remove from the set
464  * @param cont continuation called after the element has been removed
465  * @param cont_cls closure for cont
466  * @return GNUNET_OK on success, GNUNET_SYSERR if the
467  *         set is invalid (e.g. the set service crashed)
468  */
469 int
470 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
471                            const struct GNUNET_SET_Element *element,
472                            GNUNET_SET_Continuation cont,
473                            void *cont_cls)
474 {
475   struct GNUNET_MQ_Envelope *mqm;
476   struct GNUNET_SET_ElementMessage *msg;
477
478   if (GNUNET_YES == set->invalid)
479   {
480     if (NULL != cont)
481       cont (cont_cls);
482     return GNUNET_SYSERR;
483   }
484
485   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_REMOVE);
486   msg->element_type = element->type;
487   memcpy (&msg[1], element->data, element->size);
488   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
489   GNUNET_MQ_send (set->mq, mqm);
490   return GNUNET_OK;
491 }
492
493
494 /**
495  * Destroy the set handle, and free all associated resources.
496  */
497 void
498 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
499 {
500   if (NULL != set->ops_head)
501   {
502     set->destroy_requested = GNUNET_YES;
503     return;
504   }
505   GNUNET_CLIENT_disconnect (set->client);
506   set->client = NULL;
507   GNUNET_MQ_destroy (set->mq);
508   set->mq = NULL;
509   GNUNET_free (set);
510 }
511
512
513 /**
514  * Prepare a set operation to be evaluated with another peer.
515  * The evaluation will not start until the client provides
516  * a local set with GNUNET_SET_commit.
517  *
518  * @param other_peer peer with the other set
519  * @param app_id hash for the application using the set
520  * @param context_msg additional information for the request
521  * @param salt salt used for the set operation; sometimes set operations
522  *        fail due to hash collisions, using a different salt for each operation
523  *        makes it harder for an attacker to exploit this
524  * @param result_mode specified how results will be returned,
525  *        see 'GNUNET_SET_ResultMode'.
526  * @param result_cb called on error or success
527  * @param result_cls closure for result_cb
528  * @return a handle to cancel the operation
529  */
530 struct GNUNET_SET_OperationHandle *
531 GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
532                     const struct GNUNET_HashCode *app_id,
533                     const struct GNUNET_MessageHeader *context_msg,
534                     uint16_t salt,
535                     enum GNUNET_SET_ResultMode result_mode,
536                     GNUNET_SET_ResultIterator result_cb,
537                     void *result_cls)
538 {
539   struct GNUNET_MQ_Envelope *mqm;
540   struct GNUNET_SET_OperationHandle *oh;
541   struct GNUNET_SET_EvaluateMessage *msg;
542
543   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
544   oh->result_cb = result_cb;
545   oh->result_cls = result_cls;
546
547   mqm = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_EVALUATE, context_msg);
548
549   msg->app_id = *app_id;
550   msg->target_peer = *other_peer;
551   msg->salt = salt;
552   msg->reserved = 0;
553   oh->conclude_mqm = mqm;
554   oh->request_id_addr = &msg->request_id;
555
556   return oh;
557 }
558
559
560 /**
561  * Connect to the set service in order to listen
562  * for request.
563  *
564  * @param cls the listen handle to connect
565  * @param tc task context if invoked as a task, NULL otherwise
566  */
567 static void
568 listen_connect (void *cls,
569                 const struct GNUNET_SCHEDULER_TaskContext *tc)
570 {
571   struct GNUNET_MQ_Envelope *mqm;
572   struct GNUNET_SET_ListenMessage *msg;
573   struct GNUNET_SET_ListenHandle *lh = cls;
574   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
575     {handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST},
576     GNUNET_MQ_HANDLERS_END
577   };
578
579   GNUNET_assert (NULL == lh->client);
580   lh->client = GNUNET_CLIENT_connect ("set", lh->cfg);
581   if (NULL == lh->client)
582   {
583     LOG (GNUNET_ERROR_TYPE_ERROR,
584          "could not connect to set (wrong configuration?), giving up listening\n");
585     return;
586   }
587   GNUNET_assert (NULL == lh->mq);
588   lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers,
589                                                   handle_client_listener_error, lh);
590   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
591   msg->operation = htonl (lh->operation);
592   msg->app_id = lh->app_id;
593   GNUNET_MQ_send (lh->mq, mqm);
594 }
595
596
597 /**
598  * Wait for set operation requests for the given application id
599  * 
600  * @param cfg configuration to use for connecting to
601  *            the set service, needs to be valid for the lifetime of the listen handle
602  * @param operation operation we want to listen for
603  * @param app_id id of the application that handles set operation requests
604  * @param listen_cb called for each incoming request matching the operation
605  *                  and application id
606  * @param listen_cls handle for listen_cb
607  * @return a handle that can be used to cancel the listen operation
608  */
609 struct GNUNET_SET_ListenHandle *
610 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
611                    enum GNUNET_SET_OperationType operation,
612                    const struct GNUNET_HashCode *app_id,
613                    GNUNET_SET_ListenCallback listen_cb,
614                    void *listen_cls)
615 {
616   struct GNUNET_SET_ListenHandle *lh;
617
618   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
619   lh->listen_cb = listen_cb;
620   lh->listen_cls = listen_cls;
621   lh->cfg = cfg;
622   lh->operation = operation;
623   lh->app_id = *app_id;
624   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
625   listen_connect (lh, NULL);
626   return lh;
627 }
628
629
630 /**
631  * Cancel the given listen operation.
632  *
633  * @param lh handle for the listen operation
634  */
635 void
636 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
637 {
638   LOG (GNUNET_ERROR_TYPE_DEBUG, "canceling listener\n");
639   GNUNET_MQ_destroy (lh->mq);
640   GNUNET_CLIENT_disconnect (lh->client);
641   GNUNET_free (lh);
642 }
643
644
645 /**
646  * Accept a request we got via GNUNET_SET_listen.  Must be called during
647  * GNUNET_SET_listen, as the 'struct GNUNET_SET_Request' becomes invalid
648  * afterwards.
649  * Call GNUNET_SET_conclude to provide the local set to use for the operation,
650  * and to begin the exchange with the remote peer. 
651  *
652  * @param request request to accept
653  * @param result_mode specified how results will be returned,
654  *        see 'GNUNET_SET_ResultMode'.
655  * @param result_cb callback for the results
656  * @param result_cls closure for result_cb
657  * @return a handle to cancel the operation
658  */
659 struct GNUNET_SET_OperationHandle *
660 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
661                    enum GNUNET_SET_ResultMode result_mode,
662                    GNUNET_SET_ResultIterator result_cb,
663                    void *result_cls)
664 {
665   struct GNUNET_MQ_Envelope *mqm;
666   struct GNUNET_SET_OperationHandle *oh;
667   struct GNUNET_SET_AcceptRejectMessage *msg;
668
669   GNUNET_assert (NULL != request);
670   GNUNET_assert (GNUNET_NO == request->accepted);
671   request->accepted = GNUNET_YES;
672
673   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
674   oh->result_cb = result_cb;
675   oh->result_cls = result_cls;
676
677   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
678   msg->accept_reject_id = htonl (request->accept_id);
679
680   oh->conclude_mqm = mqm;
681   oh->request_id_addr = &msg->request_id;
682
683   return oh;
684 }
685
686
687 /**
688  * Cancel the given set operation.
689  * We need to send an explicit cancel message, as
690  * all operations communicate with the set's client
691  * handle.
692  *
693  * @param oh set operation to cancel
694  */
695 void
696 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
697 {
698   if (NULL != oh->conclude_mqm)
699     GNUNET_MQ_discard (oh->conclude_mqm);
700
701   /* is the operation already commited? */
702   if (NULL != oh->set)
703   {
704     struct GNUNET_SET_OperationHandle *h_assoc;
705     struct GNUNET_MQ_Envelope *mqm;
706
707     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
708     h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
709     GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
710     mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
711     GNUNET_MQ_send (oh->set->mq, mqm);
712
713     if (GNUNET_YES == oh->set->destroy_requested)
714       GNUNET_SET_destroy (oh->set);
715   }
716
717   GNUNET_free (oh);
718 }
719
720
721 /**
722  * Commit a set to be used with a set operation.
723  * This function is called once we have fully constructed
724  * the set that we want to use for the operation.  At this
725  * time, the P2P protocol can then begin to exchange the
726  * set information and call the result callback with the
727  * result information.
728  *
729  * @param oh handle to the set operation 
730  * @param set the set to use for the operation
731  * @return GNUNET_OK on success, GNUNET_SYSERR if the
732  *         set is invalid (e.g. the set service crashed)
733  */
734 int
735 GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
736                    struct GNUNET_SET_Handle *set)
737 {
738   GNUNET_assert (NULL == oh->set);
739   if (GNUNET_YES == set->invalid)
740     return GNUNET_SYSERR;
741   GNUNET_assert (NULL != oh->conclude_mqm);
742   oh->set = set;
743   GNUNET_CONTAINER_DLL_insert (set->ops_head, set->ops_tail, oh);
744   oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
745   *oh->request_id_addr = htonl (oh->request_id);
746   GNUNET_MQ_send (set->mq, oh->conclude_mqm);
747   oh->conclude_mqm = NULL;
748   oh->request_id_addr = NULL;
749   return GNUNET_OK;
750 }
751
752
753 /**
754  * Iterate over all elements in the given set.
755  * Note that this operation involves transferring every element of the set
756  * from the service to the client, and is thus costly.
757  *
758  * @param set the set to iterate over
759  * @param iter the iterator to call for each element
760  * @param cls closure for 'iter'
761  * @return GNUNET_YES if the iteration started successfuly,
762  *         GNUNET_NO if another iteration is active
763  *         GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
764  */
765 int
766 GNUNET_SET_iterate (struct GNUNET_SET_Handle *set, GNUNET_SET_ElementIterator iter, void *cls)
767 {
768   struct GNUNET_MQ_Envelope *ev;
769
770   GNUNET_assert (NULL != iter);
771
772   if (GNUNET_YES == set->invalid)
773     return GNUNET_SYSERR;
774   if (NULL != set->iterator)
775     return GNUNET_NO;
776
777   set->iterator = iter;
778   set->iterator_cls = cls;
779   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
780   GNUNET_MQ_send (set->mq, ev);
781   return GNUNET_YES;
782 }
783