-doxygen fixes
[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   const struct GNUNET_SET_RequestMessage *msg = (const 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   /* we got another request => reset the backoff */
326   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
327
328   if (GNUNET_NO == req->accepted)
329   {
330     struct GNUNET_MQ_Envelope *mqm;
331     struct GNUNET_SET_AcceptRejectMessage *amsg;
332
333     mqm = GNUNET_MQ_msg (amsg, GNUNET_MESSAGE_TYPE_SET_REJECT);
334     /* no request id, as we refused */
335     amsg->request_id = htonl (0);
336     amsg->accept_reject_id = msg->accept_id;
337     GNUNET_MQ_send (lh->mq, mqm);
338     LOG (GNUNET_ERROR_TYPE_DEBUG, "rejecting request\n");
339   }
340   GNUNET_free (req);
341
342   LOG (GNUNET_ERROR_TYPE_DEBUG, "processed op request from service\n");
343
344   /* the accept-case is handled in GNUNET_SET_accept,
345    * as we have the accept message available there */
346 }
347
348
349 static void
350 handle_client_listener_error (void *cls, enum GNUNET_MQ_Error error)
351 {
352   struct GNUNET_SET_ListenHandle *lh = cls;
353
354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "listener broke down, re-connecting\n");
355   GNUNET_CLIENT_disconnect (lh->client);
356   lh->client = NULL;
357   GNUNET_MQ_destroy (lh->mq);
358   lh->mq = NULL;
359
360   GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff, listen_connect, lh);
361   lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
362 }
363
364
365 static void
366 handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
367 {
368   struct GNUNET_SET_Handle *set = cls;
369
370   while (NULL != set->ops_head)
371   {
372     if (NULL != set->ops_head->result_cb)
373       set->ops_head->result_cb (set->ops_head->result_cls, NULL,
374                                 GNUNET_SET_STATUS_FAILURE);
375     GNUNET_SET_operation_cancel (set->ops_head);
376   }
377
378   set->invalid = GNUNET_YES;
379 }
380
381
382 /**
383  * Create an empty set, supporting the specified operation.
384  *
385  * @param cfg configuration to use for connecting to the
386  *        set service
387  * @param op operation supported by the set
388  *        Note that the operation has to be specified
389  *        beforehand, as certain set operations need to maintain
390  *        data structures spefific to the operation
391  * @return a handle to the set
392  */
393 struct GNUNET_SET_Handle *
394 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
395                    enum GNUNET_SET_OperationType op)
396 {
397   struct GNUNET_SET_Handle *set;
398   struct GNUNET_MQ_Envelope *mqm;
399   struct GNUNET_SET_CreateMessage *msg;
400   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
401     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
402     {handle_iter_element, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT, 0},
403     {handle_iter_done, GNUNET_MESSAGE_TYPE_SET_ITER_DONE, 0},
404     GNUNET_MQ_HANDLERS_END
405   };
406
407   set = GNUNET_new (struct GNUNET_SET_Handle);
408   set->client = GNUNET_CLIENT_connect ("set", cfg);
409   LOG (GNUNET_ERROR_TYPE_DEBUG, "set client created\n");
410   GNUNET_assert (NULL != set->client);
411   set->mq = GNUNET_MQ_queue_for_connection_client (set->client, mq_handlers,
412                                                    handle_client_set_error, set);
413   GNUNET_assert (NULL != set->mq);
414   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_CREATE);
415   msg->operation = htons (op);
416   GNUNET_MQ_send (set->mq, mqm);
417   return set;
418 }
419
420
421 /**
422  * Add an element to the given set.
423  * After the element has been added (in the sense of being
424  * transmitted to the set service), cont will be called.
425  * Calls to add_element can be queued
426  *
427  * @param set set to add element to
428  * @param element element to add to the set
429  * @param cont continuation called after the element has been added
430  * @param cont_cls closure for @a cont
431  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
432  *         set is invalid (e.g. the set service crashed)
433  */
434 int
435 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
436                         const struct GNUNET_SET_Element *element,
437                         GNUNET_SET_Continuation cont,
438                         void *cont_cls)
439 {
440   struct GNUNET_MQ_Envelope *mqm;
441   struct GNUNET_SET_ElementMessage *msg;
442
443   if (GNUNET_YES == set->invalid)
444   {
445     if (NULL != cont)
446       cont (cont_cls);
447     return GNUNET_SYSERR;
448   }
449
450   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_ADD);
451   msg->element_type = element->type;
452   memcpy (&msg[1], element->data, element->size);
453   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
454   GNUNET_MQ_send (set->mq, mqm);
455   return GNUNET_OK;
456 }
457
458
459 /**
460  * Remove an element to the given set.
461  * After the element has been removed (in the sense of the
462  * request being transmitted to the set service), cont will be called.
463  * Calls to remove_element can be queued
464  *
465  * @param set set to remove element from
466  * @param element element to remove from the set
467  * @param cont continuation called after the element has been removed
468  * @param cont_cls closure for cont
469  * @return GNUNET_OK on success, GNUNET_SYSERR if the
470  *         set is invalid (e.g. the set service crashed)
471  */
472 int
473 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
474                            const struct GNUNET_SET_Element *element,
475                            GNUNET_SET_Continuation cont,
476                            void *cont_cls)
477 {
478   struct GNUNET_MQ_Envelope *mqm;
479   struct GNUNET_SET_ElementMessage *msg;
480
481   if (GNUNET_YES == set->invalid)
482   {
483     if (NULL != cont)
484       cont (cont_cls);
485     return GNUNET_SYSERR;
486   }
487
488   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_REMOVE);
489   msg->element_type = element->type;
490   memcpy (&msg[1], element->data, element->size);
491   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
492   GNUNET_MQ_send (set->mq, mqm);
493   return GNUNET_OK;
494 }
495
496
497 /**
498  * Destroy the set handle, and free all associated resources.
499  */
500 void
501 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
502 {
503   if (NULL != set->ops_head)
504   {
505     set->destroy_requested = GNUNET_YES;
506     return;
507   }
508   GNUNET_CLIENT_disconnect (set->client);
509   set->client = NULL;
510   GNUNET_MQ_destroy (set->mq);
511   set->mq = NULL;
512   GNUNET_free (set);
513 }
514
515
516 /**
517  * Prepare a set operation to be evaluated with another peer.
518  * The evaluation will not start until the client provides
519  * a local set with GNUNET_SET_commit.
520  *
521  * @param other_peer peer with the other set
522  * @param app_id hash for the application using the set
523  * @param context_msg additional information for the request
524  * @param salt salt used for the set operation; sometimes set operations
525  *        fail due to hash collisions, using a different salt for each operation
526  *        makes it harder for an attacker to exploit this
527  * @param result_mode specified how results will be returned,
528  *        see 'GNUNET_SET_ResultMode'.
529  * @param result_cb called on error or success
530  * @param result_cls closure for result_cb
531  * @return a handle to cancel the operation
532  */
533 struct GNUNET_SET_OperationHandle *
534 GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
535                     const struct GNUNET_HashCode *app_id,
536                     const struct GNUNET_MessageHeader *context_msg,
537                     uint16_t salt,
538                     enum GNUNET_SET_ResultMode result_mode,
539                     GNUNET_SET_ResultIterator result_cb,
540                     void *result_cls)
541 {
542   struct GNUNET_MQ_Envelope *mqm;
543   struct GNUNET_SET_OperationHandle *oh;
544   struct GNUNET_SET_EvaluateMessage *msg;
545
546   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
547   oh->result_cb = result_cb;
548   oh->result_cls = result_cls;
549
550   mqm = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_EVALUATE, context_msg);
551
552   msg->app_id = *app_id;
553   msg->target_peer = *other_peer;
554   msg->salt = salt;
555   msg->reserved = 0;
556   oh->conclude_mqm = mqm;
557   oh->request_id_addr = &msg->request_id;
558
559   return oh;
560 }
561
562
563 /**
564  * Connect to the set service in order to listen
565  * for request.
566  *
567  * @param cls the listen handle to connect
568  * @param tc task context if invoked as a task, NULL otherwise
569  */
570 static void
571 listen_connect (void *cls,
572                 const struct GNUNET_SCHEDULER_TaskContext *tc)
573 {
574   struct GNUNET_MQ_Envelope *mqm;
575   struct GNUNET_SET_ListenMessage *msg;
576   struct GNUNET_SET_ListenHandle *lh = cls;
577   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
578     {handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST},
579     GNUNET_MQ_HANDLERS_END
580   };
581
582   GNUNET_assert (NULL == lh->client);
583   lh->client = GNUNET_CLIENT_connect ("set", lh->cfg);
584   if (NULL == lh->client)
585   {
586     LOG (GNUNET_ERROR_TYPE_ERROR,
587          "could not connect to set (wrong configuration?), giving up listening\n");
588     return;
589   }
590   GNUNET_assert (NULL == lh->mq);
591   lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers,
592                                                   handle_client_listener_error, lh);
593   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
594   msg->operation = htonl (lh->operation);
595   msg->app_id = lh->app_id;
596   GNUNET_MQ_send (lh->mq, mqm);
597 }
598
599
600 /**
601  * Wait for set operation requests for the given application id
602  *
603  * @param cfg configuration to use for connecting to
604  *            the set service, needs to be valid for the lifetime of the listen handle
605  * @param operation operation we want to listen for
606  * @param app_id id of the application that handles set operation requests
607  * @param listen_cb called for each incoming request matching the operation
608  *                  and application id
609  * @param listen_cls handle for listen_cb
610  * @return a handle that can be used to cancel the listen operation
611  */
612 struct GNUNET_SET_ListenHandle *
613 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
614                    enum GNUNET_SET_OperationType operation,
615                    const struct GNUNET_HashCode *app_id,
616                    GNUNET_SET_ListenCallback listen_cb,
617                    void *listen_cls)
618 {
619   struct GNUNET_SET_ListenHandle *lh;
620
621   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
622   lh->listen_cb = listen_cb;
623   lh->listen_cls = listen_cls;
624   lh->cfg = cfg;
625   lh->operation = operation;
626   lh->app_id = *app_id;
627   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
628   listen_connect (lh, NULL);
629   return lh;
630 }
631
632
633 /**
634  * Cancel the given listen operation.
635  *
636  * @param lh handle for the listen operation
637  */
638 void
639 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
640 {
641   LOG (GNUNET_ERROR_TYPE_DEBUG, "canceling listener\n");
642   GNUNET_MQ_destroy (lh->mq);
643   GNUNET_CLIENT_disconnect (lh->client);
644   GNUNET_free (lh);
645 }
646
647
648 /**
649  * Accept a request we got via #GNUNET_SET_listen.  Must be called during
650  * #GNUNET_SET_listen, as the 'struct GNUNET_SET_Request' becomes invalid
651  * afterwards.
652  * Call #GNUNET_SET_commit to provide the local set to use for the operation,
653  * and to begin the exchange with the remote peer.
654  *
655  * @param request request to accept
656  * @param result_mode specified how results will be returned,
657  *        see 'GNUNET_SET_ResultMode'.
658  * @param result_cb callback for the results
659  * @param result_cls closure for result_cb
660  * @return a handle to cancel the operation
661  */
662 struct GNUNET_SET_OperationHandle *
663 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
664                    enum GNUNET_SET_ResultMode result_mode,
665                    GNUNET_SET_ResultIterator result_cb,
666                    void *result_cls)
667 {
668   struct GNUNET_MQ_Envelope *mqm;
669   struct GNUNET_SET_OperationHandle *oh;
670   struct GNUNET_SET_AcceptRejectMessage *msg;
671
672   GNUNET_assert (NULL != request);
673   GNUNET_assert (GNUNET_NO == request->accepted);
674   request->accepted = GNUNET_YES;
675
676   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
677   oh->result_cb = result_cb;
678   oh->result_cls = result_cls;
679
680   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
681   msg->accept_reject_id = htonl (request->accept_id);
682
683   oh->conclude_mqm = mqm;
684   oh->request_id_addr = &msg->request_id;
685
686   return oh;
687 }
688
689
690 /**
691  * Cancel the given set operation.
692  * We need to send an explicit cancel message, as
693  * all operations communicate with the set's client
694  * handle.
695  *
696  * @param oh set operation to cancel
697  */
698 void
699 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
700 {
701   if (NULL != oh->conclude_mqm)
702     GNUNET_MQ_discard (oh->conclude_mqm);
703
704   /* is the operation already commited? */
705   if (NULL != oh->set)
706   {
707     struct GNUNET_SET_OperationHandle *h_assoc;
708     struct GNUNET_MQ_Envelope *mqm;
709
710     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
711     h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
712     GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
713     mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
714     GNUNET_MQ_send (oh->set->mq, mqm);
715
716     if (GNUNET_YES == oh->set->destroy_requested)
717       GNUNET_SET_destroy (oh->set);
718   }
719
720   GNUNET_free (oh);
721 }
722
723
724 /**
725  * Commit a set to be used with a set operation.
726  * This function is called once we have fully constructed
727  * the set that we want to use for the operation.  At this
728  * time, the P2P protocol can then begin to exchange the
729  * set information and call the result callback with the
730  * result information.
731  *
732  * @param oh handle to the set operation
733  * @param set the set to use for the operation
734  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
735  *         set is invalid (e.g. the set service crashed)
736  */
737 int
738 GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
739                    struct GNUNET_SET_Handle *set)
740 {
741   GNUNET_assert (NULL == oh->set);
742   if (GNUNET_YES == set->invalid)
743     return GNUNET_SYSERR;
744   GNUNET_assert (NULL != oh->conclude_mqm);
745   oh->set = set;
746   GNUNET_CONTAINER_DLL_insert (set->ops_head, set->ops_tail, oh);
747   oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
748   *oh->request_id_addr = htonl (oh->request_id);
749   GNUNET_MQ_send (set->mq, oh->conclude_mqm);
750   oh->conclude_mqm = NULL;
751   oh->request_id_addr = NULL;
752   return GNUNET_OK;
753 }
754
755
756 /**
757  * Iterate over all elements in the given set.
758  * Note that this operation involves transferring every element of the set
759  * from the service to the client, and is thus costly.
760  *
761  * @param set the set to iterate over
762  * @param iter the iterator to call for each element
763  * @param cls closure for @a iter
764  * @return #GNUNET_YES if the iteration started successfuly,
765  *         #GNUNET_NO if another iteration is active
766  *         #GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
767  */
768 int
769 GNUNET_SET_iterate (struct GNUNET_SET_Handle *set, GNUNET_SET_ElementIterator iter, void *cls)
770 {
771   struct GNUNET_MQ_Envelope *ev;
772
773   GNUNET_assert (NULL != iter);
774
775   if (GNUNET_YES == set->invalid)
776     return GNUNET_SYSERR;
777   if (NULL != set->iterator)
778     return GNUNET_NO;
779
780   set->iterator = iter;
781   set->iterator_cls = cls;
782   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
783   GNUNET_MQ_send (set->mq, ev);
784   return GNUNET_YES;
785 }
786
787 /* end of set_api.c */