/**
 * Deserialize the given records to the given destination.
 *
 * @param len size of the serialized record data
 * @param src the serialized record data
 * @param rd_count number of records in the rd array
 * @param dest where to put the data
 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
 */
int
GNUNET_GNSRECORD_records_deserialize (size_t len,
				      const char *src,
				      unsigned int rd_count,
				      struct GNUNET_GNSRECORD_Data *dest)
{
  struct NetworkRecord rec;
  unsigned int i;
  size_t off;

  off = 0;
  for (i=0;i<rd_count;i++)
  {
    if (off + sizeof (rec) > len)
      return GNUNET_SYSERR;
    GNUNET_memcpy (&rec, &src[off], sizeof (rec));
    dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
    dest[i].data_size = ntohl ((uint32_t) rec.data_size);
    dest[i].record_type = ntohl (rec.record_type);
    dest[i].flags = ntohl (rec.flags);
    off += sizeof (rec);
    if (off + dest[i].data_size > len)
      return GNUNET_SYSERR;
    dest[i].data = &src[off];
    off += dest[i].data_size;
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Deserialized record %u with flags %d and expiration time %llu\n",
         i,
         dest[i].flags,
         (unsigned long long) dest[i].expiration_time);
  }
  return GNUNET_OK;
}
Beispiel #2
0
/**
 * Free memory. Merely a wrapper for the case that we
 * want to keep track of allocations.
 *
 * @param ptr the pointer to free
 * @param filename where in the code was the call to GNUNET_free
 * @param linenumber where in the code was the call to GNUNET_free
 */
void
GNUNET_xfree_ (void *ptr,
	       const char *filename,
	       int linenumber)
{
  GNUNET_assert_at (NULL != ptr,
		    filename,
		    linenumber);
#ifdef W32_MEM_LIMIT
  ptr = &((size_t *) ptr)[-1];
  mem_used -= *((size_t *) ptr);
#endif
#if defined(M_SIZE)
#if ENABLE_POISONING
  {
    const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
    uint64_t *base = ptr;
    size_t s = M_SIZE (ptr);
    size_t i;

    for (i=0;i<s/8;i++)
      base[i] = baadfood;
    GNUNET_memcpy (&base[s/8], &baadfood, s % 8);
  }
#endif
#endif
  free (ptr);
}
/**
 * Deserialize the given records to the given destination.
 *
 * @param len size of the serialized record data
 * @param src the serialized record data
 * @param rd_count number of records in the rd array
 * @param dest where to put the data
 *
 * @return GNUNET_OK on success, GNUNET_SYSERR on error
 */
int
GNUNET_NAMESTORE_records_deserialize (size_t len,
				      const char *src,
				      unsigned int rd_count,
				      struct GNUNET_NAMESTORE_RecordData *dest)
{
  struct NetworkRecord rec;
  unsigned int i;
  size_t off;
  
  off = 0;
  for (i=0;i<rd_count;i++)
  {
    if (off + sizeof (rec) > len)
      return GNUNET_SYSERR;
    memcpy (&rec, &src[off], sizeof (rec));
    dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
    dest[i].data_size = ntohl ((uint32_t) rec.data_size);
    dest[i].record_type = ntohl (rec.record_type);
    dest[i].flags = ntohl (rec.flags);
    off += sizeof (rec);

    if (off + dest[i].data_size > len)
      return GNUNET_SYSERR;
    dest[i].data = &src[off];
    off += dest[i].data_size;
  }
  return GNUNET_OK; 
}
Beispiel #4
0
/**
 * An incoming flood message has been received which claims
 * to have more bits matching than any we know in this time
 * period.  Verify the signature and/or proof of work.
 *
 * @param incoming_flood the message to verify
 * @return #GNUNET_YES if the message is verified
 *         #GNUNET_NO if the key/signature don't verify
 */
static int
verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
{
  if (GNUNET_YES !=
      check_proof_of_work (&incoming_flood->origin.public_key,
                           incoming_flood->proof_of_work))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Proof of work invalid: %llu!\n",
                (unsigned long long)
                GNUNET_ntohll (incoming_flood->proof_of_work));
    GNUNET_break_op (0);
    return GNUNET_NO;
  }
  if ((nse_work_required > 0) &&
      (GNUNET_OK !=
       GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
                                 &incoming_flood->purpose,
                                 &incoming_flood->signature,
                                 &incoming_flood->origin.public_key)))
  {
    GNUNET_break_op (0);
    return GNUNET_NO;
  }
  return GNUNET_YES;
}
Beispiel #5
0
static int
fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2,
             enum GNUNET_PSYCSTORE_MessageFlags flags)
{
  struct FragmentClosure *fcls = cls;
  struct GNUNET_MULTICAST_MessageHeader *msg1;
  uint64_t flags1;
  int ret;

  if (fcls->n >= MAX_MSG)
    {
      GNUNET_break (0);
      return GNUNET_SYSERR;
    }
  msg1 = fcls->msg[fcls->n];
  flags1 = fcls->flags[fcls->n++];
  if (NULL == msg1)
    {
      GNUNET_break (0);
      return GNUNET_SYSERR;
    }

  if (flags1 == flags && msg1->header.size == msg2->header.size
      && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size)))
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n",
         GNUNET_ntohll (msg1->fragment_id));
    ret = GNUNET_YES;
  }
  else
  {
    LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n",
         GNUNET_ntohll (msg1->fragment_id));
    ret = GNUNET_SYSERR;
  }

  GNUNET_free (msg2);
  return ret;
}
Beispiel #6
0
/**
 * Find our proof of work.
 *
 * @param cls closure (unused)
 */
static void
find_proof (void *cls)
{
#define ROUND_SIZE 10
  uint64_t counter;
  char buf[sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
           sizeof (uint64_t)] GNUNET_ALIGN;
  struct GNUNET_HashCode result;
  unsigned int i;

  proof_task = NULL;
  GNUNET_memcpy (&buf[sizeof (uint64_t)], &my_identity,
          sizeof (struct GNUNET_PeerIdentity));
  i = 0;
  counter = my_proof;
  while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
  {
    GNUNET_memcpy (buf, &counter, sizeof (uint64_t));
    pow_hash (buf, sizeof (buf), &result);
    if (nse_work_required <= count_leading_zeroes (&result))
    {
      my_proof = counter;
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n",
                  (unsigned long long) GNUNET_ntohll (counter));
      write_proof ();
      setup_flood_message (estimate_index, current_timestamp);
      return;
    }
    counter++;
    i++;
  }
  if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Testing proofs currently at %llu\n",
                (unsigned long long) counter);
    /* remember progress every 100 rounds */
    my_proof = counter;
    write_proof ();
  }
  else
  {
    my_proof = counter;
  }
  proof_task =
      GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
						  GNUNET_SCHEDULER_PRIORITY_IDLE,
						  &find_proof, NULL);
}
Beispiel #7
0
/**
 * Retrieve all fragments of the latest messages.
 *
 * @param h
 *        Handle for the PSYCstore.
 * @param channel_key
 *        The channel we are interested in.
 * @param slave_key
 *        The slave requesting the message.
 *        If not NULL, a membership test is performed first
 *        and the message is only returned if the slave has access to it.
 * @param message_limit
 *        Maximum number of messages to retrieve.
 * @param method_prefix
 *        Retrieve only messages with a matching method prefix.
 * @todo Implement method_prefix query.
 * @param fragment_cb
 *        Callback to call with the retrieved fragments.
 * @param result_cb
 *        Callback to call with the result of the operation.
 * @param cls
 *        Closure for the callbacks.
 *
 * @return Handle that can be used to cancel the operation.
 */
struct GNUNET_PSYCSTORE_OperationHandle *
GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
                                     const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
                                     const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
                                     uint64_t message_limit,
                                     const char *method_prefix,
                                     GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
                                     GNUNET_PSYCSTORE_ResultCallback rcb,
                                     void *cls)
{
  struct MessageGetRequest *req;

  if (NULL == method_prefix)
    method_prefix = "";
  uint16_t method_size = strnlen (method_prefix,
                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
                                  - sizeof (*req)) + 1;
  GNUNET_assert ('\0' == method_prefix[method_size - 1]);

  struct GNUNET_PSYCSTORE_OperationHandle *
    op = GNUNET_malloc (sizeof (*op) + sizeof (*req) + method_size);
  op->h = h;
  op->data_cb = (DataCallback) fragment_cb;
  op->res_cb = rcb;
  op->cls = cls;

  req = (struct MessageGetRequest *) &op[1];
  op->msg = (struct GNUNET_MessageHeader *) req;
  req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET);
  req->header.size = htons (sizeof (*req) + method_size);
  req->channel_key = *channel_key;
  req->message_limit = GNUNET_ntohll (message_limit);
  if (NULL != slave_key)
  {
    req->slave_key = *slave_key;
    req->do_membership_test = GNUNET_YES;
  }

  op->op_id = get_next_op_id (h);
  req->op_id = GNUNET_htonll (op->op_id);
  memcpy (&req[1], method_prefix, method_size);

  GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op);
  transmit_next (h);

  return op;
}
/**
 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
 *
 * @param cls NULL
 * @param client identification of the client
 * @param message the actual message
 */
static void
handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
                         const struct GNUNET_MessageHeader *message)
{
  struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
  struct Slave *slave;
  struct GNUNET_TESTBED_SlaveConfiguration *reply;
  const struct GNUNET_CONFIGURATION_Handle *cfg;
  char *config;
  char *xconfig;
  size_t config_size;
  size_t xconfig_size;
  size_t reply_size;
  uint64_t op_id;
  uint32_t slave_id;

  msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
  slave_id = ntohl (msg->slave_id);
  op_id = GNUNET_ntohll (msg->operation_id);
  if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
  {
    /* FIXME: Add forwardings for this type of message here.. */
    GST_send_operation_fail_msg (client, op_id, "Slave not found");
    GNUNET_SERVER_receive_done (client, GNUNET_OK);
    return;
  }
  slave = GST_slave_list[slave_id];
  GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
  config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
  xconfig_size =
      GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
  GNUNET_free (config);
  reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
  GNUNET_break (reply_size <= UINT16_MAX);
  GNUNET_break (config_size <= UINT16_MAX);
  reply = GNUNET_realloc (xconfig, reply_size);
  (void) memmove (&reply[1], reply, xconfig_size);
  reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
  reply->header.size = htons ((uint16_t) reply_size);
  reply->slave_id = msg->slave_id;
  reply->operation_id = msg->operation_id;
  reply->config_size = htons ((uint16_t) config_size);
  GST_queue_message (client, &reply->header);
  GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
Beispiel #9
0
void
GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
                         const struct GNUNET_MessageHeader *msg)
{
  uint16_t size = ntohs (msg->size);
  uint16_t type = ntohs (msg->type);
  GNUNET_log (kind, "Message of type %d and size %u:\n", type, size);
  switch (type)
  {
  case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE:
  {
    struct GNUNET_PSYC_MessageHeader *pmsg
      = (struct GNUNET_PSYC_MessageHeader *) msg;
    GNUNET_log (kind, "\tID: %" PRIu64 "\tflags: %x" PRIu32 "\n",
                GNUNET_ntohll (pmsg->message_id), ntohl (pmsg->flags));
    break;
  }
  case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
  {
    struct GNUNET_PSYC_MessageMethod *meth
      = (struct GNUNET_PSYC_MessageMethod *) msg;
    GNUNET_log (kind, "\t%.*s\n", size - sizeof (*meth), &meth[1]);
    break;
  }
  case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  {
    struct GNUNET_PSYC_MessageModifier *mod
      = (struct GNUNET_PSYC_MessageModifier *) msg;
    uint16_t name_size = ntohs (mod->name_size);
    char oper = ' ' < mod->oper ? mod->oper : ' ';
    GNUNET_log (kind, "\t%c%.*s\t%.*s\n", oper, name_size, &mod[1],
                size - sizeof (*mod) - name_size,
                ((char *) &mod[1]) + name_size);
    break;
  }
  case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
  case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
    GNUNET_log (kind, "\t%.*s\n", size - sizeof (*msg), &msg[1]);
    break;
  }
}
Beispiel #10
0
/**
 * Get an estimate of how much space the database is
 * currently using.
 *
 * @param cls our `struct Plugin *`
 * @return number of bytes used on disk
 */
static void
postgres_plugin_estimate_size (void *cls, unsigned long long *estimate)
{
  struct Plugin *plugin = cls;
  unsigned long long total;
  PGresult *ret;

  if (NULL == estimate)
    return;
  ret =
      PQexecParams (plugin->dbh,
                    "SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090", 0,
                    NULL, NULL, NULL, NULL, 1);
  if (GNUNET_OK !=
      GNUNET_POSTGRES_check_result (plugin->dbh, 
				    ret, 
				    PGRES_TUPLES_OK, 
				    "PQexecParams", 
				    "get_size"))
  {
    *estimate = 0;
    return;
  }
  if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) )
  {
    GNUNET_break (0);
    PQclear (ret);
    *estimate = 0;
    return;
  }
  if (PQgetlength (ret, 0, 0) != sizeof (unsigned long long))
  {
    GNUNET_break (0 == PQgetlength (ret, 0, 0));
    PQclear (ret);
    *estimate = 0;
    return;
  }
  total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0));
  PQclear (ret);
  *estimate = total;
}
/**
 * Iterator to copy over messages from the hash map
 * into an array for sorting.
 *
 * @param cls the `struct BobServiceSession *`
 * @param key the key (unused)
 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
 * TODO: code duplication with Alice!
 */
static int
copy_element_cb (void *cls,
                 const struct GNUNET_HashCode *key,
                 void *value)
{
  struct BobServiceSession *s = cls;
  struct GNUNET_SCALARPRODUCT_Element *e = value;
  gcry_mpi_t mval;
  int64_t val;

  mval = gcry_mpi_new (0);
  val = (int64_t) GNUNET_ntohll (e->value);
  if (0 > val)
    gcry_mpi_sub_ui (mval, mval, -val);
  else
    gcry_mpi_add_ui (mval, mval, val);
  s->sorted_elements [s->used_element_count].value = mval;
  s->sorted_elements [s->used_element_count].key = &e->key;
  s->used_element_count++;
  return GNUNET_OK;
}
Beispiel #12
0
/**
 * Retrieve latest message fragments.
 *
 * @param h
 *        Handle for the PSYCstore.
 * @param channel_key
 *        The channel we are interested in.
 * @param slave_key
 *        The slave requesting the fragment.  If not NULL, a membership test is
 *        performed first and the fragment is only returned if the slave has
 *        access to it.
 * @param first_fragment_id
 *        First fragment ID to retrieve.
 *        Use 0 to get the latest message fragment.
 * @param last_fragment_id
 *        Last consecutive fragment ID to retrieve.
 *        Use 0 to get the latest message fragment.
 * @param fragment_limit
 *        Maximum number of fragments to retrieve.
 * @param fragment_cb
 *        Callback to call with the retrieved fragments.
 * @param rcb
 *        Callback to call with the result of the operation.
 * @param cls
 *        Closure for the callbacks.
 *
 * @return Handle that can be used to cancel the operation.
 */
struct GNUNET_PSYCSTORE_OperationHandle *
GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
                                      const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
                                      const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
                                      uint64_t fragment_limit,
                                      GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
                                      GNUNET_PSYCSTORE_ResultCallback rcb,
                                      void *cls)
{
  struct FragmentGetRequest *req;
  struct GNUNET_PSYCSTORE_OperationHandle *
    op = GNUNET_malloc (sizeof (*op) + sizeof (*req));
  op->h = h;
  op->data_cb = (DataCallback) fragment_cb;
  op->res_cb = rcb;
  op->cls = cls;

  req = (struct FragmentGetRequest *) &op[1];
  op->msg = (struct GNUNET_MessageHeader *) req;
  req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET);
  req->header.size = htons (sizeof (*req));
  req->channel_key = *channel_key;
  req->fragment_limit = GNUNET_ntohll (fragment_limit);
  if (NULL != slave_key)
  {
    req->slave_key = *slave_key;
    req->do_membership_test = GNUNET_YES;
  }

  op->op_id = get_next_op_id (h);
  req->op_id = GNUNET_htonll (op->op_id);

  GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op);
  transmit_next (h);

  return op;
}
Beispiel #13
0
static int
testFile (int i)
{
  char *uri;
  struct GNUNET_FS_Uri *ret;
  char *emsg;

  if (NULL !=
      (ret =
       GNUNET_FS_uri_parse
       ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42",
        &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  if (NULL !=
      (ret =
       GNUNET_FS_uri_parse
       ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000",
        &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  if (NULL !=
      (ret =
       GNUNET_FS_uri_parse
       ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH",
        &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  ret =
      GNUNET_FS_uri_parse
      ("gnunet://fs/chk/4QZP479A9SKGFNMQ2ZBCYE71YV2QMTVGWTVPB6A10ASVCKXDHB05DKPSC7ZF6E9P9W1VE47394EQY7NXA47Q6R35M7P1MJPGP59D1Z8.D54QD1K5XCG5878T6YZ19AM60MQ6FC0YNVK7QY08KK0KM0FJJ3KQWYG112FN5T07KN7J0X35DF6WVBT9B8ZMZ3X2BXJ22X3KFQ6MV2G.42",
       &emsg);
  if (ret == NULL)
  {
    GNUNET_free (emsg);
    GNUNET_assert (0);
  }
  if (GNUNET_FS_uri_test_ksk (ret))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  if (GNUNET_FS_uri_test_sks (ret))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  if (GNUNET_ntohll (ret->data.chk.file_length) != 42)
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }

  uri = GNUNET_FS_uri_to_string (ret);
  if (0 !=
      strcmp (uri,
              "gnunet://fs/chk/4QZP479A9SKGFNMQ2ZBCYE71YV2QMTVGWTVPB6A10ASVCKXDHB05DKPSC7ZF6E9P9W1VE47394EQY7NXA47Q6R35M7P1MJPGP59D1Z8.D54QD1K5XCG5878T6YZ19AM60MQ6FC0YNVK7QY08KK0KM0FJJ3KQWYG112FN5T07KN7J0X35DF6WVBT9B8ZMZ3X2BXJ22X3KFQ6MV2G.42"))
  {
    GNUNET_free (uri);
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (uri);
  GNUNET_FS_uri_destroy (ret);
  return 0;
}
/**
 * We've received an on-demand encoded block from the datastore.
 * Attempt to do on-demand encoding and (if successful), call the
 * continuation with the resulting block.  On error, clean up and ask
 * the datastore for more results.
 *
 * @param key key for the content
 * @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 expiration expiration time for the content
 * @param uid unique identifier for the datum;
 *        maybe 0 if no unique identifier is available
 * @param cont function to call with the actual block (at most once, on success)
 * @param cont_cls closure for cont
 * @return GNUNET_OK on success
 */
int
GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size,
                                  const void *data, enum GNUNET_BLOCK_Type type,
                                  uint32_t priority, uint32_t anonymity,
                                  struct GNUNET_TIME_Absolute expiration,
                                  uint64_t uid,
                                  GNUNET_DATASTORE_DatumProcessor cont,
                                  void *cont_cls)
{
  const struct OnDemandBlock *odb;
  struct GNUNET_HashCode nkey;
  struct GNUNET_CRYPTO_AesSessionKey skey;
  struct GNUNET_CRYPTO_AesInitializationVector iv;
  struct GNUNET_HashCode query;
  ssize_t nsize;
  char ndata[DBLOCK_SIZE];
  char edata[DBLOCK_SIZE];
  const char *fn;
  struct GNUNET_DISK_FileHandle *fh;
  uint64_t off;
  struct IndexInfo *ii;

  if (size != sizeof (struct OnDemandBlock))
  {
    GNUNET_break (0);
    GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1,
                             GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL);
    return GNUNET_SYSERR;
  }
  odb = (const struct OnDemandBlock *) data;
  off = GNUNET_ntohll (odb->offset);
  ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id);
  if (NULL == ii)
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  fn = ii->filename;
  if ((NULL == fn) || (0 != ACCESS (fn, R_OK)))
  {
    GNUNET_STATISTICS_update (GSF_stats,
                              gettext_noop
                              ("# index blocks removed: original file inaccessible"),
                              1, GNUNET_YES);
    GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1,
                             GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL);
    return GNUNET_SYSERR;
  }
  if ((NULL ==
       (fh =
        GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ,
                               GNUNET_DISK_PERM_NONE))) ||
      (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) ||
      (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata)))))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _
                ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"),
                GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off,
                (fn == NULL) ? _("not indexed") : STRERROR (errno));
    if (fh != NULL)
      GNUNET_DISK_file_close (fh);
    GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1,
                             GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL);
    return GNUNET_SYSERR;
  }
  GNUNET_DISK_file_close (fh);
  GNUNET_CRYPTO_hash (ndata, nsize, &nkey);
  GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv);
  GNUNET_CRYPTO_aes_encrypt (ndata, nsize, &skey, &iv, edata);
  GNUNET_CRYPTO_hash (edata, nsize, &query);
  if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode)))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Indexed file `%s' changed at offset %llu\n"), fn,
                (unsigned long long) off);
    GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1,
                             GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL);
    return GNUNET_SYSERR;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "On-demand encoded block for query `%s'\n", GNUNET_h2s (key));
  cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority,
        anonymity, expiration, uid);
  return GNUNET_OK;
}
/**
 * Handle INDEX_START-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
void
GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client,
                              const struct GNUNET_MessageHeader *message)
{
  const struct IndexStartMessage *ism;
  char *fn;
  uint16_t msize;
  struct IndexInfo *ii;
  size_t slen;
  uint64_t dev;
  uint64_t ino;
  uint64_t mydev;
  uint64_t myino;

  msize = ntohs (message->size);
  if ((msize <= sizeof (struct IndexStartMessage)) ||
      (((const char *) message)[msize - 1] != '\0'))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  ism = (const struct IndexStartMessage *) message;
  if (0 != ism->reserved)
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
  if (fn == NULL)
  {
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  dev = GNUNET_ntohll (ism->device);
  ino = GNUNET_ntohll (ism->inode);
  ism = (const struct IndexStartMessage *) message;
  slen = strlen (fn) + 1;
  ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
  ii->filename = (const char *) &ii[1];
  memcpy (&ii[1], fn, slen);
  ii->file_id = ism->file_id;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n",
              "START_INDEX", ii->filename);
  ii->tc = GNUNET_SERVER_transmit_context_create (client);
  mydev = 0;
  myino = 0;
  if (((dev != 0) || (ino != 0)) &&
      (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) &&
      ((dev == mydev) && (ino == myino)))
  {
    /* fast validation OK! */
    signal_index_ok (ii);
    GNUNET_free (fn);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
              (unsigned long long) ino, (unsigned long long) myino,
              (unsigned int) dev, (unsigned int) mydev);
  /* slow validation, need to hash full file (again) */
  ii->fhc =
      GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, fn,
                               HASHING_BLOCKSIZE, &hash_for_index_val, ii);
  if (ii->fhc == NULL)
    hash_for_index_val (ii, NULL);
  GNUNET_free (fn);
}
/**
 * Handler for Bob's a client request message.  Bob is in the response
 * role, keep the values + session and waiting for a matching session
 * or process a waiting request from Alice.
 *
 * @param cls identification of the client
 * @param msg the actual message
 */
static void
handle_bob_client_message (void *cls,
			   const struct BobComputationMessage *msg)
{
  struct BobServiceSession *s = cls;
  struct CadetIncomingSession *in;
  uint32_t contained_count;
  uint32_t total_count;
  const struct GNUNET_SCALARPRODUCT_Element *elements;
  struct GNUNET_SET_Element set_elem;
  struct GNUNET_SCALARPRODUCT_Element *elem;

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

  s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
  s->total = total_count;
  s->client_received_element_count = contained_count;
  s->session_id = msg->session_key;
  s->port = GNUNET_CADET_open_port (my_cadet,
                                    &msg->session_key,
                                    &cb_channel_incoming,
                                    s);
  if (NULL == s->port)
  {
    GNUNET_break (0);
    GNUNET_SERVICE_client_drop (s->client);
    return;
  }
  GNUNET_break (GNUNET_YES ==
                GNUNET_CONTAINER_multihashmap_put (client_sessions,
                                                   &s->session_id,
                                                   s,
                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
  s->intersected_elements
    = GNUNET_CONTAINER_multihashmap_create (s->total,
					    GNUNET_YES);
  s->intersection_set
    = GNUNET_SET_create (cfg,
			 GNUNET_SET_OPERATION_INTERSECTION);
  for (uint32_t i = 0; i < contained_count; i++)
  {
    if (0 == GNUNET_ntohll (elements[i].value))
      continue;
    elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
    GNUNET_memcpy (elem,
            &elements[i],
            sizeof (struct GNUNET_SCALARPRODUCT_Element));
    if (GNUNET_SYSERR ==
        GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
                                           &elem->key,
                                           elem,
                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
    {
      GNUNET_break (0);
      GNUNET_free (elem);
      continue;
    }
    set_elem.data = &elem->key;
    set_elem.size = sizeof (elem->key);
    set_elem.element_type = 0;
    GNUNET_SET_add_element (s->intersection_set,
                            &set_elem,
                            NULL, NULL);
    s->used_element_count++;
  }
  GNUNET_SERVICE_client_continue (s->client);
  if (s->total != s->client_received_element_count)
  {
    /* multipart msg */
    return;
  }
  in = find_matching_cadet_session (&s->session_id);
  if (NULL == in)
  {
    /* nothing yet, wait for Alice */
    return;
  }
  GNUNET_assert (NULL == in->s);
  /* pair them up */
  in->s = s;
  s->cadet = in;
  start_intersection (s);
}
/**
 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
 *
 * @param cls identification of the client
 * @param msg the actual message
 */
void
handle_peer_create (void *cls,
                    const struct GNUNET_TESTBED_PeerCreateMessage *msg)
{
  struct GNUNET_SERVICE_Client *client = cls;
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
  struct GNUNET_CONFIGURATION_Handle *cfg;
  struct ForwardedOperationContext *fo_ctxt;
  struct Route *route;
  struct Peer *peer;
  char *emsg;
  uint32_t host_id;
  uint32_t peer_id;

  host_id = ntohl (msg->host_id);
  peer_id = ntohl (msg->peer_id);
  if (VALID_PEER_ID (peer_id))
  {
    (void) GNUNET_asprintf (&emsg,
                            "Peer with ID %u already exists",
                            peer_id);
    GST_send_operation_fail_msg (client,
                                 GNUNET_ntohll (msg->operation_id),
                                 emsg);
    GNUNET_free (emsg);
    GNUNET_SERVICE_client_continue (client);
    return;
  }
  if (UINT32_MAX == peer_id)
  {
    GST_send_operation_fail_msg (client,
                                 GNUNET_ntohll (msg->operation_id),
                                 "Cannot create peer with given ID");
    GNUNET_SERVICE_client_continue (client);
    return;
  }
  if (host_id == GST_context->host_id)
  {
    /* We are responsible for this peer */
    cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
    if (NULL == cfg)
    {
      GNUNET_break (0);
      GNUNET_SERVICE_client_drop (client);
      return;
    }
    GNUNET_CONFIGURATION_set_value_number (cfg,
                                           "TESTBED",
                                           "PEERID",
                                           (unsigned long long) peer_id);

    GNUNET_CONFIGURATION_set_value_number (cfg,
                                           "PATHS",
                                           "PEERID",
                                           (unsigned long long) peer_id);
    peer = GNUNET_new (struct Peer);
    peer->is_remote = GNUNET_NO;
    peer->details.local.cfg = cfg;
    peer->id = peer_id;
    LOG_DEBUG ("Creating peer with id: %u\n",
               (unsigned int) peer->id);
    peer->details.local.peer =
        GNUNET_TESTING_peer_configure (GST_context->system,
                                       peer->details.local.cfg, peer->id,
                                       NULL /* Peer id */ ,
                                       &emsg);
    if (NULL == peer->details.local.peer)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
           "Configuring peer failed: %s\n",
           emsg);
      GNUNET_free (emsg);
      GNUNET_free (peer);
      GNUNET_break (0);
      GNUNET_SERVICE_client_drop (client);
      return;
    }
    peer->details.local.is_running = GNUNET_NO;
    peer_list_add (peer);
    env = GNUNET_MQ_msg (reply,
                         GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
    reply->peer_id = msg->peer_id;
    reply->operation_id = msg->operation_id;
    GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
                    env);
    GNUNET_SERVICE_client_continue (client);
    return;
  }
/**
 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
 *
 * @param cls identification of the client
 * @param msg the actual message
 */
void
handle_link_controllers (void *cls,
                         const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
{
  struct GNUNET_SERVICE_Client *client = cls;
  struct LCFContext *lcf;
  struct Route *route;
  struct Route *new_route;
  uint64_t op_id;
  uint32_t delegated_host_id;
  uint32_t slave_host_id;

  if (NULL == GST_context)
  {
    GNUNET_break (0);
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  delegated_host_id = ntohl (msg->delegated_host_id);
  if (delegated_host_id == GST_context->host_id)
  {
    GNUNET_break (0);
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Trying to link ourselves\n");
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  if ((delegated_host_id >= GST_host_list_size) ||
      (NULL == GST_host_list[delegated_host_id]))
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Delegated host %u not registered with us\n",
         delegated_host_id);
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  slave_host_id = ntohl (msg->slave_host_id);
  if ((slave_host_id >= GST_host_list_size) ||
      (NULL == GST_host_list[slave_host_id]))
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Slave host %u not registered with us\n",
         slave_host_id);
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  if (slave_host_id == delegated_host_id)
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Slave and delegated host are same\n");
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  op_id = GNUNET_ntohll (msg->operation_id);
  if (slave_host_id == GST_context->host_id)    /* Link from us */
  {
    struct Slave *slave;
    struct LinkControllersContext *lcc;

    if (1 != msg->is_subordinate)
    {
      struct Neighbour *n;
      struct NeighbourConnectCtxt *ncc;

      if ((delegated_host_id < neighbour_list_size) &&
        (NULL != neighbour_list[delegated_host_id]))
      {
        GNUNET_break (0);
        GNUNET_SERVICE_client_drop (client);
        return;
      }
      LOG_DEBUG ("Received request to establish a link to host %u\n",
                 delegated_host_id);
      n = GST_create_neighbour (GST_host_list[delegated_host_id]);
      ncc = GNUNET_new (struct NeighbourConnectCtxt);
      ncc->n = n;
      ncc->op_id = op_id;
      ncc->client = client;
      ncc->nh = GST_neighbour_get_connection (n,
                                              &neighbour_connect_cb,
                                              ncc);
      ncc->timeout_task
        = GNUNET_SCHEDULER_add_delayed (GST_timeout,
                                        &timeout_neighbour_connect,
                                        ncc);
      GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
                                        ncc_tail,
                                        ncc);
      GNUNET_SERVICE_client_continue (client);
      return;
    }
    if ( (delegated_host_id < GST_slave_list_size) &&
         (NULL != GST_slave_list[delegated_host_id]) )
    {
      GNUNET_break (0);
      GNUNET_SERVICE_client_drop (client);
      return;
    }
    LOG_DEBUG ("Received request to start and establish a link to host %u\n",
               delegated_host_id);
    slave = GNUNET_new (struct Slave);
    slave->host_id = delegated_host_id;
    slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
                                                               GNUNET_NO);
    slave_list_add (slave);
    lcc = GNUNET_new (struct LinkControllersContext);
    lcc->operation_id = op_id;
    lcc->client = client;
    slave->lcc = lcc;
    slave->controller_proc
      = GNUNET_TESTBED_controller_start (GST_context->master_ip,
                                         GST_host_list[slave->host_id],
                                         &slave_status_cb,
                                         slave);
    new_route = GNUNET_new (struct Route);
    new_route->dest = delegated_host_id;
    new_route->thru = GST_context->host_id;
    route_list_add (new_route);
    return;
  }

  /* Route the request */
  if (slave_host_id >= route_list_size)
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "No route towards slave host");
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  lcf = GNUNET_new (struct LCFContext);
  lcf->delegated_host_id = delegated_host_id;
  lcf->slave_host_id = slave_host_id;
  route = GST_find_dest_route (slave_host_id);
  GNUNET_assert (NULL != route);        /* because we add routes carefully */
  GNUNET_assert (route->dest < GST_slave_list_size);
  GNUNET_assert (NULL != GST_slave_list[route->dest]);
  lcf->is_subordinate = msg->is_subordinate;
  lcf->state = INIT;
  lcf->operation_id = op_id;
  lcf->gateway = GST_slave_list[route->dest];
  lcf->client = client;
  if (NULL == lcf_head)
  {
    GNUNET_assert (NULL == lcf_proc_task_id);
    GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
                                      lcf_tail,
                                      lcf);
    lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
                                                 lcf);
  }
  else
  {
    GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
                                      lcf_tail,
                                      lcf);
  }
  /* FIXME: Adding a new route should happen after the controllers are linked
   * successfully */
  if (1 != msg->is_subordinate)
  {
    GNUNET_SERVICE_client_continue (client);
    return;
  }
  if ( (delegated_host_id < route_list_size) &&
       (NULL != route_list[delegated_host_id]) )
  {
    GNUNET_break_op (0);        /* Are you trying to link delegated host twice
                                 * with is subordinate flag set to GNUNET_YES? */
    GNUNET_SERVICE_client_drop (client);
    return;
  }
  new_route = GNUNET_new (struct Route);
  new_route->dest = delegated_host_id;
  new_route->thru = route->dest;
  route_list_add (new_route);
  GNUNET_SERVICE_client_continue (client);
}
/**
 * Callback for set operation results. Called for each element
 * that needs to be removed from the result set.
 *
 * @param cls closure with the `struct BobServiceSession`
 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
 * @param status what has happened with the set intersection?
 */
static void
cb_intersection_element_removed (void *cls,
                                 const struct GNUNET_SET_Element *element,
                                 enum GNUNET_SET_Status status)
{
  struct BobServiceSession *s = cls;
  struct GNUNET_SCALARPRODUCT_Element *se;

  switch (status)
  {
  case GNUNET_SET_STATUS_OK:
    /* this element has been removed from the set */
    se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
                                            element->data);
    GNUNET_assert (NULL != se);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Removed element with key %s and value %lld\n",
         GNUNET_h2s (&se->key),
         (long long) GNUNET_ntohll (se->value));
    GNUNET_assert (GNUNET_YES ==
                   GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
                                                         element->data,
                                                         se));
    GNUNET_free (se);
    return;
  case GNUNET_SET_STATUS_DONE:
    s->intersection_op = NULL;
    GNUNET_break (NULL == s->intersection_set);
    GNUNET_CADET_receive_done (s->cadet->channel);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Finished intersection, %d items remain\n",
         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
    if (s->client_received_element_count ==
        GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
    {
      /* CADET transmission from Alice is also already done,
         start with our own reply */
      transmit_bobs_cryptodata_message (s);
    }
    return;
  case GNUNET_SET_STATUS_HALF_DONE:
    /* unexpected for intersection */
    GNUNET_break (0);
    return;
  case GNUNET_SET_STATUS_FAILURE:
    /* unhandled status code */
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Set intersection failed!\n");
    s->intersection_op = NULL;
    if (NULL != s->intersection_set)
    {
      GNUNET_SET_destroy (s->intersection_set);
      s->intersection_set = NULL;
    }
    s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
    prepare_client_end_notification (s);
    return;
  default:
    GNUNET_break (0);
    return;
  }
}
Beispiel #20
0
/**
 * Type of a function to call when we receive a message
 * from the service.
 *
 * @param cls closure
 * @param msg message received, NULL on timeout or fatal error
 */
static void
message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_PSYCSTORE_Handle *h = cls;
  struct GNUNET_PSYCSTORE_OperationHandle *op;
  const struct OperationResult *opres;
  const struct CountersResult *cres;
  const struct FragmentResult *fres;
  const struct StateResult *sres;
  const char *str;

  if (NULL == msg)
  {
    reschedule_connect (h);
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received message of type %d from PSYCstore service.\n",
       ntohs (msg->type));
  uint16_t size = ntohs (msg->size);
  uint16_t type = ntohs (msg->type);
  switch (type)
  {
  case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE:
    if (size < sizeof (struct OperationResult))
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received message of type %d with length %lu bytes. "
           "Expected >= %lu\n",
           type, size, sizeof (struct OperationResult));
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    opres = (const struct OperationResult *) msg;
    str = (const char *) &opres[1];
    if ( (size > sizeof (struct OperationResult)) &&
	 ('\0' != str[size - sizeof (struct OperationResult) - 1]) )
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    if (size == sizeof (struct OperationResult))
      str = "";

    op = find_op_by_id (h, GNUNET_ntohll (opres->op_id));
    if (NULL == op)
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "No callback registered for operation with ID %" PRIu64 ".\n",
           type, GNUNET_ntohll (opres->op_id));
    }
    else
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "Received result message (type %d) with operation ID: %" PRIu64 "\n",
           type, op->op_id);

      int64_t result_code = GNUNET_ntohll (opres->result_code) + INT64_MIN;
      GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
      if (NULL != op->res_cb)
      {
        const struct StateSyncRequest *ssreq;
        switch (ntohs (op->msg->type))
        {
        case GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC:
          ssreq = (const struct StateSyncRequest *) op->msg;
          if (!(ssreq->flags & STATE_OP_LAST
                || GNUNET_OK != result_code))
            op->res_cb = NULL;
          break;
        }
      }
      if (NULL != op->res_cb)
        op->res_cb (op->cls, result_code, str, size - sizeof (*opres));
      GNUNET_free (op);
    }
    break;

  case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS:
    if (size != sizeof (struct CountersResult))
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received message of type %d with length %lu bytes. "
           "Expected %lu\n",
           type, size, sizeof (struct CountersResult));
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    cres = (const struct CountersResult *) msg;

    op = find_op_by_id (h, GNUNET_ntohll (cres->op_id));
    if (NULL == op)
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "No callback registered for operation with ID %" PRIu64 ".\n",
           type, GNUNET_ntohll (cres->op_id));
    }
    else
    {
      GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
      if (NULL != op->data_cb)
        ((GNUNET_PSYCSTORE_CountersCallback)
         op->data_cb) (op->cls,
                       ntohl (cres->result_code),
                       GNUNET_ntohll (cres->max_fragment_id),
                       GNUNET_ntohll (cres->max_message_id),
                       GNUNET_ntohll (cres->max_group_generation),
                       GNUNET_ntohll (cres->max_state_message_id));
      GNUNET_free (op);
    }
    break;

  case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT:
    if (size < sizeof (struct FragmentResult))
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received message of type %d with length %lu bytes. "
           "Expected >= %lu\n",
           type, size, sizeof (struct FragmentResult));
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    fres = (const struct FragmentResult *) msg;
    struct GNUNET_MULTICAST_MessageHeader *mmsg =
      (struct GNUNET_MULTICAST_MessageHeader *) &fres[1];
    if (size != sizeof (struct FragmentResult) + ntohs (mmsg->header.size))
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received message of type %d with length %lu bytes. "
           "Expected = %lu\n",
           type, size,
           sizeof (struct FragmentResult) + ntohs (mmsg->header.size));
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    op = find_op_by_id (h, GNUNET_ntohll (fres->op_id));
    if (NULL == op)
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "No callback registered for operation with ID %" PRIu64 ".\n",
           type, GNUNET_ntohll (fres->op_id));
    }
    else
    {
      if (NULL != op->data_cb)
        ((GNUNET_PSYCSTORE_FragmentCallback)
         op->data_cb) (op->cls, mmsg, ntohl (fres->psycstore_flags));
    }
    break;

  case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE:
    if (size < sizeof (struct StateResult))
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received message of type %d with length %lu bytes. "
           "Expected >= %lu\n",
           type, size, sizeof (struct StateResult));
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    sres = (const struct StateResult *) msg;
    const char *name = (const char *) &sres[1];
    uint16_t name_size = ntohs (sres->name_size);

    if (name_size <= 2 || '\0' != name[name_size - 1])
    {
      LOG (GNUNET_ERROR_TYPE_ERROR,
           "Received state result message (type %d) with invalid name.\n",
           type);
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }

    op = find_op_by_id (h, GNUNET_ntohll (sres->op_id));
    if (NULL == op)
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "No callback registered for operation with ID %" PRIu64 ".\n",
           type, GNUNET_ntohll (sres->op_id));
    }
    else
    {
      if (NULL != op->data_cb)
        ((GNUNET_PSYCSTORE_StateCallback)
         op->data_cb) (op->cls, name, (char *) &sres[1] + name_size,
                       ntohs (sres->header.size) - sizeof (*sres) - name_size);
    }
    break;

  default:
    GNUNET_break (0);
    reschedule_connect (h);
    return;
  }

  GNUNET_CLIENT_receive (h->client, &message_handler, h,
                         GNUNET_TIME_UNIT_FOREVER_REL);
}
Beispiel #21
0
/**
 * Handle incoming PSYC message.
 *
 * @param recv  Receive handle.
 * @param msg   The message.
 *
 * @return #GNUNET_OK on success,
 *         #GNUNET_SYSERR on receive error.
 */
int
GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
                             const struct GNUNET_PSYC_MessageHeader *msg)
{
  uint16_t size = ntohs (msg->header.size);
  uint32_t flags = ntohl (msg->flags);
  uint64_t message_id;

  GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG,
                           (struct GNUNET_MessageHeader *) msg);

  if (GNUNET_PSYC_MESSAGE_STATE_START == recv->state)
  {
    recv->message_id = GNUNET_ntohll (msg->message_id);
    recv->flags = flags;
    recv->slave_key = msg->slave_key;
    recv->mod_value_size = 0;
    recv->mod_value_size_expected = 0;
  }
  else if (GNUNET_ntohll (msg->message_id) != recv->message_id)
  {
    // FIXME
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n",
         GNUNET_ntohll (msg->message_id), recv->message_id);
    GNUNET_break_op (0);
    recv_error (recv);
    return GNUNET_SYSERR;
  }
  else if (flags != recv->flags)
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Unexpected message flags. Got: %lu, expected: %lu\n",
         flags, recv->flags);
    GNUNET_break_op (0);
    recv_error (recv);
    return GNUNET_SYSERR;
  }
  message_id = recv->message_id;

  uint16_t pos = 0, psize = 0, ptype, size_eq, size_min;

  for (pos = 0; sizeof (*msg) + pos < size; pos += psize)
  {
    const struct GNUNET_MessageHeader *pmsg
      = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos);
    psize = ntohs (pmsg->size);
    ptype = ntohs (pmsg->type);
    size_eq = size_min = 0;

    if (psize < sizeof (*pmsg) || sizeof (*msg) + pos + psize > size)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  "Dropping message of type %u with invalid size %u.\n",
                  ptype, psize);
      recv_error (recv);
      return GNUNET_SYSERR;
    }

    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Received message part of type %u and size %u from PSYC.\n",
                ptype, psize);
    GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);

    switch (ptype)
    {
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
      size_min = sizeof (struct GNUNET_PSYC_MessageMethod);
      break;
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
      size_min = sizeof (struct GNUNET_PSYC_MessageModifier);
      break;
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
      size_min = sizeof (struct GNUNET_MessageHeader);
      break;
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
      size_eq = sizeof (struct GNUNET_MessageHeader);
      break;
    default:
      GNUNET_break_op (0);
      recv_error (recv);
      return GNUNET_SYSERR;
    }

    if (! ((0 < size_eq && psize == size_eq)
           || (0 < size_min && size_min <= psize)))
    {
      GNUNET_break_op (0);
      recv_error (recv);
      return GNUNET_SYSERR;
    }

    switch (ptype)
    {
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
    {
      struct GNUNET_PSYC_MessageMethod *meth
        = (struct GNUNET_PSYC_MessageMethod *) pmsg;

      if (GNUNET_PSYC_MESSAGE_STATE_START != recv->state)
      {
        LOG (GNUNET_ERROR_TYPE_WARNING,
             "Dropping out of order message method (%u).\n",
             recv->state);
        /* It is normal to receive an incomplete message right after connecting,
         * but should not happen later.
         * FIXME: add a check for this condition.
         */
        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }

      if ('\0' != *((char *) meth + psize - 1))
      {
        LOG (GNUNET_ERROR_TYPE_WARNING,
             "Dropping message with malformed method. "
             "Message ID: %" PRIu64 "\n", recv->message_id);
        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }
      recv->state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
      break;
    }
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
    {
      if (!(GNUNET_PSYC_MESSAGE_STATE_METHOD == recv->state
            || GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
            || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state))
      {
        LOG (GNUNET_ERROR_TYPE_WARNING,
             "Dropping out of order message modifier (%u).\n",
             recv->state);
        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }

      struct GNUNET_PSYC_MessageModifier *mod
        = (struct GNUNET_PSYC_MessageModifier *) pmsg;

      uint16_t name_size = ntohs (mod->name_size);
      recv->mod_value_size_expected = ntohl (mod->value_size);
      recv->mod_value_size = psize - sizeof (*mod) - name_size;

      if (psize < sizeof (*mod) + name_size
          || '\0' != *((char *) &mod[1] + name_size - 1)
          || recv->mod_value_size_expected < recv->mod_value_size)
      {
        LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n");
        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }
      recv->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
      break;
    }
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
    {
      recv->mod_value_size += psize - sizeof (*pmsg);

      if (!(GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
            || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state)
          || recv->mod_value_size_expected < recv->mod_value_size)
      {
        LOG (GNUNET_ERROR_TYPE_WARNING,
             "Dropping out of order message modifier continuation "
             "!(%u == %u || %u == %u) || %lu < %lu.\n",
             GNUNET_PSYC_MESSAGE_STATE_MODIFIER, recv->state,
             GNUNET_PSYC_MESSAGE_STATE_MOD_CONT, recv->state,
             recv->mod_value_size_expected, recv->mod_value_size);
        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }
      break;
    }
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
    {
      if (recv->state < GNUNET_PSYC_MESSAGE_STATE_METHOD
          || recv->mod_value_size_expected != recv->mod_value_size)
      {
        LOG (GNUNET_ERROR_TYPE_WARNING,
             "Dropping out of order message data fragment "
             "(%u < %u || %lu != %lu).\n",
             recv->state, GNUNET_PSYC_MESSAGE_STATE_METHOD,
             recv->mod_value_size_expected, recv->mod_value_size);

        GNUNET_break_op (0);
        recv_error (recv);
        return GNUNET_SYSERR;
      }
      recv->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
      break;
    }
    }

    if (NULL != recv->message_part_cb)
      recv->message_part_cb (recv->cb_cls, &recv->slave_key,
                             recv->message_id, recv->flags,
                             0, // FIXME: data_offset
                             pmsg);

    switch (ptype)
    {
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
    case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
      GNUNET_PSYC_receive_reset (recv);
      break;
    }
  }

  if (NULL != recv->message_cb)
    recv->message_cb (recv->cb_cls, message_id, flags, msg);
  return GNUNET_OK;
}
Beispiel #22
0
static void
run (void *cls, char *const *args, const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  struct GNUNET_PSYCSTORE_PluginFunctions *db;

  ok = 1;
  db = load_plugin (cfg);
  if (NULL == db)
  {
    FPRINTF (stderr,
             "%s",
	     "Failed to initialize PSYCstore.  "
             "Database likely not setup, skipping test.\n");
    ok = 77;
    return;
  }

  /* Store & test membership */

  LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");

  channel_key = GNUNET_CRYPTO_eddsa_key_create ();
  slave_key = GNUNET_CRYPTO_ecdsa_key_create ();

  GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
                                                  &channel_pub_key);
  GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);

  LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");

  GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
                                                    &slave_pub_key, GNUNET_YES,
                                                    4, 2, 1));

  LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");

  GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
                                                    &slave_pub_key, 4));

  GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
                                                    &slave_pub_key, 2));

  GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
                                                   &slave_pub_key, 1));

  /* Store & get messages */

  LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");

  struct GNUNET_MULTICAST_MessageHeader *msg
    = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
  GNUNET_assert (msg != NULL);

  msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));

  uint64_t fragment_id = INT64_MAX - 1;
  msg->fragment_id = GNUNET_htonll (fragment_id);

  uint64_t message_id = INT64_MAX - 10;
  msg->message_id = GNUNET_htonll (message_id);

  uint64_t group_generation = INT64_MAX - 3;
  msg->group_generation = GNUNET_htonll (group_generation);

  msg->hop_counter = htonl (9);
  msg->fragment_offset = GNUNET_htonll (0);
  msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);

  GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));

  msg->purpose.size = htonl (ntohs (msg->header.size)
                             - sizeof (msg->header)
                             - sizeof (msg->hop_counter)
                             - sizeof (msg->signature));
  msg->purpose.purpose = htonl (234);
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");

  struct FragmentClosure fcls = { 0 };
  fcls.n = 0;
  fcls.msg[0] = msg;
  fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;

  GNUNET_assert (
    GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
                                     fcls.flags[0]));

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);

  uint64_t ret_frags = 0;
  GNUNET_assert (
    GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
                                   fragment_id, fragment_id,
                                   &ret_frags, fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");

  fcls.n = 0;
  GNUNET_assert (
    GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
                                           GNUNET_ntohll (msg->message_id),
                                           GNUNET_ntohll (msg->fragment_offset),
                                           fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
  GNUNET_assert (
    GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
                                        GNUNET_ntohll (msg->message_id),
                                        GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);

  fcls.n = 0;
  fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;

  GNUNET_assert (
    GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
                                   fragment_id, fragment_id,
                                   &ret_frags, fragment_cb, &fcls));

  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");

  struct GNUNET_MULTICAST_MessageHeader *msg1
    = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));

  GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));

  msg1->fragment_id = GNUNET_htonll (INT64_MAX);
  msg1->fragment_offset = GNUNET_htonll (32768);

  fcls.n = 0;
  fcls.msg[1] = msg1;
  fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;

  GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
                                                  fcls.flags[1]));

  LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");

  GNUNET_assert (
    GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
                                  message_id, message_id, 0,
                                  &ret_frags, fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 2 && ret_frags == 2);

  /* Message counters */

  LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");

  fragment_id = 0;
  message_id = 0;
  group_generation = 0;
  GNUNET_assert (
    GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
                                           &fragment_id, &message_id,
                                           &group_generation)
    && fragment_id == GNUNET_ntohll (msg1->fragment_id)
    && message_id == GNUNET_ntohll (msg1->message_id)
    && group_generation == GNUNET_ntohll (msg1->group_generation));

  /* Modify state */

  LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");

  LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");

  message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
  GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
                                                      message_id, 0));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_foo",
                                                   C2ARG("one two three")));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_foo_bar", slave_key,
                                                   sizeof (*slave_key)));

  GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
                                                    message_id));

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");

  struct StateClosure scls = { 0 };
  scls.n = 0;
  scls.value[0] = "one two three";
  scls.value_size[0] = strlen ("one two three");

  GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
                                             state_cb, &scls));
  GNUNET_assert (scls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");

  scls.n = 0;
  scls.value[1] = slave_key;
  scls.value_size[1] = sizeof (*slave_key);

  GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_foo", state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
                                                    state_cb, &scls));
  GNUNET_assert (scls.n == 0);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");

  GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
                                                       &channel_pub_key));

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
                                                     state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  /* State counters */

  LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");

  uint64_t max_state_msg_id = 0;
  GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
                                                      &max_state_msg_id)
                 && max_state_msg_id == message_id);

  /* State sync */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");

  scls.n = 0;
  scls.value[0] = channel_key;
  scls.value_size[0] = sizeof (*channel_key);
  scls.value[1] = "three two one";
  scls.value_size[1] = strlen ("three two one");

  GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));

  GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
                                                     "_sync_bar", scls.value[0],
                                                     scls.value_size[0]));

  GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
                                                     "_sync_foo", scls.value[1],
                                                     scls.value_size[1]));

  GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
                                                  max_state_msg_id,
                                                  INT64_MAX - 5));

  GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_foo", state_cb, &scls));
  GNUNET_assert (scls.n == 0);

  GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_sync", state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  scls.n = 0;
  GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
                                                    state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  /* Modify state after sync */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");

  message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
  GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
                                                      message_id,
                                                      message_id - max_state_msg_id));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_sync_foo",
                                                   C2ARG("five six seven")));

  GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
                                                    message_id));

  /* Reset state */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
  GNUNET_assert (scls.n == 0);

  ok = 0;

  if (NULL != channel_key)
  {
    GNUNET_free (channel_key);
    channel_key = NULL;
  }
  if (NULL != slave_key)
  {
    GNUNET_free (slave_key);
    slave_key = NULL;
  }

  unload_plugin (db);
}
Beispiel #23
0
/**
 * Iterate over the results for a particular key
 * in the datastore.
 *
 * @param cls closure with the 'struct Plugin'
 * @param offset offset of the result (modulo num-results);
 *        specific ordering does not matter for the offset
 * @param key maybe NULL (to match all entries)
 * @param vhash hash of the value, maybe NULL (to
 *        match all values that have the right key).
 *        Note that for DBlocks there is no difference
 *        betwen key and vhash, but for other blocks
 *        there may be!
 * @param type entries of which type are relevant?
 *     Use 0 for any type.
 * @param proc function to call on the matching value;
 *        will be called once with a NULL if no value matches
 * @param proc_cls closure for iter
 */
static void
postgres_plugin_get_key (void *cls, 
			 uint64_t offset,
                         const struct GNUNET_HashCode *key,
                         const struct GNUNET_HashCode *vhash,
                         enum GNUNET_BLOCK_Type type,
			 PluginDatumProcessor proc,
                         void *proc_cls)
{
  struct Plugin *plugin = cls;
  uint32_t utype = type;
  PGresult *ret;
  uint64_t total;
  uint64_t limit_off;

  if (0 != type)
  {
    if (NULL != vhash)
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_auto_from_type (vhash),
	GNUNET_PQ_query_param_uint32 (&utype),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "count_getvt",
				     params);
    }
    else
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_uint32 (&utype),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "count_gett",
				     params);
    }
  }
  else
  {
    if (NULL != vhash)
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_auto_from_type (vhash),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "count_getv",
				     params);
    }
    else
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "count_get",
				     params);
    }
  }

  if (GNUNET_OK !=
      GNUNET_POSTGRES_check_result (plugin->dbh, 
				    ret,
				    PGRES_TUPLES_OK, 
				    "PQexecParams", 
				    "count"))
  {
    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 
	  GNUNET_TIME_UNIT_ZERO_ABS, 0);
    return;
  }
  if ( (PQntuples (ret) != 1) || 
       (PQnfields (ret) != 1) ||
       (PQgetlength (ret, 0, 0) != sizeof (uint64_t)))
  {
    GNUNET_break (0);
    PQclear (ret);
    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 
	  GNUNET_TIME_UNIT_ZERO_ABS, 0);
    return;
  }
  total = GNUNET_ntohll (*(const uint64_t *) PQgetvalue (ret, 0, 0));
  PQclear (ret);
  if (0 == total)
  {
    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 
	  GNUNET_TIME_UNIT_ZERO_ABS, 0);
    return;
  }
  limit_off = offset % total;

  if (0 != type)
  {
    if (NULL != vhash)
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_auto_from_type (&vhash),
	GNUNET_PQ_query_param_uint32 (&utype),
	GNUNET_PQ_query_param_uint64 (&limit_off),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "getvt",
				     params);
    }
    else
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_uint32 (&utype),
	GNUNET_PQ_query_param_uint64 (&limit_off),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "gett",
				     params);
    }
  }
  else
  {
    if (NULL != vhash)
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_auto_from_type (&vhash),
	GNUNET_PQ_query_param_uint64 (&limit_off),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "getv",
				     params);
    }
    else
    {
      struct GNUNET_PQ_QueryParam params[] = { 
	GNUNET_PQ_query_param_auto_from_type (key),
	GNUNET_PQ_query_param_uint64 (&limit_off),
	GNUNET_PQ_query_param_end
      };
      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
				     "get",
				     params);
    }
  }
  process_result (plugin,
		  proc,
		  proc_cls, 
		  ret, 
		  __FILE__, __LINE__);
}
/**
 * Obtain a random key-value pair from the datacache.
 *
 * @param cls closure (our `struct Plugin`)
 * @param iter maybe NULL (to just count)
 * @param iter_cls closure for @a iter
 * @return the number of results found, zero (datacache empty) or one
 */
static unsigned int
postgres_plugin_get_random (void *cls,
                            GNUNET_DATACACHE_Iterator iter,
                            void *iter_cls)
{
  struct Plugin *plugin = cls;
  unsigned int off;
  uint32_t off_be;
  struct GNUNET_TIME_Absolute expiration_time;
  uint32_t size;
  unsigned int path_len;
  const struct GNUNET_PeerIdentity *path;
  const struct GNUNET_HashCode *key;
  unsigned int type;
  PGresult *res;
  const char *paramValues[] = {
    (const char *) &off_be
  };
  int paramLengths[] = {
    sizeof (off_be)
  };
  const int paramFormats[] = { 1 };

  if (0 == plugin->num_items)
    return 0;
  if (NULL == iter)
    return 1;
  off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
                                  plugin->num_items);
  off_be = htonl (off);
  res =
    PQexecPrepared (plugin->dbh, "get_random",
                    1, paramValues, paramLengths, paramFormats,
                    1);
  if (GNUNET_OK !=
      GNUNET_POSTGRES_check_result (plugin->dbh,
                                    res,
                                    PGRES_TUPLES_OK,
                                    "PQexecPrepared",
				    "get_random"))
  {
    GNUNET_break (0);
    return 0;
  }
  if (0 == PQntuples (res))
  {
    GNUNET_break (0);
    return 0;
  }
  if ( (5 != PQnfields (res)) ||
       (sizeof (uint64_t) != PQfsize (res, 0)) ||
       (sizeof (uint32_t) != PQfsize (res, 1)) ||
       (sizeof (struct GNUNET_HashCode) != PQfsize (res, 4)) )
  {
    GNUNET_break (0);
    PQclear (res);
    return 0;
  }
  expiration_time.abs_value_us =
    GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, 0, 0));
  type = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1));
  size = PQgetlength (res, 0, 2);
  path_len = PQgetlength (res, 0, 3);
  if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break (0);
    path_len = 0;
  }
  path_len %= sizeof (struct GNUNET_PeerIdentity);
  path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, 0, 3);
  key = (const struct GNUNET_HashCode *) PQgetvalue (res, 0, 4);
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Found random value with key %s of size %u bytes and type %u in database\n",
       GNUNET_h2s (key),
       (unsigned int) size,
       (unsigned int) type);
  (void) iter (iter_cls,
               key,
               size,
               PQgetvalue (res, 0, 2),
               (enum GNUNET_BLOCK_Type) type,
               expiration_time,
               path_len,
               path);
  PQclear (res);
  return 1;
}
/**
 * Iterate over the results that are "close" to a particular key in
 * the datacache.  "close" is defined as numerically larger than @a
 * key (when interpreted as a circular address space), with small
 * distance.
 *
 * @param cls closure (internal context for the plugin)
 * @param key area of the keyspace to look into
 * @param num_results number of results that should be returned to @a iter
 * @param iter maybe NULL (to just count)
 * @param iter_cls closure for @a iter
 * @return the number of results found
 */
static unsigned int
postgres_plugin_get_closest (void *cls,
                             const struct GNUNET_HashCode *key,
                             unsigned int num_results,
                             GNUNET_DATACACHE_Iterator iter,
                             void *iter_cls)
{
  struct Plugin *plugin = cls;
  uint32_t nbo_limit = htonl (num_results);
  const char *paramValues[] = {
    (const char *) key,
    (const char *) &nbo_limit,
  };
  int paramLengths[] = {
    sizeof (struct GNUNET_HashCode),
    sizeof (nbo_limit)

  };
  const int paramFormats[] = { 1, 1 };
  struct GNUNET_TIME_Absolute expiration_time;
  uint32_t size;
  unsigned int type;
  unsigned int cnt;
  unsigned int i;
  unsigned int path_len;
  const struct GNUNET_PeerIdentity *path;
  PGresult *res;

  res =
      PQexecPrepared (plugin->dbh,
                      "get_closest",
                      2,
                      paramValues,
                      paramLengths,
                      paramFormats,
                      1);
  if (GNUNET_OK !=
      GNUNET_POSTGRES_check_result (plugin->dbh,
                                    res,
                                    PGRES_TUPLES_OK,
                                    "PQexecPrepared",
				    "get_closest"))
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Ending iteration (postgres error)\n");
    return 0;
  }

  if (0 == (cnt = PQntuples (res)))
  {
    /* no result */
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Ending iteration (no more results)\n");
    PQclear (res);
    return 0;
  }
  if (NULL == iter)
  {
    PQclear (res);
    return cnt;
  }
  if ( (5 != PQnfields (res)) ||
       (sizeof (uint64_t) != PQfsize (res, 0)) ||
       (sizeof (uint32_t) != PQfsize (res, 1)) ||
       (sizeof (struct GNUNET_HashCode) != PQfsize (res, 4)) )
  {
    GNUNET_break (0);
    PQclear (res);
    return 0;
  }
  for (i = 0; i < cnt; i++)
  {
    expiration_time.abs_value_us =
        GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0));
    type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1));
    size = PQgetlength (res, i, 2);
    path_len = PQgetlength (res, i, 3);
    if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
    {
      GNUNET_break (0);
      path_len = 0;
    }
    path_len %= sizeof (struct GNUNET_PeerIdentity);
    path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3);
    key = (const struct GNUNET_HashCode *) PQgetvalue (res, i, 4);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Found result of size %u bytes and type %u in database\n",
	 (unsigned int) size,
         (unsigned int) type);
    if (GNUNET_SYSERR ==
        iter (iter_cls,
              key,
              size,
              PQgetvalue (res, i, 2),
              (enum GNUNET_BLOCK_Type) type,
	      expiration_time,
	      path_len,
	      path))
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
	   "Ending iteration (client error)\n");
      PQclear (res);
      return cnt;
    }
  }
  PQclear (res);
  return cnt;
}
Beispiel #26
0
/**
 * Type of a function to call when we receive a message
 * from the service.
 *
 * @param cls closure
 * @param msg message received, NULL on timeout or fatal error
 */
static void
process_result_message (void *cls, const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_DATASTORE_Handle *h = cls;
  struct GNUNET_DATASTORE_QueueEntry *qe;
  struct ResultContext rc;
  const struct DataMessage *dm;
  int was_transmitted;

  if (NULL == msg)
  {
    qe = h->queue_head;
    GNUNET_assert (NULL != qe);
    rc = qe->qc.rc;
    was_transmitted = qe->was_transmitted;
    free_queue_entry (qe);
    if (GNUNET_YES == was_transmitted)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
           _("Failed to receive response from database.\n"));
      do_disconnect (h);
    }
    else
    {
      process_queue (h);
    }
    if (NULL != rc.proc)
      rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS,
               0);
    return;
  }
  if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END)
  {
    GNUNET_break (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader));
    qe = h->queue_head;
    rc = qe->qc.rc;
    GNUNET_assert (GNUNET_YES == qe->was_transmitted);
    free_queue_entry (qe);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Received end of result set, new queue size is %u\n", h->queue_size);
    h->retry_time = GNUNET_TIME_UNIT_ZERO;
    h->result_count = 0;
    process_queue (h);
    if (rc.proc != NULL)
      rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS,
               0);
    return;
  }
  qe = h->queue_head;
  GNUNET_assert (NULL != qe);
  rc = qe->qc.rc;
  if (GNUNET_YES != qe->was_transmitted)
  {
    GNUNET_break (0);
    free_queue_entry (qe);
    h->retry_time = GNUNET_TIME_UNIT_ZERO;
    do_disconnect (h);
    if (rc.proc != NULL)
      rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS,
               0);
    return;
  }
  if ((ntohs (msg->size) < sizeof (struct DataMessage)) ||
      (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_DATA) ||
      (ntohs (msg->size) !=
       sizeof (struct DataMessage) +
       ntohl (((const struct DataMessage *) msg)->size)))
  {
    GNUNET_break (0);
    free_queue_entry (qe);
    h->retry_time = GNUNET_TIME_UNIT_ZERO;
    do_disconnect (h);
    if (rc.proc != NULL)
      rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS,
               0);
    return;
  }
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (h->stats, gettext_noop ("# Results received"), 1,
                            GNUNET_NO);
#endif
  dm = (const struct DataMessage *) msg;
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received result %llu with type %u and size %u with key %s\n",
       (unsigned long long) GNUNET_ntohll (dm->uid), ntohl (dm->type),
       ntohl (dm->size), GNUNET_h2s (&dm->key));
  free_queue_entry (qe);
  h->retry_time = GNUNET_TIME_UNIT_ZERO;
  process_queue (h);
  if (rc.proc != NULL)
    rc.proc (rc.proc_cls, &dm->key, ntohl (dm->size), &dm[1], ntohl (dm->type),
             ntohl (dm->priority), ntohl (dm->anonymity),
             GNUNET_TIME_absolute_ntoh (dm->expiration),
             GNUNET_ntohll (dm->uid));
}
Beispiel #27
0
/**
 * Handler for ARM replies.
 *
 * @param cls our `struct GNUNET_ARM_Handle`
 * @param msg the message received from the arm service
 */
static void
client_notify_handler (void *cls,
                       const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_ARM_Handle *h = cls;
  const struct GNUNET_ARM_Message *arm_msg;
  const struct GNUNET_ARM_ResultMessage *res;
  const struct GNUNET_ARM_ListResultMessage *lres;
  struct ARMControlMessage *cm;
  const char **list;
  const char *pos;
  uint64_t id;
  enum GNUNET_ARM_Result result;
  uint16_t size_check;
  uint16_t rcount;
  uint16_t msize;
  unsigned char fail;

  list = NULL;
  rcount = 0;
  if (NULL == msg)
  {
    LOG (GNUNET_ERROR_TYPE_INFO,
         _("Client was disconnected from arm service, trying to reconnect.\n"));
    reconnect_arm_later (h);
    return;
  }
  msize = ntohs (msg->size);
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Processing message of type %u and size %u from arm service\n",
       ntohs (msg->type), msize);
  if (msize < sizeof (struct GNUNET_ARM_Message))
  {
    GNUNET_break (0);
    reconnect_arm_later (h);
    return;
  }
  arm_msg = (const struct GNUNET_ARM_Message *) msg;
  GNUNET_break (0 == ntohl (arm_msg->reserved));
  id = GNUNET_ntohll (arm_msg->request_id);
  cm = find_cm_by_id (h, id);
  if (NULL == cm)
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Message with unknown id %llu\n",
         id);
    return;
  }
  fail = GNUNET_NO;
  switch (ntohs (msg->type))
  {
  case GNUNET_MESSAGE_TYPE_ARM_RESULT:
    if (msize < sizeof (struct GNUNET_ARM_ResultMessage))
    {
      GNUNET_assert (0);
      fail = GNUNET_YES;
    }
    break;
  case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT:
    if (msize < sizeof (struct GNUNET_ARM_ListResultMessage))
    {
      GNUNET_break (0);
      fail = GNUNET_YES;
      break;
    }
    size_check = 0;
    lres = (const struct GNUNET_ARM_ListResultMessage *) msg;
    rcount = ntohs (lres->count);
    {
      unsigned int i;

      list = GNUNET_malloc (sizeof (const char *) * rcount);
      pos = (const char *)&lres[1];
      for (i = 0; i < rcount; i++)
      {
        const char *end = memchr (pos, 0, msize - size_check);
        if (NULL == end)
        {
          GNUNET_break (0);
          fail = GNUNET_YES;
          break;
        }
        list[i] = pos;
        size_check += (end - pos) + 1;
        pos = end + 1;
      }
      if (GNUNET_YES == fail)
      {
        GNUNET_free (list);
        list = NULL;
      }
    }
    break;
  default:
    fail = GNUNET_YES;
    break;
  }
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cm->timeout_task_id);
  GNUNET_SCHEDULER_cancel (cm->timeout_task_id);
  GNUNET_CONTAINER_DLL_remove (h->control_sent_head,
                               h->control_sent_tail, cm);
  if (GNUNET_YES == fail)
  {
    reconnect_arm_later (h);
    GNUNET_free (cm->msg);
    GNUNET_free (cm);
    return;
  }
  if ( (GNUNET_MESSAGE_TYPE_ARM_RESULT == ntohs (msg->type)) &&
       (0 == strcasecmp ((const char *) &cm->msg[1],
			 "arm")) &&
       (NULL != (res = (const struct GNUNET_ARM_ResultMessage *) msg)) &&
       (GNUNET_ARM_RESULT_STOPPING == ntohl (res->result)) )
  {
    /* special case: if we are stopping 'gnunet-service-arm', we do not just
       wait for the result message, but also wait for the service to close
       the connection (and then we have to close our client handle as well);
       this is done by installing a different receive handler, waiting for
       the connection to go down */
    if (NULL != h->thm)
    {
      GNUNET_break (0);
      cm->result_cont (h->thm->cont_cls,
		       GNUNET_ARM_REQUEST_SENT_OK,
                       (const char *) &h->thm->msg[1],
		       GNUNET_ARM_RESULT_IS_NOT_KNOWN);
      GNUNET_free (h->thm->msg);
      GNUNET_free (h->thm);
    }
    h->thm = cm;
    GNUNET_CLIENT_receive (h->client, &arm_termination_handler, h,
			   GNUNET_TIME_UNIT_FOREVER_REL);
    return;
  }
  GNUNET_CLIENT_receive (h->client, &client_notify_handler, h,
                         GNUNET_TIME_UNIT_FOREVER_REL);
  switch (ntohs (msg->type))
  {
  case GNUNET_MESSAGE_TYPE_ARM_RESULT:
    res = (const struct GNUNET_ARM_ResultMessage *) msg;
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Received response from ARM for service `%s': %u\n",
         (const char *) &cm->msg[1], ntohs (msg->type));
    result = (enum GNUNET_ARM_Result) ntohl (res->result);
    if (NULL != cm->result_cont)
      cm->result_cont (cm->cont_cls, GNUNET_ARM_REQUEST_SENT_OK,
                       (const char *) &cm->msg[1], result);
    break;
  case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT:
    if (NULL != cm->list_cont)
        cm->list_cont (cm->cont_cls, GNUNET_ARM_REQUEST_SENT_OK, rcount,
                       list);
    GNUNET_free_non_null (list);
    break;
  }
  GNUNET_free (cm->msg);
  GNUNET_free (cm);
}