/**
 * Clean up node
 *
 * @param cls the peermap to clean up
 * @param key key of the current node
 * @param value related node object
 * @return always #GNUNET_OK
 */
static int
cleanup_node (void *cls,
	      const struct GNUNET_PeerIdentity * key,
	      void *value)
{
  struct Node *n;
  struct NodeComCtx *e_cur;
  struct NodeComCtx *e_next;
  struct GNUNET_CONTAINER_MultiPeerMap *cur = cls;

  n = value;
  if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
  {
    GNUNET_SCHEDULER_cancel (n->timeout_task);
    n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  }

  if (NULL != n->cth)
  {
    GNUNET_CORE_notify_transmit_ready_cancel (n->cth);
    n->cth = NULL;
  }
  e_next = n->e_req_head;
  while (NULL != (e_cur = e_next))
  {
    e_next = e_cur->next;
    GNUNET_CONTAINER_DLL_remove (n->e_req_head, n->e_req_tail, e_cur);
    GNUNET_free (e_cur);
  }
  GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_remove (cur, key, value));
  GNUNET_free (value);
  return GNUNET_OK;
}
Esempio n. 2
0
/**
 * Free all resources associated with the given peer.
 *
 * @param cls closure (not used)
 * @param pid identity of the peer
 * @param value peer to free
 * @return #GNUNET_YES (always: continue to iterate)
 */
static int
free_peer (void *cls,
           const struct GNUNET_PeerIdentity * pid,
           void *value)
{
  struct Peer *pos = value;

  GNUNET_break (NULL == pos->mq);
  GNUNET_break (GNUNET_OK ==
                GNUNET_CONTAINER_multipeermap_remove (peers,
                                                      pid,
                                                      pos));
  if (NULL != pos->hello_delay_task)
  {
    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
    pos->hello_delay_task = NULL;
  }
  if (NULL != pos->sh)
  {
    GNUNET_ATS_connectivity_suggest_cancel (pos->sh);
    pos->sh = NULL;
  }
  if (NULL != pos->hello)
  {
    GNUNET_free_non_null (pos->hello);
    pos->hello = NULL;
  }
  if (NULL != pos->filter)
  {
    GNUNET_CONTAINER_bloomfilter_free (pos->filter);
    pos->filter = NULL;
  }
  GNUNET_free (pos);
  return GNUNET_YES;
}
/**
 * Release memory used by the given address data.
 *
 * @param ai the `struct AddressInfo`
 */
static void
destroy_ai (struct AddressInfo *ai)
{
  GNUNET_assert (NULL == ai->session);
  if (NULL != ai->unblock_task)
  {
    GNUNET_SCHEDULER_cancel (ai->unblock_task);
    ai->unblock_task = NULL;
    num_blocked--;
  }
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (p2a,
                                                       &ai->address->peer,
                                                       ai));
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Telling ATS to destroy address from peer %s\n",
       GNUNET_i2s (&ai->address->peer));
  if (NULL != ai->ar)
  {
    GNUNET_ATS_address_destroy (ai->ar);
    ai->ar = NULL;
  }
  publish_p2a_stat_update ();
  GNUNET_HELLO_address_free (ai->address);
  GNUNET_free (ai);
}
Esempio n. 4
0
/**
 * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
 * any pending transmission requests to that peer.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 * @parma internal_cls the `struct NSEPeerEntry` for the @a peer
 */
static void
handle_core_disconnect (void *cls,
			const struct GNUNET_PeerIdentity *peer,
			void *internal_cls)
{
  struct NSEPeerEntry *pos = internal_cls;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Peer `%s' disconnected from us\n",
              GNUNET_i2s (peer));
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (peers,
						       peer,
                                                       pos));
  if (NULL != pos->transmit_task)
  {
    GNUNET_SCHEDULER_cancel (pos->transmit_task);
    pos->transmit_task = NULL;
  }
  GNUNET_free (pos);
  GNUNET_STATISTICS_update (stats,
			    "# peers connected",
			    -1,
			    GNUNET_NO);
}
/**
 * @ingroup hashmap
 * Iterator over hash map entries.
 *
 * @param cls closure
 * @param key current key code
 * @param value value in the hash map
 * @return #GNUNET_YES if we should continue to
 *         iterate,
 *         #GNUNET_NO if not.
 */
static int
iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
{
    GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
                   value));
    return GNUNET_YES;
}
/**
 * Free `struct PreferencePeer` entry in map.
 *
 * @param cls the `struct PreferenceClient` with the map
 * @param key the peer the entry is for
 * @param value the `struct PreferencePeer` entry to free
 * @return #GNUNET_OK (continue to iterate)
 */
static int
free_preference (void *cls,
                 const struct GNUNET_PeerIdentity *key,
                 void *value)
{
  struct PreferenceClient *pc = cls;
  struct PreferencePeer *p = value;
  struct PeerRelative *pr;

  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_remove (pc->peer2pref,
                                                       key,
                                                       p));
  GNUNET_free (p);
  pr = GNUNET_CONTAINER_multipeermap_get (preference_peers,
                                          key);
  GNUNET_assert (NULL != pr);
  GNUNET_assert (pr->num_clients > 0);
  pr->num_clients--;
  if (0 == pr->num_clients)
  {
    free_peer (NULL,
               key,
               pr);
  }
  return GNUNET_OK;
}
Esempio n. 7
0
 int destroy_it (void *cls,
    const struct GNUNET_PeerIdentity *key,
    void *value)
{
   struct MonitoredPeer *m = value;
   GNUNET_CONTAINER_multipeermap_remove (monitored_peers, key, value);
   GNUNET_free_non_null (m->address);
   GNUNET_free (value);
   return GNUNET_OK;
}
/**
 * @ingroup hashmap
 * Iterator over hash map entries.
 *
 * @param cls closure
 * @param key current public key
 * @param value value in the hash map
 * @return #GNUNET_YES if we should continue to
 *         iterate,
 *         #GNUNET_NO if not.
 */
static int
free_iterator (void *cls,
               const struct GNUNET_PeerIdentity *key,
               void *value)
{
  struct Entry *e = cls;

  GNUNET_assert (GNUNET_YES == 
                 GNUNET_CONTAINER_multipeermap_remove (map, key, e));
  GNUNET_free (e);
  return GNUNET_YES;
}
/**
 * Handler called by CORE when CORE is ready to transmit message
 *
 * @param cls closure with the `const struct GNUNET_PeerIdentity *` of
 *            the peer we are sending to
 * @param size size of buffer to copy message to
 * @param buf buffer to copy message to
 * @return number of bytes copied to @a buf
 */
static size_t
adv_transmit_ready (void *cls,
                    size_t size,
                    void *buf)
{
  const struct GNUNET_PeerIdentity *peer = cls;
  static uint64_t hostlist_adv_count;
  size_t transmission_size;
  size_t uri_size;              /* Including \0 termination! */
  struct GNUNET_MessageHeader header;
  char *cbuf;
  struct GNUNET_CORE_TransmitHandle *th;

  th = GNUNET_CONTAINER_multipeermap_get (advertisements,
                                          peer);
  GNUNET_assert (NULL != th);
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (advertisements,
                                                       peer,
                                                       th));
  if (NULL == buf)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Transmission failed, buffer invalid!\n");
    return 0;
  }
  uri_size = strlen (hostlist_uri) + 1;
  transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size;
  header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
  header.size = htons (transmission_size);
  GNUNET_assert (size >= transmission_size);
  memcpy (buf,
          &header,
          sizeof (struct GNUNET_MessageHeader));
  cbuf = buf;
  memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)],
          hostlist_uri,
          uri_size);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sent advertisement message: Copied %u bytes into buffer!\n",
              (unsigned int) transmission_size);
  hostlist_adv_count++;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              " # Sent advertisement message: %u\n",
              hostlist_adv_count);
  GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# hostlist advertisements send"), 1,
                            GNUNET_NO);
  return transmission_size;
}
/**
 * Free a peer's `struct PeerRelative`.
 *
 * @param cls unused
 * @param key the key
 * @param value the `struct PeerRelative` to free.
 * @return #GNUNET_OK to continue
 */
static int
free_peer (void *cls,
           const struct GNUNET_PeerIdentity *key,
           void *value)
{
  struct PeerRelative *rp = value;

  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (preference_peers,
                                                       key,
                                                       value));
  GNUNET_free (rp);
  return GNUNET_OK;
}
/**
 * End the session with the given peer (we are no longer
 * connected).
 *
 * @param pid identity of peer to kill session with
 */
void
GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid)
{
  struct Session *session;
  struct GSC_ClientActiveRequest *car;
  struct SessionMessageEntry *sme;

  session = find_session (pid);
  if (NULL == session)
    return;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Destroying session for peer `%4s'\n",
              GNUNET_i2s (&session->peer));
  if (NULL != session->cork_task)
  {
    GNUNET_SCHEDULER_cancel (session->cork_task);
    session->cork_task = NULL;
  }
  while (NULL != (car = session->active_client_request_head))
  {
    GNUNET_CONTAINER_DLL_remove (session->active_client_request_head,
                                 session->active_client_request_tail, car);
    GSC_CLIENTS_reject_request (car,
                                GNUNET_NO);
  }
  while (NULL != (sme = session->sme_head))
  {
    GNUNET_CONTAINER_DLL_remove (session->sme_head,
                                 session->sme_tail,
                                 sme);
    GNUNET_free (sme);
  }
  if (NULL != session->typemap_task)
  {
    GNUNET_SCHEDULER_cancel (session->typemap_task);
    session->typemap_task = NULL;
  }
  GSC_CLIENTS_notify_clients_about_neighbour (&session->peer,
                                              session->tmap, NULL);
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (sessions,
                                                       &session->peer,
                                                       session));
  GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"),
                         GNUNET_CONTAINER_multipeermap_size (sessions),
                         GNUNET_NO);
  GSC_TYPEMAP_destroy (session->tmap);
  session->tmap = NULL;
  GNUNET_free (session);
}
Esempio n. 12
0
/**
 * Free `struct AddressInformationData` entry.
 *
 * @param cls NULL
 * @param key ignored
 * @param value the `struct AddressSuggestData` to release
 * @return #GNUNET_OK (continue to iterate)
 */
static int
free_aid (void *cls,
          const struct GNUNET_PeerIdentity *key,
          void *value)
{
  struct AddressInformationData *aid = value;

  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (p2aid,
                                                       key,
                                                       aid));
  GNUNET_free (aid->address);
  GNUNET_free (aid);
  return GNUNET_OK;
}
Esempio n. 13
0
/**
 * Free `struct AddressSuggestData` entry.
 *
 * @param cls NULL
 * @param key ignored
 * @param value the `struct AddressSuggestData` to release
 * @return #GNUNET_OK (continue to iterate)
 */
static int
free_asd (void *cls,
          const struct GNUNET_PeerIdentity *key,
          void *value)
{
  struct AddressSuggestData *asd = value;

  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (p2asd,
                                                       key,
                                                       asd));
  GNUNET_free_non_null (asd->address);
  GNUNET_free (asd);
  return GNUNET_OK;
}
/**
 * Free the given entry for the neighbour.
 *
 * @param n neighbour to free
 */
static void
free_neighbour (struct Neighbour *n)
{
  struct NeighbourMessageEntry *m;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Destroying neighbour entry for peer `%s'\n",
              GNUNET_i2s (&n->peer));
  while (NULL != (m = n->message_head))
  {
    GNUNET_CONTAINER_DLL_remove (n->message_head,
                                 n->message_tail,
                                 m);
    n->queue_size--;
    GNUNET_free (m);
  }
  GNUNET_assert (0 == n->queue_size);
  if (NULL != n->th)
  {
    GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
    n->th = NULL;
  }
  GNUNET_STATISTICS_update (GSC_stats,
                            gettext_noop
                            ("# sessions terminated by transport disconnect"),
                            1, GNUNET_NO);
  if (NULL != n->kxinfo)
  {
    GSC_KX_stop (n->kxinfo);
    n->kxinfo = NULL;
  }
  if (NULL != n->retry_plaintext_task)
  {
    GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
    n->retry_plaintext_task = NULL;
  }
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_remove (neighbours,
                                                       &n->peer, n));
  GNUNET_STATISTICS_set (GSC_stats,
                         gettext_noop ("# neighbour entries allocated"),
                         GNUNET_CONTAINER_multipeermap_size (neighbours),
                         GNUNET_NO);
  GNUNET_free (n);
}
/**
 * Remove experimentation request due to timeout
 *
 * @param cls the related node
 * @param tc scheduler's task context
 */
static void
remove_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct Node *n = cls;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Removing request for peer %s due to timeout\n",
	      GNUNET_i2s (&n->id));
  if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (nodes_requested, &n->id))
  {
    GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_remove (nodes_requested, &n->id, n));
    update_stats (nodes_requested);
    GNUNET_CONTAINER_multipeermap_put (nodes_inactive, &n->id, n,
				       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
    update_stats (nodes_inactive);
  }
  n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
}
/**
 * Method called whenever a given peer disconnects.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 */
static void
disconnect_handler (void *cls,
                    const struct GNUNET_PeerIdentity *peer)
{
  struct GNUNET_CORE_TransmitHandle *th;

  if (! advertising)
    return;
  th = GNUNET_CONTAINER_multipeermap_get (advertisements,
                                          peer);
  if (NULL == th)
    return;
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (advertisements,
                                                       peer,
                                                       th));
  GNUNET_CORE_notify_transmit_ready_cancel (th);
}
Esempio n. 17
0
/**
 * Notify clients about disconnect and free
 * the entry for connected peer.
 *
 * @param cls the `struct GNUNET_CORE_Handle *`
 * @param key the peer identity (not used)
 * @param value the `struct PeerRecord` to free.
 * @return #GNUNET_YES (continue)
 */
static int
disconnect_and_free_peer_entry (void *cls,
				const struct GNUNET_PeerIdentity *key,
                                void *value)
{
  struct GNUNET_CORE_Handle *h = cls;
  struct GNUNET_CORE_TransmitHandle *th;
  struct PeerRecord *pr = value;

  if (GNUNET_SCHEDULER_NO_TASK != pr->timeout_task)
  {
    GNUNET_SCHEDULER_cancel (pr->timeout_task);
    pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  }
  if (GNUNET_SCHEDULER_NO_TASK != pr->ntr_task)
  {
    GNUNET_SCHEDULER_cancel (pr->ntr_task);
    pr->ntr_task = GNUNET_SCHEDULER_NO_TASK;
  }
  if ((NULL != pr->prev) || (NULL != pr->next) || (h->ready_peer_head == pr))
    GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  if (NULL != h->disconnects)
    h->disconnects (h->cls, &pr->peer);
  /* all requests should have been cancelled, clean up anyway, just in case */
  th = &pr->th;
  if (NULL != th->peer)
  {
    GNUNET_break (0);
    th->peer = NULL;
    if (NULL != th->cm)
      th->cm->th = NULL;
  }
  /* done with 'voluntary' cleanups, now on to normal freeing */
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
  GNUNET_assert (pr->ch == h);
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pr->timeout_task);
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pr->ntr_task);
  GNUNET_free (pr);
  return GNUNET_YES;
}
/**
 * Free the connection request from the map if the
 * closure matches the client.
 *
 * @param cls the client to match
 * @param pid peer for which the request was made
 * @param value the `struct ConnectionRequest`
 * @return #GNUNET_OK (continue to iterate)
 */
static int
free_matching_requests (void *cls,
                        const struct GNUNET_PeerIdentity *pid,
                        void *value)
{
  struct GNUNET_SERVER_Client *client = cls;
  struct ConnectionRequest *cr = value;

  if (cr->client == client)
  {
    GAS_plugin_request_connect_stop (pid);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Removed request pending for peer `%s\n",
                GNUNET_i2s (pid));
    GNUNET_assert (GNUNET_YES ==
                   GNUNET_CONTAINER_multipeermap_remove (connection_requests,
                                                         pid,
                                                         cr));
    GNUNET_free (cr);
  }
  return GNUNET_OK;
}
Esempio n. 19
0
File: dv_api.c Progetto: tg-x/gnunet
/**
 * We got disconnected from the service and thus all of the
 * pending send callbacks will never be confirmed.  Clean up.
 *
 * @param cls the 'struct GNUNET_DV_ServiceHandle'
 * @param key a peer identity
 * @param value a `struct ConnectedPeer` to clean up
 * @return #GNUNET_OK (continue to iterate)
 */
static int
cleanup_send_cb (void *cls,
		 const struct GNUNET_PeerIdentity *key,
		 void *value)
{
  struct GNUNET_DV_ServiceHandle *sh = cls;
  struct ConnectedPeer *peer = value;
  struct GNUNET_DV_TransmitHandle *th;

  GNUNET_assert (GNUNET_YES ==
		 GNUNET_CONTAINER_multipeermap_remove (sh->peers,
						       key,
						       peer));
  sh->disconnect_cb (sh->cls,
                     key);
  while (NULL != (th = peer->head))
  {
    GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, th);
    th->cb (th->cb_cls, GNUNET_SYSERR);
    GNUNET_free (th);
  }
  GNUNET_free (peer);
  return GNUNET_OK;
}
static int
testMap (int i)
{
  struct GNUNET_CONTAINER_MultiPeerMap *m;
  struct GNUNET_PeerIdentity k1;
  struct GNUNET_PeerIdentity k2;
  struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
  struct GNUNET_PeerIdentity key_ret;
  const char *ret;
  int j;

  CHECK (NULL != (m = GNUNET_CONTAINER_multipeermap_create (i, GNUNET_NO)));
  memset (&k1, 0, sizeof (k1));
  memset (&k2, 1, sizeof (k2));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k1));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k1, NULL));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k2, NULL));
  CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k1));
  CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k2));
  CHECK (0 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1));
  CHECK (0 == GNUNET_CONTAINER_multipeermap_size (m));
  CHECK (0 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL));
  CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL));

  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
  CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m));
  ret = GNUNET_CONTAINER_multipeermap_get (m, &k1);
  GNUNET_assert (ret != NULL);
  CHECK (0 == strcmp ("v1", ret));
  CHECK (GNUNET_NO ==
         GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
  CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m));
  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multipeermap_put (m, &k1, "v3",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  CHECK (3 == GNUNET_CONTAINER_multipeermap_size (m));
  CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (m, &k1, "v3"));
  CHECK (2 == GNUNET_CONTAINER_multipeermap_size (m));
  CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (m, &k1));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2));
  CHECK (2 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL));
  CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k2, NULL, NULL));
  CHECK (2 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL));
  iter = GNUNET_CONTAINER_multipeermap_iterator_create (m);
  CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, &key_ret, (const void **)&ret));
  CHECK (0 == memcmp (&key_ret, &k1, sizeof (key_ret)));
  CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, &key_ret, (const void **)&ret));
  CHECK (0 == memcmp (&key_ret, &k1, sizeof (key_ret)));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL));
  GNUNET_free (iter);

  CHECK (2 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1));
  for (j = 0; j < 1024; j++)
    CHECK (GNUNET_OK ==
           GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2",
                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  iter = GNUNET_CONTAINER_multipeermap_iterator_create (m);
  for (j = 0; j < GNUNET_CONTAINER_multipeermap_size (m); j++)
    CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL));
  GNUNET_free (iter);

  GNUNET_CONTAINER_multipeermap_destroy (m);
  return 0;
}
/**
 * Handle a request and send a response
 *
 * @param peer the source
 * @param message the message
 */
static void
handle_request (const struct GNUNET_PeerIdentity *peer,
		const struct GNUNET_MessageHeader *message)
{
  struct Node *n;
  struct NodeComCtx *e_ctx;
  const struct Experimentation_Request *rm = (const struct Experimentation_Request *) message;
  const struct GNUNET_CRYPTO_EddsaPublicKey *rmi = (const struct GNUNET_CRYPTO_EddsaPublicKey *) &rm[1];
  unsigned int my_issuer_count = GNUNET_CONTAINER_multihashmap_size (valid_issuers);
  int c1;
  int c2;
  uint32_t ic;
  uint32_t ic_accepted;
  int make_active;

  if (ntohs (message->size) < sizeof (struct Experimentation_Request))
  {
    GNUNET_break (0);
    return;
  }
  ic = ntohl (rm->issuer_count);
  if (ntohs (message->size) !=
      sizeof (struct Experimentation_Request) + ic * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))
  {
    GNUNET_break (0);
    return;
  }

  make_active = GNUNET_NO;
  if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_active, peer)))
  {
    /* Nothing to do */
  }
  else if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_requested, peer)))
  {
    GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (nodes_requested, peer, n));
    if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
      {
	GNUNET_SCHEDULER_cancel (n->timeout_task);
	n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
      }
    update_stats (nodes_requested);
    make_active = GNUNET_YES;
  }
  else if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_inactive, peer)))
  {
    GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_remove (nodes_inactive, peer, n));
    update_stats (nodes_inactive);
    make_active = GNUNET_YES;
  }
  else
  {
    /* Create new node */
    n = GNUNET_new (struct Node);
    n->id = *peer;
    n->capabilities = NONE;
    make_active = GNUNET_YES;
  }

  /* Update node */
  n->capabilities = ntohl (rm->capabilities);

  /* Filter accepted issuer */
  ic_accepted = 0;
  for (c1 = 0; c1 < ic; c1++)
  {
    if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1]))
      ic_accepted ++;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Request from peer `%s' with %u issuers, we accepted %u issuer \n",
	      GNUNET_i2s (peer), ic, ic_accepted);
  GNUNET_free_non_null (n->issuer_id);
  n->issuer_id = GNUNET_malloc (ic_accepted * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
  c2 = 0;
  for (c1 = 0; c1 < ic; c1++)
  {
    if (GNUNET_YES == GED_experiments_issuer_accepted (&rmi[c1]))
    {
      n->issuer_id[c2] = rmi[c1];
      c2 ++;
    }
  }
  n->issuer_count = ic_accepted;

  if (GNUNET_YES == make_active)
    node_make_active (n);

  /* Send response */
  e_ctx = GNUNET_new (struct NodeComCtx);
  e_ctx->n = n;
  e_ctx->e = NULL;
  e_ctx->size = sizeof (struct Experimentation_Response) +
    my_issuer_count * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey);
  e_ctx->notify = &send_response_cb;
  e_ctx->notify_cls = n;

  GNUNET_CONTAINER_DLL_insert_tail(n->e_req_head, n->e_req_tail, e_ctx);
  schedule_transmisson (e_ctx);
}
/**
 * Handle a response
 *
 * @param peer the source
 * @param message the message
 */
static void handle_response (const struct GNUNET_PeerIdentity *peer,
			     const struct GNUNET_MessageHeader *message)
{
  struct Node *n;
  const struct Experimentation_Response *rm = (const struct Experimentation_Response *) message;
  const struct GNUNET_CRYPTO_EddsaPublicKey *rmi = (const struct GNUNET_CRYPTO_EddsaPublicKey *) &rm[1];
  uint32_t ic;
  uint32_t ic_accepted;
  int make_active;
  unsigned int c1;
  unsigned int c2;

  if (ntohs (message->size) < sizeof (struct Experimentation_Response))
    {
      GNUNET_break (0);
      return;
    }
  ic = ntohl (rm->issuer_count);
  if (ntohs (message->size) != sizeof (struct Experimentation_Response) + ic * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))
  {
    GNUNET_break (0);
    return;
  }

  make_active = GNUNET_NO;
  if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_active, peer)))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
		"Received %s from %s peer `%s'\n",
		"RESPONSE", "active", GNUNET_i2s (peer));
  }
  else if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_requested, peer)))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %s from %s peer `%s'\n",
		"RESPONSE", "requested", GNUNET_i2s (peer));
    GNUNET_assert (GNUNET_OK ==  GNUNET_CONTAINER_multipeermap_remove (nodes_requested, peer, n));
    if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
    {
      GNUNET_SCHEDULER_cancel (n->timeout_task);
      n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
    }
    update_stats (nodes_requested);
    make_active = GNUNET_YES;
  }
  else if (NULL != (n = GNUNET_CONTAINER_multipeermap_get (nodes_inactive, peer)))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
		"Received %s from peer `%s'\n",
		"RESPONSE", "inactive", GNUNET_i2s (peer));
    GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_remove (nodes_inactive, peer, n));
    update_stats (nodes_inactive);
    make_active = GNUNET_YES;
  }
  else
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %s from %s peer `%s'\n",
		"RESPONSE", "unknown", GNUNET_i2s (peer));
    return;
  }

  /* Update */
  n->capabilities = ntohl (rm->capabilities);

  /* Filter accepted issuer */
  ic_accepted = 0;
  for (c1 = 0; c1 < ic; c1++)
  {
    if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1]))
      ic_accepted ++;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Response from peer `%s' with %u issuers, we accepted %u issuer \n",
	      GNUNET_i2s (peer), ic, ic_accepted);
  GNUNET_free_non_null (n->issuer_id);
  n->issuer_id = GNUNET_malloc (ic_accepted * sizeof (struct GNUNET_PeerIdentity));
  c2 = 0;
  for (c1 = 0; c1 < ic; c1++)
  {
    if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1]))
    {
      n->issuer_id[c2] = rmi[c1];
      c2 ++;
    }
  }
  n->issuer_count = ic_accepted;

  if (GNUNET_YES == make_active)
    node_make_active (n);
}