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