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