88f334cbcf2eef5eae9f1c0ebbd7bc67ed6a35a7
[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
73 /**
74  * Opaque handle to a set operation request from another peer.
75  */
76 struct GNUNET_SET_Request
77 {
78   /**
79    * Id of the request, used to identify the request when
80    * accepting/rejecting it.
81    */
82   uint32_t accept_id;
83
84   /**
85    * Has the request been accepted already?
86    * GNUNET_YES/GNUNET_NO
87    */
88   int accepted;
89 };
90
91
92 /**
93  * Handle to an operation.
94  * Only known to the service after commiting
95  * the handle with a set.
96  */
97 struct GNUNET_SET_OperationHandle
98 {
99   /**
100    * Function to be called when we have a result,
101    * or an error.
102    */
103   GNUNET_SET_ResultIterator result_cb;
104
105   /**
106    * Closure for result_cb.
107    */
108   void *result_cls;
109
110   /**
111    * Local set used for the operation,
112    * NULL if no set has been provided by conclude yet.
113    */
114   struct GNUNET_SET_Handle *set;
115
116   /**
117    * Request ID to identify the operation within the set.
118    */
119   uint32_t request_id;
120
121   /**
122    * Message sent to the server on calling conclude,
123    * NULL if conclude has been called.
124    */
125   struct GNUNET_MQ_Envelope *conclude_mqm;
126
127   /**
128    * Address of the request if in the conclude message,
129    * used to patch the request id into the message when the set is known.
130    */
131   uint32_t *request_id_addr;
132
133   /**
134    * Handles are kept in a linked list.
135    */
136   struct GNUNET_SET_OperationHandle *prev;
137
138   /**
139    * Handles are kept in a linked list.
140    */
141   struct GNUNET_SET_OperationHandle *next;
142 };
143
144
145 /**
146  * Opaque handle to a listen operation.
147  */
148 struct GNUNET_SET_ListenHandle
149 {
150   /**
151    * Connection to the service.
152    */
153   struct GNUNET_CLIENT_Connection *client;
154
155   /**
156    * Message queue for the client.
157    */
158   struct GNUNET_MQ_Handle* mq;
159
160   /**
161    * Function to call on a new incoming request,
162    * or on error.
163    */
164   GNUNET_SET_ListenCallback listen_cb;
165
166   /**
167    * Closure for listen_cb.
168    */
169   void *listen_cls;
170 };
171
172
173 /**
174  * Handle result message for a set operation.
175  *
176  * @param cls the set
177  * @param mh the message
178  */
179 static void
180 handle_result (void *cls, const struct GNUNET_MessageHeader *mh)
181 {
182   const struct GNUNET_SET_ResultMessage *msg;
183   struct GNUNET_SET_Handle *set = cls;
184   struct GNUNET_SET_OperationHandle *oh;
185   struct GNUNET_SET_Element e;
186   enum GNUNET_SET_Status result_status;
187
188   msg = (const struct GNUNET_SET_ResultMessage *) mh;
189   GNUNET_assert (NULL != set);
190   GNUNET_assert (NULL != set->mq);
191
192   result_status = ntohs (msg->result_status);
193
194   oh = GNUNET_MQ_assoc_get (set->mq, ntohl (msg->request_id));
195   GNUNET_assert (NULL != oh);
196   /* status is not STATUS_OK => there's no attached element,
197    * and this is the last result message we get */
198   if (GNUNET_SET_STATUS_OK != result_status)
199   {
200     GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
201     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
202     if (GNUNET_YES == oh->set->destroy_requested)
203       GNUNET_SET_destroy (oh->set);
204     if (NULL != oh->result_cb)
205       oh->result_cb (oh->result_cls, NULL, result_status);
206     GNUNET_free (oh);
207     return;
208   }
209
210   e.data = &msg[1];
211   e.size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ResultMessage);
212   e.type = msg->element_type;
213   if (NULL != oh->result_cb)
214     oh->result_cb (oh->result_cls, &e, result_status);
215 }
216
217 /**
218  * Handle request message for a listen operation
219  *
220  * @param cls the listen handle
221  * @param mh the message
222  */
223 static void
224 handle_request (void *cls, const struct GNUNET_MessageHeader *mh)
225 {
226   struct GNUNET_SET_RequestMessage *msg = (struct GNUNET_SET_RequestMessage *) mh;
227   struct GNUNET_SET_ListenHandle *lh = cls;
228   struct GNUNET_SET_Request *req;
229   struct GNUNET_MessageHeader *context_msg;
230
231   LOG (GNUNET_ERROR_TYPE_DEBUG, "processing operation request\n");
232   req = GNUNET_new (struct GNUNET_SET_Request);
233   req->accept_id = ntohl (msg->accept_id);
234   context_msg = GNUNET_MQ_extract_nested_mh (msg);
235   /* calling GNUNET_SET_accept in the listen cb will set req->accepted */
236   lh->listen_cb (lh->listen_cls, &msg->peer_id, context_msg, req);
237
238   if (GNUNET_NO == req->accepted)
239   {
240     struct GNUNET_MQ_Envelope *mqm;
241     struct GNUNET_SET_AcceptRejectMessage *amsg;
242
243     mqm = GNUNET_MQ_msg (amsg, GNUNET_MESSAGE_TYPE_SET_REJECT);
244     /* no request id, as we refused */
245     amsg->request_id = htonl (0);
246     amsg->accept_reject_id = msg->accept_id;
247     GNUNET_MQ_send (lh->mq, mqm);
248     GNUNET_free (req);
249     LOG (GNUNET_ERROR_TYPE_DEBUG, "rejecting request\n");
250   }
251
252   LOG (GNUNET_ERROR_TYPE_DEBUG, "processed op request from service\n");
253
254   /* the accept-case is handled in GNUNET_SET_accept,
255    * as we have the accept message available there */
256 }
257
258
259 static void
260 handle_client_listener_error (void *cls, enum GNUNET_MQ_Error error)
261 {
262   struct GNUNET_SET_ListenHandle *lh = cls;
263
264   lh->listen_cb (lh->listen_cls, NULL, NULL, NULL);
265 }
266
267
268 static void
269 handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
270 {
271   struct GNUNET_SET_Handle *set = cls;
272
273   while (NULL != set->ops_head)
274   {
275     if (NULL != set->ops_head->result_cb)
276       set->ops_head->result_cb (set->ops_head->result_cls, NULL,
277                                 GNUNET_SET_STATUS_FAILURE);
278     GNUNET_SET_operation_cancel (set->ops_head);
279   }
280
281   set->invalid = GNUNET_YES;
282 }
283
284
285 /**
286  * Create an empty set, supporting the specified operation.
287  *
288  * @param cfg configuration to use for connecting to the
289  *        set service
290  * @param op operation supported by the set
291  *        Note that the operation has to be specified
292  *        beforehand, as certain set operations need to maintain
293  *        data structures spefific to the operation
294  * @return a handle to the set
295  */
296 struct GNUNET_SET_Handle *
297 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
298                    enum GNUNET_SET_OperationType op)
299 {
300   struct GNUNET_SET_Handle *set;
301   struct GNUNET_MQ_Envelope *mqm;
302   struct GNUNET_SET_CreateMessage *msg;
303   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
304     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
305     GNUNET_MQ_HANDLERS_END
306   };
307
308   set = GNUNET_new (struct GNUNET_SET_Handle);
309   set->client = GNUNET_CLIENT_connect ("set", cfg);
310   LOG (GNUNET_ERROR_TYPE_DEBUG, "set client created\n");
311   GNUNET_assert (NULL != set->client);
312   set->mq = GNUNET_MQ_queue_for_connection_client (set->client, mq_handlers,
313                                                    handle_client_set_error, set);
314   GNUNET_assert (NULL != set->mq);
315   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_CREATE);
316   msg->operation = htons (op);
317   GNUNET_MQ_send (set->mq, mqm);
318   return set;
319 }
320
321
322 /**
323  * Add an element to the given set.
324  * After the element has been added (in the sense of being
325  * transmitted to the set service), cont will be called.
326  * Calls to add_element can be queued
327  *
328  * @param set set to add element to
329  * @param element element to add to the set
330  * @param cont continuation called after the element has been added
331  * @param cont_cls closure for cont
332  * @return GNUNET_OK on success, GNUNET_SYSERR if the
333  *         set is invalid (e.g. the set service crashed)
334  */
335 int
336 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
337                         const struct GNUNET_SET_Element *element,
338                         GNUNET_SET_Continuation cont,
339                         void *cont_cls)
340 {
341   struct GNUNET_MQ_Envelope *mqm;
342   struct GNUNET_SET_ElementMessage *msg;
343
344   if (GNUNET_YES == set->invalid)
345   {
346     if (NULL != cont)
347       cont (cont_cls);
348     return GNUNET_SYSERR;
349   }
350
351   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_ADD);
352   msg->element_type = element->type;
353   memcpy (&msg[1], element->data, element->size);
354   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
355   GNUNET_MQ_send (set->mq, mqm);
356   return GNUNET_OK;
357 }
358
359
360 /**
361  * Remove an element to the given set.
362  * After the element has been removed (in the sense of the
363  * request being transmitted to the set service), cont will be called.
364  * Calls to remove_element can be queued
365  *
366  * @param set set to remove element from
367  * @param element element to remove from the set
368  * @param cont continuation called after the element has been removed
369  * @param cont_cls closure for cont
370  * @return GNUNET_OK on success, GNUNET_SYSERR if the
371  *         set is invalid (e.g. the set service crashed)
372  */
373 int
374 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
375                            const struct GNUNET_SET_Element *element,
376                            GNUNET_SET_Continuation cont,
377                            void *cont_cls)
378 {
379   struct GNUNET_MQ_Envelope *mqm;
380   struct GNUNET_SET_ElementMessage *msg;
381
382   if (GNUNET_YES == set->invalid)
383   {
384     if (NULL != cont)
385       cont (cont_cls);
386     return GNUNET_SYSERR;
387   }
388
389   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_REMOVE);
390   msg->element_type = element->type;
391   memcpy (&msg[1], element->data, element->size);
392   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
393   GNUNET_MQ_send (set->mq, mqm);
394   return GNUNET_OK;
395 }
396
397
398 /**
399  * Destroy the set handle, and free all associated resources.
400  */
401 void
402 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
403 {
404   if (NULL != set->ops_head)
405   {
406     set->destroy_requested = GNUNET_YES;
407     return;
408   }
409   GNUNET_CLIENT_disconnect (set->client);
410   set->client = NULL;
411   GNUNET_MQ_destroy (set->mq);
412   set->mq = NULL;
413 }
414
415
416 /**
417  * Prepare a set operation to be evaluated with another peer.
418  * The evaluation will not start until the client provides
419  * a local set with GNUNET_SET_commit.
420  *
421  * @param other_peer peer with the other set
422  * @param app_id hash for the application using the set
423  * @param context_msg additional information for the request
424  * @param salt salt used for the set operation; sometimes set operations
425  *        fail due to hash collisions, using a different salt for each operation
426  *        makes it harder for an attacker to exploit this
427  * @param result_mode specified how results will be returned,
428  *        see 'GNUNET_SET_ResultMode'.
429  * @param result_cb called on error or success
430  * @param result_cls closure for result_cb
431  * @return a handle to cancel the operation
432  */
433 struct GNUNET_SET_OperationHandle *
434 GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
435                     const struct GNUNET_HashCode *app_id,
436                     const struct GNUNET_MessageHeader *context_msg,
437                     uint16_t salt,
438                     enum GNUNET_SET_ResultMode result_mode,
439                     GNUNET_SET_ResultIterator result_cb,
440                     void *result_cls)
441 {
442   struct GNUNET_MQ_Envelope *mqm;
443   struct GNUNET_SET_OperationHandle *oh;
444   struct GNUNET_SET_EvaluateMessage *msg;
445
446   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
447   oh->result_cb = result_cb;
448   oh->result_cls = result_cls;
449
450   mqm = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_EVALUATE, context_msg);
451
452   msg->app_id = *app_id;
453   msg->target_peer = *other_peer;
454   msg->salt = salt;
455   msg->reserved = 0;
456   oh->conclude_mqm = mqm;
457   oh->request_id_addr = &msg->request_id;
458
459   return oh;
460 }
461
462 /**
463  * Wait for set operation requests for the given application id
464  * 
465  * @param cfg configuration to use for connecting to
466  *            the set service
467  * @param operation operation we want to listen for
468  * @param app_id id of the application that handles set operation requests
469  * @param listen_cb called for each incoming request matching the operation
470  *                  and application id
471  * @param listen_cls handle for listen_cb
472  * @return a handle that can be used to cancel the listen operation
473  */
474 struct GNUNET_SET_ListenHandle *
475 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
476                    enum GNUNET_SET_OperationType operation,
477                    const struct GNUNET_HashCode *app_id,
478                    GNUNET_SET_ListenCallback listen_cb,
479                    void *listen_cls)
480 {
481   struct GNUNET_SET_ListenHandle *lh;
482   struct GNUNET_MQ_Envelope *mqm;
483   struct GNUNET_SET_ListenMessage *msg;
484   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
485     {handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST},
486     GNUNET_MQ_HANDLERS_END
487   };
488
489   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
490   lh->client = GNUNET_CLIENT_connect ("set", cfg);
491   lh->listen_cb = listen_cb;
492   lh->listen_cls = listen_cls;
493   GNUNET_assert (NULL != lh->client);
494   lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers,
495                                                   handle_client_listener_error, lh);
496   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
497   msg->operation = htons (operation);
498   msg->app_id = *app_id;
499   GNUNET_MQ_send (lh->mq, mqm);
500
501   return lh;
502 }
503
504
505 /**
506  * Cancel the given listen operation.
507  *
508  * @param lh handle for the listen operation
509  */
510 void
511 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
512 {
513   GNUNET_CLIENT_disconnect (lh->client);
514   GNUNET_MQ_destroy (lh->mq);
515   GNUNET_free (lh);
516 }
517
518
519 /**
520  * Accept a request we got via GNUNET_SET_listen.  Must be called during
521  * GNUNET_SET_listen, as the 'struct GNUNET_SET_Request' becomes invalid
522  * afterwards.
523  * Call GNUNET_SET_conclude to provide the local set to use for the operation,
524  * and to begin the exchange with the remote peer. 
525  *
526  * @param request request to accept
527  * @param result_mode specified how results will be returned,
528  *        see 'GNUNET_SET_ResultMode'.
529  * @param result_cb callback for the results
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_accept (struct GNUNET_SET_Request *request,
535                    enum GNUNET_SET_ResultMode result_mode,
536                    GNUNET_SET_ResultIterator result_cb,
537                    void *result_cls)
538 {
539   struct GNUNET_MQ_Envelope *mqm;
540   struct GNUNET_SET_OperationHandle *oh;
541   struct GNUNET_SET_AcceptRejectMessage *msg;
542
543   GNUNET_assert (NULL != request);
544   GNUNET_assert (GNUNET_NO == request->accepted);
545   request->accepted = GNUNET_YES;
546
547   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
548   oh->result_cb = result_cb;
549   oh->result_cls = result_cls;
550
551   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
552   msg->accept_reject_id = htonl (request->accept_id);
553
554   oh->conclude_mqm = mqm;
555   oh->request_id_addr = &msg->request_id;
556
557   return oh;
558 }
559
560
561 /**
562  * Cancel the given set operation.
563  * We need to send an explicit cancel message, as
564  * all operations communicate with the set's client
565  * handle.
566  *
567  * @param oh set operation to cancel
568  */
569 void
570 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
571 {
572   if (NULL != oh->conclude_mqm)
573     GNUNET_MQ_discard (oh->conclude_mqm);
574
575   /* is the operation already commited? */
576   if (NULL != oh->set)
577   {
578     struct GNUNET_SET_OperationHandle *h_assoc;
579     struct GNUNET_MQ_Envelope *mqm;
580
581     GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
582     h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
583     GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
584     mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
585     GNUNET_MQ_send (oh->set->mq, mqm);
586
587     if (GNUNET_YES == oh->set->destroy_requested)
588       GNUNET_SET_destroy (oh->set);
589   }
590
591   GNUNET_free (oh);
592 }
593
594
595 /**
596  * Commit a set to be used with a set operation.
597  * This function is called once we have fully constructed
598  * the set that we want to use for the operation.  At this
599  * time, the P2P protocol can then begin to exchange the
600  * set information and call the result callback with the
601  * result information.
602  *
603  * @param oh handle to the set operation 
604  * @param set the set to use for the operation
605  * @return GNUNET_OK on success, GNUNET_SYSERR if the
606  *         set is invalid (e.g. the set service crashed)
607  */
608 int
609 GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
610                    struct GNUNET_SET_Handle *set)
611 {
612   GNUNET_assert (NULL == oh->set);
613   if (GNUNET_YES == set->invalid)
614     return GNUNET_SYSERR;
615   GNUNET_assert (NULL != oh->conclude_mqm);
616   oh->set = set;
617   GNUNET_CONTAINER_DLL_insert (set->ops_head, set->ops_tail, oh);
618   oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh);
619   *oh->request_id_addr = htonl (oh->request_id);
620   GNUNET_MQ_send (set->mq, oh->conclude_mqm);
621   oh->conclude_mqm = NULL;
622   oh->request_id_addr = NULL;
623   return GNUNET_OK;
624 }
625