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