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