removed unnecessary malloc
[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 = NULL;
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_break (0);
340       GNUNET_SERVER_client_disconnect (client);
341       return;
342   }
343
344   GNUNET_assert (NULL != set);
345
346   set->client = client;
347   GNUNET_SERVER_client_keep (client);
348   set->client_mq = GNUNET_MQ_queue_for_server_client (client);
349   GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
350   GNUNET_SERVER_receive_done (client, GNUNET_OK);
351 }
352
353
354 /**
355  * Called when a client wants to create a new listener.
356  *
357  * @param cls unused
358  * @param client client that sent the message
359  * @param m message sent by the client
360  */
361 static void
362 handle_client_listen (void *cls,
363                       struct GNUNET_SERVER_Client *client,
364                       const struct GNUNET_MessageHeader *m)
365 {
366   struct ListenMessage *msg = (struct ListenMessage *) m;
367   struct Listener *listener;
368
369   if (NULL != get_listener (client))
370   {
371     GNUNET_break (0);
372     GNUNET_SERVER_client_disconnect (client);
373     return;
374   }
375   listener = GNUNET_new (struct Listener);
376   listener->client = client;
377   GNUNET_SERVER_client_keep (client);
378   listener->client_mq = GNUNET_MQ_queue_for_server_client (client);
379   listener->app_id = msg->app_id;
380   listener->operation = ntohs (msg->operation);
381   GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
382   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new listener created (op %u, app %s)\n",
383               listener->operation, GNUNET_h2s (&listener->app_id));
384   GNUNET_SERVER_receive_done (client, GNUNET_OK);
385 }
386
387
388 /**
389  * Called when a client wants to remove an element
390  * from the set it inhabits.
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_remove (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     GNUNET_SERVER_client_disconnect (client);
408     return;
409   }
410   switch (set->operation)
411   {
412     case GNUNET_SET_OPERATION_UNION:
413       _GSS_union_remove ((struct ElementMessage *) m, set);
414     case GNUNET_SET_OPERATION_INTERSECTION:
415       /* FIXME: cfuchs */
416       break;
417     default:
418       GNUNET_assert (0);
419       break;
420   }
421
422   GNUNET_SERVER_receive_done (client, GNUNET_OK);
423 }
424
425
426 /**
427  * Called when a client wants to add an element to a
428  * set it inhabits.
429  *
430  * @param cls unused
431  * @param client client that sent the message
432  * @param m message sent by the client
433  */
434 static void
435 handle_client_add (void *cls,
436                       struct GNUNET_SERVER_Client *client,
437                       const struct GNUNET_MessageHeader *m)
438 {
439   struct Set *set;
440
441   set = get_set (client);
442   if (NULL == set)
443   {
444     GNUNET_break (0);
445     GNUNET_SERVER_client_disconnect (client);
446     return;
447   }
448   switch (set->operation)
449   {
450     case GNUNET_SET_OPERATION_UNION:
451       _GSS_union_add ((struct ElementMessage *) m, set);
452     case GNUNET_SET_OPERATION_INTERSECTION:
453       /* FIXME: cfuchs */
454       break;
455     default:
456       GNUNET_assert (0);
457       break;
458   }
459
460   GNUNET_SERVER_receive_done (client, GNUNET_OK);
461 }
462
463
464 /**
465  * Called when a client wants to evaluate a set operation with another peer.
466  *
467  * @param cls unused
468  * @param client client that sent the message
469  * @param m message sent by the client
470  */
471 static void
472 handle_client_evaluate (void *cls,
473                         struct GNUNET_SERVER_Client *client,
474                         const struct GNUNET_MessageHeader *m)
475 {
476   struct Set *set;
477
478   set = get_set (client);
479   if (NULL == set)
480   {
481     GNUNET_break (0);
482     GNUNET_SERVER_client_disconnect (client);
483     return;
484   }
485
486
487   switch (set->operation)
488   {
489     case GNUNET_SET_OPERATION_INTERSECTION:
490       /* FIXME: cfuchs */
491       break;
492     case GNUNET_SET_OPERATION_UNION:
493       _GSS_union_evaluate ((struct EvaluateMessage *) m, set);
494       break;
495     default:
496       GNUNET_assert (0);
497       break;
498   }
499
500   GNUNET_SERVER_receive_done (client, GNUNET_OK);
501 }
502
503
504 /**
505  * Handle a cancel request from a client.
506  *
507  * @param cls unused
508  * @param client the client
509  * @param m the cancel message
510  */
511 static void
512 handle_client_cancel (void *cls,
513                       struct GNUNET_SERVER_Client *client,
514                       const struct GNUNET_MessageHeader *m)
515 {
516   /* FIXME: implement */
517   GNUNET_SERVER_receive_done (client, GNUNET_OK);
518 }
519
520
521 /**
522  * Handle an ack from a client.
523  *
524  * @param cls unused
525  * @param client the client
526  * @param m the message
527  */
528 static void
529 handle_client_ack (void *cls,
530                    struct GNUNET_SERVER_Client *client,
531                    const struct GNUNET_MessageHeader *m)
532 {
533   /* FIXME: implement */
534   GNUNET_SERVER_receive_done (client, GNUNET_OK);
535 }
536
537
538 /**
539  * Handle a request from the client to accept
540  * a set operation that came from a remote peer.
541  *
542  * @param cls unused
543  * @param client the client
544  * @param mh the message
545  */
546 static void
547 handle_client_accept (void *cls,
548                       struct GNUNET_SERVER_Client *client,
549                       const struct GNUNET_MessageHeader *mh)
550 {
551   struct Set *set;
552   struct Incoming *incoming;
553   struct AcceptMessage *msg = (struct AcceptMessage *) mh;
554
555
556   incoming = get_incoming (ntohl (msg->accept_id));
557
558   if (NULL == incoming)
559   {
560     GNUNET_break (0);
561     GNUNET_SERVER_client_disconnect (client);
562     return;
563   }
564
565   if (0 == ntohl (msg->request_id))
566   {
567     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "peer request rejected by client\n");
568     destroy_incoming (incoming);
569     GNUNET_SERVER_receive_done (client, GNUNET_OK);
570     return;
571   }
572
573   set = get_set (client);
574
575   if (NULL == set)
576   {
577     GNUNET_break (0);
578     GNUNET_SERVER_client_disconnect (client);
579     return;
580   }
581
582   switch (set->operation)
583   {
584     case GNUNET_SET_OPERATION_INTERSECTION:
585       /* FIXME: cfuchs*/
586       GNUNET_assert (0);
587       break;
588     case GNUNET_SET_OPERATION_UNION:
589       _GSS_union_accept (msg, set, incoming);
590       break;
591     default:
592       GNUNET_assert (0);
593       break;
594   }
595
596   /* note: _GSS_*_accept has to make sure the socket and mq are set to NULL,
597    * otherwise they will be destroyed and disconnected */
598   destroy_incoming (incoming);
599   GNUNET_SERVER_receive_done (client, GNUNET_OK);
600 }
601
602
603 /**
604  * Functions of this type are called upon new stream connection from other peers
605  * or upon binding error which happen when the app_port given in
606  * GNUNET_STREAM_listen() is already taken.
607  *
608  * @param cls the closure from GNUNET_STREAM_listen
609  * @param socket the socket representing the stream; NULL on binding error
610  * @param initiator the identity of the peer who wants to establish a stream
611  *            with us; NULL on binding error
612  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
613  *             stream (the socket will be invalid after the call)
614  */
615 static int
616 stream_listen_cb (void *cls,
617                   struct GNUNET_STREAM_Socket *socket,
618                   const struct GNUNET_PeerIdentity *initiator)
619 {
620   struct Incoming *incoming;
621   static const struct GNUNET_MQ_Handler handlers[] = {
622     {handle_p2p_operation_request, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST},
623     GNUNET_MQ_HANDLERS_END
624   };
625
626   if (NULL == socket)
627   {
628     GNUNET_break (0);
629     return GNUNET_SYSERR;
630   }
631
632   incoming = GNUNET_new (struct Incoming);
633   incoming->peer = *initiator;
634   incoming->socket = socket;
635   incoming->mq = GNUNET_MQ_queue_for_stream_socket (incoming->socket, handlers, incoming);
636   /* FIXME: timeout for peers that only connect but don't send anything */
637   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
638   return GNUNET_OK;
639 }
640
641
642 /**
643  * Called to clean up, after a shutdown has been requested.
644  *
645  * @param cls closure
646  * @param tc context information (why was this task triggered now)
647  */
648 static void
649 shutdown_task (void *cls,
650                const struct GNUNET_SCHEDULER_TaskContext *tc)
651 {
652   if (NULL != stream_listen_socket)
653   {
654     GNUNET_STREAM_listen_close (stream_listen_socket);
655     stream_listen_socket = NULL;
656   }
657
658   while (NULL != incoming_head)
659   {
660     destroy_incoming (incoming_head);
661   }
662
663   while (NULL != listeners_head)
664   {
665     destroy_listener (listeners_head);
666   }
667
668   while (NULL != sets_head)
669   {
670     destroy_set (sets_head);
671   }
672
673   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
674 }
675
676
677 /**
678  * Function called by the service's run
679  * method to run service-specific setup code.
680  *
681  * @param cls closure
682  * @param server the initialized server
683  * @param cfg configuration to use
684  */
685 static void
686 run (void *cls, struct GNUNET_SERVER_Handle *server,
687      const struct GNUNET_CONFIGURATION_Handle *cfg)
688 {
689   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
690     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
691     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
692     {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
693     {handle_client_remove, NULL, GNUNET_MESSAGE_TYPE_SET_REMOVE, 0},
694     {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_CANCEL, 0},
695     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
696     {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
697     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
698     {NULL, NULL, 0, 0}
699   };
700
701   configuration = cfg;
702   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
703   GNUNET_SERVER_disconnect_notify (server, handle_client_disconnect, NULL);
704   GNUNET_SERVER_add_handlers (server, server_handlers);
705   stream_listen_socket = GNUNET_STREAM_listen (cfg, GNUNET_APPLICATION_TYPE_SET,
706                                                &stream_listen_cb, NULL,
707                                                GNUNET_STREAM_OPTION_END);
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