9210e1ea83cd304f5086c57e5bb249fea5de1f0d
[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  * Peer that has connected to us, but is not yet evaluating a set operation.
32  * Once the peer has sent a request, and the client has
33  * accepted or rejected it, this information will be deleted.
34  */
35 struct Incoming
36 {
37   /**
38    * Incoming peers are held in a linked list
39    */
40   struct Incoming *next;
41
42   /**
43    * Incoming peers are held in a linked list
44    */
45   struct Incoming *prev;
46
47   /**
48    * Detail information about the operation.
49    * NULL as long as we did not receive the operation
50    * request from the remote peer.
51    */
52   struct OperationSpecification *spec;
53
54   /**
55    * The identity of the requesting peer.  Needs to
56    * be stored here as the op spec might not have been created yet.
57    */
58   struct GNUNET_PeerIdentity peer;
59
60   /**
61    * Tunnel to the peer.
62    */
63   struct GNUNET_MESH_Tunnel *tunnel;
64
65   /**
66    * Unique request id for the request from
67    * a remote peer, sent to the client, which will
68    * accept or reject the request.
69    * Set to '0' iff the request has not been
70    * suggested yet.
71    */
72   uint32_t suggest_id;
73
74   /**
75    * Timeout task, if the incoming peer has not been accepted
76    * after the timeout, it will be disconnected.
77    */
78   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
79
80   /**
81    * Tunnel context, needs to be stored here as a client's accept will change
82    * the tunnel context.
83    */
84   struct TunnelContext *tc;
85 };
86
87
88 /**
89  * A listener is inhabited by a client, and
90  * waits for evaluation requests from remote peers.
91  */
92 struct Listener
93 {
94   /**
95    * Listeners are held in a doubly linked list.
96    */
97   struct Listener *next;
98
99   /**
100    * Listeners are held in a doubly linked list.
101    */
102   struct Listener *prev;
103
104   /**
105    * Client that owns the listener.
106    * Only one client may own a listener.
107    */
108   struct GNUNET_SERVER_Client *client;
109
110   /**
111    * Message queue for the client
112    */
113   struct GNUNET_MQ_Handle *client_mq;
114
115   /**
116    * The type of the operation.
117    */
118   enum GNUNET_SET_OperationType operation;
119
120   /**
121    * Application ID for the operation, used to distinguish
122    * multiple operations of the same type with the same peer.
123    */
124   struct GNUNET_HashCode app_id;
125 };
126
127
128 /**
129  * Configuration of our local peer.
130  */
131 static const struct GNUNET_CONFIGURATION_Handle *configuration;
132
133 /**
134  * Handle to the mesh service, used
135  * to listen for and connect to remote peers.
136  */
137 static struct GNUNET_MESH_Handle *mesh;
138
139 /**
140  * Sets are held in a doubly linked list.
141  */
142 static struct Set *sets_head;
143
144 /**
145  * Sets are held in a doubly linked list.
146  */
147 static struct Set *sets_tail;
148
149 /**
150  * Listeners are held in a doubly linked list.
151  */
152 static struct Listener *listeners_head;
153
154 /**
155  * Listeners are held in a doubly linked list.
156  */
157 static struct Listener *listeners_tail;
158
159 /**
160  * Incoming sockets from remote peers are
161  * held in a doubly linked list.
162  */
163 static struct Incoming *incoming_head;
164
165 /**
166  * Incoming sockets from remote peers are
167  * held in a doubly linked list.
168  */
169 static struct Incoming *incoming_tail;
170
171 /**
172  * Counter for allocating unique IDs for clients,
173  * used to identify incoming operation requests from remote peers,
174  * that the client can choose to accept or refuse.
175  */
176 static uint32_t suggest_id = 1;
177
178
179 /**
180  * Get set that is owned by the given client, if any.
181  *
182  * @param client client to look for
183  * @return set that the client owns, NULL if the client
184  *         does not own a set
185  */
186 static struct Set *
187 set_get (struct GNUNET_SERVER_Client *client)
188 {
189   struct Set *set;
190
191   for (set = sets_head; NULL != set; set = set->next)
192     if (set->client == client)
193       return set;
194   return NULL;
195 }
196
197
198 /**
199  * Get the listener associated with the given client, if any.
200  *
201  * @param client the client
202  * @return listener associated with the client, NULL
203  *         if there isn't any
204  */
205 static struct Listener *
206 listener_get (struct GNUNET_SERVER_Client *client)
207 {
208   struct Listener *listener;
209
210   for (listener = listeners_head; NULL != listener; listener = listener->next)
211     if (listener->client == client)
212       return listener;
213   return NULL;
214 }
215
216
217 /**
218  * Get the incoming socket associated with the given id.
219  *
220  * @param id id to look for
221  * @return the incoming socket associated with the id,
222  *         or NULL if there is none
223  */
224 static struct Incoming *
225 get_incoming (uint32_t id)
226 {
227   struct Incoming *incoming;
228
229   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
230     if (incoming->suggest_id == id)
231       return incoming;
232   return NULL;
233 }
234
235
236 /**
237  * Destroy a listener, free all resources associated with it.
238  *
239  * @param listener listener to destroy
240  */
241 static void
242 listener_destroy (struct Listener *listener)
243 {
244   /* If the client is not dead yet, destroy it.
245    * The client's destroy callback will destroy the listener again. */
246   if (NULL != listener->client)
247   {
248     struct GNUNET_SERVER_Client *client = listener->client;
249     listener->client = NULL;
250     GNUNET_SERVER_client_disconnect (client);
251     return;
252   }
253   if (NULL != listener->client_mq)
254   {
255     GNUNET_MQ_destroy (listener->client_mq);
256     listener->client_mq = NULL;
257   }
258   GNUNET_CONTAINER_DLL_remove (listeners_head, listeners_tail, listener);
259   GNUNET_free (listener);
260 }
261
262
263 /**
264  * Iterator over hash map entries.
265  *
266  * @param cls closure
267  * @param key current key code
268  * @param value value in the hash map
269  * @return GNUNET_YES if we should continue to
270  *         iterate,
271  *         GNUNET_NO if not.
272  */
273 static int
274 destroy_elements_iterator (void *cls,
275                            const struct GNUNET_HashCode * key,
276                            void *value)
277 {
278   struct ElementEntry *ee = value;
279
280   GNUNET_free (ee);
281   return GNUNET_YES;
282 }
283
284
285 /**
286  * Destroy a set, and free all resources associated with it.
287  *
288  * @param set the set to destroy
289  */
290 static void
291 set_destroy (struct Set *set)
292 {
293   /* If the client is not dead yet, destroy it.
294    * The client's destroy callback will destroy the set again. */
295   if (NULL != set->client)
296   {
297     struct GNUNET_SERVER_Client *client = set->client;
298     set->client = NULL;
299     GNUNET_SERVER_client_disconnect (client);
300     return;
301   }
302   if (NULL != set->client_mq)
303   {
304     GNUNET_MQ_destroy (set->client_mq);
305     set->client_mq = NULL;
306   }
307   if (NULL != set->elements)
308   {
309     GNUNET_CONTAINER_multihashmap_iterate (set->elements,
310                                            destroy_elements_iterator, NULL);
311     GNUNET_CONTAINER_multihashmap_destroy (set->elements);
312     set->elements = NULL;
313   }
314   if (NULL != set->iter)
315   {
316     GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
317     set->iter = NULL;
318   }
319   GNUNET_assert (NULL != set->state);
320   set->vt->destroy_set (set->state);
321   set->state = NULL;
322   GNUNET_CONTAINER_DLL_remove (sets_head, sets_tail, set);
323   GNUNET_free (set);
324 }
325
326
327 /**
328  * Clean up after a client after it is
329  * disconnected (either by us or by itself)
330  *
331  * @param cls closure, unused
332  * @param client the client to clean up after
333  */
334 static void
335 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
336 {
337   struct Set *set;
338   struct Listener *listener;
339
340   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disconnected, cleaning up\n");
341
342   set = set_get (client);
343   if (NULL != set)
344   {
345     set->client = NULL;
346     set_destroy (set);
347     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(client's set destroyed)\n");
348   }
349   listener = listener_get (client);
350   if (NULL != listener)
351   {
352     listener->client = NULL;
353     listener_destroy (listener);
354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(client's listener destroyed)\n");
355   }
356 }
357
358
359 /**
360  * Destroy an incoming request from a remote peer
361  *
362  * @param incoming remote request to destroy
363  */
364 static void
365 incoming_destroy (struct Incoming *incoming)
366 {
367   GNUNET_CONTAINER_DLL_remove (incoming_head, incoming_tail, incoming);
368   if (NULL != incoming->tunnel)
369   {
370     struct GNUNET_MESH_Tunnel *t = incoming->tunnel;
371     incoming->tunnel = NULL;
372     GNUNET_MESH_tunnel_destroy (t);
373     return;
374   }
375   GNUNET_free (incoming);
376 }
377
378
379 static struct Listener *
380 listener_get_by_target (enum GNUNET_SET_OperationType op,
381                         const struct GNUNET_HashCode *app_id)
382 {
383   struct Listener *l;
384
385   for (l = listeners_head; NULL != l; l = l->next)
386   {
387     if (l->operation != op)
388       continue;
389     if (0 != GNUNET_CRYPTO_hash_cmp (app_id, &l->app_id))
390       continue;
391     return l;
392   }
393   return NULL;
394 }
395
396
397 /**
398  * Suggest the given request to the listener,
399  * who can accept or reject the request.
400  *
401  * @param incoming the incoming peer with the request to suggest
402  * @param listener the listener to suggest the request to
403  */
404 static void
405 incoming_suggest (struct Incoming *incoming, struct Listener *listener)
406 {
407   struct GNUNET_MQ_Envelope *mqm;
408   struct GNUNET_SET_RequestMessage *cmsg;
409
410   GNUNET_assert (0 == incoming->suggest_id);
411   GNUNET_assert (NULL != incoming->spec);
412   incoming->suggest_id = suggest_id++;
413
414   GNUNET_SCHEDULER_cancel (incoming->timeout_task);
415   mqm = GNUNET_MQ_msg_nested_mh (cmsg, GNUNET_MESSAGE_TYPE_SET_REQUEST,
416                                  incoming->spec->context_msg);
417   GNUNET_assert (NULL != mqm);
418   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "suggesting request with accept id %u\n",
419               incoming->suggest_id);
420   cmsg->accept_id = htonl (incoming->suggest_id);
421   cmsg->peer_id = incoming->spec->peer;
422   GNUNET_MQ_send (listener->client_mq, mqm);
423
424 }
425
426
427 /**
428  * Handle a request for a set operation from
429  * another peer.
430  *
431  * @param op the operation state
432  * @param mh the received message
433  * @return GNUNET_OK if the tunnel should be kept alive,
434  *         GNUNET_SYSERR to destroy the tunnel
435  */
436 static int
437 handle_incoming_msg (struct OperationState *op,
438                      const struct GNUNET_MessageHeader *mh)
439 {
440   struct Incoming *incoming = (struct Incoming *) op;
441   const struct OperationRequestMessage *msg = (const struct OperationRequestMessage *) mh;
442   struct Listener *listener;
443   struct OperationSpecification *spec;
444
445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got op request\n");
446
447   if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type))
448   {
449     GNUNET_break_op (0);
450     return GNUNET_SYSERR;
451   }
452
453   if (NULL != incoming->spec)
454   {
455     /* double operation request */
456     GNUNET_break_op (0);
457     return GNUNET_SYSERR;
458   }
459
460   spec = GNUNET_new (struct OperationSpecification);
461   spec->context_msg = GNUNET_MQ_extract_nested_mh (msg);
462   if (NULL != spec->context_msg)
463     spec->context_msg = GNUNET_copy_message (spec->context_msg);
464   spec->operation = ntohl (msg->operation);
465   spec->app_id = msg->app_id;
466   spec->salt = ntohl (msg->salt);
467   spec->peer = incoming->peer;
468
469   incoming->spec = spec;
470
471   if ( (NULL != spec->context_msg) &&
472        (ntohs (spec->context_msg->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
473   {
474     GNUNET_break_op (0);
475     return GNUNET_SYSERR;
476   }
477
478   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "received P2P operation request (op %u, app %s)\n",
479               ntohl (msg->operation), GNUNET_h2s (&msg->app_id));
480   listener = listener_get_by_target (ntohl (msg->operation), &msg->app_id);
481   if (NULL == listener)
482   {
483     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484                 "no listener matches incoming request, waiting with timeout\n");
485     return GNUNET_OK;
486   }
487   incoming_suggest (incoming, listener);
488   return GNUNET_OK;
489 }
490
491
492 static void
493 send_client_element (struct Set *set)
494 {
495   int ret;
496   struct ElementEntry *ee;
497   struct GNUNET_MQ_Envelope *ev;
498
499   GNUNET_assert (NULL != set->iter);
500   ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, NULL, (const void **) &ee);
501   if (GNUNET_NO == ret)
502   {
503     ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
504   }
505   else
506   {
507     struct GNUNET_SET_IterResponseMessage *msg;
508
509     GNUNET_assert (NULL != ee);
510     ev = GNUNET_MQ_msg_extra (msg, ee->element.size, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
511     memcpy (&msg[1], ee->element.data, ee->element.size);
512     msg->element_type = ee->element.type;
513   }
514   GNUNET_MQ_send (set->client_mq, ev);
515 }
516
517
518 /**
519  * Called when a client wants to iterate the elements of a set.
520  *
521  * @param cls unused
522  * @param client client that sent the message
523  * @param m message sent by the client
524  */
525 static void
526 handle_client_iterate (void *cls,
527                        struct GNUNET_SERVER_Client *client,
528                        const struct GNUNET_MessageHeader *m)
529 {
530   struct Set *set;
531   
532   set = set_get (client);
533   if (NULL == set)
534   {
535     GNUNET_break (0);
536     GNUNET_SERVER_client_disconnect (client);
537     return;
538   }
539
540   if (NULL != set->iter)
541   {
542     GNUNET_break (0);
543     GNUNET_SERVER_client_disconnect (client);
544     return;
545   }
546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "iterating union set with %u elements\n",
547               GNUNET_CONTAINER_multihashmap_size (set->elements));
548   GNUNET_SERVER_receive_done (client, GNUNET_OK);
549   set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->elements);
550   send_client_element (set);
551 }
552
553
554 /**
555  * Called when a client wants to create a new set.
556  *
557  * @param cls unused
558  * @param client client that sent the message
559  * @param m message sent by the client
560  */
561 static void
562 handle_client_create (void *cls,
563                       struct GNUNET_SERVER_Client *client,
564                       const struct GNUNET_MessageHeader *m)
565 {
566   struct GNUNET_SET_CreateMessage *msg = (struct GNUNET_SET_CreateMessage *) m;
567   struct Set *set;
568
569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client created new set (operation %u)\n",
570               ntohs (msg->operation));
571
572   if (NULL != set_get (client))
573   {
574     GNUNET_break (0);
575     GNUNET_SERVER_client_disconnect (client);
576     return;
577   }
578
579   set = GNUNET_new (struct Set);
580
581   switch (ntohs (msg->operation))
582   {
583     case GNUNET_SET_OPERATION_INTERSECTION:
584       // FIXME
585       break;
586     case GNUNET_SET_OPERATION_UNION:
587       set->vt = _GSS_union_vt ();
588       break;
589     default:
590       GNUNET_free (set);
591       GNUNET_break (0);
592       GNUNET_SERVER_client_disconnect (client);
593       return;
594   }
595
596   set->state = set->vt->create ();
597   set->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
598   set->client = client;
599   set->client_mq = GNUNET_MQ_queue_for_server_client (client);
600   GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
601   GNUNET_SERVER_receive_done (client, GNUNET_OK);
602 }
603
604
605 /**
606  * Called when a client wants to create a new listener.
607  *
608  * @param cls unused
609  * @param client client that sent the message
610  * @param m message sent by the client
611  */
612 static void
613 handle_client_listen (void *cls,
614                       struct GNUNET_SERVER_Client *client,
615                       const struct GNUNET_MessageHeader *m)
616 {
617   struct GNUNET_SET_ListenMessage *msg = (struct GNUNET_SET_ListenMessage *) m;
618   struct Listener *listener;
619   struct Incoming *incoming;
620
621   if (NULL != listener_get (client))
622   {
623     GNUNET_break (0);
624     GNUNET_SERVER_client_disconnect (client);
625     return;
626   }
627   listener = GNUNET_new (struct Listener);
628   listener->client = client;
629   listener->client_mq = GNUNET_MQ_queue_for_server_client (client);
630   listener->app_id = msg->app_id;
631   listener->operation = ntohl (msg->operation);
632   GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
633   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new listener created (op %u, app %s)\n",
634               listener->operation, GNUNET_h2s (&listener->app_id));
635   for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
636   {
637     if (NULL == incoming->spec)
638     {
639       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "request has no spec yet\n");
640       continue;
641     }
642     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "considering (op: %u, app: %s, suggest: %u)\n",
643                 incoming->spec->operation, GNUNET_h2s (&incoming->spec->app_id), incoming->suggest_id);
644
645     if (0 != incoming->suggest_id)
646       continue;
647     if (listener->operation != incoming->spec->operation)
648       continue;
649     if (0 != GNUNET_CRYPTO_hash_cmp (&listener->app_id, &incoming->spec->app_id))
650       continue;
651     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "request suggested\n");
652     incoming_suggest (incoming, listener);
653   }
654   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "considered all incoming requests\n");
655   GNUNET_SERVER_receive_done (client, GNUNET_OK);
656 }
657
658
659 /**
660  * Called when the client wants to reject an operation
661  * request from another peer.
662  *
663  * @param cls unused
664  * @param client client that sent the message
665  * @param m message sent by the client
666  */
667 static void
668 handle_client_reject (void *cls,
669                       struct GNUNET_SERVER_Client *client,
670                       const struct GNUNET_MessageHeader *m)
671 {
672   struct Incoming *incoming;
673   const struct GNUNET_SET_AcceptRejectMessage *msg;
674
675   msg = (const struct GNUNET_SET_AcceptRejectMessage *) m;
676   GNUNET_break (0 == ntohl (msg->request_id));
677
678   incoming = get_incoming (ntohl (msg->accept_reject_id));
679   if (NULL == incoming)
680   {
681     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
682     return;
683   }
684   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer request rejected by client\n");
685   GNUNET_MESH_tunnel_destroy (incoming->tunnel);
686   GNUNET_SERVER_receive_done (client, GNUNET_OK);
687 }
688
689
690 /**
691  * Called when a client wants to add an element to a
692  * set it inhabits.
693  *
694  * @param cls unused
695  * @param client client that sent the message
696  * @param m message sent by the client
697  */
698 static void
699 handle_client_add_remove (void *cls,
700                           struct GNUNET_SERVER_Client *client,
701                           const struct GNUNET_MessageHeader *m)
702 {
703   struct Set *set;
704   const struct GNUNET_SET_ElementMessage *msg;
705   struct GNUNET_SET_Element el;
706   struct ElementEntry *ee;
707
708   set = set_get (client);
709   if (NULL == set)
710   {
711     GNUNET_break (0);
712     GNUNET_SERVER_client_disconnect (client);
713     return;
714   }
715   GNUNET_SERVER_receive_done (client, GNUNET_OK);
716   msg = (const struct GNUNET_SET_ElementMessage *) m;
717   el.size = ntohs (m->size) - sizeof *msg;
718   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
719               "client ins/rem element of size %u\n", el.size);
720   el.data = &msg[1];
721   if (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type))
722   {
723     struct GNUNET_HashCode hash;
724
725     GNUNET_CRYPTO_hash (el.data, el.size, &hash);
726     ee = GNUNET_CONTAINER_multihashmap_get (set->elements, &hash);
727     if (NULL == ee)
728     {
729       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove non-existing element\n");
730       return;
731     }
732     if (GNUNET_YES == ee->removed)
733     {
734       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove element twice\n");
735       return;
736     }
737     ee->removed = GNUNET_YES;
738     ee->generation_removed = set->current_generation;
739     set->vt->remove (set->state, ee);
740   }
741   else
742   {
743     struct ElementEntry *ee_dup;
744
745     ee = GNUNET_malloc (el.size + sizeof *ee);
746     ee->element.size = el.size;
747     memcpy (&ee[1], el.data, el.size);
748     ee->element.data = &ee[1];
749     ee->generation_added = set->current_generation;
750     ee->remote = GNUNET_NO;
751     GNUNET_CRYPTO_hash (ee->element.data, el.size, &ee->element_hash);
752     ee_dup = GNUNET_CONTAINER_multihashmap_get (set->elements,
753                                                 &ee->element_hash);
754     if (NULL != ee_dup)
755     {
756       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element inserted twice, ignoring\n");
757       GNUNET_free (ee);
758       return;
759     }
760     GNUNET_CONTAINER_multihashmap_put (set->elements, &ee->element_hash, ee,
761                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
762     set->vt->add (set->state, ee);
763   }
764 }
765
766
767 /**
768  * Called when a client wants to evaluate a set operation with another peer.
769  *
770  * @param cls unused
771  * @param client client that sent the message
772  * @param m message sent by the client
773  */
774 static void
775 handle_client_evaluate (void *cls,
776                         struct GNUNET_SERVER_Client *client,
777                         const struct GNUNET_MessageHeader *m)
778 {
779   struct Set *set;
780   struct TunnelContext *tc;
781   struct GNUNET_MESH_Tunnel *tunnel;
782   struct GNUNET_SET_EvaluateMessage *msg;
783   struct OperationSpecification *spec;
784
785   set = set_get (client);
786   if (NULL == set)
787   {
788     GNUNET_break (0);
789     GNUNET_SERVER_client_disconnect (client);
790     return;
791   }
792
793   msg = (struct GNUNET_SET_EvaluateMessage *) m;
794   tc = GNUNET_new (struct TunnelContext);
795   spec = GNUNET_new (struct OperationSpecification);
796   spec->operation = set->operation;
797   spec->app_id = msg->app_id;
798   spec->salt = ntohl (msg->salt);
799   spec->peer = msg->target_peer;
800   spec->set = set;
801   spec->client_request_id = ntohl (msg->request_id);
802   spec->context_msg = GNUNET_MQ_extract_nested_mh (msg);
803   if (NULL != spec->context_msg)
804     spec->context_msg = GNUNET_copy_message (spec->context_msg);
805
806   tunnel = GNUNET_MESH_tunnel_create (mesh, tc, &msg->target_peer,
807                                       GNUNET_APPLICATION_TYPE_SET,
808                                       GNUNET_YES,
809                                       GNUNET_YES);
810
811   set->vt->evaluate (spec, tunnel, tc);
812
813   GNUNET_SERVER_receive_done (client, GNUNET_OK);
814 }
815
816
817 /**
818  * Handle an ack from a client.
819  *
820  * @param cls unused
821  * @param client the client
822  * @param m the message
823  */
824 static void
825 handle_client_iter_ack (void *cls,
826                    struct GNUNET_SERVER_Client *client,
827                    const struct GNUNET_MessageHeader *m)
828 {
829   struct Set *set;
830   
831   set = set_get (client);
832   if (NULL == set)
833   {
834     GNUNET_break (0);
835     GNUNET_SERVER_client_disconnect (client);
836     return;
837   }
838
839   if (NULL == set->iter)
840   {
841     GNUNET_break (0);
842     GNUNET_SERVER_client_disconnect (client);
843     return;
844   }
845
846   GNUNET_SERVER_receive_done (client, GNUNET_OK);
847   send_client_element (set);
848 }
849
850
851 /**
852  * Handle a request from the client to accept
853  * a set operation that came from a remote peer.
854  *
855  * @param cls unused
856  * @param client the client
857  * @param mh the message
858  */
859 static void
860 handle_client_cancel (void *cls,
861                       struct GNUNET_SERVER_Client *client,
862                       const struct GNUNET_MessageHeader *mh)
863 {
864   const struct GNUNET_SET_CancelMessage *msg =
865       (const struct GNUNET_SET_CancelMessage *) mh;
866   struct Set *set;
867
868   set = set_get (client);
869   if (NULL == set)
870   {
871     GNUNET_break (0);
872     GNUNET_SERVER_client_disconnect (client);
873     return;
874   }
875   /* FIXME: maybe cancel should return success/error code? */
876   set->vt->cancel (set->state, ntohl (msg->request_id));
877 }
878
879
880 /**
881  * Handle a request from the client to accept
882  * a set operation that came from a remote peer.
883  *
884  * @param cls unused
885  * @param client the client
886  * @param mh the message
887  */
888 static void
889 handle_client_accept (void *cls,
890                       struct GNUNET_SERVER_Client *client,
891                       const struct GNUNET_MessageHeader *mh)
892 {
893   struct Set *set;
894   struct Incoming *incoming;
895   struct GNUNET_SET_AcceptRejectMessage *msg = (struct GNUNET_SET_AcceptRejectMessage *) mh;
896
897   incoming = get_incoming (ntohl (msg->accept_reject_id));
898
899   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client accepting %u\n", ntohl (msg->accept_reject_id));
900
901   if (NULL == incoming)
902   {
903
904     GNUNET_break (0);
905     GNUNET_SERVER_client_disconnect (client);
906     return;
907   }
908
909   set = set_get (client);
910
911   if (NULL == set)
912   {
913     GNUNET_break (0);
914     GNUNET_SERVER_client_disconnect (client);
915     return;
916   }
917
918   incoming->spec->set = set;
919   incoming->spec->client_request_id = ntohl (msg->request_id);
920   set->vt->accept (incoming->spec, incoming->tunnel, incoming->tc);
921   /* tunnel ownership goes to operation */
922   incoming->tunnel = NULL;
923   incoming_destroy (incoming);
924   GNUNET_SERVER_receive_done (client, GNUNET_OK);
925 }
926
927
928 /**
929  * Called to clean up, after a shutdown has been requested.
930  *
931  * @param cls closure
932  * @param tc context information (why was this task triggered now)
933  */
934 static void
935 shutdown_task (void *cls,
936                const struct GNUNET_SCHEDULER_TaskContext *tc)
937 {
938   while (NULL != incoming_head)
939     incoming_destroy (incoming_head);
940
941   while (NULL != listeners_head)
942     listener_destroy (listeners_head);
943
944   while (NULL != sets_head)
945     set_destroy (sets_head);
946
947
948   /* it's important to destroy mesh at the end, as tunnels
949    * must be destroyed first! */
950   if (NULL != mesh)
951   {
952     GNUNET_MESH_disconnect (mesh);
953     mesh = NULL;
954   }
955
956   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handled shutdown request\n");
957 }
958
959
960 /**
961  * Signature of the main function of a task.
962  *
963  * @param cls closure
964  * @param tc context information (why was this task triggered now)
965  */
966 static void
967 incoming_timeout_cb (void *cls,
968                      const struct GNUNET_SCHEDULER_TaskContext *tc)
969 {
970   struct Incoming *incoming = cls;
971
972   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "remote peer timed out\n");
973   incoming_destroy (incoming);
974 }
975
976
977 static void
978 handle_incoming_disconnect (struct OperationState *op_state)
979 {
980   struct Incoming *incoming = (struct Incoming *) op_state;
981   if (NULL == incoming->tunnel)
982     return;
983
984   incoming_destroy (incoming);
985 }
986
987
988 /**
989  * Method called whenever another peer has added us to a tunnel
990  * the other peer initiated.
991  * Only called (once) upon reception of data with a message type which was
992  * subscribed to in GNUNET_MESH_connect. A call to GNUNET_MESH_tunnel_destroy
993  * causes te tunnel to be ignored and no further notifications are sent about
994  * the same tunnel.
995  *
996  * @param cls closure
997  * @param tunnel new handle to the tunnel
998  * @param initiator peer that started the tunnel
999  * @param port Port this tunnel is for.
1000  * @return initial tunnel context for the tunnel
1001  *         (can be NULL -- that's not an error)
1002  */
1003 static void *
1004 tunnel_new_cb (void *cls,
1005                struct GNUNET_MESH_Tunnel *tunnel,
1006                const struct GNUNET_PeerIdentity *initiator,
1007                uint32_t port)
1008 {
1009   struct Incoming *incoming;
1010   static const struct SetVT incoming_vt = {
1011     .msg_handler = handle_incoming_msg,
1012     .peer_disconnect = handle_incoming_disconnect
1013   };
1014
1015   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new incoming tunnel\n");
1016
1017   GNUNET_assert (port == GNUNET_APPLICATION_TYPE_SET);
1018   incoming = GNUNET_new (struct Incoming);
1019   incoming->peer = *initiator;
1020   incoming->tunnel = tunnel;
1021   incoming->tc = GNUNET_new (struct TunnelContext);;
1022   incoming->tc->vt = &incoming_vt;
1023   incoming->tc->op = (struct OperationState *) incoming;
1024   incoming->timeout_task = 
1025       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, incoming_timeout_cb, incoming);
1026   GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
1027
1028   return incoming->tc;
1029 }
1030
1031
1032 /**
1033  * Function called whenever a tunnel is destroyed.  Should clean up
1034  * any associated state.
1035  * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on
1036  * the tunnel.
1037  *
1038  * @param cls closure (set from GNUNET_MESH_connect)
1039  * @param tunnel connection to the other end (henceforth invalid)
1040  * @param tunnel_ctx place where local state associated
1041  *                   with the tunnel is stored
1042  */
1043 static void
1044 tunnel_end_cb (void *cls,
1045                const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
1046 {
1047   struct TunnelContext *ctx = tunnel_ctx;
1048
1049   ctx->vt->peer_disconnect (ctx->op);
1050   /* mesh will never call us with the context again! */
1051   GNUNET_free (tunnel_ctx);
1052 }
1053
1054
1055 /**
1056  * Functions with this signature are called whenever a message is
1057  * received.
1058  * 
1059  * Each time the function must call GNUNET_MESH_receive_done on the tunnel
1060  * in order to receive the next message. This doesn't need to be immediate:
1061  * can be delayed if some processing is done on the message.
1062  *
1063  * @param cls Closure (set from GNUNET_MESH_connect).
1064  * @param tunnel Connection to the other end.
1065  * @param tunnel_ctx Place to store local state associated with the tunnel.
1066  * @param message The actual message.
1067  * 
1068  * @return GNUNET_OK to keep the tunnel open,
1069  *         GNUNET_SYSERR to close it (signal serious error).
1070  */
1071 static int
1072 dispatch_p2p_message (void *cls,
1073                       struct GNUNET_MESH_Tunnel *tunnel,
1074                       void **tunnel_ctx,
1075                       const struct GNUNET_MessageHeader *message)
1076 {
1077   struct TunnelContext *tc = *tunnel_ctx;
1078   int ret;
1079
1080   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "dispatching mesh message (type: %u)\n",
1081               ntohs (message->type));
1082   /* FIXME: do this before or after the handler? */
1083   GNUNET_MESH_receive_done (tunnel);
1084   ret = tc->vt->msg_handler (tc->op, message);
1085   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handled mesh message (type: %u)\n",
1086               ntohs (message->type));
1087   return ret;
1088 }
1089
1090
1091 /**
1092  * Function called by the service's run
1093  * method to run service-specific setup code.
1094  *
1095  * @param cls closure
1096  * @param server the initialized server
1097  * @param cfg configuration to use
1098  */
1099 static void
1100 run (void *cls, struct GNUNET_SERVER_Handle *server,
1101      const struct GNUNET_CONFIGURATION_Handle *cfg)
1102 {
1103   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1104     {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT,
1105         sizeof (struct GNUNET_SET_AcceptRejectMessage)},
1106     {handle_client_iter_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ITER_ACK, 0},
1107     {handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
1108     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE,
1109         sizeof (struct GNUNET_SET_CreateMessage)},
1110     {handle_client_iterate, NULL, GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST,
1111         sizeof (struct GNUNET_MessageHeader)},
1112     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
1113     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN,
1114         sizeof (struct GNUNET_SET_ListenMessage)},
1115     {handle_client_reject, NULL, GNUNET_MESSAGE_TYPE_SET_REJECT,
1116         sizeof (struct GNUNET_SET_AcceptRejectMessage)},
1117     {handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_REMOVE, 0},
1118     {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_REMOVE,
1119         sizeof (struct GNUNET_SET_CancelMessage)},
1120     {NULL, NULL, 0, 0}
1121   };
1122   static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1123     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 0},
1124     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_IBF, 0},
1125     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 0},
1126     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_DONE, 0},
1127     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENT_REQUESTS, 0},
1128     {dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_SE, 0},
1129     {NULL, 0, 0}
1130   };
1131   static const uint32_t mesh_ports[] = {GNUNET_APPLICATION_TYPE_SET, 0};
1132
1133   configuration = cfg;
1134   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1135                                 &shutdown_task, NULL);
1136   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1137   GNUNET_SERVER_add_handlers (server, server_handlers);
1138
1139   mesh = GNUNET_MESH_connect (cfg, NULL, tunnel_new_cb, tunnel_end_cb,
1140                               mesh_handlers, mesh_ports);
1141   if (NULL == mesh)
1142   {
1143     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not connect to mesh\n");
1144     return;
1145   }
1146
1147   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "started\n");
1148 }
1149
1150
1151 /**
1152  * The main function for the set service.
1153  *
1154  * @param argc number of arguments from the command line
1155  * @param argv command line arguments
1156  * @return 0 ok, 1 on error
1157  */
1158 int
1159 main (int argc, char *const *argv)
1160 {
1161   int ret;
1162   ret = GNUNET_SERVICE_run (argc, argv, "set",
1163                             GNUNET_SERVICE_OPTION_NONE, &run, NULL);
1164   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit (%d)\n", GNUNET_OK != ret);
1165   return (GNUNET_OK == ret) ? 0 : 1;
1166 }
1167