/**
 * Signature of the 'main' function for a (single-peer) testcase that
 * is run using 'GNUNET_TESTING_peer_run'.
 *
 * @param cls closure
 * @param cfg configuration of the peer that was started
 * @param peer identity of the peer that was created
 */
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
  config = cfg;
  GNUNET_TESTING_peer_get_identity (peer, &local_id);
  if (0) test_iter ();

  set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
  set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
  GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id);

  /* test the real set reconciliation */
  init_set1 ();
}
/**
 * Signature of the 'main' function for a (single-peer) testcase that
 * is run using 'GNUNET_TESTING_peer_run'.
 *
 * @param cls closure
 * @param cfg configuration of the peer that was started
 * @param peer identity of the peer that was created
 */
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
                                &timeout_fail,
                                NULL);

  config = cfg;
  GNUNET_TESTING_peer_get_identity (peer,
                                    &local_id);

  test_iter ();

  set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
  set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
  GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id);

  /* test the real set reconciliation */
  init_set1 ();
}
static void
test_iter ()
{
  struct GNUNET_SET_Element element;
  struct GNUNET_SET_Handle *iter_set;

  iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_INTERSECTION);
  element.element_type = 0;
  element.data = "hello";
  element.size = strlen(element.data);
  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
  element.data = "bar";
  element.size = strlen(element.data);
  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
  element.data = "quux";
  element.size = strlen(element.data);
  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
  GNUNET_SET_iterate (iter_set, &iter_cb, iter_set);
}
/**
 * Handler for Bob's a client request message.  Bob is in the response
 * role, keep the values + session and waiting for a matching session
 * or process a waiting request from Alice.
 *
 * @param cls identification of the client
 * @param msg the actual message
 */
static void
handle_bob_client_message (void *cls,
			   const struct BobComputationMessage *msg)
{
  struct BobServiceSession *s = cls;
  struct CadetIncomingSession *in;
  uint32_t contained_count;
  uint32_t total_count;
  const struct GNUNET_SCALARPRODUCT_Element *elements;
  struct GNUNET_SET_Element set_elem;
  struct GNUNET_SCALARPRODUCT_Element *elem;

  total_count = ntohl (msg->element_count_total);
  contained_count = ntohl (msg->element_count_contained);

  s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
  s->total = total_count;
  s->client_received_element_count = contained_count;
  s->session_id = msg->session_key;
  s->port = GNUNET_CADET_open_port (my_cadet,
                                    &msg->session_key,
                                    &cb_channel_incoming,
                                    s);
  if (NULL == s->port)
  {
    GNUNET_break (0);
    GNUNET_SERVICE_client_drop (s->client);
    return;
  }
  GNUNET_break (GNUNET_YES ==
                GNUNET_CONTAINER_multihashmap_put (client_sessions,
                                                   &s->session_id,
                                                   s,
                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
  s->intersected_elements
    = GNUNET_CONTAINER_multihashmap_create (s->total,
					    GNUNET_YES);
  s->intersection_set
    = GNUNET_SET_create (cfg,
			 GNUNET_SET_OPERATION_INTERSECTION);
  for (uint32_t i = 0; i < contained_count; i++)
  {
    if (0 == GNUNET_ntohll (elements[i].value))
      continue;
    elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
    GNUNET_memcpy (elem,
            &elements[i],
            sizeof (struct GNUNET_SCALARPRODUCT_Element));
    if (GNUNET_SYSERR ==
        GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
                                           &elem->key,
                                           elem,
                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
    {
      GNUNET_break (0);
      GNUNET_free (elem);
      continue;
    }
    set_elem.data = &elem->key;
    set_elem.size = sizeof (elem->key);
    set_elem.element_type = 0;
    GNUNET_SET_add_element (s->intersection_set,
                            &set_elem,
                            NULL, NULL);
    s->used_element_count++;
  }
  GNUNET_SERVICE_client_continue (s->client);
  if (s->total != s->client_received_element_count)
  {
    /* multipart msg */
    return;
  }
  in = find_matching_cadet_session (&s->session_id);
  if (NULL == in)
  {
    /* nothing yet, wait for Alice */
    return;
  }
  GNUNET_assert (NULL == in->s);
  /* pair them up */
  in->s = s;
  s->cadet = in;
  start_intersection (s);
}