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