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