/**
 * Method called to retrieve information about a specific tunnel the mesh peer
 * has established, o`r is trying to establish.
 *
 * @param cls Closure.
 * @param peer Peer towards whom the tunnel is directed.
 * @param n_channels Number of channels.
 * @param n_connections Number of connections.
 * @param channels Channels.
 * @param connections Connections.
 * @param estate Encryption status.
 * @param cstate Connectivity status.
 */
void
tunnel_callback (void *cls,
                 const struct GNUNET_PeerIdentity *peer,
                 unsigned int n_channels,
                 unsigned int n_connections,
                 uint32_t *channels,
                 struct GNUNET_HashCode *connections,
                 unsigned int estate,
                 unsigned int cstate)
{
  unsigned int i;

  if (NULL != peer)
  {
    FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
    FPRINTF (stdout, "- %u channels\n", n_channels);
    for (i = 0; i < n_channels; i++)
      FPRINTF (stdout, "   %u\n", channels[i]);
    FPRINTF (stdout, "- %u connections\n", n_connections);
    for (i = 0; i < n_connections; i++)
      FPRINTF (stdout, "   %s\n", GNUNET_h2s_full (&connections[i]));
    FPRINTF (stdout, "- enc state: %u\n", estate);
    FPRINTF (stdout, "- con state: %u\n", cstate);
  }
  if (GNUNET_YES != monitor_connections)
  {
    GNUNET_SCHEDULER_shutdown();
  }
  return;

}
/**
 * Connect both PUT and GET connection for a session
 * 
 * @param s the session to connect
 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
 */
static int
client_connect (struct Session *s)
{

  struct HTTP_Client_Plugin *plugin = s->plugin;
  int res = GNUNET_OK;


  /* create url */
  if (NULL == http_common_plugin_address_to_string (NULL, s->addr, s->addrlen))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                     "Invalid address peer `%s'\n",
                     GNUNET_i2s (&s->target));
    return GNUNET_SYSERR;
  }

  GNUNET_asprintf (&s->url, "%s/%s;%u",
      http_common_plugin_address_to_string (plugin, s->addr, s->addrlen),
                   GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey),
                   plugin->last_tag);

  plugin->last_tag++;

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                   "Initiating outbound session peer `%s' using address `%s'\n",
                   GNUNET_i2s (&s->target), s->url);

  if ((GNUNET_SYSERR == client_connect_get (s)) ||
      (GNUNET_SYSERR == client_connect_put (s)))
  {
      GNUNET_break (0);
      return GNUNET_SYSERR;
  }

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
               "Session %p: connected with connections GET %p and PUT %p\n",
               s, s->client_get, s->client_put);

  /* Perform connect */
  plugin->cur_connections += 2;
  GNUNET_STATISTICS_set (plugin->env->stats,
      "# HTTP client connections",
      plugin->cur_connections,
      GNUNET_NO);

  /* Re-schedule since handles have changed */
  if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
    plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
  }
  plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin);
  return res;
}
Exemple #3
0
/**
 * Get the block for a particular zone and label in the
 * datastore.  Will return at most one result to the iterator.
 *
 * @param cls closure (internal context for the plugin)
 * @param query hash of public key derived from the zone and the label
 * @param iter function to call with the result
 * @param iter_cls closure for @a iter
 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
 */
static int
namecache_lookup_block (void *cls,
                        const struct GNUNET_HashCode *query,
                        GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
{
  struct Plugin *plugin = cls;
  const struct GNUNET_GNSRECORD_Block *block;

  block = GNUNET_CONTAINER_multihashmap_get (plugin->hm, query);
  if (NULL == block)
    return GNUNET_NO;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Found block under derived key `%s'\n",
              GNUNET_h2s_full (query));
  iter (iter_cls, block);
  return GNUNET_YES;
}
/**
 * Function called to notify transport users that another
 * peer connected to us.
 *
 * @param cls closure
 * @param peer the peer that connected
 * @param ats performance data
 * @param ats_count number of entries in ats (excluding 0-termination)
 */
static void
notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
                const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
{
  if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity)))
    return;
  ret = 0;
  if (try_connect)
  {
      /* all done, terminate instantly */
      FPRINTF (stdout, _("Successfully connected to `%s'\n"), GNUNET_h2s_full (&peer->hashPubKey));
      ret = 0;

      if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
      {
        GNUNET_SCHEDULER_cancel (op_timeout);
        op_timeout = GNUNET_SCHEDULER_NO_TASK;
      }

      if (GNUNET_SCHEDULER_NO_TASK != end)
        GNUNET_SCHEDULER_cancel (end);
      end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
      return;
  }
  if (benchmark_send)
  {
    if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
    {
      GNUNET_SCHEDULER_cancel (op_timeout);
      op_timeout = GNUNET_SCHEDULER_NO_TASK;
    }
    if (verbosity > 0)
      FPRINTF (stdout, _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
          GNUNET_i2s (&pid), BLOCKSIZE);
    start_time = GNUNET_TIME_absolute_get ();
    if (NULL == th)
      th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
                                                   BLOCKSIZE * 1024, 0,
                                                   GNUNET_TIME_UNIT_FOREVER_REL,
                                                   &transmit_data, NULL);
    else
      GNUNET_break (0);
    return;
  }
}
static void
operation_timeout (void *cls,
               const struct GNUNET_SCHEDULER_TaskContext *tc)
{
	struct ResolutionContext *cur;
	struct ResolutionContext *next;
  op_timeout = GNUNET_SCHEDULER_NO_TASK;
  if ((try_connect) || (benchmark_send) ||
  		(benchmark_receive))
  {
      FPRINTF (stdout, _("Failed to connect to `%s'\n"), GNUNET_h2s_full (&pid.hashPubKey));
      if (GNUNET_SCHEDULER_NO_TASK != end)
        GNUNET_SCHEDULER_cancel (end);
      end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
      ret = 1;
      return;
  }
  if (iterate_connections)
  {
  		next = rc_head;
  		while (NULL != (cur = next))
  		{
  				next = cur->next;
  				FPRINTF (stdout, _("Failed to resolve address for peer `%s'\n"),
  						GNUNET_i2s (&cur->addrcp->peer));

  				GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, cur);
  				GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
  				GNUNET_free (cur->addrcp);
  				GNUNET_free (cur);

  		}
  		FPRINTF (stdout, "%s", _("Failed to list connections, timeout occured\n"));
      if (GNUNET_SCHEDULER_NO_TASK != end)
        GNUNET_SCHEDULER_cancel (end);
      end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
      ret = 1;
      return;
  }

}
Exemple #6
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;
}
Exemple #7
0
DownloadItem* DownloadsModel::addDownload(DownloadItem *pde, struct GNUNET_FS_DownloadContext *dc,
                                          const struct GNUNET_FS_Uri *uri, QString filePath,
                                          const struct GNUNET_CONTAINER_MetaData *meta, qint64 size,
                                          qint64 completed )
{


    //Convert uri to Key
    GNUNET_HashCode hashcode;
    GNUNET_FS_uri_to_key(uri,&hashcode);

    //Get as QString
    const char * hash = GNUNET_h2s_full(&hashcode);
    QString strHash = QString(hash);



    DownloadItem* download = new DownloadItem(strHash);

    download->setParent(pde);
    download->setContext(dc);
    char* fancyName =  GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
                                                                 EXTRACTOR_METATYPE_PACKAGE_NAME,
                                                                 EXTRACTOR_METATYPE_TITLE,
                                                                 EXTRACTOR_METATYPE_BOOK_TITLE,
                                                                 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
                                                                 EXTRACTOR_METATYPE_FILENAME,
                                                                 EXTRACTOR_METATYPE_DESCRIPTION,
                                                                 EXTRACTOR_METATYPE_SUMMARY,
                                                                 EXTRACTOR_METATYPE_ALBUM,
                                                                 EXTRACTOR_METATYPE_COMMENT,
                                                                 EXTRACTOR_METATYPE_SUBJECT,
                                                                 EXTRACTOR_METATYPE_KEYWORDS,
                                                                 -1);

    char* fileName =  GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
                                                                 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
                                                                 EXTRACTOR_METATYPE_PACKAGE_NAME,
                                                                 EXTRACTOR_METATYPE_TITLE,
                                                                 EXTRACTOR_METATYPE_BOOK_TITLE,
                                                                 EXTRACTOR_METATYPE_FILENAME,
                                                                 EXTRACTOR_METATYPE_DESCRIPTION,
                                                                 EXTRACTOR_METATYPE_SUMMARY,
                                                                 EXTRACTOR_METATYPE_ALBUM,
                                                                 EXTRACTOR_METATYPE_COMMENT,
                                                                 EXTRACTOR_METATYPE_SUBJECT,
                                                                 EXTRACTOR_METATYPE_KEYWORDS,
                                                                 -1);



    download->setPath(filePath);
    download->setFancyName(QString(fancyName));
    download->setFileName(QString(fileName));
    download->setMetadata(meta);
    download->setSize(size);
    download->setCompleted(completed);


    emit addDownloadSignal(download);

    return download;


}
/**
 * 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, "R5N CLIENT-GET %s\n",
               GNUNET_h2s_full (&get->key));


  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);
}
/**
 * Handler for PUT messages.
 *
 * @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_put (void *cls, struct GNUNET_SERVER_Client *client,
                      const struct GNUNET_MessageHeader *message)
{
  const struct GNUNET_DHT_ClientPutMessage *dht_msg;
  struct GNUNET_CONTAINER_BloomFilter *peer_bf;
  uint16_t size;
  struct PendingMessage *pm;
  struct GNUNET_DHT_ClientPutConfirmationMessage *conf;

  size = ntohs (message->size);
  if (size < sizeof (struct GNUNET_DHT_ClientPutMessage))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop
                            ("# PUT requests received from clients"), 1,
                            GNUNET_NO);
  dht_msg = (const struct GNUNET_DHT_ClientPutMessage *) message;
  LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "R5N CLIENT-PUT %s\n",
               GNUNET_h2s_full (&dht_msg->key));
  /* give to local clients */
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Handling local PUT of %u-bytes for query %s\n",
       size - sizeof (struct GNUNET_DHT_ClientPutMessage),
       GNUNET_h2s (&dht_msg->key));
  GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
                            &dht_msg->key, 0, NULL, 0, NULL,
                            ntohl (dht_msg->type),
                            size - sizeof (struct GNUNET_DHT_ClientPutMessage),
                            &dht_msg[1]);
  /* store locally */
  GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
                            &dht_msg->key, 0, NULL, ntohl (dht_msg->type),
                            size - sizeof (struct GNUNET_DHT_ClientPutMessage),
                            &dht_msg[1]);
  /* route to other peers */
  peer_bf =
      GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE,
                                         GNUNET_CONSTANTS_BLOOMFILTER_K);
  GDS_NEIGHBOURS_handle_put (ntohl (dht_msg->type), ntohl (dht_msg->options),
                             ntohl (dht_msg->desired_replication_level),
                             GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
                             0 /* hop count */ ,
                             peer_bf, &dht_msg->key, 0, NULL, &dht_msg[1],
                             size -
                             sizeof (struct GNUNET_DHT_ClientPutMessage));
  GDS_CLIENTS_process_put (ntohl (dht_msg->options),
                           ntohl (dht_msg->type),
                           0,
                           ntohl (dht_msg->desired_replication_level),
                           1,
                           GDS_NEIGHBOURS_get_id(),
                           GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
                           &dht_msg->key,
                           &dht_msg[1],
                           size - sizeof (struct GNUNET_DHT_ClientPutMessage));
  GNUNET_CONTAINER_bloomfilter_free (peer_bf);
  pm = GNUNET_malloc (sizeof (struct PendingMessage) +
		      sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
  conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1];
  conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
  conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK);
  conf->reserved = htonl (0);
  conf->unique_id = dht_msg->unique_id;
  pm->msg = &conf->header;
  add_pending_message (find_active_client (client), pm);
  GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
/**
 * Iterator over hash map entries that send a given reply to
 * each of the matching clients.  With some tricky recycling
 * of the buffer.
 *
 * @param cls the 'struct ForwardReplyContext'
 * @param key current key
 * @param value value in the hash map, a ClientQueryRecord
 * @return GNUNET_YES (we should continue to iterate),
 *         if the result is mal-formed, GNUNET_NO
 */
static int
forward_reply (void *cls, const struct GNUNET_HashCode * key, void *value)
{
  struct ForwardReplyContext *frc = cls;
  struct ClientQueryRecord *record = value;
  struct PendingMessage *pm;
  struct GNUNET_DHT_ClientResultMessage *reply;
  enum GNUNET_BLOCK_EvaluationResult eval;
  int do_free;
  struct GNUNET_HashCode ch;
  unsigned int i;

  LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
	       "R5N CLIENT-RESULT %s\n",
               GNUNET_h2s_full (key));
  if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type))
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Record type missmatch, not passing request for key %s to local client\n",
         GNUNET_h2s (key));
    GNUNET_STATISTICS_update (GDS_stats,
                              gettext_noop
                              ("# Key match, type mismatches in REPLY to CLIENT"),
                              1, GNUNET_NO);
    return GNUNET_YES;          /* type mismatch */
  }
  GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch);
  for (i = 0; i < record->seen_replies_count; i++)
    if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (struct GNUNET_HashCode)))
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "Duplicate reply, not passing request for key %s to local client\n",
           GNUNET_h2s (key));
      GNUNET_STATISTICS_update (GDS_stats,
                                gettext_noop
                                ("# Duplicate REPLIES to CLIENT request dropped"),
                                1, GNUNET_NO);
      return GNUNET_YES;        /* duplicate */
    }
  eval =
      GNUNET_BLOCK_evaluate (GDS_block_context, record->type, key, NULL, 0,
                             record->xquery, record->xquery_size, frc->data,
                             frc->data_size);
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Evaluation result is %d for key %s for local client's query\n",
       (int) eval, GNUNET_h2s (key));
  switch (eval)
  {
  case GNUNET_BLOCK_EVALUATION_OK_LAST:
    do_free = GNUNET_YES;
    break;
  case GNUNET_BLOCK_EVALUATION_OK_MORE:
    GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch);
    do_free = GNUNET_NO;
    break;
  case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
    /* should be impossible to encounter here */
    GNUNET_break (0);
    return GNUNET_YES;
  case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
    GNUNET_break_op (0);
    return GNUNET_NO;
  case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
    GNUNET_break (0);
    return GNUNET_NO;
  case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
    GNUNET_break (0);
    return GNUNET_NO;
  case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
    return GNUNET_YES;
  case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Unsupported block type (%u) in request!\n"), record->type);
    return GNUNET_NO;
  default:
    GNUNET_break (0);
    return GNUNET_NO;
  }
  if (GNUNET_NO == frc->do_copy)
  {
    /* first time, we can use the original data */
    pm = frc->pm;
    frc->do_copy = GNUNET_YES;
  }
  else
  {
    /* two clients waiting for same reply, must copy for queueing */
    pm = GNUNET_malloc (sizeof (struct PendingMessage) +
                        ntohs (frc->pm->msg->size));
    memcpy (pm, frc->pm,
            sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size));
    pm->next = pm->prev = NULL;
    pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
  }
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop ("# RESULTS queued for clients"), 1,
                            GNUNET_NO);
  reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1];
  reply->unique_id = record->unique_id;
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Queueing reply to query %s for client %p\n",
       GNUNET_h2s (key),
       record->client->client_handle);
  add_pending_message (record->client, pm);
  if (GNUNET_YES == do_free)
    remove_client_records (record->client, key, record);
  return GNUNET_YES;
}
/**
 * Get the block for a particular zone and label in the
 * datastore.  Will return at most one result to the iterator.
 *
 * @param cls closure (internal context for the plugin)
 * @param query hash of public key derived from the zone and the label
 * @param iter function to call with the result
 * @param iter_cls closure for @a iter
 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
 */
static int
namecache_sqlite_lookup_block (void *cls,
			       const struct GNUNET_HashCode *query,
			       GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
{
  struct Plugin *plugin = cls;
  int ret;
  int sret;
  size_t block_size;
  const struct GNUNET_GNSRECORD_Block *block;

  if (SQLITE_OK != sqlite3_bind_blob (plugin->lookup_block, 1,
				      query, sizeof (struct GNUNET_HashCode),
				      SQLITE_STATIC))
  {
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_bind_XXXX");
    if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
      LOG_SQLITE (plugin,
		  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		  "sqlite3_reset");
    return GNUNET_SYSERR;
  }
  ret = GNUNET_NO;
  if (SQLITE_ROW == (sret = sqlite3_step (plugin->lookup_block)))
  {
    block = sqlite3_column_blob (plugin->lookup_block, 0);
    block_size = sqlite3_column_bytes (plugin->lookup_block, 0);
    if ( (block_size < sizeof (struct GNUNET_GNSRECORD_Block)) ||
	 (ntohl (block->purpose.size) +
	  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
	  sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
    {
      GNUNET_break (0);
      ret = GNUNET_SYSERR;
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
		  "Found block under derived key `%s'\n",
		  GNUNET_h2s_full (query));
      iter (iter_cls, block);
      ret = GNUNET_YES;
    }
  }
  else
  {
    if (SQLITE_DONE != sret)
    {
      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
      ret = GNUNET_SYSERR;
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
		  "No block found under derived key `%s'\n",
		  GNUNET_h2s_full (query));
    }
  }
  if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
    LOG_SQLITE (plugin,
		GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_reset");
  return ret;
}
/**
 * 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_sqlite_cache_block (void *cls,
			      const struct GNUNET_GNSRECORD_Block *block)
{
  struct Plugin *plugin = cls;
  struct GNUNET_HashCode query;
  struct GNUNET_TIME_Absolute expiration;
  int64_t dval;
  size_t block_size;
  int n;

  namecache_sqlite_expire_blocks (plugin);
  GNUNET_CRYPTO_hash (&block->derived_key,
		      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
		      &query);
  expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time);
  dval = (int64_t) expiration.abs_value_us;
  if (dval < 0)
    dval = INT64_MAX;
  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;
  }

  /* delete old version of the block */
  if ( (SQLITE_OK !=
        sqlite3_bind_blob (plugin->delete_block, 1,
                           &query, sizeof (struct GNUNET_HashCode),
                           SQLITE_STATIC)) ||
       (SQLITE_OK !=
        sqlite3_bind_int64 (plugin->delete_block,
                            2, dval)) )
  {
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_bind_XXXX");
    if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
      LOG_SQLITE (plugin,
                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  "sqlite3_reset");
    return GNUNET_SYSERR;
  }
  n = sqlite3_step (plugin->delete_block);
  switch (n)
  {
  case SQLITE_DONE:
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Old block deleted\n");
    break;
  case SQLITE_BUSY:
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
    break;
  default:
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
    break;
  }
  if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_reset");

  /* insert new version of the block */
  if ((SQLITE_OK !=
       sqlite3_bind_blob (plugin->cache_block, 1,
			  &query, sizeof (struct GNUNET_HashCode),
			  SQLITE_STATIC)) ||
      (SQLITE_OK !=
       sqlite3_bind_blob (plugin->cache_block, 2,
			  block, block_size,
			  SQLITE_STATIC)) ||
      (SQLITE_OK !=
       sqlite3_bind_int64 (plugin->cache_block, 3,
			   dval)))
  {
    LOG_SQLITE (plugin,
		GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_bind_XXXX");
    if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
      LOG_SQLITE (plugin,
		  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		  "sqlite3_reset");
    return GNUNET_SYSERR;

  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Caching block under derived key `%s'\n",
	      GNUNET_h2s_full (&query));
  n = sqlite3_step (plugin->cache_block);
  if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_reset");
  switch (n)
  {
  case SQLITE_DONE:
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Record stored\n");
    return GNUNET_OK;
  case SQLITE_BUSY:
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_step");
    return GNUNET_NO;
  default:
    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
		"sqlite3_step");
    return GNUNET_SYSERR;
  }
}
int
client_connect (struct Session *s)
{
  struct Plugin *plugin = s->plugin;
  int res = GNUNET_OK;
  char *url;
  CURLMcode mret;

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                   "Initiating outbound session peer `%s'\n",
                   GNUNET_i2s (&s->target));
  s->inbound = GNUNET_NO;
  plugin->last_tag++;
  /* create url */
  GNUNET_asprintf (&url, "%s%s;%u",
                   http_plugin_address_to_string (plugin, s->addr, s->addrlen),
                   GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey),
                   plugin->last_tag);
#if 0
  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url);
#endif
  /* create get connection */
  s->client_get = curl_easy_init ();
#if VERBOSE_CURL
  curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log);
  curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get);
#endif
#if BUILD_HTTPS
  curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0);
#endif
  curl_easy_setopt (s->client_get, CURLOPT_URL, url);
  //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
  //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps);
  curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb);
  curl_easy_setopt (s->client_get, CURLOPT_READDATA, s);
  curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive);
  curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s);
  curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS,
                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s);
  curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS,
                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE,
                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
#if CURL_TCP_NODELAY
  curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1);
#endif

  /* create put connection */
  s->client_put = curl_easy_init ();
#if VERBOSE_CURL
  curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log);
  curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put);
#endif
#if BUILD_HTTPS
  curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0);
#endif
  curl_easy_setopt (s->client_put, CURLOPT_URL, url);
  curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L);
  //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
  //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps);
  curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb);
  curl_easy_setopt (s->client_put, CURLOPT_READDATA, s);
  curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive);
  curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s);
  curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS,
                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s);
  curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS,
                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE,
                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
#if CURL_TCP_NODELAY
  curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1);
#endif

  GNUNET_free (url);

  mret = curl_multi_add_handle (plugin->client_mh, s->client_get);
  if (mret != CURLM_OK)
  {
    curl_easy_cleanup (s->client_get);
    res = GNUNET_SYSERR;
    GNUNET_break (0);
  }

  mret = curl_multi_add_handle (plugin->client_mh, s->client_put);
  if (mret != CURLM_OK)
  {
    curl_multi_remove_handle (plugin->client_mh, s->client_get);
    curl_easy_cleanup (s->client_get);
    curl_easy_cleanup (s->client_put);
    res = GNUNET_SYSERR;
    GNUNET_break (0);
  }

  /* Perform connect */
  plugin->cur_connections += 2;

  plugin->outbound_sessions ++;
  GNUNET_STATISTICS_set (plugin->env->stats,
      "# HTTP outbound sessions",
      plugin->outbound_sessions,
      GNUNET_NO);

  /* Re-schedule since handles have changed */
  if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
    plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
  }
  plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin);

  return res;
}