2 This file is part of GNUnet
3 (C) 2013, 2014 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.
21 * @file set/gnunet-service-set_intersection.c
22 * @brief two-peer set intersection
23 * @author Christian Fuchs
26 #include "gnunet_util_lib.h"
27 #include "gnunet-service-set.h"
28 #include "gnunet_block_lib.h"
29 #include "gnunet-service-set_protocol.h"
32 #define BLOOMFILTER_SIZE GNUNET_CRYPTO_HASH_LENGTH
34 #define CALCULATE_BF_SIZE(A, B, s, k) \
36 k = ceil(1 + log2((double) (2*B / (double) A)));\
37 if (k<1) k=1; /* k can be calculated as 0 */\
38 s = ceil((double) (A * k / log(2))); \
42 * Current phase we are in for a intersection operation.
44 enum IntersectionOperationPhase
47 * Alices has suggested an operation to bob,
48 * and is waiting for a bf or session end.
52 * Bob has accepted the operation, Bob and Alice are now exchanging bfs
53 * until one notices the their element count is equal
57 * if both peers have an equal peercount, they enter this state for
58 * one more turn, to see if they actually have agreed on a correct set.
59 * if a peer finds the same element count after the next iteration,
60 * it ends the the session
64 * The protocol is over.
65 * Results may still have to be sent to the client.
72 * State of an evaluate operation with another peer.
77 * The bf we currently receive
79 struct GNUNET_CONTAINER_BloomFilter *remote_bf;
82 * BF of the set's element.
84 struct GNUNET_CONTAINER_BloomFilter *local_bf;
87 * Iterator for sending elements on the key to element mapping to the client.
89 struct GNUNET_CONTAINER_MultiHashMapIterator *full_result_iter;
92 * Evaluate operations are held in a linked list.
94 struct OperationState *next;
97 * Evaluate operations are held in a linked list.
99 struct OperationState *prev;
102 * for multipart msgs we have to store the bloomfilter-data until we fully sent it.
107 * Maps element-id-hashes to 'elements in our set'.
109 struct GNUNET_CONTAINER_MultiHashMap *my_elements;
112 * Current element count contained within @e my_elements
114 uint32_t my_element_count;
117 * size of the bloomfilter in @e bf_data.
119 uint32_t bf_data_size;
122 * size of the bloomfilter
124 uint32_t bf_bits_per_element;
127 * Current state of the operation.
129 enum IntersectionOperationPhase phase;
132 * Generation in which the operation handle
135 unsigned int generation_created;
138 * Did we send the client that we are done?
140 int client_done_sent;
145 * Extra state required for efficient set intersection.
150 * Number of currently valid elements in the set which have not been removed
152 uint32_t current_set_element_count;
157 * Send a result message to the client indicating
158 * we removed an element
160 * @param op union operation
161 * @param element element to send
164 send_client_element (struct Operation *op,
165 struct GNUNET_SET_Element *element)
167 struct GNUNET_MQ_Envelope *ev;
168 struct GNUNET_SET_ResultMessage *rm;
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "sending removed element (size %u) to client\n",
173 GNUNET_assert (0 != op->spec->client_request_id);
174 ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
177 GNUNET_MQ_discard (ev);
181 rm->result_status = htons (GNUNET_SET_STATUS_OK);
182 rm->request_id = htonl (op->spec->client_request_id);
183 rm->element_type = element->element_type;
184 memcpy (&rm[1], element->data, element->size);
185 GNUNET_MQ_send (op->spec->set->client_mq, ev);
192 * fills the contained-elements hashmap with all relevant
193 * elements and adds their mutated hashes to our local bloomfilter with mutator+1
196 * @param key current key code
197 * @param value value in the hash map
198 * @return #GNUNET_YES if we should continue to
203 iterator_initialization_by_alice (void *cls,
204 const struct GNUNET_HashCode *key,
207 struct ElementEntry *ee = value;
208 struct Operation *op = cls;
209 struct GNUNET_HashCode mutated_hash;
211 //only consider this element, if it is valid for us
212 if ((op->generation_created < ee->generation_removed)
213 && (op->generation_created >= ee->generation_added))
216 // not contained according to bob's bloomfilter
217 GNUNET_BLOCK_mingle_hash(&ee->element_hash,
220 if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf,
222 if (GNUNET_SET_RESULT_REMOVED == op->spec->result_mode)
223 send_client_element (op, &ee->element);
227 op->state->my_element_count++;
228 GNUNET_assert (GNUNET_YES ==
229 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
230 &ee->element_hash, ee,
231 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
238 * fills the contained-elements hashmap with all relevant
239 * elements and adds their mutated hashes to our local bloomfilter
242 * @param key current key code
243 * @param value value in the hash map
244 * @return #GNUNET_YES if we should continue to
249 iterator_initialization (void *cls,
250 const struct GNUNET_HashCode *key,
253 struct ElementEntry *ee = value;
254 struct Operation *op = cls;
256 //only consider this element, if it is valid for us
257 if ((op->generation_created < ee->generation_removed)
258 && (op->generation_created >= ee->generation_added))
261 GNUNET_assert (GNUNET_YES ==
262 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
263 &ee->element_hash, ee,
264 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
270 * removes element from a hashmap if it is not contained within the
271 * provided remote bloomfilter. Then, fill our new bloomfilter.
274 * @param key current key code
275 * @param value value in the hash map
276 * @return #GNUNET_YES if we should continue to
281 iterator_bf_reduce (void *cls,
282 const struct GNUNET_HashCode *key,
285 struct ElementEntry *ee = value;
286 struct Operation *op = cls;
287 struct GNUNET_HashCode mutated_hash;
289 GNUNET_BLOCK_mingle_hash(&ee->element_hash, op->spec->salt, &mutated_hash);
292 GNUNET_CONTAINER_bloomfilter_test (op->state->remote_bf,
295 op->state->my_element_count--;
296 GNUNET_assert (GNUNET_YES ==
297 GNUNET_CONTAINER_multihashmap_remove (op->state->my_elements,
300 if (GNUNET_SET_RESULT_REMOVED == op->spec->result_mode)
301 send_client_element (op, &ee->element);
309 * Create a bloomfilter based on the elements given
312 * @param key current key code
313 * @param value value in the hash map
314 * @return #GNUNET_YES if we should continue to
319 iterator_bf_create (void *cls,
320 const struct GNUNET_HashCode *key,
323 struct ElementEntry *ee = value;
324 struct Operation *op = cls;
325 struct GNUNET_HashCode mutated_hash;
327 GNUNET_BLOCK_mingle_hash (&ee->element_hash,
330 GNUNET_CONTAINER_bloomfilter_add (op->state->local_bf,
337 * Inform the client that the union operation has failed,
338 * and proceed to destroy the evaluate operation.
340 * @param op the intersection operation to fail
343 fail_intersection_operation (struct Operation *op)
345 struct GNUNET_MQ_Envelope *ev;
346 struct GNUNET_SET_ResultMessage *msg;
348 if (op->state->my_elements)
350 GNUNET_CONTAINER_multihashmap_destroy(op->state->my_elements);
351 op->state->my_elements = NULL;
353 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
354 "intersection operation failed\n");
356 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
357 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
358 msg->request_id = htonl (op->spec->client_request_id);
359 msg->element_type = htons (0);
360 GNUNET_MQ_send (op->spec->set->client_mq, ev);
361 _GSS_operation_destroy (op, GNUNET_YES);
366 send_bloomfilter_multipart (struct Operation *op,
369 struct GNUNET_MQ_Envelope *ev;
371 uint32_t chunk_size = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof(struct BFPart));
372 uint32_t todo_size = op->state->bf_data_size - offset;
374 if (todo_size < chunk_size)
375 chunk_size = todo_size;
377 ev = GNUNET_MQ_msg_extra (msg,
379 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF_PART);
381 msg->chunk_length = htonl (chunk_size);
382 msg->chunk_offset = htonl (offset);
383 memcpy(&msg[1], &op->state->bf_data[offset], chunk_size);
385 GNUNET_MQ_send (op->mq, ev);
387 if (op->state->bf_data_size == offset + chunk_size)
390 GNUNET_free(op->state->bf_data);
391 op->state->bf_data = NULL;
394 send_bloomfilter_multipart (op, offset + chunk_size);
399 * Send a bloomfilter to our peer.
400 * that the operation is over.
401 * After the result done message has been sent to the client,
402 * destroy the evaluate operation.
404 * @param op intersection operation
407 send_bloomfilter (struct Operation *op)
409 struct GNUNET_MQ_Envelope *ev;
410 struct BFMessage *msg;
412 uint32_t bf_elementbits;
414 struct GNUNET_CONTAINER_BloomFilter * local_bf;
416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
417 "sending bf of size %u\n");
419 CALCULATE_BF_SIZE(op->state->my_element_count,
420 op->spec->remote_element_count,
424 local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
429 GNUNET_CONTAINER_multihashmap_iterate (op->state->my_elements,
433 // send our bloomfilter
434 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > bf_size + sizeof (struct BFMessage))
437 chunk_size = bf_size;
438 ev = GNUNET_MQ_msg_extra (msg, chunk_size, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF);
439 GNUNET_assert (GNUNET_SYSERR !=
440 GNUNET_CONTAINER_bloomfilter_get_raw_data (local_bf,
447 chunk_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BFMessage);
448 ev = GNUNET_MQ_msg_extra (msg, chunk_size, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF);
449 op->state->bf_data = (char *) GNUNET_malloc (bf_size);
450 GNUNET_assert (GNUNET_SYSERR !=
451 GNUNET_CONTAINER_bloomfilter_get_raw_data (local_bf,
454 memcpy (&msg[1], op->state->bf_data, chunk_size);
455 op->state->bf_data_size = bf_size;
457 GNUNET_CONTAINER_bloomfilter_free (local_bf);
459 msg->sender_element_count = htonl (op->state->my_element_count);
460 msg->bloomfilter_total_length = htonl (bf_size);
461 msg->bloomfilter_length = htonl (chunk_size);
462 msg->bits_per_element = htonl (bf_elementbits);
463 msg->sender_mutator = htonl (op->spec->salt);
465 GNUNET_MQ_send (op->mq, ev);
467 if (op->state->bf_data)
468 send_bloomfilter_multipart (op, chunk_size);
473 * Signal to the client that the operation has finished and
474 * destroy the operation.
476 * @param cls operation to destroy
479 send_client_done_and_destroy (void *cls)
481 struct Operation *op = cls;
482 struct GNUNET_MQ_Envelope *ev;
483 struct GNUNET_SET_ResultMessage *rm;
485 ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT);
486 rm->request_id = htonl (op->spec->client_request_id);
487 rm->result_status = htons (GNUNET_SET_STATUS_DONE);
488 rm->element_type = htons (0);
489 GNUNET_MQ_send (op->spec->set->client_mq, ev);
490 _GSS_operation_destroy (op, GNUNET_YES);
495 * Send all elements in the full result iterator.
497 * @param cls operation
500 send_remaining_elements (void *cls)
502 struct Operation *op = cls;
503 struct ElementEntry *remaining; //TODO rework this, key entry does not exist here
504 struct GNUNET_MQ_Envelope *ev;
505 struct GNUNET_SET_ResultMessage *rm;
506 struct GNUNET_SET_Element *element;
509 res = GNUNET_CONTAINER_multihashmap_iterator_next (op->state->full_result_iter,
511 (const void **) &remaining);
512 if (GNUNET_NO == res)
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "sending done and destroy because iterator ran out\n");
516 send_client_done_and_destroy (op);
520 element = &remaining->element;
521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522 "sending element (size %u) to client (full set)\n",
524 GNUNET_assert (0 != op->spec->client_request_id);
526 ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
527 GNUNET_assert (NULL != ev);
529 rm->result_status = htons (GNUNET_SET_STATUS_OK);
530 rm->request_id = htonl (op->spec->client_request_id);
531 rm->element_type = element->element_type;
532 memcpy (&rm[1], element->data, element->size);
534 GNUNET_MQ_notify_sent (ev, send_remaining_elements, op);
535 GNUNET_MQ_send (op->spec->set->client_mq, ev);
540 * Inform the peer that this operation is complete.
542 * @param op the intersection operation to fail
545 send_peer_done (struct Operation *op)
547 struct GNUNET_MQ_Envelope *ev;
549 op->state->phase = PHASE_FINISHED;
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Intersection succeeded, sending DONE\n");
552 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
553 op->state->local_bf = NULL;
555 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_P2P_DONE);
556 GNUNET_MQ_send (op->mq, ev);
561 * Process a Bloomfilter once we got all the chunks
563 * @param op the intersection operation
566 process_bf (struct Operation *op)
568 uint32_t old_elements;
569 uint32_t peer_elements;
571 old_elements = op->state->my_element_count;
572 peer_elements = op->spec->remote_element_count;
573 switch (op->state->phase)
576 // If we are ot our first msg
577 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, GNUNET_YES);
579 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
580 &iterator_initialization_by_alice,
583 case PHASE_BF_EXCHANGE:
584 case PHASE_MAYBE_FINISHED:
585 // if we are bob or alice and are continuing operation
586 GNUNET_CONTAINER_multihashmap_iterate (op->state->my_elements,
592 fail_intersection_operation(op);
594 // the iterators created a new BF with salt+1
595 // the peer needs this information for decoding the next BF
596 // this behavior can be modified at will later on.
599 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
600 op->state->remote_bf = NULL;
602 if ((0 == op->state->my_element_count) // fully disjoint
603 || ((op->state->phase == PHASE_MAYBE_FINISHED) // we agree on a shared set of elements
604 && (old_elements == op->state->my_element_count)
605 && (op->state->my_element_count == peer_elements)))
607 // In the last round we though we were finished, we now know this is correct
612 op->state->phase = PHASE_BF_EXCHANGE;
613 if (op->state->my_element_count == peer_elements)
614 // maybe we are finished, but we do one more round to make certain
615 // we don't have false positives ...
616 op->state->phase = PHASE_MAYBE_FINISHED;
618 send_bloomfilter (op);
623 * Handle an BF multipart message from a remote peer.
625 * @param cls the intersection operation
626 * @param mh the header of the message
629 handle_p2p_bf_part (void *cls, const struct GNUNET_MessageHeader *mh)
631 struct Operation *op = cls;
632 const struct BFPart *msg = (const struct BFPart *) mh;
634 uint32_t chunk_offset;
636 chunk_size = ntohl(msg->chunk_length);
637 chunk_offset = ntohl(msg->chunk_offset);
639 if ((NULL == op->state->bf_data)
640 || (op->state->bf_data_size < chunk_size + chunk_offset))
642 // unexpected multipart chunk
644 fail_intersection_operation(op);
648 memcpy (&op->state->bf_data[chunk_offset], (const char*) &msg[1], chunk_size);
650 if (op->state->bf_data_size != chunk_offset + chunk_size)
651 // wait for next chunk
654 op->state->remote_bf = GNUNET_CONTAINER_bloomfilter_init ((const char*) &msg[1],
655 op->state->bf_data_size,
656 op->state->bf_bits_per_element);
658 GNUNET_free (op->state->bf_data);
659 op->state->bf_data = NULL;
666 * Handle an BF message from a remote peer.
668 * @param cls the intersection operation
669 * @param mh the header of the message
672 handle_p2p_bf (void *cls,
673 const struct GNUNET_MessageHeader *mh)
675 struct Operation *op = cls;
676 const struct BFMessage *msg = (const struct BFMessage *) mh;
679 uint32_t bf_bits_per_element;
681 switch (op->state->phase)
684 case PHASE_BF_EXCHANGE:
685 case PHASE_MAYBE_FINISHED:
686 if (NULL == op->state->bf_data)
688 // no colliding multipart transaction going on currently
689 op->spec->salt = ntohl (msg->sender_mutator);
690 bf_size = ntohl (msg->bloomfilter_total_length);
691 bf_bits_per_element = ntohl (msg->bits_per_element);
692 chunk_size = ntohl (msg->bloomfilter_length);
693 op->spec->remote_element_count = ntohl(msg->sender_element_count);
694 if (bf_size == chunk_size)
696 // single part, done here
697 op->state->remote_bf = GNUNET_CONTAINER_bloomfilter_init ((const char*) &msg[1],
699 bf_bits_per_element);
704 //first multipart chunk
705 op->state->bf_data = GNUNET_malloc (bf_size);
706 op->state->bf_data_size = bf_size;
707 op->state->bf_bits_per_element = bf_bits_per_element;
708 memcpy (op->state->bf_data, (const char*) &msg[1], chunk_size);
713 fail_intersection_operation (op);
719 * Handle an BF message from a remote peer.
721 * @param cls the intersection operation
722 * @param mh the header of the message
725 handle_p2p_element_info (void *cls,
726 const struct GNUNET_MessageHeader *mh)
728 struct Operation *op = cls;
729 const struct BFMessage *msg = (const struct BFMessage *) mh;
731 op->spec->remote_element_count = ntohl(msg->sender_element_count);
732 if ((op->state->phase != PHASE_INITIAL)
733 || (op->state->my_element_count > op->spec->remote_element_count)
734 || (0 == op->state->my_element_count)
735 || (0 == op->spec->remote_element_count))
738 fail_intersection_operation(op);
742 op->state->phase = PHASE_BF_EXCHANGE;
743 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
745 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
746 &iterator_initialization,
749 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
750 op->state->remote_bf = NULL;
752 if (op->state->my_element_count == ntohl (msg->sender_element_count))
753 op->state->phase = PHASE_MAYBE_FINISHED;
755 send_bloomfilter (op);
760 * Send our element count to the peer, in case our element count is lower than his
762 * @param op intersection operation
765 send_element_count (struct Operation *op)
767 struct GNUNET_MQ_Envelope *ev;
768 struct BFMessage *msg;
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "sending element count (bf_msg)\n");
773 // just send our element count, as the other peer must start
774 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
775 msg->sender_element_count = htonl (op->state->my_element_count);
776 msg->bloomfilter_length = htonl (0);
777 msg->sender_mutator = htonl (0);
779 GNUNET_MQ_send (op->mq, ev);
784 * Send a result message to the client indicating
785 * that the operation is over.
786 * After the result done message has been sent to the client,
787 * destroy the evaluate operation.
789 * @param op intersection operation
792 finish_and_destroy (struct Operation *op)
794 GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
796 if (GNUNET_SET_RESULT_FULL == op->spec->result_mode)
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "sending full result set\n");
800 op->state->full_result_iter =
801 GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
802 send_remaining_elements (op);
805 send_client_done_and_destroy (op);
810 * Handle a done message from a remote peer
812 * @param cls the union operation
813 * @param mh the message
816 handle_p2p_done (void *cls,
817 const struct GNUNET_MessageHeader *mh)
819 struct Operation *op = cls;
821 if ( (op->state->phase = PHASE_FINISHED) ||
822 (op->state->phase = PHASE_MAYBE_FINISHED) )
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827 finish_and_destroy (op);
832 fail_intersection_operation (op);
837 * Initiate a set union operation with a remote peer.
839 * @param op operation that is created, should be initialized to
840 * begin the evaluation
841 * @param opaque_context message to be transmitted to the listener
842 * to convince him to accept, may be NULL
845 intersection_evaluate (struct Operation *op,
846 const struct GNUNET_MessageHeader *opaque_context)
848 struct GNUNET_MQ_Envelope *ev;
849 struct OperationRequestMessage *msg;
851 op->state = GNUNET_new (struct OperationState);
852 /* we started the operation, thus we have to send the operation request */
853 op->state->phase = PHASE_INITIAL;
854 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
855 op->state->my_element_count = op->spec->set->state->current_set_element_count;
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 "Initiating intersection operation evaluation");
859 ev = GNUNET_MQ_msg_nested_mh (msg,
860 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
864 /* the context message is too large */
866 GNUNET_SERVER_client_disconnect (op->spec->set->client);
869 msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION);
870 msg->app_id = op->spec->app_id;
871 msg->salt = htonl (op->spec->salt);
872 msg->element_count = htonl(op->state->my_element_count);
873 GNUNET_MQ_send (op->mq, ev);
874 if (NULL != opaque_context)
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876 "sent op request with context message\n");
878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
879 "sent op request without context message\n");
884 * Accept an union operation request from a remote peer.
885 * Only initializes the private operation state.
887 * @param op operation that will be accepted as a union operation
890 intersection_accept (struct Operation *op)
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "accepting set union operation\n");
894 op->state = GNUNET_new (struct OperationState);
895 op->state->my_elements = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_YES);
896 op->state->my_element_count = op->spec->set->state->current_set_element_count;
898 // if Alice (the peer) has more elements than Bob (us), she should start
899 if (op->spec->remote_element_count < op->state->my_element_count){
900 op->state->phase = PHASE_INITIAL;
901 send_element_count(op);
904 // create a new bloomfilter in case we have fewer elements
905 op->state->phase = PHASE_BF_EXCHANGE;
906 op->state->local_bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
908 GNUNET_CONSTANTS_BLOOMFILTER_K);
909 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements,
910 &iterator_initialization,
912 send_bloomfilter (op);
917 * Create a new set supporting the intersection operation
919 * @return the newly created set
921 static struct SetState *
922 intersection_set_create ()
924 struct SetState *set_state;
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927 "intersection set created\n");
928 set_state = GNUNET_new (struct SetState);
929 set_state->current_set_element_count = 0;
936 * Add the element from the given element message to the set.
938 * @param set_state state of the set want to add to
939 * @param ee the element to add to the set
942 intersection_add (struct SetState *set_state,
943 struct ElementEntry *ee)
945 set_state->current_set_element_count++;
950 * Destroy a set that supports the intersection operation
952 * @param set_state the set to destroy
955 intersection_set_destroy (struct SetState *set_state)
957 GNUNET_free (set_state);
962 * Remove the element given in the element message from the set.
964 * @param set_state state of the set to remove from
965 * @param element set element to remove
968 intersection_remove (struct SetState *set_state,
969 struct ElementEntry *element)
971 GNUNET_assert(0 < set_state->current_set_element_count);
972 set_state->current_set_element_count--;
977 * Dispatch messages for a intersection operation.
979 * @param op the state of the intersection evaluate operation
980 * @param mh the received message
981 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
982 * #GNUNET_OK otherwise
985 intersection_handle_p2p_message (struct Operation *op,
986 const struct GNUNET_MessageHeader *mh)
988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
989 "received p2p message (t: %u, s: %u)\n",
990 ntohs (mh->type), ntohs (mh->size));
991 switch (ntohs (mh->type))
993 /* this message handler is not active until after we received an
994 * operation request message, thus the ops request is not handled here
996 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
997 handle_p2p_element_info (op, mh);
999 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
1000 handle_p2p_bf (op, mh);
1002 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF_PART:
1003 handle_p2p_bf_part (op, mh);
1005 case GNUNET_MESSAGE_TYPE_SET_P2P_DONE:
1006 handle_p2p_done (op, mh);
1009 /* something wrong with cadet's message handlers? */
1017 * handler for peer-disconnects, notifies the client about the aborted operation
1019 * @param op the destroyed operation
1022 intersection_peer_disconnect (struct Operation *op)
1024 if (PHASE_FINISHED != op->state->phase)
1026 struct GNUNET_MQ_Envelope *ev;
1027 struct GNUNET_SET_ResultMessage *msg;
1029 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
1030 msg->request_id = htonl (op->spec->client_request_id);
1031 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
1032 msg->element_type = htons (0);
1033 GNUNET_MQ_send (op->spec->set->client_mq, ev);
1034 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1035 "other peer disconnected prematurely\n");
1036 _GSS_operation_destroy (op, GNUNET_YES);
1039 // else: the session has already been concluded
1040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1041 "other peer disconnected (finished)\n");
1042 if (GNUNET_NO == op->state->client_done_sent)
1043 finish_and_destroy (op);
1048 * Destroy the union operation. Only things specific to the union operation are destroyed.
1050 * @param op union operation to destroy
1053 intersection_op_cancel (struct Operation *op)
1055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1056 "destroying intersection op\n");
1057 /* check if the op was canceled twice */
1058 GNUNET_assert (NULL != op->state);
1059 if (NULL != op->state->remote_bf)
1061 GNUNET_CONTAINER_bloomfilter_free (op->state->remote_bf);
1062 op->state->remote_bf = NULL;
1064 if (NULL != op->state->local_bf)
1066 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
1067 op->state->local_bf = NULL;
1069 /* if (NULL != op->state->my_elements)
1071 // no need to free the elements, they are still part of the set
1072 GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
1073 op->state->my_elements = NULL;
1075 GNUNET_free (op->state);
1077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078 "destroying intersection op done\n");
1083 * Get the table with implementing functions for set intersection.
1085 * @return the operation specific VTable
1087 const struct SetVT *
1088 _GSS_intersection_vt ()
1090 static const struct SetVT intersection_vt = {
1091 .create = &intersection_set_create,
1092 .msg_handler = &intersection_handle_p2p_message,
1093 .add = &intersection_add,
1094 .remove = &intersection_remove,
1095 .destroy_set = &intersection_set_destroy,
1096 .evaluate = &intersection_evaluate,
1097 .accept = &intersection_accept,
1098 .peer_disconnect = &intersection_peer_disconnect,
1099 .cancel = &intersection_op_cancel,
1102 return &intersection_vt;