3ed8967757f8bbf47ce5fcbeb9a860dae2318162
[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
230 /**
231  * Handle a request for a set operation from
232  * another peer.
233  *
234  * @param cls the incoming socket
235  * @param mh the message
236  */
237 static void
238 handle_p2p_operation_request (void *cls, const struct GNUNET_MessageHeader *mh)
239 {
240   struct Incoming *incoming = cls;
241   const struct OperationRequestMessage *msg = (const struct OperationRequestMessage *) mh;
242   struct GNUNET_MQ_Message *mqm;
243   struct RequestMessage *cmsg;
244   struct Listener *listener;
245   const struct GNUNET_MessageHeader *context_msg;
246
247   if (ntohs (mh->size) < sizeof *msg)
248   {
249     /* message is to small for its type */
250     GNUNET_break (0);
251     destroy_incoming (incoming);
252     return;
253   }
254   else if (ntohs (mh->size) == sizeof *msg)
255   {
256     /* there is no context message */
257     context_msg = NULL;
258   }
259   else
260   {
261     context_msg = &msg[1].header;
262     if ((ntohs (context_msg->size) + sizeof *msg) != ntohs (msg->header.size))
263     {
264       /* size of context message is invalid */
265       GNUNET_break (0);
266       destroy_incoming (incoming);
267       return;
268     }
269   }
270
271   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "received P2P operation request (op %u, app %s)\n",
272               ntohs (msg->operation), GNUNET_h2s (&msg->app_id));
273
274   /* find the appropriate listener */
275   for (listener = listeners_head;
276        listener != NULL;
277        listener = listener->next)
278   {
279     if ( (0 != GNUNET_CRYPTO_hash_cmp (&msg->app_id, &listener->app_id)) ||
280          (ntohs (msg->operation) != listener->operation) )
281       continue;
282     mqm = GNUNET_MQ_msg (cmsg, GNUNET_MESSAGE_TYPE_SET_REQUEST);
283     if (GNUNET_OK != GNUNET_MQ_nest_mh (mqm, context_msg))
284     {
285       /* FIXME: disconnect the peer */
286       GNUNET_MQ_discard (mqm);
287       GNUNET_break (0);
288       return;
289     }
290     incoming->accept_id = accept_id++;
291     cmsg->accept_id = htonl (incoming->accept_id);
292     GNUNET_MQ_send (listener->client_mq, mqm);
293     return;
294   }
295
296   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
297               "set operation request from peer failed: "
298               "no set with matching application ID and operation type\n");
299 }
300
301
302 /**
303  * Called when a client wants to create a new set.
304  *
305  * @param cls unused
306  * @param client client that sent the message
307  * @param m message sent by the client
308  */
309 static void
310 handle_client_create (void *cls,
311                       struct GNUNET_SERVER_Client *client,
312                       const struct GNUNET_MessageHeader *m)
313 {
314   struct SetCreateMessage *msg = (struct SetCreateMessage *) m;
315   struct Set *set;
316
317   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client created new set (operation %u)\n",
318               ntohs (msg->operation));
319
320   if (NULL != get_set (client))
321   {
322     GNUNET_break (0);
323     GNUNET_SERVER_client_disconnect (client);
324     return;
325   }
326
327   set = GNUNET_new (struct Set);
328
329   switch (ntohs (msg->operation))
330   {
331     case GNUNET_SET_OPERATION_INTERSECTION:
332       /* FIXME: cfuchs */
333       GNUNET_assert (0);
334       break;
335     case GNUNET_SET_OPERATION_UNION:
336       set = _GSS_union_set_create ();
337       break;
338     default:
339       GNUNET_free (set);
340       GNUNET_break (0);
341       GNUNET_SERVER_client_disconnect (client);
342       return;
343   }
344
345   set->client = client;
346   GNUNET_SERVER_client_keep (client);
347   set->client_mq = GNUNET_MQ_queue_for_server_client (client);
348   GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
349   GNUNET_SERVER_receive_done (client, GNUNET_OK);
350 }
351
352
353 /**
354  * Called when a client wants to create a new listener.
355  *
356  * @param cls unused
357  * @param client client that sent the message
358  * @param m message sent by the client
359  */
360 static void
361 handle_client_listen (void *cls,
362                       struct GNUNET_SERVER_Client *client,
363                       const struct GNUNET_MessageHeader *m)
364 {
365   struct ListenMessage *msg = (struct ListenMessage *) m;
366   struct Listener *listener;
367
368   if (NULL != get_listener (client))
369   {
370     GNUNET_break (0);
371     GNUNET_SERVER_client_disconnect (client);
372     return;
373   }
374   listener = GNUNET_new (struct Listener);
375   listener->client = client;
376   GNUNET_SERVER_client_keep (client);
377   listener->client_mq = GNUNET_MQ_queue_for_server_client (client);
378   listener->app_id = msg->app_id;
379   listener->operation = ntohs (msg->operation);
380   GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
381   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new listener created (op %u, app %s)\n",
382               listener->operation, GNUNET_h2s (&listener->app_id));
383   GNUNET_SERVER_receive_done (client, GNUNET_OK);
384 }
385
386
387 /**
388  * Called when a client wants to remove an element
389  * from the set it inhabits.
390  *
391  * @param cls unused
392  * @param client client that sent the message
393  * @param m message sent by the client
394  */
395 static void
396 handle_client_remove (void *cls,
397                       struct GNUNET_SERVER_Client *client,
398                       const struct GNUNET_MessageHeader *m)
399 {
400   struct Set *set;
401
402   set = get_set (client);
403   if (NULL == set)
404   {
405     GNUNET_break (0);
406     GNUNET_SERVER_client_disconnect (client);
407     return;
408   }
409   switch (set->operation)
410   {
411     case GNUNET_SET_OPERATION_UNION:
412       _GSS_union_remove ((struct ElementMessage *) m, set);
413     case GNUNET_SET_OPERATION_INTERSECTION:
414       /* FIXME: cfuchs */
415       break;
416     default:
417       GNUNET_assert (0);
418       break;
419   }
420
421   GNUNET_SERVER_receive_done (client, GNUNET_OK);
422 }
423
424
425 /**
426  * Called when a client wants to add an element to a
427  * set it inhabits.
428  *
429  * @param cls unused
430  * @param client client that sent the message
431  * @param m message sent by the client
432  */
433 static void
434 handle_client_add (void *cls,
435                       struct GNUNET_SERVER_Client *client,
436                       const struct GNUNET_MessageHeader *m)
437 {
438   struct Set *set;
439
440   set = get_set (client);
441   if (NULL == set)
442   {
443     GNUNET_break (0);
444     GNUNET_SERVER_client_disconnect (client);
445     return;
446   }
447   switch (set->operation)
448   {
449     case GNUNET_SET_OPERATION_UNION:
450       _GSS_union_add ((struct ElementMessage *) m, set);
451     case GNUNET_SET_OPERATION_INTERSECTION:
452       /* FIXME: cfuchs */
453       break;
454     default:
455       GNUNET_assert (0);
456       break;
457   }
458
459   GNUNET_SERVER_receive_done (client, GNUNET_OK);
460 }
461
462
463 /**
464  * Called when a client wants to evaluate a set operation with another peer.
465  *
466  * @param cls unused
467  * @param client client that sent the message
468  * @param m message sent by the client
469  */
470 static void
471 handle_client_evaluate (void *cls,
472                         struct GNUNET_SERVER_Client *client,
473                         const struct GNUNET_MessageHeader *m)
474 {
475   struct Set *set;
476
477   set = get_set (client);
478   if (NULL == set)
479   {
480     GNUNET_break (0);
481     GNUNET_SERVER_client_disconnect (client);
482     return;
483   }
484
485
486   switch (set->operation)
487   {
488     case GNUNET_SET_OPERATION_INTERSECTION:
489       /* FIXME: cfuchs */
490       break;
491     case GNUNET_SET_OPERATION_UNION:
492       _GSS_union_evaluate ((struct EvaluateMessage *) m, set);
493       break;
494     default:
495       GNUNET_assert (0);
496       break;
497   }
498
499   GNUNET_SERVER_receive_done (client, GNUNET_OK);
500 }
501
502
503 /**
504  * Handle a cancel request from a client.
505  *
506  * @param cls unused
507  * @param client the client
508  * @param m the cancel message
509  */
510 static void
511 handle_client_cancel (void *cls,
512                       struct GNUNET_SERVER_Client *client,
513                       const struct GNUNET_MessageHeader *m)
514 {
515   /* FIXME: implement */
516   GNUNET_SERVER_receive_done (client, GNUNET_OK);
517 }
518
519
520 /**
521  * Handle an ack from a client.
522  *
523  * @param cls unused
524  * @param client the client
525  * @param m the message
526  */
527 static void
528 handle_client_ack (void *cls,
529                    struct GNUNET_SERVER_Client *client,
530                    const struct GNUNET_MessageHeader *m)
531 {
532   /* FIXME: implement */
533   GNUNET_SERVER_receive_done (client, GNUNET_OK);
534 }
535
536
537 /**
538  * Handle a request from the client to accept
539  * a set operation that came from a remote peer.
540  *
541  * @param cls unused
542  * @param client the client
543  * @param mh the message
544  */
545 static void
546 handle_client_accept (void *cls,
547                       struct GNUNET_SERVER_Client *client,
548                       const struct GNUNET_MessageHeader *mh)
549 {
550   struct Set *set;
551   struct Incoming *incoming;
552   struct AcceptMessage *msg = (struct AcceptMessage *) mh;
553
554
555   incoming = get_incoming (ntohl (msg->accept_id));
556
557   if (NULL == incoming)
558   {
559     GNUNET_break (0);
560     GNUNET_SERVER_client_disconnect (client);
561     return;
562   }
563
564   if (0 == ntohl (msg->request_id))
565   {
566     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "peer request rejected by client\n");
567     destroy_incoming (incoming);
568     GNUNET_SERVER_receive_done (client, GNUNET_OK);
569     return;
570   }
571
572   set = get_set (client);
573
574   if (NULL == set)
575   {
576     GNUNET_break (0);
577     GNUNET_SERVER_client_disconnect (client);
578     return;
579   }
580
581   switch (set->operation)
582   {
583     case GNUNET_SET_OPERATION_INTERSECTION:
584       /* FIXME: cfuchs*/
585       GNUNET_assert (0);
586       break;
587     case GNUNET_SET_OPERATION_UNION:
588       _GSS_union_accept (msg, set, incoming);
589       break;
590     default:
591       GNUNET_assert (0);
592       break;
593   }
594
595   /* note: _GSS_*_accept has to make sure the socket and mq are set to NULL,
596    * otherwise they will be destroyed and disconnected */
597   destroy_incoming (incoming);
598   GNUNET_SERVER_receive_done (client, GNUNET_OK);
599 }
600
601
602 /**
603  * Functions of this type are called upon new stream connection from other peers
604  * or upon binding error which happen when the app_port given in
605  * GNUNET_STREAM_listen() is already taken.
606  *
607  * @param cls the closure from GNUNET_STREAM_listen
608  * @param socket the socket representing the stream; NULL on binding error
609  * @param initiator the identity of the peer who wants to establish a stream
610  *            with us; NULL on binding error
611  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
612  *             stream (the socket will be invalid after the call)
613  */
614 static int
615 stream_listen_cb (void *cls,
616                   struct GNUNET_STREAM_Socket *socket,
617                   const struct GNUNET_PeerIdentity *initiator)
618 {
619   struct Incoming *incoming;
620   static const struct GNUNET_MQ_Handler handlers[] = {
621     {handle_p2p_operation_request, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST},
622     GNUNET_MQ_HANDLERS_END
623   };
624
625   if (NULL == socket)
626   {
627     GNUNET_break (0);
628     return GNUNET_SYSERR;
629   }
630
631   incoming = GNUNET_new (struct Incoming);
632   incoming->peer = *initiator;
633   incoming->socket = socket;
634   incoming->mq = GNUNET_MQ_queue_for_stream_socket (incoming->socket, handlers, incoming);
635   /* FIXME: timeout for peers that only connect but don't send anything */
636   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
637   return GNUNET_OK;
638 }
639
640
641 /**
642  * Called to clean up, after a shutdown has been requested.
643  *
644  * @param cls closure
645  * @param tc context information (why was this task triggered now)
646  */
647 static void
648 shutdown_task (void *cls,
649                const struct GNUNET_SCHEDULER_TaskContext *tc)
650 {
651   if (NULL != stream_listen_socket)
652   {
653     GNUNET_STREAM_listen_close (stream_listen_socket);
654     stream_listen_socket = NULL;
655   }
656
657   while (NULL != incoming_head)
658   {
659     destroy_incoming (incoming_head);
660   }
661
662   while (NULL != listeners_head)
663   {
664     destroy_listener (listeners_head);
665   }
666
667   while (NULL != sets_head)
668   {
669     destroy_set (sets_head);
670   }
671
672   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
673 }
674
675
676 /**
677  * Function called by the service's run
678  * method to run service-specific setup code.
679  *
680  * @param cls closure
681  * @param server the initialized server
682  * @param cfg configuration to use
683  */
684 static void
685 run (void *cls, struct GNUNET_SERVER_Handle *server,
686      const struct GNUNET_CONFIGURATION_Handle *cfg)
687 {
688   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
689     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
690     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
691     {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
692     {handle_client_remove, NULL, GNUNET_MESSAGE_TYPE_SET_REMOVE, 0},
693     {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_CANCEL, 0},
694     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
695     {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
696     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
697     {NULL, NULL, 0, 0}
698   };
699
700   configuration = cfg;
701   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
702   GNUNET_SERVER_disconnect_notify (server, handle_client_disconnect, NULL);
703   GNUNET_SERVER_add_handlers (server, server_handlers);
704   stream_listen_socket = GNUNET_STREAM_listen (cfg, GNUNET_APPLICATION_TYPE_SET,
705                                                &stream_listen_cb, NULL,
706                                                GNUNET_STREAM_OPTION_END);
707 }
708
709
710 /**
711  * The main function for the set service.
712  *
713  * @param argc number of arguments from the command line
714  * @param argv command line arguments
715  * @return 0 ok, 1 on error
716  */
717 int
718 main (int argc, char *const *argv)
719 {
720   int ret;
721   ret = GNUNET_SERVICE_run (argc, argv, "set", GNUNET_SERVICE_OPTION_NONE, &run, NULL);
722   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit\n");
723   return (GNUNET_OK == ret) ? 0 : 1;
724 }
725