implemented most parts of the set service
[oweals/gnunet.git] / src / set / gnunet-service-set.c
1 /*
2       This file is part of GNUnet
3       (C) 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 2, 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/gnunet-service-set.c
23  * @brief two-peer set operations
24  * @author Florian Dold
25  */
26
27
28 #include "gnunet-service-set.h"
29 #include "set_protocol.h"
30
31
32 /**
33  * Configuration of our local peer.
34  */
35 const struct GNUNET_CONFIGURATION_Handle *configuration;
36
37 /**
38  * Socket listening for other peers via stream.
39  */
40 static struct GNUNET_STREAM_ListenSocket *stream_listen_socket;
41
42 /**
43  * Sets are held in a doubly linked list.
44  */
45 static struct Set *sets_head;
46
47 /**
48  * Sets are held in a doubly linked list.
49  */
50 static struct Set *sets_tail;
51
52 /**
53  * Listeners are held in a doubly linked list.
54  */
55 static struct Listener *listeners_head;
56
57 /**
58  * Listeners are held in a doubly linked list.
59  */
60 static struct Listener *listeners_tail;
61
62 /**
63  * Incoming sockets from remote peers are
64  * held in a doubly linked list.
65  */
66 static struct Incoming *incoming_head;
67
68 /**
69  * Incoming sockets from remote peers are
70  * held in a doubly linked list.
71  */
72 static struct Incoming *incoming_tail;
73
74 /**
75  * Counter for allocating unique request IDs for clients.
76  * Used to identify incoming requests from remote peers.
77  */
78 static uint32_t request_id = 1;
79
80
81 /**
82  * Disconnect a client and free all resources
83  * that the client allocated (e.g. Sets or Listeners)
84  *
85  * @param client the client to disconnect
86  */
87 void
88 _GSS_client_disconnect (struct GNUNET_SERVER_Client *client)
89 {
90   /* FIXME: clean up any data structures belonging to the client */
91   GNUNET_SERVER_client_disconnect (client);
92 }
93
94
95 /**
96  * Get set that is owned by the client, if any.
97  *
98  * @param client client to look for
99  * @return set that the client owns, NULL if the client
100  *         does not own a set
101  */
102 static struct Set *
103 get_set (struct GNUNET_SERVER_Client *client)
104 {
105   struct Set *set;
106   for (set = sets_head; NULL != set; set = set->next)
107     if (set->client == client)
108       return set;
109   return NULL;
110 }
111
112
113 /**
114  * Get the listener associated to a client, if any.
115  *
116  * @param client the client
117  * @return listener associated with the client, NULL
118  *         if there isn't any
119  */
120 static struct Listener *
121 get_listener (struct GNUNET_SERVER_Client *client)
122 {
123   struct Listener *listener;
124   for (listener = listeners_head; NULL != listener; listener = listener->next)
125     if (listener->client == client)
126       return listener;
127   return NULL;
128 }
129
130
131 /**
132  * Get the incoming socket associated with the given id.
133  *
134  * @param id id to look for
135  * @return the incoming socket associated with the id,
136  *         or NULL if there is none
137  */
138 static struct Incoming *
139 get_incoming (uint32_t id)
140 {
141   struct Incoming *incoming;
142   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
143     if (incoming->request_id == id)
144       return incoming;
145   return NULL;
146 }
147
148
149 static void
150 destroy_incoming (struct Incoming *incoming)
151 {
152   if (NULL != incoming->mq)
153   {
154     GNUNET_MQ_destroy (incoming->mq);
155     incoming->mq = NULL;
156   }
157   if (NULL != incoming->socket)
158   {
159     GNUNET_STREAM_close (incoming->socket);
160     incoming->socket = NULL;
161   }
162   GNUNET_CONTAINER_DLL_remove (incoming_head, incoming_tail, incoming);
163   GNUNET_free (incoming);
164 }
165
166
167 /**
168  * Handle a request for a set operation from
169  * another peer.
170  *
171  * @param cls the incoming socket
172  * @param mh the message
173  */
174 static void
175 handle_p2p_operation_request (void *cls, const struct GNUNET_MessageHeader *mh)
176 {
177   struct Incoming *incoming = cls;
178   const struct OperationRequestMessage *msg = (const struct OperationRequestMessage *) mh;
179   struct GNUNET_MQ_Message *mqm;
180   struct RequestMessage *cmsg;
181   struct Listener *listener;
182   const struct GNUNET_MessageHeader *context_msg;
183
184   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got operation request\n");
185
186   if (ntohs (mh->size) < sizeof *msg)
187   {
188     GNUNET_break (0);
189     destroy_incoming (incoming);
190     return;
191   }
192   else if (ntohs (mh->size) == sizeof *msg)
193   {
194     context_msg = NULL;
195   }
196   else
197   {
198     context_msg = &msg[1].header;
199     if ((ntohs (context_msg->size) + sizeof *msg) != ntohs (msg->header.size))
200     {
201       /* size of context message is invalid */
202       GNUNET_break (0);
203       destroy_incoming (incoming);
204       return;
205     }
206   }
207   /* find the appropriate listener */
208   for (listener = listeners_head;
209        listener != NULL;
210        listener = listener->next)
211   {
212     if ( (0 != GNUNET_CRYPTO_hash_cmp (&msg->app_id, &listener->app_id)) ||
213          (htons (msg->operation) != listener->operation) )
214       continue;
215     mqm = GNUNET_MQ_msg (cmsg, GNUNET_MESSAGE_TYPE_SET_REQUEST);
216     if (GNUNET_OK != GNUNET_MQ_nest_mh (mqm, context_msg))
217     {
218       /* FIXME: disconnect the peer */
219       GNUNET_MQ_discard (mqm);
220       GNUNET_break (0);
221       return;
222     }
223     incoming->request_id = request_id++;
224     cmsg->request_id = htonl (incoming->request_id);
225     GNUNET_MQ_send (listener->client_mq, mqm);
226     return;
227   }
228   /* FIXME: send a reject message */
229 }
230
231
232 /**
233  * Called when a client wants to create a new set.
234  *
235  * @param cls unused
236  * @param client client that sent the message
237  * @param m message sent by the client
238  */
239 static void
240 handle_client_create (void *cls,
241                       struct GNUNET_SERVER_Client *client,
242                       const struct GNUNET_MessageHeader *m)
243 {
244   struct SetCreateMessage *msg = (struct SetCreateMessage *) m;
245   struct Set *set;
246
247   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new set created\n");
248
249   if (NULL != get_set (client))
250   {
251     GNUNET_break (0);
252     GNUNET_SERVER_client_disconnect (client);
253     return;
254   }
255
256   set = GNUNET_new (struct Set);
257
258   switch (ntohs (msg->operation))
259   {
260     case GNUNET_SET_OPERATION_INTERSECTION:
261       /* FIXME: cfuchs */
262       GNUNET_assert (0);
263       break;
264     case GNUNET_SET_OPERATION_UNION:
265       set = _GSS_union_set_create ();
266       break;
267     default:
268       GNUNET_free (set);
269       GNUNET_break (0);
270       GNUNET_SERVER_client_disconnect (client);
271       return;
272   }
273
274   set->client = client;
275   set->client_mq = GNUNET_MQ_queue_for_server_client (client);
276   GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
277   
278   GNUNET_SERVER_receive_done (client, GNUNET_OK);
279 }
280
281
282 /**
283  * Called when a client wants to create a new listener.
284  *
285  * @param cls unused
286  * @param client client that sent the message
287  * @param m message sent by the client
288  */
289 static void
290 handle_client_listen (void *cls,
291                       struct GNUNET_SERVER_Client *client,
292                       const struct GNUNET_MessageHeader *m)
293 {
294   struct ListenMessage *msg = (struct ListenMessage *) m;
295   struct Listener *listener;
296   
297   if (NULL != get_listener (client))
298   {
299     GNUNET_break (0);
300     GNUNET_SERVER_client_disconnect (client);
301     return;
302   }
303   
304   listener = GNUNET_new (struct Listener);
305   listener->app_id = msg->app_id;
306   listener->operation = msg->operation;
307   GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
308
309   GNUNET_SERVER_receive_done (client, GNUNET_OK);
310 }
311
312
313 /**
314  * Called when a client wants to remove an element
315  * from the set it inhabits.
316  *
317  * @param cls unused
318  * @param client client that sent the message
319  * @param m message sent by the client
320  */
321 static void
322 handle_client_remove (void *cls,
323                       struct GNUNET_SERVER_Client *client,
324                       const struct GNUNET_MessageHeader *m)
325 {
326   struct Set *set;
327
328   set = get_set (client);
329   if (NULL == set)
330   {
331     GNUNET_break (0);
332     _GSS_client_disconnect (client);
333     return;
334   }
335   switch (set->operation)
336   {
337     case GNUNET_SET_OPERATION_UNION:
338       _GSS_union_add ((struct ElementMessage *) m, set);
339     case GNUNET_SET_OPERATION_INTERSECTION:
340       /* FIXME: cfuchs */
341       break;
342     default:
343       GNUNET_assert (0);
344       break;
345   }
346
347   GNUNET_SERVER_receive_done (client, GNUNET_OK);
348 }
349
350
351 /**
352  * Called when a client wants to add an element to a
353  * set it inhabits.
354  *
355  * @param cls unused
356  * @param client client that sent the message
357  * @param m message sent by the client
358  */
359 static void
360 handle_client_add (void *cls,
361                       struct GNUNET_SERVER_Client *client,
362                       const struct GNUNET_MessageHeader *m)
363 {
364   struct Set *set;
365
366   set = get_set (client);
367   if (NULL == set)
368   {
369     GNUNET_break (0);
370     _GSS_client_disconnect (client);
371     return;
372   }
373   switch (set->operation)
374   {
375     case GNUNET_SET_OPERATION_UNION:
376       _GSS_union_remove ((struct ElementMessage *) m, set);
377     case GNUNET_SET_OPERATION_INTERSECTION:
378       /* FIXME: cfuchs */
379       break;
380     default:
381       GNUNET_assert (0);
382       break;
383   }
384
385   GNUNET_SERVER_receive_done (client, GNUNET_OK);
386 }
387
388
389 /**
390  * Called when a client wants to evaluate a set operation with another peer.
391  *
392  * @param cls unused
393  * @param client client that sent the message
394  * @param m message sent by the client
395  */
396 static void
397 handle_client_evaluate (void *cls,
398                         struct GNUNET_SERVER_Client *client,
399                         const struct GNUNET_MessageHeader *m)
400 {
401   struct Set *set;
402
403   set = get_set (client);
404   if (NULL == set)
405   {
406     GNUNET_break (0);
407     _GSS_client_disconnect (client);
408     return;
409   }
410
411
412   switch (set->operation)
413   {
414     case GNUNET_SET_OPERATION_INTERSECTION:
415       /* FIXME: cfuchs */
416       break;
417     case GNUNET_SET_OPERATION_UNION:
418       _GSS_union_evaluate ((struct EvaluateMessage *) m, set);
419       break;
420     default:
421       GNUNET_assert (0);
422       break;
423   }
424
425   GNUNET_SERVER_receive_done (client, GNUNET_OK);
426 }
427
428
429 /**
430  * Handle a cancel request from a client.
431  *
432  * @param cls unused
433  * @param client the client
434  * @param m the cancel message
435  */
436 static void
437 handle_client_cancel (void *cls,
438                       struct GNUNET_SERVER_Client *client,
439                       const struct GNUNET_MessageHeader *m)
440 {
441   /* FIXME: implement */
442   GNUNET_SERVER_receive_done (client, GNUNET_OK);
443 }
444
445
446 /**
447  * Handle an ack from a client.
448  *
449  * @param cls unused
450  * @param client the client
451  * @param m the message
452  */
453 static void
454 handle_client_ack (void *cls,
455                    struct GNUNET_SERVER_Client *client,
456                    const struct GNUNET_MessageHeader *m)
457 {
458   /* FIXME: implement */
459   GNUNET_SERVER_receive_done (client, GNUNET_OK);
460 }
461
462
463 /**
464  * Handle a request from the client to accept
465  * a set operation that came from a remote peer.
466  *
467  * @param cls unused
468  * @param client the client
469  * @param mh the message
470  */
471 static void
472 handle_client_accept (void *cls,
473                       struct GNUNET_SERVER_Client *client,
474                       const struct GNUNET_MessageHeader *mh)
475 {
476   struct Set *set;
477   struct Incoming *incoming;
478   struct AcceptMessage *msg = (struct AcceptMessage *) mh;
479
480   set = get_set (client);
481
482   if (NULL == set)
483   {
484     GNUNET_break (0);
485     _GSS_client_disconnect (client);
486     return;
487   }
488
489   incoming = get_incoming (ntohl (msg->request_id));
490
491   if ( (NULL == incoming) ||
492        (incoming->operation != set->operation) )
493   {
494     GNUNET_break (0);
495     _GSS_client_disconnect (client);
496     return;
497   }
498
499   switch (set->operation)
500   {
501     case GNUNET_SET_OPERATION_INTERSECTION:
502       /* FIXME: cfuchs*/
503       GNUNET_assert (0);
504       break;
505     case GNUNET_SET_OPERATION_UNION:
506       _GSS_union_accept (msg, set, incoming);
507       break;
508     default:
509       GNUNET_assert (0);
510       break;
511   }
512   /* FIXME: destroy incoming */
513
514   GNUNET_SERVER_receive_done (client, GNUNET_OK);
515 }
516
517
518 /**
519  * Functions of this type are called upon new stream connection from other peers
520  * or upon binding error which happen when the app_port given in
521  * GNUNET_STREAM_listen() is already taken.
522  *
523  * @param cls the closure from GNUNET_STREAM_listen
524  * @param socket the socket representing the stream; NULL on binding error
525  * @param initiator the identity of the peer who wants to establish a stream
526  *            with us; NULL on binding error
527  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
528  *             stream (the socket will be invalid after the call)
529  */
530 static int
531 stream_listen_cb (void *cls,
532                   struct GNUNET_STREAM_Socket *socket,
533                   const struct GNUNET_PeerIdentity *initiator)
534 {
535   struct Incoming *incoming;
536   static const struct GNUNET_MQ_Handler handlers[] = {
537     {handle_p2p_operation_request, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST},
538     GNUNET_MQ_HANDLERS_END
539   };
540
541   if (NULL == socket)
542   {
543     GNUNET_break (0);
544     return GNUNET_SYSERR;
545   }
546
547   incoming = GNUNET_new (struct Incoming);
548   incoming->peer = *initiator;
549   incoming->socket = socket;
550   incoming->mq = GNUNET_MQ_queue_for_stream_socket (incoming->socket, handlers, incoming);
551   /* FIXME: timeout for peers that only connect but don't send anything */
552   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
553   return GNUNET_OK;
554 }
555
556
557 /**
558  * Called to clean up, after a shutdown has been requested.
559  *
560  * @param cls closure
561  * @param tc context information (why was this task triggered now)
562  */
563 static void
564 shutdown_task (void *cls,
565                const struct GNUNET_SCHEDULER_TaskContext *tc)
566 {
567   if (NULL != stream_listen_socket)
568   {
569     GNUNET_STREAM_listen_close (stream_listen_socket);
570     stream_listen_socket = NULL;
571   }
572
573   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
574 }
575
576
577 /**
578  * Function called by the service's run
579  * method to run service-specific setup code.
580  *
581  * @param cls closure
582  * @param server the initialized server
583  * @param cfg configuration to use
584  */
585 static void
586 run (void *cls, struct GNUNET_SERVER_Handle *server,
587      const struct GNUNET_CONFIGURATION_Handle *cfg)
588 {
589   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
590     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
591     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
592     {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
593     {handle_client_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
594     {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_CANCEL, 0},
595     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
596     {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
597     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
598     {NULL, NULL, 0, 0}
599   };
600
601   configuration = cfg;
602   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
603   GNUNET_SERVER_add_handlers (server, server_handlers);
604   stream_listen_socket = GNUNET_STREAM_listen (cfg, GNUNET_APPLICATION_TYPE_SET,
605                                                &stream_listen_cb, NULL,
606                                                GNUNET_STREAM_OPTION_END);
607 }
608
609
610 /**
611  * The main function for the set service.
612  *
613  * @param argc number of arguments from the command line
614  * @param argv command line arguments
615  * @return 0 ok, 1 on error
616  */
617 int
618 main (int argc, char *const *argv)
619 {
620   int ret;
621   ret = GNUNET_SERVICE_run (argc, argv, "set", GNUNET_SERVICE_OPTION_NONE, &run, NULL);
622   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit\n");
623   return (GNUNET_OK == ret) ? 0 : 1;
624 }
625