work on gnunet-set, isolated bug in stream
[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  */
77 static uint32_t request_id = 1;
78
79
80 /**
81  * Disconnect a client and free all resources
82  * that the client allocated (e.g. Sets or Listeners)
83  *
84  * @param client the client to disconnect
85  */
86 void
87 _GSS_client_disconnect (struct GNUNET_SERVER_Client *client)
88 {
89   /* FIXME: clean up any data structures belonging to the client */
90   GNUNET_SERVER_client_disconnect (client);
91 }
92
93
94 /**
95  * Get set that is owned by the client, if any.
96  *
97  * @param client client to look for
98  * @return set that the client owns, NULL if the client
99  *         does not own a set
100  */
101 static struct Set *
102 get_set (struct GNUNET_SERVER_Client *client)
103 {
104   struct Set *set;
105   for (set = sets_head; NULL != set; set = set->next)
106     if (set->client == client)
107       return set;
108   return NULL;
109 }
110
111
112 /**
113  * Get the listener associated to a client, if any.
114  *
115  * @param client the client
116  * @return listener associated with the client, NULL
117  *         if there isn't any
118  */
119 static struct Listener *
120 get_listener (struct GNUNET_SERVER_Client *client)
121 {
122   struct Listener *listener;
123   for (listener = listeners_head; NULL != listener; listener = listener->next)
124     if (listener->client == client)
125       return listener;
126   return NULL;
127 }
128
129
130 /**
131  * Get the incoming socket associated with the given id
132  *
133  * @param id id to look for
134  * @return the incoming socket associated with the id,
135  *         or NULL if there is none
136  */
137 static struct Incoming *
138 get_incoming (uint32_t id)
139 {
140   struct Incoming *incoming;
141   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
142     if (incoming->request_id == id)
143       return incoming;
144   return NULL;
145 }
146
147
148 static void
149 destroy_incoming (struct Incoming *incoming)
150 {
151   if (NULL != incoming->mq)
152   {
153     GNUNET_MQ_destroy (incoming->mq);
154     incoming->mq = NULL;
155   }
156   if (NULL != incoming->socket)
157   {
158     GNUNET_STREAM_close (incoming->socket);
159     incoming->socket = NULL;
160   }
161   GNUNET_CONTAINER_DLL_remove (incoming_head, incoming_tail, incoming);
162   GNUNET_free (incoming);
163 }
164
165
166 /**
167  * Handle a request for a set operation for
168  * another peer.
169  *
170  * @param cls the incoming socket
171  * @param mh the message
172  */
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 !=
217         GNUNET_MQ_nest (mqm, context_msg))
218     {
219       /* FIXME: disconnect the peer */
220       GNUNET_MQ_discard (mqm);
221       GNUNET_break (0);
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 set.
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 create a new set.
315  *
316  * @param cls unused
317  * @param client client that sent the message
318  * @param m message sent by the client
319  */
320 static void
321 handle_client_add (void *cls,
322                       struct GNUNET_SERVER_Client *client,
323                       const struct GNUNET_MessageHeader *m)
324 {
325   struct Set *set;
326
327   set = get_set (client);
328   if (NULL == set)
329   {
330     GNUNET_break (0);
331     _GSS_client_disconnect (client);
332     return;
333   }
334   switch (set->operation)
335   {
336     case GNUNET_SET_OPERATION_UNION:
337       _GSS_union_add ((struct ElementMessage *) m, set);
338     case GNUNET_SET_OPERATION_INTERSECTION:
339       /* FIXME: cfuchs */
340       break;
341     default:
342       GNUNET_assert (0);
343       break;
344   }
345
346   GNUNET_SERVER_receive_done (client, GNUNET_OK);
347 }
348
349
350 /**
351  * Called when a client wants to evaluate a set operation with another peer.
352  *
353  * @param cls unused
354  * @param client client that sent the message
355  * @param m message sent by the client
356  */
357 static void
358 handle_client_evaluate (void *cls,
359                         struct GNUNET_SERVER_Client *client,
360                         const struct GNUNET_MessageHeader *m)
361 {
362   struct Set *set;
363
364   set = get_set (client);
365   if (NULL == set)
366   {
367     GNUNET_break (0);
368     _GSS_client_disconnect (client);
369     return;
370   }
371
372
373   switch (set->operation)
374   {
375     case GNUNET_SET_OPERATION_INTERSECTION:
376       /* FIXME: cfuchs */
377       break;
378     case GNUNET_SET_OPERATION_UNION:
379       _GSS_union_evaluate ((struct EvaluateMessage *) m, set);
380       break;
381     default:
382       GNUNET_assert (0);
383       break;
384   }
385
386   GNUNET_SERVER_receive_done (client, GNUNET_OK);
387 }
388
389
390 /**
391  * Handle a cancel request from a client.
392  *
393  * @param cls unused
394  * @param client the client
395  * @param m the cancel message
396  */
397 static void
398 handle_client_cancel (void *cls,
399                       struct GNUNET_SERVER_Client *client,
400                       const struct GNUNET_MessageHeader *m)
401 {
402   /* FIXME: implement */
403   GNUNET_SERVER_receive_done (client, GNUNET_OK);
404 }
405
406
407 /**
408  * Handle an ack from a client.
409  *
410  * @param cls unused
411  * @param client the client
412  * @param m the message
413  */
414 static void
415 handle_client_ack (void *cls,
416                    struct GNUNET_SERVER_Client *client,
417                    const struct GNUNET_MessageHeader *m)
418 {
419   /* FIXME: implement */
420   GNUNET_SERVER_receive_done (client, GNUNET_OK);
421 }
422
423
424 /**
425  * Handle a request from the client to accept
426  * a set operation.
427  *
428  * @param cls unused
429  * @param client the client
430  * @param m the message
431  */
432 static void
433 handle_client_accept (void *cls,
434                       struct GNUNET_SERVER_Client *client,
435                       const struct GNUNET_MessageHeader *mh)
436 {
437   struct Set *set;
438   struct Incoming *incoming;
439   struct AcceptMessage *msg = (struct AcceptMessage *) mh;
440
441   set = get_set (client);
442
443   if (NULL == set)
444   {
445     GNUNET_break (0);
446     _GSS_client_disconnect (client);
447     return;
448   }
449
450   incoming = get_incoming (ntohl (msg->request_id));
451
452   if ( (NULL == incoming) ||
453        (incoming->operation != set->operation) )
454   {
455     GNUNET_break (0);
456     _GSS_client_disconnect (client);
457     return;
458   }
459
460   switch (set->operation)
461   {
462     case GNUNET_SET_OPERATION_INTERSECTION:
463       /* FIXME: cfuchs*/
464       GNUNET_assert (0);
465       break;
466     case GNUNET_SET_OPERATION_UNION:
467       _GSS_union_accept (msg, set, incoming);
468       break;
469     default:
470       GNUNET_assert (0);
471       break;
472   }
473   /* FIXME: destroy incoming */
474
475   GNUNET_SERVER_receive_done (client, GNUNET_OK);
476 }
477
478
479 /**
480  * Functions of this type are called upon new stream connection from other peers
481  * or upon binding error which happen when the app_port given in
482  * GNUNET_STREAM_listen() is already taken.
483  *
484  * @param cls the closure from GNUNET_STREAM_listen
485  * @param socket the socket representing the stream; NULL on binding error
486  * @param initiator the identity of the peer who wants to establish a stream
487  *            with us; NULL on binding error
488  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
489  *             stream (the socket will be invalid after the call)
490  */
491 static int
492 stream_listen_cb (void *cls,
493                   struct GNUNET_STREAM_Socket *socket,
494                   const struct GNUNET_PeerIdentity *initiator)
495 {
496   struct Incoming *incoming;
497   static const struct GNUNET_MQ_Handler handlers[] = {
498     {handle_p2p_operation_request, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST},
499     GNUNET_MQ_HANDLERS_END
500   };
501
502   if (NULL == socket)
503   {
504     GNUNET_break (0);
505     return GNUNET_SYSERR;
506   }
507
508   incoming = GNUNET_new (struct Incoming);
509   incoming->peer = *initiator;
510   incoming->socket = socket;
511   incoming->mq = GNUNET_MQ_queue_for_stream_socket (incoming->socket, handlers, incoming);
512   /* FIXME: timeout for peers that only connect but don't send anything */
513   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
514   return GNUNET_OK;
515 }
516
517
518 /**
519  * Called to clean up, after a shutdown has been requested.
520  *
521  * @param cls closure
522  * @param tc context information (why was this task triggered now)
523  */
524 static void
525 shutdown_task (void *cls,
526                const struct GNUNET_SCHEDULER_TaskContext *tc)
527 {
528   if (NULL != stream_listen_socket)
529   {
530     GNUNET_STREAM_listen_close (stream_listen_socket);
531     stream_listen_socket = NULL;
532   }
533
534   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
535 }
536
537
538 /**
539  * Function called by the service's run
540  * method to run service-specific setup code.
541  *
542  * @param cls closure
543  * @param server the initialized server
544  * @param cfg configuration to use
545  */
546 static void
547 run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg)
548 {
549   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
550     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
551     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
552     {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
553     {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_CANCEL, 0},
554     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
555     {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
556     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
557     {NULL, NULL, 0, 0}
558   };
559
560   configuration = cfg;
561   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
562   GNUNET_SERVER_add_handlers (server, server_handlers);
563   stream_listen_socket = GNUNET_STREAM_listen (cfg, GNUNET_APPLICATION_TYPE_SET,
564                                                &stream_listen_cb, NULL,
565                                                GNUNET_STREAM_OPTION_END);
566 }
567
568
569 /**
570  * The main function for the set service.
571  *
572  * @param argc number of arguments from the command line
573  * @param argv command line arguments
574  * @return 0 ok, 1 on error
575  */
576 int
577 main (int argc, char *const *argv)
578 {
579   int ret;
580   ret = GNUNET_SERVICE_run (argc, argv, "set", GNUNET_SERVICE_OPTION_NONE, &run, NULL);
581   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit\n");
582   return (GNUNET_OK == ret) ? 0 : 1;
583 }
584