3e317a9390b0add76cb940f2aae383d98d37cb9f
[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    * Function to call on a new incoming request,
173    * or on error.
174    */
175   GNUNET_SET_ListenCallback listen_cb;
176
177   /**
178    * Closure for listen_cb.
179    */
180   void *listen_cls;
181 };
182
183
184 /**
185  * Handle element for iteration over the set.
186  *
187  * @param cls the set
188  * @param mh the message
189  */
190 static void
191 handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh)
192 {
193   struct GNUNET_SET_Handle *set = cls;
194   struct GNUNET_SET_Element element;
195   const struct GNUNET_SET_IterResponseMessage *msg =
196     (const struct GNUNET_SET_IterResponseMessage *) mh;
197
198   if (NULL == set->iterator)
199     return;
200
201   element.type = htons (mh->type);
202   element.data = &msg[1];
203   set->iterator (set->iterator_cls, &element);
204 }
205
206
207 /**
208  * Handle element for iteration over the set.
209  *
210  * @param cls the set
211  * @param mh the message
212  */
213 static void
214 handle_iter_done (void *cls, const struct GNUNET_MessageHeader *mh)
215 {
216   struct GNUNET_SET_Handle *set = cls;
217
218   if (NULL == set->iterator)
219     return;
220
221   set->iterator (set->iterator_cls, NULL);
222 }
223
224
225 /**
226  * Handle result message for a set operation.
227  *
228  * @param cls the set
229  * @param mh the message
230  */
231 static void
232 handle_result (void *cls, const struct GNUNET_MessageHeader *mh)
233 {
234   const struct GNUNET_SET_ResultMessage *msg;
235   struct GNUNET_SET_Handle *set = cls;
236   struct GNUNET_SET_OperationHandle *oh;
237   struct GNUNET_SET_Element e;
238   enum GNUNET_SET_Status result_status;
239
240   msg = (const struct GNUNET_SET_ResultMessage *) mh;
241   GNUNET_assert (NULL != set);
242   GNUNET_assert (NULL != set->mq);
243
244   result_status = ntohs (msg->result_status);
245
246   oh = GNUNET_MQ_assoc_get (set->mq, ntohl (msg->request_id));
247   GNUNET_assert (NULL != oh);
248   /* status is not STATUS_OK => there's no attached element,
249    * and this is the last result message we get */
250   if (GNUNET_SET_STATUS_OK != result_status)
251   {
252     GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
253     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
254     if (GNUNET_YES == oh->set->destroy_requested)
255       GNUNET_SET_destroy (oh->set);
256     if (NULL != oh->result_cb)
257       oh->result_cb (oh->result_cls, NULL, result_status);
258     GNUNET_free (oh);
259     return;
260   }
261
262   e.data = &msg[1];
263   e.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ResultMessage);
264   e.type = msg->element_type;
265   if (NULL != oh->result_cb)
266     oh->result_cb (oh->result_cls, &e, result_status);
267 }
268
269 /**
270  * Handle request message for a listen operation
271  *
272  * @param cls the listen handle
273  * @param mh the message
274  */
275 static void
276 handle_request (void *cls, const struct GNUNET_MessageHeader *mh)
277 {
278   struct GNUNET_SET_RequestMessage *msg = (struct GNUNET_SET_RequestMessage *) mh;
279   struct GNUNET_SET_ListenHandle *lh = cls;
280   struct GNUNET_SET_Request *req;
281   struct GNUNET_MessageHeader *context_msg;
282
283   LOG (GNUNET_ERROR_TYPE_DEBUG, "processing operation request\n");
284   req = GNUNET_new (struct GNUNET_SET_Request);
285   req->accept_id = ntohl (msg->accept_id);
286   context_msg = GNUNET_MQ_extract_nested_mh (msg);
287   /* calling GNUNET_SET_accept in the listen cb will set req->accepted */
288   lh->listen_cb (lh->listen_cls, &msg->peer_id, context_msg, req);
289
290   if (GNUNET_NO == req->accepted)
291   {
292     struct GNUNET_MQ_Envelope *mqm;
293     struct GNUNET_SET_AcceptRejectMessage *amsg;
294
295     mqm = GNUNET_MQ_msg (amsg, GNUNET_MESSAGE_TYPE_SET_REJECT);
296     /* no request id, as we refused */
297     amsg->request_id = htonl (0);
298     amsg->accept_reject_id = msg->accept_id;
299     GNUNET_MQ_send (lh->mq, mqm);
300     GNUNET_free (req);
301     LOG (GNUNET_ERROR_TYPE_DEBUG, "rejecting request\n");
302   }
303
304   LOG (GNUNET_ERROR_TYPE_DEBUG, "processed op request from service\n");
305
306   /* the accept-case is handled in GNUNET_SET_accept,
307    * as we have the accept message available there */
308 }
309
310
311 static void
312 handle_client_listener_error (void *cls, enum GNUNET_MQ_Error error)
313 {
314   struct GNUNET_SET_ListenHandle *lh = cls;
315
316   /* FIXME: why do you do this? */
317   lh->listen_cb (lh->listen_cls, NULL, NULL, NULL);
318 }
319
320
321 static void
322 handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
323 {
324   struct GNUNET_SET_Handle *set = cls;
325
326   while (NULL != set->ops_head)
327   {
328     if (NULL != set->ops_head->result_cb)
329       set->ops_head->result_cb (set->ops_head->result_cls, NULL,
330                                 GNUNET_SET_STATUS_FAILURE);
331     GNUNET_SET_operation_cancel (set->ops_head);
332   }
333
334   set->invalid = GNUNET_YES;
335 }
336
337
338 /**
339  * Create an empty set, supporting the specified operation.
340  *
341  * @param cfg configuration to use for connecting to the
342  *        set service
343  * @param op operation supported by the set
344  *        Note that the operation has to be specified
345  *        beforehand, as certain set operations need to maintain
346  *        data structures spefific to the operation
347  * @return a handle to the set
348  */
349 struct GNUNET_SET_Handle *
350 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
351                    enum GNUNET_SET_OperationType op)
352 {
353   struct GNUNET_SET_Handle *set;
354   struct GNUNET_MQ_Envelope *mqm;
355   struct GNUNET_SET_CreateMessage *msg;
356   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
357     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
358     {handle_iter_element, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT, 0},
359     {handle_iter_done, GNUNET_MESSAGE_TYPE_SET_ITER_DONE, 0},
360     GNUNET_MQ_HANDLERS_END
361   };
362
363   set = GNUNET_new (struct GNUNET_SET_Handle);
364   set->client = GNUNET_CLIENT_connect ("set", cfg);
365   LOG (GNUNET_ERROR_TYPE_DEBUG, "set client created\n");
366   GNUNET_assert (NULL != set->client);
367   set->mq = GNUNET_MQ_queue_for_connection_client (set->client, mq_handlers,
368                                                    handle_client_set_error, set);
369   GNUNET_assert (NULL != set->mq);
370   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_CREATE);
371   msg->operation = htons (op);
372   GNUNET_MQ_send (set->mq, mqm);
373   return set;
374 }
375
376
377 /**
378  * Add an element to the given set.
379  * After the element has been added (in the sense of being
380  * transmitted to the set service), cont will be called.
381  * Calls to add_element can be queued
382  *
383  * @param set set to add element to
384  * @param element element to add to the set
385  * @param cont continuation called after the element has been added
386  * @param cont_cls closure for cont
387  * @return GNUNET_OK on success, GNUNET_SYSERR if the
388  *         set is invalid (e.g. the set service crashed)
389  */
390 int
391 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
392                         const struct GNUNET_SET_Element *element,
393                         GNUNET_SET_Continuation cont,
394                         void *cont_cls)
395 {
396   struct GNUNET_MQ_Envelope *mqm;
397   struct GNUNET_SET_ElementMessage *msg;
398
399   if (GNUNET_YES == set->invalid)
400   {
401     if (NULL != cont)
402       cont (cont_cls);
403     return GNUNET_SYSERR;
404   }
405
406   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_ADD);
407   msg->element_type = element->type;
408   memcpy (&msg[1], element->data, element->size);
409   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
410   GNUNET_MQ_send (set->mq, mqm);
411   return GNUNET_OK;
412 }
413
414
415 /**
416  * Remove an element to the given set.
417  * After the element has been removed (in the sense of the
418  * request being transmitted to the set service), cont will be called.
419  * Calls to remove_element can be queued
420  *
421  * @param set set to remove element from
422  * @param element element to remove from the set
423  * @param cont continuation called after the element has been removed
424  * @param cont_cls closure for cont
425  * @return GNUNET_OK on success, GNUNET_SYSERR if the
426  *         set is invalid (e.g. the set service crashed)
427  */
428 int
429 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
430                            const struct GNUNET_SET_Element *element,
431                            GNUNET_SET_Continuation cont,
432                            void *cont_cls)
433 {
434   struct GNUNET_MQ_Envelope *mqm;
435   struct GNUNET_SET_ElementMessage *msg;
436
437   if (GNUNET_YES == set->invalid)
438   {
439     if (NULL != cont)
440       cont (cont_cls);
441     return GNUNET_SYSERR;
442   }
443
444   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_REMOVE);
445   msg->element_type = element->type;
446   memcpy (&msg[1], element->data, element->size);
447   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
448   GNUNET_MQ_send (set->mq, mqm);
449   return GNUNET_OK;
450 }
451
452
453 /**
454  * Destroy the set handle, and free all associated resources.
455  */
456 void
457 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
458 {
459   if (NULL != set->ops_head)
460   {
461     set->destroy_requested = GNUNET_YES;
462     return;
463   }
464   GNUNET_CLIENT_disconnect (set->client);
465   set->client = NULL;
466   GNUNET_MQ_destroy (set->mq);
467   set->mq = NULL;
468 }
469
470
471 /**
472  * Prepare a set operation to be evaluated with another peer.
473  * The evaluation will not start until the client provides
474  * a local set with GNUNET_SET_commit.
475  *
476  * @param other_peer peer with the other set
477  * @param app_id hash for the application using the set
478  * @param context_msg additional information for the request
479  * @param salt salt used for the set operation; sometimes set operations
480  *        fail due to hash collisions, using a different salt for each operation
481  *        makes it harder for an attacker to exploit this
482  * @param result_mode specified how results will be returned,
483  *        see 'GNUNET_SET_ResultMode'.
484  * @param result_cb called on error or success
485  * @param result_cls closure for result_cb
486  * @return a handle to cancel the operation
487  */
488 struct GNUNET_SET_OperationHandle *
489 GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
490                     const struct GNUNET_HashCode *app_id,
491                     const struct GNUNET_MessageHeader *context_msg,
492                     uint16_t salt,
493                     enum GNUNET_SET_ResultMode result_mode,
494                     GNUNET_SET_ResultIterator result_cb,
495                     void *result_cls)
496 {
497   struct GNUNET_MQ_Envelope *mqm;
498   struct GNUNET_SET_OperationHandle *oh;
499   struct GNUNET_SET_EvaluateMessage *msg;
500
501   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
502   oh->result_cb = result_cb;
503   oh->result_cls = result_cls;
504
505   mqm = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_EVALUATE, context_msg);
506
507   msg->app_id = *app_id;
508   msg->target_peer = *other_peer;
509   msg->salt = salt;
510   msg->reserved = 0;
511   oh->conclude_mqm = mqm;
512   oh->request_id_addr = &msg->request_id;
513
514   return oh;
515 }
516
517 /**
518  * Wait for set operation requests for the given application id
519  * 
520  * @param cfg configuration to use for connecting to
521  *            the set service
522  * @param operation operation we want to listen for
523  * @param app_id id of the application that handles set operation requests
524  * @param listen_cb called for each incoming request matching the operation
525  *                  and application id
526  * @param listen_cls handle for listen_cb
527  * @return a handle that can be used to cancel the listen operation
528  */
529 struct GNUNET_SET_ListenHandle *
530 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
531                    enum GNUNET_SET_OperationType operation,
532                    const struct GNUNET_HashCode *app_id,
533                    GNUNET_SET_ListenCallback listen_cb,
534                    void *listen_cls)
535 {
536   struct GNUNET_SET_ListenHandle *lh;
537   struct GNUNET_MQ_Envelope *mqm;
538   struct GNUNET_SET_ListenMessage *msg;
539   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
540     {handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST},
541     GNUNET_MQ_HANDLERS_END
542   };
543
544   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
545   lh->client = GNUNET_CLIENT_connect ("set", cfg);
546   lh->listen_cb = listen_cb;
547   lh->listen_cls = listen_cls;
548   GNUNET_assert (NULL != lh->client);
549   lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers,
550                                                   handle_client_listener_error, lh);
551   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
552   msg->operation = htons (operation);
553   msg->app_id = *app_id;
554   GNUNET_MQ_send (lh->mq, mqm);
555
556   return lh;
557 }
558
559
560 /**
561  * Cancel the given listen operation.
562  *
563  * @param lh handle for the listen operation
564  */
565 void
566 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
567 {
568   LOG (GNUNET_ERROR_TYPE_DEBUG, "canceling listener\n");
569   GNUNET_MQ_destroy (lh->mq);
570   GNUNET_CLIENT_disconnect (lh->client);
571   GNUNET_free (lh);
572 }
573
574
575 /**
576  * Accept a request we got via GNUNET_SET_listen.  Must be called during
577  * GNUNET_SET_listen, as the 'struct GNUNET_SET_Request' becomes invalid
578  * afterwards.
579  * Call GNUNET_SET_conclude to provide the local set to use for the operation,
580  * and to begin the exchange with the remote peer. 
581  *
582  * @param request request to accept
583  * @param result_mode specified how results will be returned,
584  *        see 'GNUNET_SET_ResultMode'.
585  * @param result_cb callback for the results
586  * @param result_cls closure for result_cb
587  * @return a handle to cancel the operation
588  */
589 struct GNUNET_SET_OperationHandle *
590 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
591                    enum GNUNET_SET_ResultMode result_mode,
592                    GNUNET_SET_ResultIterator result_cb,
593                    void *result_cls)
594 {
595   struct GNUNET_MQ_Envelope *mqm;
596   struct GNUNET_SET_OperationHandle *oh;
597   struct GNUNET_SET_AcceptRejectMessage *msg;
598
599   GNUNET_assert (NULL != request);
600   GNUNET_assert (GNUNET_NO == request->accepted);
601   request->accepted = GNUNET_YES;
602
603   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
604   oh->result_cb = result_cb;
605   oh->result_cls = result_cls;
606
607   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
608   msg->accept_reject_id = htonl (request->accept_id);
609
610   oh->conclude_mqm = mqm;
611   oh->request_id_addr = &msg->request_id;
612
613   return oh;
614 }
615
616
617 /**
618  * Cancel the given set operation.
619  * We need to send an explicit cancel message, as
620  * all operations communicate with the set's client
621  * handle.
622  *
623  * @param oh set operation to cancel
624  */
625 void
626 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
627 {
628   if (NULL != oh->conclude_mqm)
629     GNUNET_MQ_discard (oh->conclude_mqm);
630
631   /* is the operation already commited? */
632   if (NULL != oh->set)
633   {
634     struct GNUNET_SET_OperationHandle *h_assoc;
635     struct GNUNET_MQ_Envelope *mqm;
636
637     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
638     h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
639     GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
640     mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
641     GNUNET_MQ_send (oh->set->mq, mqm);
642
643     if (GNUNET_YES == oh->set->destroy_requested)
644       GNUNET_SET_destroy (oh->set);
645   }
646
647   GNUNET_free (oh);
648 }
649
650
651 /**
652  * Commit a set to be used with a set operation.
653  * This function is called once we have fully constructed
654  * the set that we want to use for the operation.  At this
655  * time, the P2P protocol can then begin to exchange the
656  * set information and call the result callback with the
657  * result information.
658  *
659  * @param oh handle to the set operation 
660  * @param set the set to use for the operation
661  * @return GNUNET_OK on success, GNUNET_SYSERR if the
662  *         set is invalid (e.g. the set service crashed)
663  */
664 int
665 GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
666                    struct GNUNET_SET_Handle *set)
667 {
668   GNUNET_assert (NULL == oh->set);
669   if (GNUNET_YES == set->invalid)
670     return GNUNET_SYSERR;
671   GNUNET_assert (NULL != oh->conclude_mqm);
672   oh->set = set;
673   GNUNET_CONTAINER_DLL_insert (set->ops_head, set->ops_tail, oh);
674   oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
675   *oh->request_id_addr = htonl (oh->request_id);
676   GNUNET_MQ_send (set->mq, oh->conclude_mqm);
677   oh->conclude_mqm = NULL;
678   oh->request_id_addr = NULL;
679   return GNUNET_OK;
680 }
681
682
683
684 /**
685  * Iterate over all elements in the given set.
686  * Note that this operation involves transferring every element of the set
687  * from the service to the client, and is thus costly.
688  *
689  * @param set the set to iterate over
690  * @param iter the iterator to call for each element
691  * @param cls closure for 'iter'
692  * @return GNUNET_YES if the iteration started successfuly,
693  *         GNUNET_NO if another iteration is active
694  *         GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
695  */
696 int
697 GNUNET_SET_iterate (struct GNUNET_SET_Handle *set, GNUNET_SET_ElementIterator iter, void *cls)
698 {
699   struct GNUNET_MQ_Envelope *ev;
700
701   GNUNET_assert (NULL != iter);
702
703   if (GNUNET_YES == set->invalid)
704     return GNUNET_SYSERR;
705   if (NULL != set->iterator)
706     return GNUNET_NO;
707
708   set->iterator = iter;
709   set->iterator_cls = cls;
710   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
711   GNUNET_MQ_send (set->mq, ev);
712   return GNUNET_YES;
713 }
714