+ * Check a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ * @return #GNUNET_OK if @a mh is well-formed
+ */
+int
+check_union_p2p_demand (void *cls,
+ const struct GNUNET_MessageHeader *mh)
+{
+ struct Operation *op = cls;
+ unsigned int num_hashes;
+
+ if (GNUNET_SET_OPERATION_UNION != op->set->operation)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ / sizeof (struct GNUNET_HashCode);
+ if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ != num_hashes * sizeof (struct GNUNET_HashCode))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ */
+void
+handle_union_p2p_demand (void *cls,
+ const struct GNUNET_MessageHeader *mh)
+{
+ struct Operation *op = cls;
+ struct ElementEntry *ee;
+ struct GNUNET_SET_ElementMessage *emsg;
+ const struct GNUNET_HashCode *hash;
+ unsigned int num_hashes;
+ struct GNUNET_MQ_Envelope *ev;
+
+ num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ / sizeof (struct GNUNET_HashCode);
+ for (hash = (const struct GNUNET_HashCode *) &mh[1];
+ num_hashes > 0;
+ hash++, num_hashes--)
+ {
+ ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
+ hash);
+ if (NULL == ee)
+ {
+ /* Demand for non-existing element. */
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
+ }
+ if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
+ {
+ /* Probably confused lazily copied sets. */
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
+ }
+ ev = GNUNET_MQ_msg_extra (emsg, ee->element.size, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS);
+ GNUNET_memcpy (&emsg[1], ee->element.data, ee->element.size);
+ emsg->reserved = htons (0);
+ emsg->element_type = htons (ee->element.element_type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "[OP %x] Sending demanded element (size %u, hash %s) to peer\n",
+ (void *) op,
+ (unsigned int) ee->element.size,
+ GNUNET_h2s (&ee->element_hash));
+ GNUNET_MQ_send (op->mq, ev);
+ GNUNET_STATISTICS_update (_GSS_statistics,
+ "# exchanged elements",
+ 1,
+ GNUNET_NO);
+
+ switch (op->result_mode)
+ {
+ case GNUNET_SET_RESULT_ADDED:
+ /* Nothing to do. */
+ break;
+ case GNUNET_SET_RESULT_SYMMETRIC:
+ send_client_element (op, &ee->element, GNUNET_SET_STATUS_ADD_REMOTE);
+ break;
+ default:
+ /* Result mode not supported, should have been caught earlier. */
+ GNUNET_break (0);
+ break;
+ }
+ }
+ GNUNET_CADET_receive_done (op->channel);
+}
+
+
+/**
+ * Check offer (of `struct GNUNET_HashCode`s).