2 This file is part of GNUnet
3 (C) 2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file set/gnunet-service-set_intersection.c
23 * @brief two-peer set intersection
24 * @author Christian Fuchs
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-set.h"
29 #include "gnunet_block_lib.h"
30 #include "set_protocol.h"
33 #define BLOOMFILTER_SIZE GNUNET_CRYPTO_HASH_LENGTH
35 * Current phase we are in for a intersection operation.
37 enum IntersectionOperationPhase
40 * Alices has suggested an operation to bob,
41 * and is waiting for a bf or session end.
45 * Bob has accepted the operation, Bob and Alice are now exchanging bfs
46 * until one notices the their element count is equal
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
57 * The protocol is over.
58 * Results may still have to be sent to the client.
65 * State of an evaluate operation
71 * The bf we currently receive
73 struct GNUNET_CONTAINER_BloomFilter *remote_bf;
76 * BF of the set's element.
78 struct GNUNET_CONTAINER_BloomFilter *local_bf;
81 * for multipart msgs we have to store the bloomfilter-data until we fully sent it.
86 * for multipart msgs we have to store the bloomfilter-data until we fully sent it.
88 uint32_t local_bf_data_size;
91 * Current state of the operation.
93 enum IntersectionOperationPhase phase;
96 * Generation in which the operation handle
99 unsigned int generation_created;
102 * Maps element-id-hashes to 'elements in our set'.
104 struct GNUNET_CONTAINER_MultiHashMap *my_elements;
107 * Current element count contained within contained_elements
109 uint32_t my_element_count;
112 * Iterator for sending elements on the key to element mapping to the client.
114 struct GNUNET_CONTAINER_MultiHashMapIterator *full_result_iter;
117 * Evaluate operations are held in
120 struct OperationState *next;
123 * Evaluate operations are held in
126 struct OperationState *prev;
129 * Did we send the client that we are done?
131 int client_done_sent;
136 * Extra state required for efficient set intersection.
141 * Number of currently valid elements in the set which have not been removed
143 uint32_t current_set_element_count;
150 * fills the contained-elements hashmap with all relevant
151 * elements and adds their mutated hashes to our local bloomfilter with mutator+1
154 * @param key current key code
155 * @param value value in the hash map
156 * @return #GNUNET_YES if we should continue to
161 iterator_initialization_by_alice (void *cls,
162 const struct GNUNET_HashCode *key,
165 struct ElementEntry *ee = value;
166 struct Operation *op = cls;
167 struct GNUNET_HashCode mutated_hash;
169 //only consider this element, if it is valid for us
170 if ((op->generation_created >= ee->generation_removed)
171 || (op->generation_created < ee->generation_added))
174 // not contained according to bob's bloomfilter
175 GNUNET_BLOCK_mingle_hash(&ee->element_hash,
178 if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf,
182 op->state->my_element_count++;
183 GNUNET_assert (GNUNET_YES ==
184 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
185 &ee->element_hash, ee,
186 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
188 /* create our own bloomfilter with salt+1 */
189 GNUNET_BLOCK_mingle_hash (&ee->element_hash,
192 GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf,
199 * fills the contained-elements hashmap with all relevant
200 * elements and adds their mutated hashes to our local bloomfilter
203 * @param key current key code
204 * @param value value in the hash map
205 * @return #GNUNET_YES if we should continue to
210 iterator_initialization (void *cls,
211 const struct GNUNET_HashCode *key,
214 struct ElementEntry *ee = value;
215 struct Operation *op = cls;
216 struct GNUNET_HashCode mutated_hash;
218 //only consider this element, if it is valid for us
219 if ((op->generation_created >= ee->generation_removed)
220 || (op->generation_created < ee->generation_added))
223 GNUNET_assert (GNUNET_YES ==
224 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
225 &ee->element_hash, ee,
226 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
227 GNUNET_BLOCK_mingle_hash (&ee->element_hash,
230 GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf,
237 * removes element from a hashmap if it is not contained within the
238 * provided remote bloomfilter. Then, fill our new bloomfilter.
241 * @param key current key code
242 * @param value value in the hash map
243 * @return #GNUNET_YES if we should continue to
248 iterator_bf_round (void *cls,
249 const struct GNUNET_HashCode *key,
252 struct ElementEntry *ee = value;
253 struct Operation *op = cls;
254 struct GNUNET_HashCode mutated_hash;
256 GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt, &mutated_hash);
259 GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf,
262 op->state->my_element_count--;
263 GNUNET_assert (GNUNET_YES ==
264 GNUNET_CONTAINER_multihashmap_remove (op->state->my_elements,
269 GNUNET_BLOCK_mingle_hash(&ee->element_hash,
272 GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf,
279 * Inform the client that the union operation has failed,
280 * and proceed to destroy the evaluate operation.
282 * @param op the intersection operation to fail
285 fail_intersection_operation (struct Operation *op)
287 struct GNUNET_MQ_Envelope *ev;
288 struct GNUNET_SET_ResultMessage *msg;
290 if (op->state->my_elements)
291 GNUNET_CONTAINER_multihashmap_destroy(op->state->my_elements);
293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "intersection operation failed\n");
295 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
296 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
297 msg->request_id = htonl (op->spec->client_request_id);
298 msg->element_type = htons (0);
299 GNUNET_MQ_send (op->spec->set->client_mq, ev);
300 _GSS_operation_destroy (op);
305 * Send a request for the evaluate operation to a remote peer
307 * @param eo operation with the other peer
310 send_operation_request (struct Operation *op)
312 struct GNUNET_MQ_Envelope *ev;
313 struct OperationRequestMessage *msg;
315 ev = GNUNET_MQ_msg_nested_mh (msg, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
316 op->spec->context_msg);
320 /* the context message is too large */
322 GNUNET_SERVER_client_disconnect (op->spec->set->client);
325 msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION);
326 msg->app_id = op->spec->app_id;
327 msg->salt = htonl (op->spec->salt);
328 msg->element_count = htonl(op->state->my_element_count);
330 GNUNET_MQ_send (op->mq, ev);
332 if (NULL != op->spec->context_msg)
333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent op request with context message\n");
335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent op request without context message\n");
337 if (NULL != op->spec->context_msg)
339 GNUNET_free (op->spec->context_msg);
340 op->spec->context_msg = NULL;
345 send_bloomfilter_multipart (struct Operation *op, uint32_t offset)
347 struct GNUNET_MQ_Envelope *ev;
348 struct BFMessage *msg;
349 uint32_t chunk_size = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof(struct BFMessage));
350 uint32_t todo_size = op->state->local_bf_data_size - offset;
352 if (todo_size < chunk_size)
353 // we probably need many chunks, thus we assume a maximum packet size by default
354 chunk_size = todo_size;
356 ev = GNUNET_MQ_msg_extra (msg, chunk_size, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF);
359 msg->sender_element_count = htonl (op->state->my_element_count);
360 msg->bloomfilter_total_length = htonl (op->state->local_bf_data_size);
361 msg->bloomfilter_length = htonl (chunk_size);
362 msg->bloomfilter_offset = htonl (offset);
363 msg->sender_mutator = htonl (op->spec->salt);
365 GNUNET_MQ_send (op->mq, ev);
367 if (op->state->local_bf_data_size == offset + chunk_size)
370 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
371 GNUNET_free(op->state->local_bf_data);
372 op->state->local_bf = NULL;
376 send_bloomfilter_multipart (op, offset + chunk_size);
380 * Send a bloomfilter to our peer.
381 * that the operation is over.
382 * After the result done message has been sent to the client,
383 * destroy the evaluate operation.
385 * @param eo intersection operation
388 send_bloomfilter (struct Operation *op)
390 struct GNUNET_MQ_Envelope *ev;
391 struct BFMessage *msg;
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending bf of size %u\n");
396 // send our bloomfilter
397 bf_size = GNUNET_CONTAINER_bloomfilter_get_size (op->state->local_bf);
398 if ( GNUNET_SERVER_MAX_MESSAGE_SIZE <= bf_size + sizeof(struct BFMessage))
401 ev = GNUNET_MQ_msg_extra (msg, bf_size, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF);
403 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
404 op->state->local_bf = NULL;
407 msg->sender_element_count = htonl (op->state->my_element_count);
408 msg->bloomfilter_length = htonl (bf_size);
409 msg->bloomfilter_offset = htonl (0);
410 msg->sender_mutator = htonl (op->spec->salt);
412 GNUNET_MQ_send (op->mq, ev);
416 op->state->local_bf_data = (char *)GNUNET_malloc(bf_size);
417 GNUNET_assert (GNUNET_SYSERR !=
418 GNUNET_CONTAINER_bloomfilter_get_raw_data (op->state->local_bf,
419 op->state->local_bf_data,
421 op->state->local_bf_data_size = bf_size;
422 send_bloomfilter_multipart (op, 0);
428 * Signal to the client that the operation has finished and
429 * destroy the operation.
431 * @param cls operation to destroy
434 send_client_done_and_destroy (void *cls)
436 struct Operation *op = cls;
437 struct GNUNET_MQ_Envelope *ev;
438 struct GNUNET_SET_ResultMessage *rm;
439 ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT);
440 rm->request_id = htonl (op->spec->client_request_id);
441 rm->result_status = htons (GNUNET_SET_STATUS_DONE);
442 rm->element_type = htons (0);
443 GNUNET_MQ_send (op->spec->set->client_mq, ev);
444 _GSS_operation_destroy (op);
449 * Send all elements in the full result iterator.
451 * @param cls operation
454 send_remaining_elements (void *cls)
456 struct Operation *op = cls;
457 struct ElementEntry *remaining; //TODO rework this, key entry does not exist here
458 struct GNUNET_MQ_Envelope *ev;
459 struct GNUNET_SET_ResultMessage *rm;
460 struct GNUNET_SET_Element *element;
463 res = GNUNET_CONTAINER_multihashmap_iterator_next (op->state->full_result_iter, NULL, (const void **) &remaining);
464 if (GNUNET_NO == res) {
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending done and destroy because iterator ran out\n");
466 send_client_done_and_destroy (op);
470 element = &remaining->element;
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending element (size %u) to client (full set)\n", element->size);
472 GNUNET_assert (0 != op->spec->client_request_id);
474 ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
475 GNUNET_assert (NULL != ev);
477 rm->result_status = htons (GNUNET_SET_STATUS_OK);
478 rm->request_id = htonl (op->spec->client_request_id);
479 rm->element_type = element->type;
480 memcpy (&rm[1], element->data, element->size);
482 GNUNET_MQ_notify_sent (ev, send_remaining_elements, op);
483 GNUNET_MQ_send (op->spec->set->client_mq, ev);
488 * Inform the peer that this operation is complete.
490 * @param eo the intersection operation to fail
493 send_peer_done (struct Operation *op)
495 struct GNUNET_MQ_Envelope *ev;
497 op->state->phase = PHASE_FINISHED;
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Intersection succeeded, sending DONE\n");
499 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
500 op->state->local_bf = NULL;
502 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_P2P_DONE);
503 GNUNET_MQ_send (op->mq, ev);
508 * Handle an BF message from a remote peer.
510 * @param cls the intersection operation
511 * @param mh the header of the message
514 handle_p2p_bf (void *cls, const struct GNUNET_MessageHeader *mh)
516 struct Operation *op = cls;
517 const struct BFMessage *msg = (const struct BFMessage *) mh;
518 uint32_t old_elements;
519 uint32_t peer_elements;
521 old_elements = op->state->my_element_count;
522 op->spec->salt = ntohl (msg->sender_mutator);
524 op->state->remote_bf = GNUNET_CONTAINER_bloomfilter_init ((const char*) &msg[1],
526 ntohl (msg->bloomfilter_length));
527 op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
529 GNUNET_CONSTANTS_BLOOMFILTER_K);
530 switch (op->state->phase)
533 // If we are ot our first msg
534 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, GNUNET_YES);
536 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
537 &iterator_initialization_by_alice,
540 case PHASE_BF_EXCHANGE:
541 case PHASE_MAYBE_FINISHED:
542 // if we are bob or alice and are continuing operation
543 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
549 fail_intersection_operation(op);
551 // the iterators created a new BF with salt+1
552 // the peer needs this information for decoding the next BF
553 // this behavior can be modified at will later on.
556 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
557 op->state->remote_bf = NULL;
559 peer_elements = ntohl(msg->sender_element_count);
560 if ((op->state->phase == PHASE_MAYBE_FINISHED)
561 && (old_elements == op->state->my_element_count)
562 && (op->state->my_element_count == peer_elements)){
563 // In the last round we though we were finished, we now know this is correct
568 op->state->phase = PHASE_BF_EXCHANGE;
569 // maybe we are finished, but we do one more round to make certain
570 // we don't have false positives ...
571 if (op->state->my_element_count == peer_elements)
572 op->state->phase = PHASE_MAYBE_FINISHED;
574 send_bloomfilter (op);
579 * Handle an BF message from a remote peer.
581 * @param cls the intersection operation
582 * @param mh the header of the message
585 handle_p2p_element_info (void *cls, const struct GNUNET_MessageHeader *mh)
587 struct Operation *op = cls;
588 struct BFMessage *msg = (struct BFMessage *) mh;
590 op->spec->remote_element_count = ntohl(msg->sender_element_count);
591 if ((op->state->phase != PHASE_INITIAL)
592 || (op->state->my_element_count > op->spec->remote_element_count)){
594 fail_intersection_operation(op);
597 op->state->phase = PHASE_BF_EXCHANGE;
598 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
600 op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
602 GNUNET_CONSTANTS_BLOOMFILTER_K);
603 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
604 &iterator_initialization,
607 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
608 op->state->remote_bf = NULL;
610 if (op->state->my_element_count == ntohl (msg->sender_element_count))
611 op->state->phase = PHASE_MAYBE_FINISHED;
613 send_bloomfilter (op);
618 * Send our element to the peer, in case our element count is lower than his
620 * @param eo intersection operation
623 send_element_count (struct Operation *op)
625 struct GNUNET_MQ_Envelope *ev;
626 struct BFMessage *msg;
628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending element count (bf_msg)\n");
630 // just send our element count, as the other peer must start
631 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
633 msg->sender_element_count = htonl (op->state->my_element_count);
634 msg->bloomfilter_length = htonl (0);
635 msg->sender_mutator = htonl (0);
637 GNUNET_MQ_send (op->mq, ev);
642 * Send a result message to the client indicating
643 * that the operation is over.
644 * After the result done message has been sent to the client,
645 * destroy the evaluate operation.
647 * @param op intersection operation
650 finish_and_destroy (struct Operation *op)
652 GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
654 if (GNUNET_SET_RESULT_FULL == op->spec->result_mode)
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending full result set\n");
657 op->state->full_result_iter =
658 GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
659 send_remaining_elements (op);
662 send_client_done_and_destroy (op);
667 * Handle a done message from a remote peer
669 * @param cls the union operation
670 * @param mh the message
673 handle_p2p_done (void *cls,
674 const struct GNUNET_MessageHeader *mh)
676 struct Operation *op = cls;
678 if ((op->state->phase = PHASE_FINISHED) || (op->state->phase = PHASE_MAYBE_FINISHED)){
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got final DONE\n");
681 finish_and_destroy (op);
686 fail_intersection_operation (op);
691 * Evaluate a union operation with
694 * @param op operation to evaluate
697 intersection_evaluate (struct Operation *op)
699 op->state = GNUNET_new (struct OperationState);
700 /* we started the operation, thus we have to send the operation request */
701 op->state->phase = PHASE_INITIAL;
702 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
703 op->state->my_element_count = op->spec->set->state->current_set_element_count;
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "evaluating intersection operation");
707 send_operation_request (op);
712 * Accept an union operation request from a remote peer.
713 * Only initializes the private operation state.
715 * @param op operation that will be accepted as a union operation
718 intersection_accept (struct Operation *op)
720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "accepting set union operation\n");
721 op->state = GNUNET_new (struct OperationState);
722 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
723 op->state->my_element_count = op->spec->set->state->current_set_element_count;
725 // if Alice (the peer) has more elements than Bob (us), she should start
726 if (op->spec->remote_element_count < op->state->my_element_count){
727 op->state->phase = PHASE_INITIAL;
728 send_element_count(op);
731 // create a new bloomfilter in case we have fewer elements
732 op->state->phase = PHASE_BF_EXCHANGE;
733 op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
735 GNUNET_CONSTANTS_BLOOMFILTER_K);
736 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
737 &iterator_initialization,
739 send_bloomfilter (op);
744 * Create a new set supporting the intersection operation
746 * @return the newly created set
748 static struct SetState *
749 intersection_set_create ()
751 struct SetState *set_state;
753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
754 "intersection set created\n");
755 set_state = GNUNET_new (struct SetState);
756 set_state->current_set_element_count = 0;
763 * Add the element from the given element message to the set.
765 * @param set_state state of the set want to add to
766 * @param ee the element to add to the set
769 intersection_add (struct SetState *set_state,
770 struct ElementEntry *ee)
772 GNUNET_assert(0 < set_state->current_set_element_count);
773 set_state->current_set_element_count++;
778 * Destroy a set that supports the intersection operation
780 * @param set_state the set to destroy
783 intersection_set_destroy (struct SetState *set_state)
785 GNUNET_free (set_state);
790 * Remove the element given in the element message from the set.
792 * @param set_state state of the set to remove from
793 * @param element set element to remove
796 intersection_remove (struct SetState *set_state,
797 struct ElementEntry *element)
799 GNUNET_assert(0 < set_state->current_set_element_count);
800 set_state->current_set_element_count--;
805 * Dispatch messages for a intersection operation.
807 * @param eo the state of the intersection evaluate operation
808 * @param mh the received message
809 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
810 * #GNUNET_OK otherwise
813 intersection_handle_p2p_message (struct Operation *op,
814 const struct GNUNET_MessageHeader *mh)
816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "received p2p message (t: %u, s: %u)\n",
817 ntohs (mh->type), ntohs (mh->size));
818 switch (ntohs (mh->type))
820 /* this message handler is not active until after we received an
821 * operation request message, thus the ops request is not handled here
823 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
824 handle_p2p_element_info (op, mh);
826 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
827 handle_p2p_bf (op, mh);
829 case GNUNET_MESSAGE_TYPE_SET_P2P_DONE:
830 handle_p2p_done (op, mh);
833 /* something wrong with mesh's message handlers? */
841 * handler for peer-disconnects, notifies the client about the aborted operation
843 * @param op the destroyed operation
846 intersection_peer_disconnect (struct Operation *op)
848 if (PHASE_FINISHED != op->state->phase)
850 struct GNUNET_MQ_Envelope *ev;
851 struct GNUNET_SET_ResultMessage *msg;
853 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
854 msg->request_id = htonl (op->spec->client_request_id);
855 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
856 msg->element_type = htons (0);
857 GNUNET_MQ_send (op->spec->set->client_mq, ev);
858 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "other peer disconnected prematurely\n");
859 _GSS_operation_destroy (op);
862 // else: the session has already been concluded
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "other peer disconnected (finished)\n");
864 if (GNUNET_NO == op->state->client_done_sent)
865 finish_and_destroy (op);
870 * Destroy the union operation. Only things specific to the union operation are destroyed.
872 * @param op union operation to destroy
875 intersection_op_cancel (struct Operation *op)
877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying intersection op\n");
878 /* check if the op was canceled twice */
879 GNUNET_assert (NULL != op->state);
880 if (NULL != op->state->remote_bf)
882 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
883 op->state->remote_bf = NULL;
885 if (NULL != op->state->local_bf)
887 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
888 op->state->local_bf = NULL;
890 if (NULL != op->state->my_elements)
892 // no need to free the elements, they are still part of the set
893 GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
894 op->state->my_elements = NULL;
896 GNUNET_free (op->state);
898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying intersection op done\n");
902 _GSS_intersection_vt ()
904 static const struct SetVT intersection_vt = {
905 .create = &intersection_set_create,
906 .msg_handler = &intersection_handle_p2p_message,
907 .add = &intersection_add,
908 .remove = &intersection_remove,
909 .destroy_set = &intersection_set_destroy,
910 .evaluate = &intersection_evaluate,
911 .accept = &intersection_accept,
912 .peer_disconnect = &intersection_peer_disconnect,
913 .cancel = &intersection_op_cancel,
916 return &intersection_vt;