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