/**
 * Create a new query plan entry.
 *
 * @param cp peer with the entry
 * @param pr request with the entry
 */
void
GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr)
{
  const struct GNUNET_PeerIdentity *id;
  struct PeerPlan *pp;
  struct GSF_PendingRequestData *prd;
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestPlanBijection *bi;
  struct MergeContext mpc;

  GNUNET_assert (NULL != cp);
  id = GSF_connected_peer_get_identity2_ (cp);
  pp = GNUNET_CONTAINER_multihashmap_get (plans, &id->hashPubKey);
  if (NULL == pp)
  {
    pp = GNUNET_malloc (sizeof (struct PeerPlan));
    pp->plan_map = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
    pp->priority_heap =
        GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
    pp->delay_heap =
        GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
    pp->cp = cp;
    GNUNET_CONTAINER_multihashmap_put (plans, 
				       &id->hashPubKey, pp,
                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  }
  mpc.merged = GNUNET_NO;
  mpc.pr = pr;
  GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
                                              &GSF_pending_request_get_data_
                                              (pr)->query, &merge_pr, &mpc); // 8 MB in 'merge_pr'
  if (GNUNET_NO != mpc.merged)
    return;
  GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
                                              &GSF_pending_request_get_data_
                                              (pr)->query, &merge_pr, &mpc);
  if (GNUNET_NO != mpc.merged)
    return;
  plan_count++;
  GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plan entries"), 1,
                            GNUNET_NO);
  prd = GSF_pending_request_get_data_ (pr);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Planning transmission of query `%s' to peer `%s'\n",
              GNUNET_h2s (&prd->query), GNUNET_i2s (id));
  rp = GNUNET_malloc (sizeof (struct GSF_RequestPlan)); // 8 MB
  bi = GNUNET_malloc (sizeof (struct GSF_PendingRequestPlanBijection));
  bi->rp = rp;
  bi->pr = pr;
  GNUNET_CONTAINER_MDLL_insert (PR, prd->pr_head, prd->pr_tail, bi);
  GNUNET_CONTAINER_MDLL_insert (PE, rp->pe_head, rp->pe_tail, bi);
  rp->pp = pp;
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_put (pp->plan_map,
                                                    get_rp_key (rp), rp,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); // 8 MB
  plan (pp, rp); // +5 MB (plan/heap-insert)
}
static int
testMap (int i)
{
  struct GNUNET_CONTAINER_MultiHashMap *m;
  GNUNET_HashCode k1;
  GNUNET_HashCode k2;
  const char *ret;
  int j;

  CHECK (NULL != (m = GNUNET_CONTAINER_multihashmap_create (i)));
  memset (&k1, 0, sizeof (k1));
  memset (&k2, 1, sizeof (k2));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k1));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k1, NULL));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k2, NULL));
  CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k1));
  CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k2));
  CHECK (0 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1));
  CHECK (0 == GNUNET_CONTAINER_multihashmap_size (m));
  CHECK (0 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL));
  CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL));

  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
  CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m));
  ret = GNUNET_CONTAINER_multihashmap_get (m, &k1);
  GNUNET_assert (ret != NULL);
  CHECK (0 == strcmp ("v1", ret));
  CHECK (GNUNET_NO ==
         GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
  CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m));
  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  CHECK (GNUNET_OK ==
         GNUNET_CONTAINER_multihashmap_put (m, &k1, "v3",
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  CHECK (3 == GNUNET_CONTAINER_multihashmap_size (m));
  CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (m, &k1, "v3"));
  CHECK (2 == GNUNET_CONTAINER_multihashmap_size (m));
  CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (m, &k1));
  CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2));
  CHECK (2 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL));
  CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k2, NULL, NULL));
  CHECK (2 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL));
  CHECK (2 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1));
  for (j = 0; j < 1024; j++)
    CHECK (GNUNET_OK ==
           GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2",
                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  GNUNET_CONTAINER_multihashmap_destroy (m);
  return 0;
}
/**
 * Store an item in the datastore.
 *
 * @param cls closure
 * @param key key for the item
 * @param size number of bytes in data
 * @param data content stored
 * @param type type of the content
 * @param priority priority of the content
 * @param anonymity anonymity-level for the content
 * @param replication replication-level for the content
 * @param expiration expiration time for the content
 * @param msg set to error message
 * @return GNUNET_OK on success
 */
static int
heap_plugin_put (void *cls, 
		 const struct GNUNET_HashCode * key, 
		 uint32_t size,
		 const void *data, 
		 enum GNUNET_BLOCK_Type type,
		 uint32_t priority, uint32_t anonymity,
		 uint32_t replication,
		 struct GNUNET_TIME_Absolute expiration, char **msg)
{
  struct Plugin *plugin = cls;
  struct Value *value;

  value = GNUNET_malloc (sizeof (struct Value) + size);
  value->key = *key;
  value->data = &value[1];
  value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration,
						     value,
						     expiration.abs_value);
  value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
							  value,
							  replication);
  value->expiration = expiration;
  if (0 == anonymity)
  {
    struct ZeroAnonByType *zabt;

    for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
      if (zabt->type == type)
	break;
    if (NULL == zabt)
    {
      zabt = GNUNET_malloc (sizeof (struct ZeroAnonByType));
      zabt->type = type;
      GNUNET_CONTAINER_DLL_insert (plugin->zero_head,
				   plugin->zero_tail,
				   zabt);
    }
    if (zabt->array_size == zabt->array_pos)
    {
      GNUNET_array_grow (zabt->array,
			 zabt->array_size,
			 zabt->array_size * 2 + 4);
    }
    value->zero_anon_offset = zabt->array_pos;
    zabt->array[zabt->array_pos++] = value;
  }
  value->size = size;
  value->priority = priority;
  value->anonymity = anonymity;
  value->replication = replication;
  value->type = type;
  memcpy (&value[1], data, size);
  GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue,
				     &value->key,
				     value,
				     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  plugin->size += size;
  return GNUNET_OK;
}
Example #4
0
/**
 * Function called on each meta data item.  Increments the
 * respective counter.
 *
 * @param cls the container multihashmap to update
 * @param plugin_name name of the plugin that produced this value;
 *        special values can be used (i.e. '&lt;zlib&gt;' for zlib being
 *        used in the main libextractor library and yielding
 *        meta data).
 * @param type libextractor-type describing the meta data
 * @param format basic format information about data
 * @param data_mime_type mime-type of data (not of the original file);
 *        can be NULL (if mime-type is not known)
 * @param data actual meta-data found
 * @param data_len number of bytes in data
 * @return GNUNET_OK to continue extracting / iterating
 */
static int
add_to_meta_counter (void *cls, const char *plugin_name,
		     enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format,
		     const char *data_mime_type, const char *data, size_t data_len)
{
  struct GNUNET_CONTAINER_MultiHashMap *map = cls;
  GNUNET_HashCode key;
  struct MetaCounter *cnt;

  GNUNET_CRYPTO_hash (data, data_len, &key);
  cnt = GNUNET_CONTAINER_multihashmap_get (map, &key);
  if (cnt == NULL)
  {
    cnt = GNUNET_malloc (sizeof (struct MetaCounter));
    cnt->data = data;
    cnt->data_size = data_len;
    cnt->plugin_name = plugin_name;
    cnt->type = type;
    cnt->format = format;
    cnt->data_mime_type = data_mime_type;
    GNUNET_assert (GNUNET_OK ==
		   GNUNET_CONTAINER_multihashmap_put (map,
						      &key, cnt,
						      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  }
  cnt->count++;
  return 0;
}
/**
 * Transmit pending requests via the stream.
 *
 * @param sh stream to process
 */
static void
transmit_pending (struct StreamHandle *sh)
{
  struct StreamQueryMessage sqm;
  struct GSF_StreamRequest *sr;

  if (NULL != sh->wh)
    return;
  sr = sh->pending_head;
  if (NULL == sr)
    return;
  GNUNET_CONTAINER_DLL_remove (sh->pending_head,
			       sh->pending_tail,
			       sr);
  GNUNET_CONTAINER_multihashmap_put (sh->waiting_map,
				     &sr->query,
				     sr,
				     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Sending query via stream to %s\n",
	      GNUNET_i2s (&sh->target));
  sr->was_transmitted = GNUNET_YES;
  sqm.header.size = htons (sizeof (sqm));
  sqm.header.type = htons (GNUNET_MESSAGE_TYPE_FS_STREAM_QUERY);
  sqm.type = htonl (sr->type);
  sqm.query = sr->query;
  sh->wh = GNUNET_STREAM_write (sh->stream,
				&sqm, sizeof (sqm),
				GNUNET_TIME_UNIT_FOREVER_REL,
				&query_write_continuation,
				sh);
}
/**
 * Find a ValidationEntry entry for the given neighbour that matches
 * the given address and transport.  If none exists, create one (but
 * without starting any validation).
 *
 * @param public_key public key of the peer, NULL for unknown
 * @param address address to find
 * @return validation entry matching the given specifications, NULL
 *         if we don't have an existing entry and no public key was given
 */
static struct ValidationEntry *
find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
                       *public_key, const struct GNUNET_HELLO_Address *address)
{
  struct ValidationEntryMatchContext vemc;
  struct ValidationEntry *ve;

  vemc.ve = NULL;
  vemc.address = address;
  GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
                                              &address->peer.hashPubKey,
                                              &validation_entry_match, &vemc);
  if (NULL != (ve = vemc.ve))
    return ve;
  if (public_key == NULL)
    return NULL;
  ve = GNUNET_malloc (sizeof (struct ValidationEntry));
  ve->in_use = GNUNET_SYSERR; /* not defined */
  ve->last_line_set_to_no  = 0;
  ve->last_line_set_to_yes  = 0;
  ve->address = GNUNET_HELLO_address_copy (address);
  ve->public_key = *public_key;
  ve->pid = address->peer;
  ve->latency = GNUNET_TIME_UNIT_FOREVER_REL;
  ve->challenge =
      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
  ve->timeout_task =
      GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE,
                                    &timeout_hello_validation, ve);
  GNUNET_CONTAINER_multihashmap_put (validation_map, &address->peer.hashPubKey,
                                     ve,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  ve->expecting_pong = GNUNET_NO;
  return ve;
}
/**
 * We've validated the hash of the file we're about to index.  Signal
 * success to the client and update our internal data structures.
 *
 * @param ii the index info entry for the request
 */
static void
signal_index_ok (struct IndexInfo *ii)
{
  struct IndexInfo *ir;
  if (GNUNET_SYSERR ==
      GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id,
                                         ii,
                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  {
    ir = GNUNET_CONTAINER_multihashmap_get (ifm,
					    &ii->file_id);
    GNUNET_assert (NULL != ir);
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _
                ("Index request received for file `%s' is already indexed as `%s'.  Permitting anyway.\n"),
                ii->filename,
		ir->filename);           
    GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
                                                GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
    GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
    GNUNET_free (ii);
    return;
  }
  GNUNET_CONTAINER_DLL_insert (indexed_files_head,
			       indexed_files_tail,
			       ii);
  write_index_list ();
  GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
  GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
  ii->tc = NULL;
}
/**
 * Set the amount of bandwidth the other peer could currently transmit
 * to us (as far as we know) to the given value.
 *
 * @param peer identity of the peer
 * @param bandwidth_in currently available bandwidth from that peer to
 *        this peer (estimate)
 */
void
GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer,
                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
{
  struct GNUNET_BANDWIDTH_Tracker *tracker;

  tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey);
  if (0 == ntohl (bandwidth_in.value__))
  {
    if (NULL == tracker)
      return;
    GNUNET_assert (GNUNET_YES ==
                   GNUNET_CONTAINER_multihashmap_remove (trackers,
                                                         &peer->hashPubKey,
                                                         tracker));
    GNUNET_free (tracker);
    return;
  }
  if (NULL == tracker)
  {
    tracker = GNUNET_malloc (sizeof (struct GNUNET_BANDWIDTH_Tracker));
    GNUNET_BANDWIDTH_tracker_init (tracker, bandwidth_in,
                                   MAX_BANDWIDTH_CARRY_S);
    GNUNET_CONTAINER_multihashmap_put (trackers, &peer->hashPubKey, tracker,
                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
    return;
  }
  GNUNET_BANDWIDTH_tracker_update_quota (tracker, bandwidth_in);
}
/**
 * Recusively update the info about what is the first hop to reach the node
 *
 * @param tree Tree this nodes belongs to.
 * @param parent ID from node form which to start updating.
 * @param hop If known, ID of the first hop.
 *            If not known, NULL to find out and pass on children.
 */
static void
tree_node_update_first_hops (struct MeshTunnelTree *tree,
                             struct MeshTunnelTreeNode *parent,
                             struct GNUNET_PeerIdentity *hop)
{
  struct GNUNET_PeerIdentity pi;
  struct GNUNET_PeerIdentity *copy;
  struct GNUNET_PeerIdentity id;
  struct MeshTunnelTreeNode *n;

#if MESH_TREE_DEBUG
  GNUNET_PEER_resolve (parent->peer, &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Finding first hop for %s.\n",
              GNUNET_i2s (&id));
#endif
  if (NULL == hop)
  {
    struct MeshTunnelTreeNode *aux;
    struct MeshTunnelTreeNode *old;

    aux = old = parent;
    while (aux != tree->me)
    {
#if MESH_TREE_DEBUG
      GNUNET_PEER_resolve (aux->peer, &id);
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   ... checking %s.\n",
                  GNUNET_i2s (&id));
#endif
      old = aux;
      aux = aux->parent;
      GNUNET_assert (NULL != aux);
    }
#if MESH_TREE_DEBUG
    GNUNET_PEER_resolve (old->peer, &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   It's %s!\n",
                GNUNET_i2s (&id));
#endif
    hop = &pi;
    GNUNET_PEER_resolve (old->peer, hop);
  }
  GNUNET_PEER_resolve (parent->peer, &id);
  copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
  if (NULL == copy)
    copy = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
  *copy = *hop;

  (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey,
                                            copy,
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);

  for (n = parent->children_head; NULL != n; n = n->next)
  {
    tree_node_update_first_hops (tree, n, hop);
  }
}
/**
 * Function that is called on each HELLO file in a particular directory.
 * Try to parse the file and add the HELLO to our list.
 *
 * @param cls pointer to 'unsigned int' to increment for each file, or NULL
 *            if the file is from a read-only, read-once resource directory
 * @param fullname name of the file to parse
 * @return GNUNET_OK (continue iteration)
 */
static int
hosts_directory_scan_callback (void *cls, const char *fullname)
{
  unsigned int *matched = cls;
  struct GNUNET_PeerIdentity identity;
  const char *filename;
  struct HostEntry *entry;
  struct GNUNET_HELLO_Message *hello;

  if (GNUNET_DISK_file_test (fullname) != GNUNET_YES)
    return GNUNET_OK;           /* ignore non-files */
  if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  filename =
      &fullname[strlen (fullname) -
                sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1];
  if (filename[-1] != DIR_SEPARATOR)
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (GNUNET_OK !=
      GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey))
  {
    if (NULL != (hello = read_host_file (filename)))
    {
      entry = GNUNET_malloc (sizeof (struct HostEntry));
      if (GNUNET_OK ==
	  GNUNET_HELLO_get_id (hello,
			       &entry->identity))
      {
	GNUNET_CONTAINER_multihashmap_put (hostmap, &entry->identity.hashPubKey, entry,
					   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
	entry->hello = hello;
	notify_all (entry);
	return GNUNET_OK;
      }
      GNUNET_free (entry);
    }
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (NULL != matched)
    (*matched)++;
  add_host_to_known_hosts (&identity);
  return GNUNET_OK;
}
static void
register_hashcode (struct GNUNET_HashCode *hash)
{
  struct GNUNET_HashCode replicated;
  struct IBF_Key key;
  key = ibf_key_from_hashcode (hash);
  ibf_hashcode_from_key (key, &replicated);
  (void) GNUNET_CONTAINER_multihashmap_put (key_to_hashcode,
                                            &replicated,
                                            GNUNET_memdup (hash, sizeof *hash),
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
}
Example #12
0
/**
 * Perform an asynchronous GET operation on the DHT identified. See
 * also #GNUNET_BLOCK_evaluate.
 *
 * @param handle handle to the DHT service
 * @param type expected type of the response object
 * @param key the key to look up
 * @param desired_replication_level estimate of how many
                  nearest peers this request should reach
 * @param options routing options for this message
 * @param xquery extended query data (can be NULL, depending on type)
 * @param xquery_size number of bytes in @a xquery
 * @param iter function to call on each result
 * @param iter_cls closure for iter
 * @return handle to stop the async get
 */
struct GNUNET_DHT_GetHandle *
GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
                      enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode * key,
                      uint32_t desired_replication_level,
                      enum GNUNET_DHT_RouteOption options, const void *xquery,
                      size_t xquery_size, GNUNET_DHT_GetIterator iter,
                      void *iter_cls)
{
  struct GNUNET_DHT_ClientGetMessage *get_msg;
  struct GNUNET_DHT_GetHandle *get_handle;
  size_t msize;
  struct PendingMessage *pending;

  msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size;
  if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
      (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
  {
    GNUNET_break (0);
    return NULL;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending query for %s to DHT %p\n",
       GNUNET_h2s (key), handle);
  pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
  get_msg = (struct GNUNET_DHT_ClientGetMessage *) &pending[1];
  pending->msg = &get_msg->header;
  pending->handle = handle;
  pending->free_on_send = GNUNET_NO;
  get_msg->header.size = htons (msize);
  get_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET);
  get_msg->options = htonl ((uint32_t) options);
  get_msg->desired_replication_level = htonl (desired_replication_level);
  get_msg->type = htonl (type);
  get_msg->key = *key;
  get_msg->unique_id = ++handle->uid_gen;
  memcpy (&get_msg[1], xquery, xquery_size);
  GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
                               pending);
  pending->in_pending_queue = GNUNET_YES;
  get_handle = GNUNET_new (struct GNUNET_DHT_GetHandle);
  get_handle->key = *key;
  get_handle->dht_handle = handle;
  get_handle->iter = iter;
  get_handle->iter_cls = iter_cls;
  get_handle->message = pending;
  get_handle->unique_id = get_msg->unique_id;
  GNUNET_CONTAINER_multihashmap_put (handle->active_requests,
                                     &get_handle->key,
                                     get_handle,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  process_pending_messages (handle);
  return get_handle;
}
/**
 * We're receiving additional set data. Add it to our
 * set and if we are done, initiate the transaction.
 *
 * @param cls identification of the client
 * @param msg the actual message
 */
static void
handle_bob_client_message_multipart (void *cls,
				     const struct ComputationBobCryptodataMultipartMessage *msg)
{
  struct BobServiceSession *s = cls;
  uint32_t contained_count;
  const struct GNUNET_SCALARPRODUCT_Element *elements;
  struct GNUNET_SET_Element set_elem;
  struct GNUNET_SCALARPRODUCT_Element *elem;

  contained_count = ntohl (msg->element_count_contained);
  elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
  for (uint32_t i = 0; i < contained_count; i++)
  {
    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->client_received_element_count += contained_count;
  GNUNET_SERVICE_client_continue (s->client);
  if (s->total != s->client_received_element_count)
  {
    /* more to come */
    return;
  }
  if (NULL == s->cadet)
  {
    /* no Alice waiting for this request, wait for Alice */
    return;
  }
  start_intersection (s);
}
Example #14
0
/**
 * Handler for port open requests.
 *
 * @param cls Identification of the client.
 * @param pmsg The actual message.
 */
static void
handle_port_open (void *cls,
                  const struct GNUNET_CADET_PortMessage *pmsg)
{
  struct CadetClient *c = cls;

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Open port %s requested by client %u\n",
       GNUNET_h2s (&pmsg->port),
       c->id);
  if (NULL == c->ports)
    c->ports = GNUNET_CONTAINER_multihashmap_create (4,
                                                     GNUNET_NO);
  if (GNUNET_OK !=
      GNUNET_CONTAINER_multihashmap_put (c->ports,
                                         &pmsg->port,
                                         c,
                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  {
    GNUNET_break (0);
    GNUNET_SERVICE_client_drop (c->client);
    return;
  }
  /* store in global hashmap */
  /* FIXME only allow one client to have the port open,
   *       have a backup hashmap with waiting clients */
  GNUNET_CONTAINER_multihashmap_put (open_ports,
                                     &pmsg->port,
                                     c,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
                                              &pmsg->port,
                                              &bind_loose_channel,
                                              c);
  GNUNET_SERVICE_client_continue (c->client);
}
Example #15
0
/**
 * Store a record in the peerstore.
 * Key is the combination of sub system and peer identity.
 * One key can store multiple values.
 *
 * @param cls closure (internal context for the plugin)
 * @param sub_system name of the GNUnet sub system responsible
 * @param peer peer identity
 * @param key record key string
 * @param value value to be stored
 * @param size size of value to be stored
 * @param expiry absolute time after which the record is (possibly) deleted
 * @param options options related to the store operation
 * @param cont continuation called when record is stored
 * @param cont_cls continuation closure
 * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
 */
static int
peerstore_flat_store_record (void *cls, const char *sub_system,
                             const struct GNUNET_PeerIdentity *peer,
                             const char *key, const void *value, size_t size,
                             struct GNUNET_TIME_Absolute expiry,
                             enum GNUNET_PEERSTORE_StoreOption options,
                             GNUNET_PEERSTORE_Continuation cont,
                             void *cont_cls)
{
  struct Plugin *plugin = cls;
  struct GNUNET_HashCode hkey;
  struct GNUNET_PEERSTORE_Record *entry;
  const char *peer_id;


  entry = GNUNET_new (struct GNUNET_PEERSTORE_Record);
  entry->sub_system = GNUNET_strdup (sub_system);
  entry->key = GNUNET_strdup (key);
  entry->value = GNUNET_malloc (size);
  GNUNET_memcpy (entry->value, value, size);
  entry->value_size = size;
  entry->peer = GNUNET_new (struct GNUNET_PeerIdentity);
  GNUNET_memcpy (entry->peer, peer, sizeof (struct GNUNET_PeerIdentity));
  entry->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
  entry->expiry->abs_value_us = expiry.abs_value_us;

  peer_id = GNUNET_i2s (peer);
  GNUNET_CRYPTO_hash (peer_id,
                      strlen (peer_id),
                      &hkey);

  if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
  {
    peerstore_flat_delete_records (cls, sub_system, peer, key);
  }

  GNUNET_CONTAINER_multihashmap_put (plugin->hm,
                                     &hkey,
                                     entry,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  if (NULL != cont)
  {
    cont (cont_cls, GNUNET_OK);
  }
  return GNUNET_OK;
}
static int
peer_it (void *cls,
         const struct GNUNET_HashCode * key,
         void *value)
{
  struct PeerIteratorContext *ip_ctx = cls;
  struct GNUNET_PeerIdentity tmp;

  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
  {
      GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
      tmp.hashPubKey = (*key);
      ip_ctx->it (ip_ctx->it_cls, &tmp);
  }

  return GNUNET_OK;
}
/**
 * Add a new entry in routing table
 * @param new_trail_id
 * @param prev_hop
 * @param next_hop
 * @return #GNUNET_OK success
 *         #GNUNET_SYSERR in case new_trail_id already exists in the network
 *                         but with different prev_hop/next_hop
 */
int
GDS_ROUTING_add (const struct GNUNET_HashCode *new_trail_id,
                 const struct GNUNET_PeerIdentity *prev_hop,
                 const struct GNUNET_PeerIdentity *next_hop)
{
  struct RoutingTrail *new_entry;

  new_entry = GNUNET_new (struct RoutingTrail);
  new_entry->trail_id = *new_trail_id;
  new_entry->next_hop = *next_hop;
  new_entry->prev_hop = *prev_hop;

  // FIXME: this leaks memory if the put fails!
  return GNUNET_CONTAINER_multihashmap_put (routing_table,
                                            &new_entry->trail_id,
					    new_entry,
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
}
/**
 * Add a new entry to our routing table.
 *
 * @param sender peer that originated the request
 * @param type type of the block
 * @param options options for processing
 * @param key key for the content
 * @param xquery extended query
 * @param xquery_size number of bytes in xquery
 * @param reply_bf bloomfilter to filter duplicates
 * @param reply_bf_mutator mutator for reply_bf
*/
void
GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
                 enum GNUNET_BLOCK_Type type,
                 enum GNUNET_DHT_RouteOption options,
                 const struct GNUNET_HashCode * key, const void *xquery,
                 size_t xquery_size,
                 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
                 uint32_t reply_bf_mutator)
{
  struct RecentRequest *recent_req;

  while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT)
    expire_oldest_entry ();
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop ("# Entries added to routing table"),
                            1, GNUNET_NO);
  recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size);
  recent_req->peer = *sender;
  recent_req->key = *key;
  recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf);
  recent_req->type = type;
  recent_req->options = options;
  recent_req->xquery = &recent_req[1];
  memcpy (&recent_req[1], xquery, xquery_size);
  recent_req->xquery_size = xquery_size;
  recent_req->reply_bf_mutator = reply_bf_mutator;
  if (GNUNET_SYSERR ==
      GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key,
						  &try_combine_recent, recent_req))
  {
    GNUNET_STATISTICS_update (GDS_stats,
                              gettext_noop
                              ("# DHT requests combined"),
                              1, GNUNET_NO);
    return;
  }
  recent_req->heap_node =
      GNUNET_CONTAINER_heap_insert (recent_heap, recent_req,
                                    GNUNET_TIME_absolute_get ().abs_value);
  GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);


}
Example #19
0
/**
 * Function to process DHT string to regex matching.
 * Called on each result obtained for the DHT search.
 *
 * @param cls closure (search context)
 * @param exp when will this value expire
 * @param key key of the result
 * @param get_path path of the get request (not used)
 * @param get_path_length length of @a get_path (not used)
 * @param put_path path of the put request (not used)
 * @param put_path_length length of the @a put_path (not used)
 * @param type type of the result
 * @param size number of bytes in data
 * @param data pointer to the result data
 *
 * TODO: re-issue the request after certain time? cancel after X results?
 */
static void
dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                        const struct GNUNET_HashCode *key,
                        const struct GNUNET_PeerIdentity *get_path,
                        unsigned int get_path_length,
                        const struct GNUNET_PeerIdentity *put_path,
                        unsigned int put_path_length,
                        enum GNUNET_BLOCK_Type type,
                        size_t size, const void *data)
{
  const struct RegexBlock *block = data;
  struct RegexSearchContext *ctx = cls;
  struct REGEX_INTERNAL_Search *info = ctx->info;
  size_t len;
  struct Result *copy;

  LOG (GNUNET_ERROR_TYPE_INFO,
       "DHT GET result for %s (%s)\n",
       GNUNET_h2s (key), ctx->info->description);
  copy = GNUNET_malloc (sizeof (struct Result) + size);
  copy->size = size;
  copy->data = &copy[1];
  GNUNET_memcpy (&copy[1], block, size);
  GNUNET_break (GNUNET_OK ==
		GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
						   key, copy,
						   GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  len = strlen (info->description);
  if (len == ctx->position) // String processed
  {
    if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size))
    {
      regex_find_path (key, ctx);
    }
    else
    {
      LOG (GNUNET_ERROR_TYPE_INFO, "block not accepting!\n");
      /* FIXME REGEX this block not successful, wait for more? start timeout? */
    }
    return;
  }
  regex_next_edge (block, size, ctx);
}
/**
 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
 *
 * @param cls closure (set from #GNUNET_CADET_connect)
 * @param channel connection to the other end
 * @param channel_ctx place to store the `struct CadetIncomingSession *`
 * @param message the actual message
 * @return #GNUNET_OK to keep the connection open,
 *         #GNUNET_SYSERR to close it (signal serious error)
 */
static int
handle_alices_computation_request (void *cls,
                                   struct GNUNET_CADET_Channel *channel,
                                   void **channel_ctx,
                                   const struct GNUNET_MessageHeader *message)
{
  struct CadetIncomingSession *in = *channel_ctx;
  struct BobServiceSession *s;
  const struct EccServiceRequestMessage *msg;

  msg = (const struct EccServiceRequestMessage *) message;
  if (GNUNET_YES == in->in_map)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  if (NULL != find_matching_cadet_session (&msg->session_id))
  {
    /* not unique, got one like this already */
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  in->session_id = msg->session_id;
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
                                                    &in->session_id,
                                                    in,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  s = find_matching_client_session (&in->session_id);
  if (NULL == s)
  {
    /* no client waiting for this request, wait for client */
    return GNUNET_OK;
  }
  GNUNET_assert (NULL == s->cadet);
  /* pair them up */
  in->s = s;
  s->cadet = in;
  if (s->client_received_element_count == s->total)
    start_intersection (s);
  return GNUNET_OK;
}
/**
 * Add a host to the list.
 *
 * @param identity the identity of the host
 */
static void
add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
{
  struct HostEntry *entry;
  char *fn;

  entry = GNUNET_CONTAINER_multihashmap_get (hostmap, &identity->hashPubKey);
  if (entry != NULL)
    return;
  GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1,
                            GNUNET_NO);
  entry = GNUNET_malloc (sizeof (struct HostEntry));
  entry->identity = *identity;
  GNUNET_CONTAINER_multihashmap_put (hostmap, &identity->hashPubKey, entry,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  fn = get_host_filename (identity);
  entry->hello = read_host_file (fn);
  GNUNET_free (fn);
  notify_all (entry);
}
/**
 * Create a new entry in the peer list.
 *
 * @param peer identity of the new entry
 * @param hello hello message, can be NULL
 * @param is_friend is the new entry for a friend?
 * @return the new entry
 */
static struct Peer *
make_peer (const struct GNUNET_PeerIdentity *peer,
           const struct GNUNET_HELLO_Message *hello, int is_friend)
{
  struct Peer *ret;

  ret = GNUNET_malloc (sizeof (struct Peer));
  ret->pid = *peer;
  ret->is_friend = is_friend;
  if (hello != NULL)
  {
    ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
    memcpy (ret->hello, hello, GNUNET_HELLO_size (hello));
  }
  GNUNET_break (GNUNET_OK ==
                GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
                                                   ret,
                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  return ret;
}
Example #23
0
/**
 * We have received a KSK result.  Check how it fits in with the
 * overall query and notify the client accordingly.
 *
 * @param sc context for the overall query
 * @param ent entry for the specific keyword
 * @param uri the URI that was found
 * @param meta metadata associated with the URI
 *        under the @a ent keyword
 */
static void
process_ksk_result (struct GNUNET_FS_SearchContext *sc,
                    struct SearchRequestEntry *ent,
                    const struct GNUNET_FS_Uri *uri,
                    const struct GNUNET_CONTAINER_MetaData *meta)
{
  struct GNUNET_HashCode key;
  struct GNUNET_FS_SearchResult *sr;
  struct GetResultContext grc;
  int is_new;
  unsigned int koff;

  /* check if new */
  GNUNET_assert (NULL != sc);
  GNUNET_FS_uri_to_key (uri, &key);
  if (GNUNET_SYSERR ==
      GNUNET_CONTAINER_multihashmap_get_multiple (ent->results, &key,
                                                  &test_result_present,
                                                  (void *) uri))
    return;                     /* duplicate result */
  /* try to find search result in master map */
  grc.sr = NULL;
  grc.uri = uri;
  GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key,
                                              &get_result_present, &grc);
  sr = grc.sr;
  is_new = (NULL == sr) || (sr->mandatory_missing > 0);
  if (NULL == sr)
  {
    sr = GNUNET_new (struct GNUNET_FS_SearchResult);
    sr->h = sc->h;
    sr->sc = sc;
    sr->anonymity = sc->anonymity;
    sr->uri = GNUNET_FS_uri_dup (uri);
    sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
    sr->mandatory_missing = sc->mandatory_count;
    sr->key = key;
    sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */
    GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr,
                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  }
Example #24
0
/**
 * Cache a block in the datastore.
 *
 * @param cls closure (internal context for the plugin)
 * @param block block to cache
 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
 */
static int
namecache_cache_block (void *cls,
                       const struct GNUNET_GNSRECORD_Block *block)
{
  struct Plugin *plugin = cls;
  struct GNUNET_HashCode query;
  struct FlatFileEntry *entry;
  size_t block_size;

  namecache_expire_blocks (plugin);
  GNUNET_CRYPTO_hash (&block->derived_key,
                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
                      &query);
  block_size = ntohl (block->purpose.size) +
    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
    sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
  if (block_size > 64 * 65536)
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  entry = GNUNET_malloc (sizeof (struct FlatFileEntry));
  entry->block = GNUNET_malloc (block_size);
  memcpy (entry->block, block, block_size);
  GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm, &query);
  if (GNUNET_OK != 
      GNUNET_CONTAINER_multihashmap_put (plugin->hm,
                                         &query,
                                         entry,
                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  {
    GNUNET_free (entry);
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Caching block under derived key `%s'\n",
              GNUNET_h2s_full (&query));
  return GNUNET_OK;
}
Example #25
0
/**
 * Request watching a given key
 * User will be notified with any new values added to key
 *
 * @param h handle to the PEERSTORE service
 * @param sub_system name of sub system
 * @param peer Peer identity
 * @param key entry key string
 * @param callback function called with each new value
 * @param callback_cls closure for @a callback
 * @return Handle to watch request
 */
struct GNUNET_PEERSTORE_WatchContext *
GNUNET_PEERSTORE_watch (struct GNUNET_PEERSTORE_Handle *h,
                        const char *sub_system,
                        const struct GNUNET_PeerIdentity *peer, const char *key,
                        GNUNET_PEERSTORE_Processor callback, void *callback_cls)
{
  struct GNUNET_MQ_Envelope *ev;
  struct StoreKeyHashMessage *hm;
  struct GNUNET_PEERSTORE_WatchContext *wc;

  GNUNET_assert (NULL != sub_system);
  GNUNET_assert (NULL != peer);
  GNUNET_assert (NULL != key);
  ev = GNUNET_MQ_msg (hm, GNUNET_MESSAGE_TYPE_PEERSTORE_WATCH);
  PEERSTORE_hash_key (sub_system,
                      peer,
                      key,
                      &hm->keyhash);
  wc = GNUNET_new (struct GNUNET_PEERSTORE_WatchContext);
  wc->callback = callback;
  wc->callback_cls = callback_cls;
  wc->h = h;
  wc->keyhash = hm->keyhash;
  if (NULL == h->watches)
    h->watches = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multihashmap_put (h->watches,
                                                    &wc->keyhash,
                                                    wc,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Sending a watch request for ss `%s', peer `%s', key `%s'.\n",
       sub_system,
       GNUNET_i2s (peer),
       key);
  GNUNET_MQ_send (h->mq, ev);
  return wc;
}
Example #26
0
/**
 * Add the given keyword to the keyword statistics tracker.
 *
 * @param cls the multihashmap we store the keyword counters in
 * @param keyword the keyword to count
 * @param is_mandatory ignored
 * @return always GNUNET_OK
 */
static int
add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory)
{
  struct GNUNET_CONTAINER_MultiHashMap *mcm = cls;
  struct KeywordCounter *cnt;
  GNUNET_HashCode hc;
  size_t klen;

  klen = strlen (keyword) + 1;
  GNUNET_CRYPTO_hash (keyword, klen - 1, &hc);
  cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc);
  if (cnt == NULL)
  {
    cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen);
    cnt->value = (const char *) &cnt[1];
    memcpy (&cnt[1], keyword, klen);
    GNUNET_assert (GNUNET_OK ==
		   GNUNET_CONTAINER_multihashmap_put (mcm, 
						      &hc, cnt,
						      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  }
  cnt->count++;
  return GNUNET_OK;
}
Example #27
0
/**
 * Find a path to a peer that offers a regex service compatible
 * with a given string.
 *
 * @param key The key of the accepting state.
 * @param ctx Context containing info about the string, tunnel, etc.
 */
static void
regex_find_path (const struct GNUNET_HashCode *key,
                 struct RegexSearchContext *ctx)
{
  struct GNUNET_DHT_GetHandle *get_h;

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Accept state found, now searching for paths to %s\n",
       GNUNET_h2s (key),
       (unsigned int) ctx->position);
  get_h = GNUNET_DHT_get_start (ctx->info->dht,    /* handle */
                                GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
                                key,     /* key to search */
                                DHT_REPLICATION, /* replication level */
                                DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
                                NULL,       /* xquery */ // FIXME BLOOMFILTER
                                0,     /* xquery bits */ // FIXME BLOOMFILTER SIZE
                                &dht_get_string_accept_handler, ctx);
  GNUNET_break (GNUNET_OK ==
                GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles,
                                                  key,
                                                  get_h,
                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
}
/**
 * Get (or create) a stream to talk to the given peer.
 *
 * @param target peer we want to communicate with
 */
static struct StreamHandle *
get_stream (const struct GNUNET_PeerIdentity *target)
{
  struct StreamHandle *sh;

  sh = GNUNET_CONTAINER_multihashmap_get (stream_map,
					  &target->hashPubKey);
  if (NULL != sh)
  {
    if (GNUNET_SCHEDULER_NO_TASK != sh->timeout_task)
    {
      GNUNET_SCHEDULER_cancel (sh->timeout_task);
      sh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
    }
    return sh;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Creating stream to %s\n",
	      GNUNET_i2s (target));
  sh = GNUNET_malloc (sizeof (struct StreamHandle));
  sh->mst = GNUNET_SERVER_mst_create (&reply_cb,
				      sh);
  sh->waiting_map = GNUNET_CONTAINER_multihashmap_create (512, GNUNET_YES);
  sh->target = *target;
  sh->stream = GNUNET_STREAM_open (GSF_cfg,
				   &sh->target,
				   GNUNET_APPLICATION_TYPE_FS_BLOCK_TRANSFER,
				   &stream_ready_cb, sh,
				   GNUNET_STREAM_OPTION_END);
  GNUNET_assert (GNUNET_OK ==
		 GNUNET_CONTAINER_multihashmap_put (stream_map,
						    &sh->target.hashPubKey,
						    sh,
						    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  return sh;
}
/**
 * Handler for DHT GET messages from the client.
 *
 * @param cls closure for the service
 * @param client the client we received this message from
 * @param message the actual message received
 */
static void
handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client,
                      const struct GNUNET_MessageHeader *message)
{
  const struct GNUNET_DHT_ClientGetMessage *get;
  struct ClientQueryRecord *cqr;
  size_t xquery_size;
  const char *xquery;
  uint16_t size;

  size = ntohs (message->size);
  if (size < sizeof (struct GNUNET_DHT_ClientGetMessage))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage);
  get = (const struct GNUNET_DHT_ClientGetMessage *) message;
  xquery = (const char *) &get[1];
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop
                            ("# GET requests received from clients"), 1,
                            GNUNET_NO);
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received GET request for %s from local client %p, xq: %.*s\n",
       GNUNET_h2s (&get->key), client, xquery_size, xquery);

  LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "XDHT CLIENT-GET %s @ %u\n",
               GNUNET_h2s (&get->key), getpid ());


  cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size);
  cqr->key = get->key;
  cqr->client = find_active_client (client);
  cqr->xquery = (void *) &cqr[1];
  memcpy (&cqr[1], xquery, xquery_size);
  cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0);
  cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS;
  cqr->retry_time = GNUNET_TIME_absolute_get ();
  cqr->unique_id = get->unique_id;
  cqr->xquery_size = xquery_size;
  cqr->replication = ntohl (get->desired_replication_level);
  cqr->msg_options = ntohl (get->options);
  cqr->type = ntohl (get->type);
  // FIXME use cqr->key, set multihashmap create to GNUNET_YES
  GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  GDS_CLIENTS_process_get (ntohl (get->options),
                           ntohl (get->type),
                           0,
                           ntohl (get->desired_replication_level),
                           1,
                           GDS_NEIGHBOURS_get_id(),
                           &get->key);
  /* start remote requests */
  if (GNUNET_SCHEDULER_NO_TASK != retry_task)
    GNUNET_SCHEDULER_cancel (retry_task);
  retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL);
  /* perform local lookup */
  GDS_DATACACHE_handle_get (&get->key, cqr->type, cqr->xquery, xquery_size,
                            NULL, 0);
  GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
/**
 * Read index information from disk.
 */
static void
read_index_list ()
{
  struct GNUNET_BIO_ReadHandle *rh;
  char *fn;
  struct IndexInfo *pos;
  char *fname;
  struct GNUNET_HashCode hc;
  size_t slen;
  char *emsg;

  if (GNUNET_OK !=
      GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn))
  {
    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
			       "fs", "INDEXDB");
    return;
  }
  if (GNUNET_NO == GNUNET_DISK_file_test (fn))
  {
    /* no index info yet */
    GNUNET_free (fn);
    return;
  }
  rh = GNUNET_BIO_read_open (fn);
  if (NULL == rh)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                _("Could not open `%s'.\n"), fn);
    GNUNET_free (fn);
    return;
  }
  while ((GNUNET_OK ==
          GNUNET_BIO_read (rh, "Hash of indexed file", &hc,
                           sizeof (struct GNUNET_HashCode))) &&
         (GNUNET_OK ==
          GNUNET_BIO_read_string (rh, "Name of indexed file", &fname,
                                  1024 * 16)) && (fname != NULL))
  {
    slen = strlen (fname) + 1;
    pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
    pos->file_id = hc;
    pos->filename = (const char *) &pos[1];
    memcpy (&pos[1], fname, slen);
    if (GNUNET_SYSERR ==
        GNUNET_CONTAINER_multihashmap_put (ifm, &pos->file_id, pos,
                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
    {
      GNUNET_free (pos);
    }
    else
    {
      GNUNET_CONTAINER_DLL_insert (indexed_files_head,
				   indexed_files_tail,
				   pos);
    }
    GNUNET_free (fname);
  }
  if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
    GNUNET_free (emsg);
  GNUNET_free (fn);
}