-cleanup and some remarks
[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   struct GNUNET_CLIENT_Connection *client;
42   struct GNUNET_MQ_MessageQueue *mq;
43   unsigned int messages_since_ack;
44 };
45
46 /**
47  * Opaque handle to a set operation request from another peer.
48  */
49 struct GNUNET_SET_Request
50 {
51   uint32_t accept_id;
52   int accepted;
53 };
54
55
56 struct GNUNET_SET_OperationHandle
57 {
58   GNUNET_SET_ResultIterator result_cb;
59   void *result_cls;
60   struct GNUNET_SET_Handle *set;
61   uint32_t request_id;
62 };
63
64
65 /**
66  * Opaque handle to a listen operation.
67  */
68 struct GNUNET_SET_ListenHandle
69 {
70   struct GNUNET_CLIENT_Connection *client;
71   struct GNUNET_MQ_MessageQueue* mq;
72   GNUNET_SET_ListenCallback listen_cb;
73   void *listen_cls;
74 };
75
76
77 /**
78  * Handle result message for a set operation.
79  *
80  * @param cls the set
81  * @param mh the message
82  */
83 static void
84 handle_result (void *cls, const struct GNUNET_MessageHeader *mh)
85 {
86   struct ResultMessage *msg = (struct ResultMessage *) mh;
87   struct GNUNET_SET_Handle *set = cls;
88   struct GNUNET_SET_OperationHandle *oh;
89   struct GNUNET_SET_Element e;
90
91   if (set->messages_since_ack >= GNUNET_SET_ACK_WINDOW/2)
92   {
93     struct GNUNET_MQ_Message *mqm;
94     mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ACK);
95     GNUNET_MQ_send (set->mq, mqm);
96   }
97
98   oh = GNUNET_MQ_assoc_get (set->mq, ntohl (msg->request_id));
99   GNUNET_assert (NULL != oh);
100   /* status is not STATUS_OK => there's no attached element,
101    * and this is the last result message we get */
102   if (htons (msg->result_status) != GNUNET_SET_STATUS_OK)
103   {
104     GNUNET_MQ_assoc_remove (set->mq, ntohl (msg->request_id));
105     if (NULL != oh->result_cb)
106       oh->result_cb (oh->result_cls, NULL, htons (msg->result_status));
107     GNUNET_free (oh);
108     return;
109   }
110
111   e.data = &msg[1];
112   e.size = ntohs (mh->size) - sizeof (struct ResultMessage);
113   e.type = msg->element_type;
114   if (NULL != oh->result_cb)
115     oh->result_cb (oh->result_cls, &e, htons (msg->result_status));
116 }
117
118 /**
119  * Handle request message for a listen operation
120  *
121  * @param cls the listen handle
122  * @param mh the message
123  */
124 static void
125 handle_request (void *cls, const struct GNUNET_MessageHeader *mh)
126 {
127   struct RequestMessage *msg = (struct RequestMessage *) mh;
128   struct GNUNET_SET_ListenHandle *lh = cls;
129   struct GNUNET_SET_Request *req;
130
131   req = GNUNET_new (struct GNUNET_SET_Request);
132   req->accept_id = ntohl (msg->accept_id);
133   /* calling GNUNET_SET_accept in the listen cb will set req->accepted */
134   lh->listen_cb (lh->listen_cls, &msg->peer_id, &mh[1], req);
135
136   if (GNUNET_NO == req->accepted)
137   {
138     struct GNUNET_MQ_Message *mqm;
139     struct AcceptMessage *amsg;
140     
141     mqm = GNUNET_MQ_msg (amsg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
142     /* no request id, as we refused */
143     amsg->request_id = htonl (0);
144     amsg->accept_id = msg->accept_id;
145     GNUNET_MQ_send (lh->mq, mqm);
146     GNUNET_free (req);
147   }
148
149   /* the accept-case is handled in GNUNET_SET_accept,
150    * as we have the accept message available there */
151 }
152
153
154 /**
155  * Create an empty set, supporting the specified operation.
156  *
157  * @param cfg configuration to use for connecting to the
158  *        set service
159  * @param op operation supported by the set
160  *        Note that the operation has to be specified
161  *        beforehand, as certain set operations need to maintain
162  *        data structures spefific to the operation
163  * @return a handle to the set
164  */
165 struct GNUNET_SET_Handle *
166 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
167                    enum GNUNET_SET_OperationType op)
168 {
169   struct GNUNET_SET_Handle *set;
170   struct GNUNET_MQ_Message *mqm;
171   struct SetCreateMessage *msg;
172   static const struct GNUNET_MQ_Handler mq_handlers[] = {
173     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT},
174     GNUNET_MQ_HANDLERS_END
175   };
176
177   set = GNUNET_new (struct GNUNET_SET_Handle);
178   set->client = GNUNET_CLIENT_connect ("set", cfg);
179   LOG (GNUNET_ERROR_TYPE_INFO, "set client created\n");
180   GNUNET_assert (NULL != set->client);
181   set->mq = GNUNET_MQ_queue_for_connection_client (set->client, mq_handlers, set);
182   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_CREATE);
183   msg->operation = htons (op);
184   GNUNET_MQ_send (set->mq, mqm);
185   return set;
186 }
187
188
189 /**
190  * Add an element to the given set.
191  * After the element has been added (in the sense of being
192  * transmitted to the set service), cont will be called.
193  * Calls to add_element can be queued
194  *
195  * @param set set to add element to
196  * @param element element to add to the set
197  * @param cont continuation called after the element has been added
198  * @param cont_cls closure for cont
199  */
200 void
201 GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
202                         const struct GNUNET_SET_Element *element,
203                         GNUNET_SET_Continuation cont,
204                         void *cont_cls)
205 {
206   struct GNUNET_MQ_Message *mqm;
207   struct ElementMessage *msg;
208
209   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_ADD);
210   msg->element_type = element->type;
211   memcpy (&msg[1], element->data, element->size);
212   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
213   GNUNET_MQ_send (set->mq, mqm);
214 }
215
216
217 /**
218  * Remove an element to the given set.
219  * After the element has been removed (in the sense of the
220  * request being transmitted to the set service), cont will be called.
221  * Calls to remove_element can be queued
222  *
223  * @param set set to remove element from
224  * @param element element to remove from the set
225  * @param cont continuation called after the element has been removed
226  * @param cont_cls closure for cont
227  */
228 void
229 GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
230                            const struct GNUNET_SET_Element *element,
231                            GNUNET_SET_Continuation cont,
232                            void *cont_cls)
233 {
234   struct GNUNET_MQ_Message *mqm;
235   struct ElementMessage *msg;
236
237   mqm = GNUNET_MQ_msg_extra (msg, element->size, GNUNET_MESSAGE_TYPE_SET_REMOVE);
238   msg->element_type = element->type;
239   memcpy (&msg[1], element->data, element->size);
240   GNUNET_MQ_notify_sent (mqm, cont, cont_cls);
241   GNUNET_MQ_send (set->mq, mqm);
242 }
243
244
245 /**
246  * Destroy the set handle, and free all associated resources.
247  */
248 void
249 GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
250 {
251   GNUNET_CLIENT_disconnect (set->client);
252   set->client = NULL;
253   GNUNET_MQ_destroy (set->mq);
254   set->mq = NULL;
255 }
256
257
258 /**
259  * Evaluate a set operation with our set and the set of another peer.
260  *
261  * @param set set to use
262  * @param salt salt for HKDF (explain more here)
263  * @param other_peer peer with the other set
264  * @param app_id hash for the application using the set
265  * @param context_msg additional information for the request
266  * @param salt salt used for the set operation; sometimes set operations
267  *        fail due to hash collisions, using a different salt for each operation
268  *        makes it harder for an attacker to exploit this
269  * @param result_mode specified how results will be returned,
270  *        see 'GNUNET_SET_ResultMode'.
271  * @param result_cb called on error or success
272  * @param result_cls closure for result_cb
273  * @return a handle to cancel the operation
274  */
275 struct GNUNET_SET_OperationHandle *
276 GNUNET_SET_evaluate (struct GNUNET_SET_Handle *set,
277                      const struct GNUNET_PeerIdentity *other_peer,
278                      const struct GNUNET_HashCode *app_id,
279                      const struct GNUNET_MessageHeader *context_msg,
280                      uint16_t salt,
281                      enum GNUNET_SET_ResultMode result_mode,
282                      GNUNET_SET_ResultIterator result_cb,
283                      void *result_cls)
284 {
285   struct GNUNET_MQ_Message *mqm;
286   struct EvaluateMessage *msg;
287   struct GNUNET_SET_OperationHandle *oh;
288
289   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
290   oh->result_cb = result_cb;
291   oh->result_cls = result_cls;
292   oh->set = set;
293
294   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_EVALUATE);
295   msg->request_id = htonl (GNUNET_MQ_assoc_add (set->mq, mqm, oh));
296   msg->peer = *other_peer;
297   msg->app_id = *app_id;
298   
299   if (NULL != context_msg)
300     if (GNUNET_OK != GNUNET_MQ_nest (mqm, context_msg, ntohs (context_msg->size)))
301       GNUNET_assert (0);
302   
303   GNUNET_MQ_send (set->mq, mqm);
304
305   return oh;
306 }
307
308
309 /**
310  * Wait for set operation requests for the given application id
311  * 
312  * @param cfg configuration to use for connecting to
313  *            the set service
314  * @param operation operation we want to listen for
315  * @param app_id id of the application that handles set operation requests
316  * @param listen_cb called for each incoming request matching the operation
317  *                  and application id
318  * @param listen_cls handle for listen_cb
319  * @return a handle that can be used to cancel the listen operation
320  */
321 struct GNUNET_SET_ListenHandle *
322 GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
323                    enum GNUNET_SET_OperationType operation,
324                    const struct GNUNET_HashCode *app_id,
325                    GNUNET_SET_ListenCallback listen_cb,
326                    void *listen_cls)
327 {
328   struct GNUNET_SET_ListenHandle *lh;
329   struct GNUNET_MQ_Message *mqm;
330   struct ListenMessage *msg;
331   static const struct GNUNET_MQ_Handler mq_handlers[] = {
332     {handle_request, GNUNET_MESSAGE_TYPE_SET_REQUEST},
333     GNUNET_MQ_HANDLERS_END
334   };
335
336   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
337   lh->client = GNUNET_CLIENT_connect ("set", cfg);
338   lh->listen_cb = listen_cb;
339   lh->listen_cls = listen_cls;
340   GNUNET_assert (NULL != lh->client);
341   lh->mq = GNUNET_MQ_queue_for_connection_client (lh->client, mq_handlers, lh);
342   mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_LISTEN);
343   msg->operation = htons (operation);
344   msg->app_id = *app_id;
345   GNUNET_MQ_send (lh->mq, mqm);
346
347   return lh;
348 }
349
350
351 /**
352  * Cancel the given listen operation.
353  *
354  * @param lh handle for the listen operation
355  */
356 void
357 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
358 {
359   GNUNET_CLIENT_disconnect (lh->client);
360   GNUNET_MQ_destroy (lh->mq);
361   GNUNET_free (lh);
362 }
363
364
365 /**
366  * Accept a request we got via GNUNET_SET_listen.
367  *
368  * @param request request to accept
369  * @param set set used for the requested operation 
370  * @param result_mode specified how results will be returned,
371  *        see 'GNUNET_SET_ResultMode'.
372  * @param result_cb callback for the results
373  * @param result_cls closure for result_cb
374  * @return a handle to cancel the operation
375  */
376 struct GNUNET_SET_OperationHandle *
377 GNUNET_SET_accept (struct GNUNET_SET_Request *request,
378                    struct GNUNET_SET_Handle *set,
379                    enum GNUNET_SET_ResultMode result_mode,
380                    GNUNET_SET_ResultIterator result_cb,
381                    void *result_cls)
382 {
383   struct GNUNET_MQ_Message *mqm;
384   struct AcceptMessage *msg;
385   struct GNUNET_SET_OperationHandle *oh;
386
387   /* don't accept a request twice! */
388   GNUNET_assert (GNUNET_NO == request->accepted);
389   request->accepted = GNUNET_YES;
390
391   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
392   oh->result_cb = result_cb;
393   oh->result_cls = result_cls;
394   oh->set = set;
395
396   mqm = GNUNET_MQ_msg (msg , GNUNET_MESSAGE_TYPE_SET_ACCEPT);
397   msg->request_id = htonl (GNUNET_MQ_assoc_add (set->mq, NULL, oh));
398   msg->accept_id = htonl (request->accept_id);
399   GNUNET_MQ_send (set->mq, mqm);
400
401   return oh;
402 }
403
404
405 /**
406  * Cancel the given set operation.
407  *
408  * @param oh set operation to cancel
409  */
410 void
411 GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
412 {
413   struct GNUNET_MQ_Message *mqm;
414   struct GNUNET_SET_OperationHandle *h_assoc;
415
416   h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
417   GNUNET_assert (h_assoc == oh);
418   mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
419   GNUNET_MQ_send (oh->set->mq, mqm);
420   GNUNET_free (oh);
421 }
422