- fixed tunnel destruction/cleanup
[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  * (Not declared 'static' as also needed in gnunet-service-set_union.c)
33  */
34 const struct GNUNET_CONFIGURATION_Handle *configuration;
35
36 /**
37  * Handle to the mesh service, used
38  * to listen for and connect to remote peers.
39  * (Not declared 'static' as also needed in gnunet-service-set_union.c)
40  */
41 struct GNUNET_MESH_Handle *mesh;
42
43 /**
44  * Sets are held in a doubly linked list.
45  */
46 static struct Set *sets_head;
47
48 /**
49  * Sets are held in a doubly linked list.
50  */
51 static struct Set *sets_tail;
52
53 /**
54  * Listeners are held in a doubly linked list.
55  */
56 static struct Listener *listeners_head;
57
58 /**
59  * Listeners are held in a doubly linked list.
60  */
61 static struct Listener *listeners_tail;
62
63 /**
64  * Incoming sockets from remote peers are
65  * held in a doubly linked list.
66  */
67 static struct Incoming *incoming_head;
68
69 /**
70  * Incoming sockets from remote peers are
71  * held in a doubly linked list.
72  */
73 static struct Incoming *incoming_tail;
74
75 /**
76  * Counter for allocating unique IDs for clients,
77  * used to identify incoming operation requests from remote peers,
78  * that the client can choose to accept or refuse.
79  */
80 static uint32_t accept_id = 1;
81
82
83 /**
84  * Get set that is owned by the given client, if any.
85  *
86  * @param client client to look for
87  * @return set that the client owns, NULL if the client
88  *         does not own a set
89  */
90 static struct Set *
91 set_get (struct GNUNET_SERVER_Client *client)
92 {
93   struct Set *set;
94
95   for (set = sets_head; NULL != set; set = set->next)
96     if (set->client == client)
97       return set;
98   return NULL;
99 }
100
101
102 /**
103  * Get the listener associated with the given client, if any.
104  *
105  * @param client the client
106  * @return listener associated with the client, NULL
107  *         if there isn't any
108  */
109 static struct Listener *
110 listener_get (struct GNUNET_SERVER_Client *client)
111 {
112   struct Listener *listener;
113
114   for (listener = listeners_head; NULL != listener; listener = listener->next)
115     if (listener->client == client)
116       return listener;
117   return NULL;
118 }
119
120
121 /**
122  * Get the incoming socket associated with the given id.
123  *
124  * @param id id to look for
125  * @return the incoming socket associated with the id,
126  *         or NULL if there is none
127  */
128 static struct Incoming *
129 get_incoming (uint32_t id)
130 {
131   struct Incoming *incoming;
132
133   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
134     if (incoming->accept_id == id)
135       return incoming;
136   return NULL;
137 }
138
139
140 /**
141  * Destroy a listener, free all resources associated with it.
142  *
143  * @param listener listener to destroy
144  */
145 static void
146 listener_destroy (struct Listener *listener)
147 {
148   if (NULL != listener->client_mq)
149   {
150     GNUNET_MQ_destroy (listener->client_mq);
151     listener->client_mq = NULL;
152   }
153   GNUNET_CONTAINER_DLL_remove (listeners_head, listeners_tail, listener);
154   GNUNET_free (listener);
155 }
156
157
158 /**
159  * Destroy a set, and free all resources associated with it.
160  *
161  * @param set the set to destroy
162  */
163 static void
164 set_destroy (struct Set *set)
165 {
166   switch (set->operation)
167   {
168     case GNUNET_SET_OPERATION_INTERSECTION:
169       GNUNET_assert (0);
170       break;
171     case GNUNET_SET_OPERATION_UNION:
172       _GSS_union_set_destroy (set);
173       break;
174     default:
175       GNUNET_assert (0);
176       break;
177   }
178   GNUNET_CONTAINER_DLL_remove (sets_head, sets_tail, set);
179   GNUNET_free (set);
180 }
181
182
183 /**
184  * Clean up after a client after it is
185  * disconnected (either by us or by itself)
186  *
187  * @param cls closure, unused
188  * @param client the client to clean up after
189  */
190 static void
191 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
192 {
193   struct Set *set;
194   struct Listener *listener;
195
196   set = set_get (client);
197   if (NULL != set)
198     set_destroy (set);
199   listener = listener_get (client);
200   if (NULL != listener)
201     listener_destroy (listener);
202 }
203
204
205 /**
206  * Destroy an incoming request from a remote peer
207  *
208  * @param incoming remote request to destroy
209  */
210 static void
211 incoming_destroy (struct Incoming *incoming)
212 {
213   GNUNET_CONTAINER_DLL_remove (incoming_head, incoming_tail, incoming);
214   GNUNET_free (incoming);
215 }
216
217
218 static struct Listener *
219 listener_get_by_target (enum GNUNET_SET_OperationType op,
220                         const struct GNUNET_HashCode *app_id)
221 {
222   struct Listener *l;
223
224   for (l = listeners_head; NULL != l; l = l->next)
225   {
226     if (l->operation != op)
227       continue;
228     if (0 != GNUNET_CRYPTO_hash_cmp (app_id, &l->app_id))
229       continue;
230     return l;
231   }
232   return NULL;
233 }
234
235
236 /**
237  * Suggest the given request to the listener,
238  * who can accept or reject the request.
239  *
240  * @param incoming the incoming peer with the request to suggest
241  * @param listener the listener to suggest the request to
242  */
243 static void
244 incoming_suggest (struct Incoming *incoming, struct Listener *listener)
245 {
246   struct GNUNET_MQ_Envelope *mqm;
247   struct GNUNET_SET_RequestMessage *cmsg;
248
249   GNUNET_assert (GNUNET_NO == incoming->suggested);
250   incoming->suggested = GNUNET_YES;
251
252   GNUNET_SCHEDULER_cancel (incoming->timeout_task);
253   mqm = GNUNET_MQ_msg_nested_mh (cmsg, GNUNET_MESSAGE_TYPE_SET_REQUEST,
254                                  incoming->context_msg);
255   GNUNET_assert (NULL != mqm);
256   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "suggesting request with accept id %u\n", incoming->accept_id);
257   cmsg->accept_id = htonl (incoming->accept_id);
258   cmsg->peer_id = incoming->tc->peer;
259   GNUNET_MQ_send (listener->client_mq, mqm);
260
261 }
262
263
264 /**
265  * Handle a request for a set operation from
266  * another peer.
267  *
268  * @param cls the incoming socket
269  * @param tunnel the tunnel that sent the message
270  * @param tunnel_ctx the tunnel context
271  * @param mh the message
272  */
273 static int
274 handle_p2p_operation_request (void *cls,
275                               struct GNUNET_MESH_Tunnel *tunnel,
276                               void **tunnel_ctx,
277                               const struct GNUNET_MessageHeader *mh)
278 {
279   struct TunnelContext *tc = *tunnel_ctx;
280   struct Incoming *incoming;
281   const struct OperationRequestMessage *msg = (const struct OperationRequestMessage *) mh;
282   struct Listener *listener;
283
284   if (CONTEXT_INCOMING != tc->type)
285   {
286     /* unexpected request */
287     GNUNET_break_op (0);
288     /* kill the tunnel, cleaner will be called */
289     return GNUNET_SYSERR;
290   }
291
292   incoming = tc->data;
293
294   if (GNUNET_YES == incoming->received_request)
295   {
296     /* double operation request */
297     GNUNET_break_op (0);
298     return GNUNET_SYSERR;
299   }
300
301   incoming->accept_id = accept_id++;
302   incoming->context_msg =
303       GNUNET_copy_message (GNUNET_MQ_extract_nested_mh (msg));
304
305   if ( (NULL != incoming->context_msg) &&
306        (ntohs (incoming->context_msg->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
307   {
308     GNUNET_break_op (0);
309     return GNUNET_SYSERR;
310   }
311
312   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "received P2P operation request (op %u, app %s)\n",
313               ntohs (msg->operation), GNUNET_h2s (&msg->app_id));
314   listener = listener_get_by_target (ntohs (msg->operation), &msg->app_id);
315   if (NULL == listener)
316   {
317     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
318                 "no listener matches incoming request, waiting with timeout\n");
319     return GNUNET_OK;
320   }
321   incoming_suggest (incoming, listener);
322   return GNUNET_OK;
323 }
324
325
326 /**
327  * Called when a client wants to create a new set.
328  *
329  * @param cls unused
330  * @param client client that sent the message
331  * @param m message sent by the client
332  */
333 static void
334 handle_client_create (void *cls,
335                       struct GNUNET_SERVER_Client *client,
336                       const struct GNUNET_MessageHeader *m)
337 {
338   struct GNUNET_SET_CreateMessage *msg = (struct GNUNET_SET_CreateMessage *) m;
339   struct Set *set;
340
341   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client created new set (operation %u)\n",
342               ntohs (msg->operation));
343
344   if (NULL != set_get (client))
345   {
346     GNUNET_break (0);
347     GNUNET_SERVER_client_disconnect (client);
348     return;
349   }
350
351   set = NULL;
352
353   switch (ntohs (msg->operation))
354   {
355     case GNUNET_SET_OPERATION_INTERSECTION:
356       //set = _GSS_intersection_set_create ();
357       break;
358     case GNUNET_SET_OPERATION_UNION:
359       set = _GSS_union_set_create ();
360       break;
361     default:
362       GNUNET_break (0);
363       GNUNET_SERVER_client_disconnect (client);
364       return;
365   }
366
367   GNUNET_assert (NULL != set);
368
369   set->client = client;
370   set->client_mq = GNUNET_MQ_queue_for_server_client (client);
371   GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
372   GNUNET_SERVER_receive_done (client, GNUNET_OK);
373 }
374
375
376 /**
377  * Called when a client wants to create a new listener.
378  *
379  * @param cls unused
380  * @param client client that sent the message
381  * @param m message sent by the client
382  */
383 static void
384 handle_client_listen (void *cls,
385                       struct GNUNET_SERVER_Client *client,
386                       const struct GNUNET_MessageHeader *m)
387 {
388   struct GNUNET_SET_ListenMessage *msg = (struct GNUNET_SET_ListenMessage *) m;
389   struct Listener *listener;
390   struct Incoming *incoming;
391
392   if (NULL != listener_get (client))
393   {
394     GNUNET_break (0);
395     GNUNET_SERVER_client_disconnect (client);
396     return;
397   }
398   listener = GNUNET_new (struct Listener);
399   listener->client = client;
400   listener->client_mq = GNUNET_MQ_queue_for_server_client (client);
401   listener->app_id = msg->app_id;
402   listener->operation = ntohs (msg->operation);
403   GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
404   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new listener created (op %u, app %s)\n",
405               listener->operation, GNUNET_h2s (&listener->app_id));
406   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
407   {
408     if ( (GNUNET_NO == incoming->received_request) ||
409          (GNUNET_YES == incoming->suggested) )
410       continue;
411     if (listener->operation != incoming->operation)
412       continue;
413     if (0 != GNUNET_CRYPTO_hash_cmp (&listener->app_id, &incoming->app_id))
414       continue;
415     incoming_suggest (incoming, listener);
416   }
417   GNUNET_SERVER_receive_done (client, GNUNET_OK);
418 }
419
420
421 /**
422  * Called when a client wants to remove an element
423  * from the set it inhabits.
424  *
425  * @param cls unused
426  * @param client client that sent the message
427  * @param m message sent by the client
428  */
429 static void
430 handle_client_remove (void *cls,
431                       struct GNUNET_SERVER_Client *client,
432                       const struct GNUNET_MessageHeader *m)
433 {
434   struct Set *set;
435
436   set = set_get (client);
437   if (NULL == set)
438   {
439     GNUNET_break (0);
440     GNUNET_SERVER_client_disconnect (client);
441     return;
442   }
443   switch (set->operation)
444   {
445     case GNUNET_SET_OPERATION_UNION:
446       _GSS_union_remove ((struct GNUNET_SET_ElementMessage *) m, set);
447       break;
448     case GNUNET_SET_OPERATION_INTERSECTION:
449       //_GSS_intersection_remove ((struct GNUNET_SET_ElementMessage *) m, set);
450       break;
451     default:
452       GNUNET_assert (0);
453       break;
454   }
455
456   GNUNET_SERVER_receive_done (client, GNUNET_OK);
457 }
458
459
460
461 /**
462  * Called when the client wants to reject an operation
463  * request from another peer.
464  *
465  * @param cls unused
466  * @param client client that sent the message
467  * @param m message sent by the client
468  */
469 static void
470 handle_client_reject (void *cls,
471                       struct GNUNET_SERVER_Client *client,
472                       const struct GNUNET_MessageHeader *m)
473 {
474   struct Incoming *incoming;
475   struct GNUNET_SET_AcceptRejectMessage *msg = (struct GNUNET_SET_AcceptRejectMessage *) m;
476
477   GNUNET_break (0 == ntohl (msg->request_id));
478
479   incoming = get_incoming (ntohl (msg->accept_reject_id));
480   if (NULL == incoming)
481   {
482     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
483     return;
484   }
485   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "peer request rejected by client\n");
486   /* the incoming peer will be destroyed in the tunnel end handler */
487   GNUNET_MESH_tunnel_destroy (incoming->tc->tunnel);
488   GNUNET_SERVER_receive_done (client, GNUNET_OK);
489 }
490
491
492
493 /**
494  * Called when a client wants to add an element to a
495  * set it inhabits.
496  *
497  * @param cls unused
498  * @param client client that sent the message
499  * @param m message sent by the client
500  */
501 static void
502 handle_client_add (void *cls,
503                    struct GNUNET_SERVER_Client *client,
504                    const struct GNUNET_MessageHeader *m)
505 {
506   struct Set *set;
507
508   set = set_get (client);
509   if (NULL == set)
510   {
511     GNUNET_break (0);
512     GNUNET_SERVER_client_disconnect (client);
513     return;
514   }
515   switch (set->operation)
516   {
517     case GNUNET_SET_OPERATION_UNION:
518       _GSS_union_add ((struct GNUNET_SET_ElementMessage *) m, set);
519       break;
520     case GNUNET_SET_OPERATION_INTERSECTION:
521       //_GSS_intersection_add ((struct GNUNET_SET_ElementMessage *) m, set);
522       break;
523     default:
524       GNUNET_assert (0);
525       break;
526   }
527
528   GNUNET_SERVER_receive_done (client, GNUNET_OK);
529 }
530
531
532 /**
533  * Called when a client wants to evaluate a set operation with another peer.
534  *
535  * @param cls unused
536  * @param client client that sent the message
537  * @param m message sent by the client
538  */
539 static void
540 handle_client_evaluate (void *cls,
541                         struct GNUNET_SERVER_Client *client,
542                         const struct GNUNET_MessageHeader *m)
543 {
544   struct Set *set;
545
546   set = set_get (client);
547   if (NULL == set)
548   {
549     GNUNET_break (0);
550     GNUNET_SERVER_client_disconnect (client);
551     return;
552   }
553
554   switch (set->operation)
555   {
556     case GNUNET_SET_OPERATION_INTERSECTION:
557       //_GSS_intersection_evaluate ((struct GNUNET_SET_EvaluateMessage *) m, set);
558       break;
559     case GNUNET_SET_OPERATION_UNION:
560       _GSS_union_evaluate ((struct GNUNET_SET_EvaluateMessage *) m, set);
561       break;
562     default:
563       GNUNET_assert (0);
564       break;
565   }
566
567   GNUNET_SERVER_receive_done (client, GNUNET_OK);
568 }
569
570
571 /**
572  * Handle an ack from a client.
573  *
574  * @param cls unused
575  * @param client the client
576  * @param m the message
577  */
578 static void
579 handle_client_ack (void *cls,
580                    struct GNUNET_SERVER_Client *client,
581                    const struct GNUNET_MessageHeader *m)
582 {
583   /* FIXME: implement */
584   GNUNET_SERVER_receive_done (client, GNUNET_OK);
585 }
586
587
588 /**
589  * Handle a request from the client to accept
590  * a set operation that came from a remote peer.
591  *
592  * @param cls unused
593  * @param client the client
594  * @param mh the message
595  */
596 static void
597 handle_client_accept (void *cls,
598                       struct GNUNET_SERVER_Client *client,
599                       const struct GNUNET_MessageHeader *mh)
600 {
601   struct Set *set;
602   struct Incoming *incoming;
603   struct GNUNET_SET_AcceptRejectMessage *msg = (struct GNUNET_SET_AcceptRejectMessage *) mh;
604
605   incoming = get_incoming (ntohl (msg->accept_reject_id));
606
607   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client accepting %u\n", ntohl (msg->accept_reject_id));
608
609   if (NULL == incoming)
610   {
611
612     GNUNET_break (0);
613     GNUNET_SERVER_client_disconnect (client);
614     return;
615   }
616
617   set = set_get (client);
618
619   if (NULL == set)
620   {
621     GNUNET_break (0);
622     GNUNET_SERVER_client_disconnect (client);
623     return;
624   }
625
626   switch (set->operation)
627   {
628     case GNUNET_SET_OPERATION_INTERSECTION:
629       // _GSS_intersection_accept (msg, set, incoming);
630       break;
631     case GNUNET_SET_OPERATION_UNION:
632       _GSS_union_accept (msg, set, incoming);
633       break;
634     default:
635       GNUNET_assert (0);
636       break;
637   }
638
639   /* note: _GSS_*_accept has to make sure the tunnel and mq are set to NULL,
640    * otherwise they will be destroyed and disconnected */
641   incoming_destroy (incoming);
642   GNUNET_SERVER_receive_done (client, GNUNET_OK);
643 }
644
645
646 /**
647  * Called to clean up, after a shutdown has been requested.
648  *
649  * @param cls closure
650  * @param tc context information (why was this task triggered now)
651  */
652 static void
653 shutdown_task (void *cls,
654                const struct GNUNET_SCHEDULER_TaskContext *tc)
655 {
656   if (NULL != mesh)
657   {
658     GNUNET_MESH_disconnect (mesh);
659     mesh = NULL;
660   }
661
662   while (NULL != incoming_head)
663     incoming_destroy (incoming_head);
664
665   while (NULL != listeners_head)
666     listener_destroy (listeners_head);
667
668   while (NULL != sets_head)
669     set_destroy (sets_head);
670
671   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
672 }
673
674
675
676 /**
677  * Signature of the main function of a task.
678  *
679  * @param cls closure
680  * @param tc context information (why was this task triggered now)
681  */
682 static void
683 incoming_timeout_cb (void *cls,
684                      const struct GNUNET_SCHEDULER_TaskContext *tc)
685 {
686   struct Incoming *incoming = cls;
687
688   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "remote peer timed out\n");
689   incoming_destroy (incoming);
690 }
691
692
693 /**
694  * Method called whenever another peer has added us to a tunnel
695  * the other peer initiated.
696  * Only called (once) upon reception of data with a message type which was
697  * subscribed to in GNUNET_MESH_connect. A call to GNUNET_MESH_tunnel_destroy
698  * causes te tunnel to be ignored and no further notifications are sent about
699  * the same tunnel.
700  *
701  * @param cls closure
702  * @param tunnel new handle to the tunnel
703  * @param initiator peer that started the tunnel
704  * @param port Port this tunnel is for.
705  * @return initial tunnel context for the tunnel
706  *         (can be NULL -- that's not an error)
707  */
708 static void *
709 tunnel_new_cb (void *cls,
710                struct GNUNET_MESH_Tunnel *tunnel,
711                const struct GNUNET_PeerIdentity *initiator,
712                uint32_t port)
713 {
714   struct Incoming *incoming;
715   struct TunnelContext *tc;
716
717   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new incoming tunnel\n");
718
719   GNUNET_assert (port == GNUNET_APPLICATION_TYPE_SET);
720   tc = GNUNET_new (struct TunnelContext);
721   incoming = GNUNET_new (struct Incoming);
722   incoming->tc = tc;
723   tc->peer = *initiator;
724   tc->tunnel = tunnel;
725   tc->mq = GNUNET_MESH_mq_create (tunnel);
726   tc->data = incoming;
727   tc->type = CONTEXT_INCOMING;
728   incoming->timeout_task = 
729       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, incoming_timeout_cb, incoming);
730   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
731
732   return tc;
733 }
734
735
736 /**
737  * Function called whenever a tunnel is destroyed.  Should clean up
738  * any associated state.
739  * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on
740  * the tunnel.
741  *
742  * @param cls closure (set from GNUNET_MESH_connect)
743  * @param tunnel connection to the other end (henceforth invalid)
744  * @param tunnel_ctx place where local state associated
745  *                   with the tunnel is stored
746  */
747 static void
748 tunnel_end_cb (void *cls,
749                const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
750 {
751   struct TunnelContext *ctx = tunnel_ctx;
752
753   /* tunnel is dead already */
754   ctx->tunnel = NULL;
755
756   if (NULL != ctx->mq)
757   {
758     GNUNET_MQ_destroy (ctx->mq);
759     ctx->mq = NULL;
760   }
761
762   switch (ctx->type)
763   {
764     case CONTEXT_INCOMING:
765       incoming_destroy ((struct Incoming *) ctx->data);
766       break;
767     case CONTEXT_OPERATION_UNION:
768       _GSS_union_operation_destroy ((struct UnionEvaluateOperation *) ctx->data);
769       break;
770     case CONTEXT_OPERATION_INTERSECTION:
771       GNUNET_assert (0);
772       /* FIXME: cfuchs */
773       break;
774     default:
775       GNUNET_assert (0);
776   }
777
778   GNUNET_free (tunnel_ctx);
779 }
780
781
782 /**
783  * Function called by the service's run
784  * method to run service-specific setup code.
785  *
786  * @param cls closure
787  * @param server the initialized server
788  * @param cfg configuration to use
789  */
790 static void
791 run (void *cls, struct GNUNET_SERVER_Handle *server,
792      const struct GNUNET_CONFIGURATION_Handle *cfg)
793 {
794   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
795     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
796     {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
797     {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
798     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
799     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
800     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
801     {handle_client_reject, NULL, GNUNET_MESSAGE_TYPE_SET_REJECT, 0},
802     {handle_client_remove, NULL, GNUNET_MESSAGE_TYPE_SET_REMOVE, 0},
803     {NULL, NULL, 0, 0}
804   };
805   static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
806     {handle_p2p_operation_request,
807       GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 0},
808     /* messages for the union operation */
809     {_GSS_union_handle_p2p_message,
810       GNUNET_MESSAGE_TYPE_SET_P2P_IBF, 0},
811     {_GSS_union_handle_p2p_message,
812       GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 0},
813     {_GSS_union_handle_p2p_message,
814       GNUNET_MESSAGE_TYPE_SET_P2P_DONE, 0},
815     {_GSS_union_handle_p2p_message,
816       GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENT_REQUESTS, 0},
817     {_GSS_union_handle_p2p_message,
818       GNUNET_MESSAGE_TYPE_SET_P2P_SE, 0},
819     /* FIXME: messages for intersection operation */
820     {NULL, 0, 0}
821   };
822   static const uint32_t mesh_ports[] = {GNUNET_APPLICATION_TYPE_SET, 0};
823
824   configuration = cfg;
825   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
826                                 &shutdown_task, NULL);
827   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
828   GNUNET_SERVER_add_handlers (server, server_handlers);
829
830   mesh = GNUNET_MESH_connect (cfg, NULL, tunnel_new_cb, tunnel_end_cb,
831                               mesh_handlers, mesh_ports);
832   if (NULL == mesh)
833   {
834     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not connect to mesh\n");
835     return;
836   }
837
838   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "service started\n");
839 }
840
841
842 /**
843  * The main function for the set service.
844  *
845  * @param argc number of arguments from the command line
846  * @param argv command line arguments
847  * @return 0 ok, 1 on error
848  */
849 int
850 main (int argc, char *const *argv)
851 {
852   int ret;
853   ret = GNUNET_SERVICE_run (argc, argv, "set",
854                             GNUNET_SERVICE_OPTION_NONE, &run, NULL);
855   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit\n");
856   return (GNUNET_OK == ret) ? 0 : 1;
857 }
858