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