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