- dont resend useless channel_destroy messages
[oweals/gnunet.git] / src / set / gnunet-service-set_intersection.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 3, 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_intersection.c
23  * @brief two-peer set intersection
24  * @author Christian Fuchs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-set.h"
29 #include "gnunet_block_lib.h"
30 #include "set_protocol.h"
31 #include <gcrypt.h>
32
33 #define BLOOMFILTER_SIZE GNUNET_CRYPTO_HASH_LENGTH
34 /**
35  * Current phase we are in for a intersection operation.
36  */
37 enum IntersectionOperationPhase
38 {
39   /**
40    * Alices has suggested an operation to bob, 
41    * and is waiting for a bf or session end.
42    */
43   PHASE_INITIAL,
44   /**
45    * Bob has accepted the operation, Bob and Alice are now exchanging bfs
46    * until one notices the their element count is equal
47    */
48   PHASE_BF_EXCHANGE,
49   /**
50    * if both peers have an equal peercount, they enter this state for 
51    * one more turn, to see if they actually have agreed on a correct set.
52    * if a peer finds the same element count after the next iteration, 
53    * it ends the the session
54    */
55   PHASE_MAYBE_FINISHED,
56   /**
57    * The protocol is over.
58    * Results may still have to be sent to the client.
59    */
60   PHASE_FINISHED
61 };
62
63
64 /**
65  * State of an evaluate operation
66  * with another peer.
67  */
68 struct OperationState
69 {
70   /**
71    * The bf we currently receive
72    */
73   struct GNUNET_CONTAINER_BloomFilter *remote_bf;
74
75   /**
76    * BF of the set's element.
77    */
78   struct GNUNET_CONTAINER_BloomFilter *local_bf;
79
80   /**
81    * Current state of the operation.
82    */
83   enum IntersectionOperationPhase phase;
84
85   /**
86    * Generation in which the operation handle
87    * was created.
88    */
89   unsigned int generation_created;
90   
91   /**
92    * Maps element-id-hashes to 'elements in our set'.
93    */
94   struct GNUNET_CONTAINER_MultiHashMap *my_elements;
95   
96   /**
97    * Current element count contained within contained_elements
98    */
99   uint32_t my_element_count;
100
101   /**
102    * Iterator for sending elements on the key to element mapping to the client.
103    */
104   struct GNUNET_CONTAINER_MultiHashMapIterator *full_result_iter;
105   
106   /**
107    * Evaluate operations are held in
108    * a linked list.
109    */
110   struct OperationState *next;
111
112    /**
113     * Evaluate operations are held in
114     * a linked list.
115     */
116   struct OperationState *prev;
117
118   /**
119    * Did we send the client that we are done?
120    */
121   int client_done_sent;
122 };
123
124
125 /**
126  * Extra state required for efficient set intersection.
127  */
128 struct SetState
129 {
130   /**
131    * Number of currently valid elements in the set which have not been removed
132    */
133   uint32_t current_set_element_count;
134 };
135
136
137 /**
138  * Alice's version:
139  * 
140  * fills the contained-elements hashmap with all relevant 
141  * elements and adds their mutated hashes to our local bloomfilter with mutator+1
142  * 
143  * @param cls closure
144  * @param key current key code
145  * @param value value in the hash map
146  * @return #GNUNET_YES if we should continue to
147  *         iterate,
148  *         #GNUNET_NO if not.
149  */
150 static int 
151 iterator_initialization_by_alice (void *cls,
152                                       const struct GNUNET_HashCode *key,
153                                       void *value){
154   struct ElementEntry *ee = value;
155   struct Operation *op = cls;
156   struct GNUNET_HashCode mutated_hash;
157   
158   //only consider this element, if it is valid for us
159   if ((op->generation_created >= ee->generation_removed) 
160        || (op->generation_created < ee->generation_added))
161     return GNUNET_YES;
162   
163   // not contained according to bob's bloomfilter
164   GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt, &mutated_hash);
165   if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf, 
166                                                       &mutated_hash))
167     return GNUNET_YES;
168   
169   op->state->my_element_count++;  
170   GNUNET_CONTAINER_multihashmap_put (op->state->my_elements, 
171                                      &ee->element_hash, ee,
172                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
173   
174   // create our own bloomfilter with salt+1
175   GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt+1, &mutated_hash);
176   GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf, 
177                                     &mutated_hash);
178   
179   return GNUNET_YES;
180 }
181
182 /**
183  * fills the contained-elements hashmap with all relevant 
184  * elements and adds their mutated hashes to our local bloomfilter
185  * 
186  * @param cls closure
187  * @param key current key code
188  * @param value value in the hash map
189  * @return #GNUNET_YES if we should continue to
190  *         iterate,
191  *         #GNUNET_NO if not.
192  */
193 static int 
194 iterator_initialization (void *cls,
195                                       const struct GNUNET_HashCode *key,
196                                       void *value){
197   struct ElementEntry *ee = value;
198   struct Operation *op = cls;
199   struct GNUNET_HashCode mutated_hash;
200   
201   //only consider this element, if it is valid for us
202   if ((op->generation_created >= ee->generation_removed) 
203        || (op->generation_created < ee->generation_added))
204     return GNUNET_YES;
205   
206   GNUNET_CONTAINER_multihashmap_put (op->state->my_elements, 
207                                      &ee->element_hash, ee,
208                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
209   
210   GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt, &mutated_hash);
211   
212   GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf, 
213                                     &mutated_hash);
214   
215   return GNUNET_YES;
216 }
217
218
219 /**
220  * removes element from a hashmap if it is not contained within the
221  * provided remote bloomfilter. Then, fill our new bloomfilter.
222  * 
223  * @param cls closure
224  * @param key current key code
225  * @param value value in the hash map
226  * @return #GNUNET_YES if we should continue to
227  *         iterate,
228  *         #GNUNET_NO if not.
229  */
230 static int
231 iterator_bf_round (void *cls,
232                                       const struct GNUNET_HashCode *key,
233                                       void *value){
234   struct ElementEntry *ee = value;
235   struct Operation *op = cls;
236   struct GNUNET_HashCode mutated_hash;
237   
238   GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt, &mutated_hash);
239   
240   if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf, 
241                                      &mutated_hash)){
242     op->state->my_element_count--;
243     GNUNET_CONTAINER_multihashmap_remove (op->state->my_elements, 
244                                      &ee->element_hash,
245                                      ee);
246     return GNUNET_YES;
247   }
248   
249   GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt+1, &mutated_hash);
250   
251   GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf, 
252                                     &mutated_hash);
253   
254   return GNUNET_YES;
255 }
256
257 /**
258  * Inform the client that the union operation has failed,
259  * and proceed to destroy the evaluate operation.
260  *
261  * @param op the intersection operation to fail
262  */
263 static void
264 fail_intersection_operation (struct Operation *op)
265 {
266   struct GNUNET_MQ_Envelope *ev;
267   struct GNUNET_SET_ResultMessage *msg;
268
269   if (op->state->my_elements)
270     GNUNET_CONTAINER_multihashmap_destroy(op->state->my_elements);
271   
272   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "intersection operation failed\n");
273
274   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
275   msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
276   msg->request_id = htonl (op->spec->client_request_id);
277   msg->element_type = htons (0);
278   GNUNET_MQ_send (op->spec->set->client_mq, ev);
279   _GSS_operation_destroy (op);
280 }
281
282
283 /**
284  * Send a request for the evaluate operation to a remote peer
285  *
286  * @param eo operation with the other peer
287  */
288 static void
289 send_operation_request (struct Operation *op)
290 {
291   struct GNUNET_MQ_Envelope *ev;
292   struct OperationRequestMessage *msg;
293
294   ev = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
295                                 op->spec->context_msg);
296
297   if (NULL == ev)
298   {
299     /* the context message is too large */
300     GNUNET_break (0);
301     GNUNET_SERVER_client_disconnect (op->spec->set->client);
302     return;
303   }
304   msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION);
305   msg->app_id = op->spec->app_id;
306   msg->salt = htonl (op->spec->salt);
307   msg->element_count = htonl(op->state->my_element_count);
308   
309   GNUNET_MQ_send (op->mq, ev);
310
311   if (NULL != op->spec->context_msg)
312     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent op request with context message\n");
313   else
314     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent op request without context message\n");
315
316   if (NULL != op->spec->context_msg)
317   {
318     GNUNET_free (op->spec->context_msg);
319     op->spec->context_msg = NULL;
320   }
321
322 }
323
324 /**
325  * Send a bloomfilter to our peer.
326  * that the operation is over.
327  * After the result done message has been sent to the client,
328  * destroy the evaluate operation.
329  *
330  * @param eo intersection operation
331  */
332 static void
333 send_bloomfilter (struct Operation *op)
334 {
335   struct GNUNET_MQ_Envelope *ev;
336   struct BFMessage *msg;
337   uint32_t bf_size;
338
339   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending bf of size %u\n");
340
341   // send our bloomfilter
342   bf_size = GNUNET_CONTAINER_bloomfilter_get_size (op->state->local_bf);
343
344   ev = GNUNET_MQ_msg_extra (msg, bf_size, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF);
345   msg->reserved = 0;
346   msg->sender_element_count = htonl (op->state->my_element_count);
347   msg->bloomfilter_length = htonl (bf_size);
348   msg->sender_mutator = htonl (op->spec->salt);
349   GNUNET_assert (GNUNET_SYSERR !=
350                  GNUNET_CONTAINER_bloomfilter_get_raw_data (op->state->local_bf,
351                                                             (char *) &msg[1],
352                                                             bf_size));
353   GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
354   op->state->local_bf = NULL;
355   GNUNET_MQ_send (op->mq, ev);
356 }
357
358
359 /**
360  * Signal to the client that the operation has finished and
361  * destroy the operation.
362  *
363  * @param cls operation to destroy
364  */
365 static void
366 send_client_done_and_destroy (void *cls)
367 {
368   struct Operation *op = cls;
369   struct GNUNET_MQ_Envelope *ev;
370   struct GNUNET_SET_ResultMessage *rm;
371   ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT);
372   rm->request_id = htonl (op->spec->client_request_id);
373   rm->result_status = htons (GNUNET_SET_STATUS_DONE);
374   rm->element_type = htons (0);
375   GNUNET_MQ_send (op->spec->set->client_mq, ev);
376   _GSS_operation_destroy (op);
377 }
378
379
380 /**
381  * Send all elements in the full result iterator.
382  *
383  * @param cls operation
384  */
385 static void
386 send_remaining_elements (void *cls)
387 {
388   struct Operation *op = cls;
389   struct ElementEntry *remaining; //TODO rework this, key entry does not exist here
390   struct GNUNET_MQ_Envelope *ev;
391   struct GNUNET_SET_ResultMessage *rm;
392   struct GNUNET_SET_Element *element;
393   int res;
394
395   res = GNUNET_CONTAINER_multihashmap_iterator_next (op->state->full_result_iter, NULL, (const void **) &remaining);
396   if (GNUNET_NO == res) {
397     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending done and destroy because iterator ran out\n");
398     send_client_done_and_destroy (op);
399     return;
400   }
401   
402   element = &remaining->element;
403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending element (size %u) to client (full set)\n", element->size);
404   GNUNET_assert (0 != op->spec->client_request_id);
405   
406   ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
407   GNUNET_assert (NULL != ev);
408   
409   rm->result_status = htons (GNUNET_SET_STATUS_OK);
410   rm->request_id = htonl (op->spec->client_request_id);
411   rm->element_type = element->type;
412   memcpy (&rm[1], element->data, element->size);
413
414   GNUNET_MQ_notify_sent (ev, send_remaining_elements, op);
415   GNUNET_MQ_send (op->spec->set->client_mq, ev);
416 }
417
418
419 /**
420  * Inform the peer that this operation is complete.
421  *
422  * @param eo the intersection operation to fail
423  */
424 static void
425 send_peer_done (struct Operation *op)
426 {
427   struct GNUNET_MQ_Envelope *ev;
428
429   op->state->phase = PHASE_FINISHED;
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Intersection succeeded, sending DONE\n");
431   GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
432   op->state->local_bf = NULL;
433
434   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_P2P_DONE);
435   GNUNET_MQ_send (op->mq, ev);
436 }
437
438
439 /**
440  * Handle an BF message from a remote peer.
441  *
442  * @param cls the intersection operation
443  * @param mh the header of the message
444  */
445 static void
446 handle_p2p_bf (void *cls, const struct GNUNET_MessageHeader *mh)
447 {
448   struct Operation *op = cls;
449   const struct BFMessage *msg = (const struct BFMessage *) mh;
450   uint32_t old_elements;
451   uint32_t peer_elements;
452
453   old_elements = op->state->my_element_count;
454   op->spec->salt = ntohl (msg->sender_mutator);
455   
456   op->state->remote_bf = GNUNET_CONTAINER_bloomfilter_init ((const char*) &msg[1],
457                                                             BLOOMFILTER_SIZE,
458                                                             ntohl (msg->bloomfilter_length));
459   op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
460                                                            BLOOMFILTER_SIZE,
461                                                            GNUNET_CONSTANTS_BLOOMFILTER_K);
462   switch (op->state->phase)
463   {
464   case PHASE_INITIAL:
465     // If we are ot our first msg
466     op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, GNUNET_YES);
467
468     GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
469                                            &iterator_initialization_by_alice,
470                                            op);
471     break;
472   case PHASE_BF_EXCHANGE:
473   case PHASE_MAYBE_FINISHED:
474     // if we are bob or alice and are continuing operation
475     GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
476                                            &iterator_bf_round,
477                                            op);
478     break;
479   default:
480     GNUNET_break_op (0);
481     fail_intersection_operation(op);
482   }
483   // the iterators created a new BF with salt+1
484   // the peer needs this information for decoding the next BF
485   // this behavior can be modified at will later on.
486   op->spec->salt++;
487   
488   GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
489   op->state->remote_bf = NULL;
490   
491   peer_elements = ntohl(msg->sender_element_count);
492   if ((op->state->phase == PHASE_MAYBE_FINISHED) 
493        && (old_elements == op->state->my_element_count)
494        && (op->state->my_element_count == peer_elements)){
495     // In the last round we though we were finished, we now know this is correct
496     send_peer_done(op);
497     return;
498   }
499   
500   op->state->phase = PHASE_BF_EXCHANGE;
501   // maybe we are finished, but we do one more round to make certain
502   // we don't have false positives ...
503   if (op->state->my_element_count == peer_elements)
504       op->state->phase = PHASE_MAYBE_FINISHED;
505
506   send_bloomfilter (op);
507 }
508
509
510 /**
511  * Handle an BF message from a remote peer.
512  *
513  * @param cls the intersection operation
514  * @param mh the header of the message
515  */
516 static void
517 handle_p2p_element_info (void *cls, const struct GNUNET_MessageHeader *mh)
518 {
519   struct Operation *op = cls;
520   struct BFMessage *msg = (struct BFMessage *) mh;
521
522   op->spec->remote_element_count = ntohl(msg->sender_element_count);
523   if ((op->state->phase != PHASE_INITIAL)
524       || (op->state->my_element_count > op->spec->remote_element_count)){
525     GNUNET_break_op (0);
526     fail_intersection_operation(op);
527   }
528
529   op->state->phase = PHASE_BF_EXCHANGE;
530   op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
531
532   op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
533                                                            BLOOMFILTER_SIZE,
534                                                            GNUNET_CONSTANTS_BLOOMFILTER_K);
535   GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
536                                          &iterator_initialization,
537                                          op);
538
539   GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
540   op->state->remote_bf = NULL;
541
542   if (op->state->my_element_count == ntohl (msg->sender_element_count))
543     op->state->phase = PHASE_MAYBE_FINISHED;
544
545   send_bloomfilter (op);
546 }
547
548
549 /**
550  * Send our element to the peer, in case our element count is lower than his
551  *
552  * @param eo intersection operation
553  */
554 static void
555 send_element_count (struct Operation *op)
556 {
557   struct GNUNET_MQ_Envelope *ev;
558   struct BFMessage *msg;
559
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending element count (bf_msg)\n");
561
562   // just send our element count, as the other peer must start
563   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
564   msg->reserved = 0;
565   msg->sender_element_count = htonl (op->state->my_element_count);
566   msg->bloomfilter_length = htonl (0);
567   msg->sender_mutator = htonl (0);
568
569   GNUNET_MQ_send (op->mq, ev);
570 }
571
572 /**
573  * Send a result message to the client indicating
574  * that the operation is over.
575  * After the result done message has been sent to the client,
576  * destroy the evaluate operation.
577  *
578  * @param op intersection operation
579  */
580 static void
581 finish_and_destroy (struct Operation *op)
582 {
583   GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
584
585   if (GNUNET_SET_RESULT_FULL == op->spec->result_mode)
586   {
587     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending full result set\n");
588     op->state->full_result_iter =
589         GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
590     send_remaining_elements (op);
591     return;
592   }
593   send_client_done_and_destroy (op);
594 }
595
596 /**
597  * Handle a done message from a remote peer
598  *
599  * @param cls the union operation
600  * @param mh the message
601  */
602 static void
603 handle_p2p_done (void *cls, const struct GNUNET_MessageHeader *mh)
604 {
605   struct Operation *op = cls;
606
607   if ((op->state->phase = PHASE_FINISHED) || (op->state->phase = PHASE_MAYBE_FINISHED)){
608     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got final DONE\n");
609     
610     finish_and_destroy (op);
611     return;
612   }
613   
614   GNUNET_break_op (0);
615   fail_intersection_operation (op);
616 }
617
618
619 /**
620  * Evaluate a union operation with
621  * a remote peer.
622  *
623  * @param op operation to evaluate
624  */
625 static void
626 intersection_evaluate (struct Operation *op)
627 {
628   op->state = GNUNET_new (struct OperationState);
629   /* we started the operation, thus we have to send the operation request */
630   op->state->phase = PHASE_INITIAL;
631   op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
632   op->state->my_element_count = op->spec->set->state->current_set_element_count;
633   
634   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "evaluating intersection operation");
635   send_operation_request (op);
636 }
637
638 /**
639  * Accept an union operation request from a remote peer.
640  * Only initializes the private operation state.
641  *
642  * @param op operation that will be accepted as a union operation
643  */
644 static void
645 intersection_accept (struct Operation *op)
646 {
647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "accepting set union operation\n");
648   op->state = GNUNET_new (struct OperationState);
649   op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
650   op->state->my_element_count = op->spec->set->state->current_set_element_count;
651   
652   // if Alice (the peer) has more elements than Bob (us), she should start
653   if (op->spec->remote_element_count < op->state->my_element_count){
654     op->state->phase = PHASE_INITIAL;
655     send_element_count(op);
656     return;
657   }
658   // create a new bloomfilter in case we have fewer elements
659   op->state->phase = PHASE_BF_EXCHANGE;
660   op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
661                                                            BLOOMFILTER_SIZE,
662                                                            GNUNET_CONSTANTS_BLOOMFILTER_K);
663   GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
664                                          &iterator_initialization,
665                                          op);
666   send_bloomfilter (op);
667 }
668
669
670 /**
671  * Create a new set supporting the intersection operation
672  *
673  * @return the newly created set
674  */
675 static struct SetState *
676 intersection_set_create (void)
677 {
678   struct SetState *set_state;
679
680   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "intersection set created\n");
681
682   set_state = GNUNET_new (struct SetState);
683   set_state->current_set_element_count = 0;
684   
685   return set_state;
686 }
687
688
689 /**
690  * Add the element from the given element message to the set.
691  *
692  * @param set_state state of the set want to add to
693  * @param ee the element to add to the set
694  */
695 static void
696 intersection_add (struct SetState *set_state, struct ElementEntry *ee)
697 {
698   GNUNET_assert(0 < set_state->current_set_element_count);
699   set_state->current_set_element_count++;
700 }
701
702
703 /**
704  * Destroy a set that supports the intersection operation
705  *
706  * @param set_state the set to destroy
707  */
708 static void
709 intersection_set_destroy (struct SetState *set_state)
710 {
711   GNUNET_free (set_state);
712 }
713
714
715 /**
716  * Remove the element given in the element message from the set.
717  *
718  * @param set_state state of the set to remove from
719  * @param element set element to remove
720  */
721 static void
722 intersection_remove (struct SetState *set_state, struct ElementEntry *element)
723 {
724   GNUNET_assert(0 < set_state->current_set_element_count);
725   set_state->current_set_element_count--;
726   //nothing to do here
727 }
728
729
730 /**
731  * Dispatch messages for a intersection operation.
732  *
733  * @param eo the state of the intersection evaluate operation
734  * @param mh the received message
735  * @return GNUNET_SYSERR if the tunnel should be disconnected,
736  *         GNUNET_OK otherwise
737  */
738 int
739 intersection_handle_p2p_message (struct Operation *op,
740                                  const struct GNUNET_MessageHeader *mh)
741 {
742   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "received p2p message (t: %u, s: %u)\n",
743               ntohs (mh->type), ntohs (mh->size));
744   switch (ntohs (mh->type))
745   {
746     /* this message handler is not active until after we received an
747      * operation request message, thus the ops request is not handled here
748      */
749   case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
750     handle_p2p_element_info (op, mh);
751     break;
752   case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
753     handle_p2p_bf (op, mh);
754     break;
755   case GNUNET_MESSAGE_TYPE_SET_P2P_DONE:
756     handle_p2p_done (op, mh);
757     break;
758   default:
759     /* something wrong with mesh's message handlers? */
760     GNUNET_assert (0);
761   }
762   return GNUNET_OK;
763 }
764
765
766 /**
767  * handler for peer-disconnects, notifies the client about the aborted operation
768  * 
769  * @param op the destroyed operation
770  */
771 static void
772 intersection_peer_disconnect (struct Operation *op)
773 {
774   if (PHASE_FINISHED != op->state->phase)
775   {
776     struct GNUNET_MQ_Envelope *ev;
777     struct GNUNET_SET_ResultMessage *msg;
778
779     ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
780     msg->request_id = htonl (op->spec->client_request_id);
781     msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
782     msg->element_type = htons (0);
783     GNUNET_MQ_send (op->spec->set->client_mq, ev);
784     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "other peer disconnected prematurely\n");
785     _GSS_operation_destroy (op);
786     return;
787   }
788   // else: the session has already been concluded
789   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "other peer disconnected (finished)\n");
790   if (GNUNET_NO == op->state->client_done_sent)
791     finish_and_destroy (op);
792 }
793
794
795 /**
796  * Destroy the union operation.  Only things specific to the union operation are destroyed.
797  * 
798  * @param op union operation to destroy
799  */
800 static void
801 intersection_op_cancel (struct Operation *op)
802 {
803   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying intersection op\n");
804   /* check if the op was canceled twice */
805   GNUNET_assert (NULL != op->state);
806   if (NULL != op->state->remote_bf)
807   {
808     GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
809     op->state->remote_bf = NULL;
810   }
811   if (NULL != op->state->local_bf)
812   {
813     GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
814     op->state->local_bf = NULL;
815   }
816   if (NULL != op->state->my_elements)
817   {
818     // no need to free the elements, they are still part of the set
819     GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
820     op->state->my_elements = NULL;
821   }
822   GNUNET_free (op->state);
823   op->state = NULL;
824   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying intersection op done\n");
825 }
826
827 const struct SetVT *
828 _GSS_intersection_vt ()
829 {
830   static const struct SetVT intersection_vt = {
831     .create = &intersection_set_create,
832     .msg_handler = &intersection_handle_p2p_message,
833     .add = &intersection_add,
834     .remove = &intersection_remove,
835     .destroy_set = &intersection_set_destroy,
836     .evaluate = &intersection_evaluate,
837     .accept = &intersection_accept,
838     .peer_disconnect = &intersection_peer_disconnect,
839     .cancel = &intersection_op_cancel,
840   };
841
842   return &intersection_vt;
843 }