예제 #1
0
/**
 * We've succeeded in establishing a connection.
 *
 * @param connection the connection we tried to establish
 */
static void
connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
{
  LOG (GNUNET_ERROR_TYPE_DEBUG, 
       "Connection to `%s' succeeded! (%p)\n",
       GNUNET_a2s (connection->addr, connection->addrlen), connection);
  /* trigger jobs that waited for the connection */
  if (NULL != connection->receiver)
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Connection succeeded, starting with receiving data (%p)\n", 
	 connection);
    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task);
    connection->read_task =
      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
                                     (connection->receive_timeout), connection->sock,
                                     &receive_ready, connection);
  }
  if (NULL != connection->nth.notify_ready)
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Connection succeeded, starting with sending data (%p)\n",
         connection);
    GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK);
    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
    connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
    GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK);
    connection->write_task =
        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
                                        (connection->nth.transmit_timeout), connection->sock,
                                        &transmit_ready, connection);
  }
}
/**
 * PEERINFO calls this function to let us know about a possible peer
 * that we might want to connect to.
 *
 * @param cls closure (not used)
 * @param peer potential peer to connect to
 * @param hello HELLO for this peer (or NULL)
 * @param err_msg NULL if successful, otherwise contains error message
 */
static void
process_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
              const struct GNUNET_HELLO_Message *hello, const char *err_msg)
{
  struct Peer *pos;

  if (err_msg != NULL)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                _("Error in communication with PEERINFO service: %s\n"),
                err_msg);
    GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
    peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL);
    return;
  }
  GNUNET_assert (peer != NULL);
  if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
    return;                     /* that's me! */
  if (hello == NULL)
  {
    /* free existing HELLO, if any */
    pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
    if (NULL != pos)
    {
      GNUNET_free_non_null (pos->hello);
      pos->hello = NULL;
      if (pos->filter != NULL)
      {
        GNUNET_CONTAINER_bloomfilter_free (pos->filter);
        pos->filter = NULL;
      }
      if ((GNUNET_NO == pos->is_connected) && (GNUNET_NO == pos->is_friend) &&
          (0 ==
           GNUNET_TIME_absolute_get_remaining (pos->
                                               greylisted_until).rel_value))
        free_peer (NULL, &pos->pid.hashPubKey, pos);
    }
    return;
  }
  consider_for_advertising (hello);
  pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
  if (pos == NULL)
    pos = make_peer (peer, hello, GNUNET_NO);
  GNUNET_assert (NULL != pos);
  if (GNUNET_YES == pos->is_connected)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n",
                GNUNET_i2s (peer));
    return;
  }
  if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\n",
                GNUNET_i2s (peer));
    return;                     /* peer still greylisted */
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s'\n",
              GNUNET_i2s (peer));
  schedule_attempt_connect (pos);
}
예제 #3
0
/**
 * Figure out when and how to transmit to the given peer.
 *
 * @param cls the 'struct PeerPlan'
 * @param tc scheduler context
 */
static void
schedule_peer_transmission (void *cls,
                            const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct PeerPlan *pp = cls;
  struct GSF_RequestPlan *rp;
  size_t msize;
  struct GNUNET_TIME_Relative delay;

  pp->task = GNUNET_SCHEDULER_NO_TASK;
  if (NULL != pp->pth)
  {
    GSF_peer_transmit_cancel_ (pp->pth);
    pp->pth = NULL;
  }
  /* move ready requests to priority queue */
  while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) &&
         (GNUNET_TIME_absolute_get_remaining
          (rp->earliest_transmission).rel_value == 0))
  {
    GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap));
    rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority);
  }
  if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap))
  {
    /* priority heap (still) empty, check for delay... */
    rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap);
    if (NULL == rp)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n",
                  pp);
      return;                   /* both queues empty */
    }
    delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Sleeping for %llu ms before retrying requests on plan %p.\n",
                (unsigned long long) delay.rel_value, pp);
    GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"),
                           delay.rel_value, GNUNET_NO);

    pp->task =
        GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp);
    return;
  }
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"),
                            1, GNUNET_NO);
#endif
  /* process from priority heap */
  rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp);
  GNUNET_assert (NULL != rp);
  msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL);
  pp->pth =
      GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority,
                          GNUNET_TIME_UNIT_FOREVER_REL, msize,
                          &transmit_message_callback, pp);
  GNUNET_assert (NULL != pp->pth);
}
/**
 * Do address validation again to keep address valid.
 *
 * @param cls the 'struct ValidationEntry'
 * @param tc scheduler context (unused)
 */
static void
revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct ValidationEntry *ve = cls;
  struct GNUNET_TIME_Relative canonical_delay;
  struct GNUNET_TIME_Relative delay;
  struct GST_BlacklistCheck *bc;
  uint32_t rdelay;

  ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK;
  delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block);
  /* How long until we can possibly permit the next PING? */
  canonical_delay =
      (ve->in_use ==
       GNUNET_YES) ? CONNECTED_PING_FREQUENCY
      : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value >
          0) ? VALIDATED_PING_FREQUENCY : UNVALIDATED_PING_KEEPALIVE);
  if (delay.rel_value > canonical_delay.rel_value * 2)
  {
    /* situation changed, recalculate delay */
    delay = canonical_delay;
    ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay);
  }
  if (delay.rel_value > 0)
  {
    /* should wait a bit longer */
    ve->revalidation_task =
        GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve);
    return;
  }
  ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay);

  /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */
  rdelay =
      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
                                canonical_delay.rel_value);
  delay =
      GNUNET_TIME_relative_add (canonical_delay,
                                GNUNET_TIME_relative_multiply
                                (GNUNET_TIME_UNIT_MILLISECONDS, rdelay));
  ve->revalidation_task =
      GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve);

  /* start PINGing by checking blacklist */
  GNUNET_STATISTICS_update (GST_stats,
                            gettext_noop ("# address revalidations started"), 1,
                            GNUNET_NO);
  bc = GST_blacklist_test_allowed (&ve->pid, ve->address->transport_name,
                                   &transmit_ping_if_allowed, ve);
  if (NULL != bc)
    ve->bc = bc;                /* only set 'bc' if 'transmit_ping_if_allowed' was not already
                                 * called... */
}
예제 #5
0
파일: client.c 프로젝트: muggenhor/GNUnet
/**
 * This task is run if we should re-try connection to the
 * service after a while.
 *
 * @param cls our `struct GNUNET_CLIENT_TransmitHandle` of the request
 * @param tc unused
 */
static void
client_delayed_retry (void *cls,
		      const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct GNUNET_CLIENT_TransmitHandle *th = cls;
  struct GNUNET_TIME_Relative delay;

  th->reconnect_task = NULL;
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  {
    /* give up, was shutdown */
    th->client->th = NULL;
    th->notify (th->notify_cls, 0, NULL);
    GNUNET_free (th);
    return;
  }
  th->client->connection =
    do_connect (th->client->service_name,
		th->client->cfg,
		th->client->attempts++);
  th->client->first_message = GNUNET_YES;
  if (NULL == th->client->connection)
  {
    /* could happen if we're out of sockets */
    delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (th->timeout),
                                      th->client->back_off);
    th->client->back_off = GNUNET_TIME_STD_BACKOFF (th->client->back_off);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Transmission failed %u times, trying again in %s.\n",
         MAX_ATTEMPTS - th->attempts_left,
         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
    GNUNET_assert (NULL == th->th);
    GNUNET_assert (NULL == th->reconnect_task);
    th->reconnect_task =
        GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
    return;
  }
  th->th =
      GNUNET_CONNECTION_notify_transmit_ready (th->client->connection, th->size,
                                               GNUNET_TIME_absolute_get_remaining
                                               (th->timeout), &client_notify,
                                               th);
  if (NULL == th->th)
  {
    GNUNET_break (0);
    th->client->th = NULL;
    th->notify (th->notify_cls, 0, NULL);
    GNUNET_free (th);
    return;
  }
}
예제 #6
0
static void
do_stop (void *cls,
         const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  char *fn = cls;

  if (0 ==
      GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time,
                                                                    TIMEOUT)).rel_value_us)
  {
    GNUNET_break (0);
    ret = 1;
  }
  else
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Finished download, shutting down\n",
                (unsigned long long) FILESIZE);
  }
  if (NULL != fn)
  {
    GNUNET_DISK_directory_remove (fn);
    GNUNET_free (fn);
  }
  GNUNET_SCHEDULER_shutdown ();
}
/**
 * Iterator which adds the given address to the set of validated
 * addresses.
 *
 * @param cls original HELLO message
 * @param address the address
 * @param expiration expiration time
 * @return GNUNET_OK (keep the address)
 */
static int
add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address,
                   struct GNUNET_TIME_Absolute expiration)
{
  const struct GNUNET_HELLO_Message *hello = cls;
  struct ValidationEntry *ve;
  struct GNUNET_PeerIdentity pid;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;

  if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
    return GNUNET_OK;           /* expired */
  if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) ||
      (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key)))
  {
    GNUNET_break (0);
    return GNUNET_OK;           /* invalid HELLO !? */
  }
  if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity)))
  {
    /* Peerinfo returned own identity, skip validation */
    return GNUNET_OK;
  }

  ve = find_validation_entry (&public_key, address);
  ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration);

  if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task)
    ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
  GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0);
  return GNUNET_OK;
}
static void
do_stop (void *cls)
{
  struct GNUNET_TIME_Relative del;
  char *fancy;

  GNUNET_SCHEDULER_shutdown ();
  if (0 ==
      GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (start_time,
                                                                    TIMEOUT)).rel_value_us)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Timeout during download, shutting down with error\n");
    ok = 1;
  }
  else
  {
    del = GNUNET_TIME_absolute_get_duration (start_time);
    if (del.rel_value_us == 0)
      del.rel_value_us = 1;
    fancy =
        GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) *
                                        1000000LL / del.rel_value_us);
    FPRINTF (stdout,
             "Download speed was %s/s\n",
             fancy);
    GNUNET_free (fancy);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Finished download, shutting down\n");
  }
}
/**
 * An iterator over a set of items stored in the datastore
 * that deletes until we're happy with respect to our quota.
 *
 * @param cls closure
 * @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
 *
 * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue
 *         (continue on call to "next", of course),
 *         GNUNET_NO to delete the item and continue (if supported)
 */
static int
quota_processor (void *cls, 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)
{
  unsigned long long *need = cls;

  if (NULL == key)
    return GNUNET_SYSERR;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Deleting %llu bytes of low-priority (%u) content `%s' of type %u at %s prior to expiration (still trying to free another %llu bytes)\n",
              (unsigned long long) (size + GNUNET_DATASTORE_ENTRY_OVERHEAD),
	      (unsigned int) priority,
              GNUNET_h2s (key), type,
	      GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (expiration),
						      GNUNET_YES),
	      *need);
  if (size + GNUNET_DATASTORE_ENTRY_OVERHEAD > *need)
    *need = 0;
  else
    *need -= size + GNUNET_DATASTORE_ENTRY_OVERHEAD;
  if (priority > 0)
    min_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
  else
    min_expiration = expiration;
  GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# bytes purged (low-priority)"),
                            size, GNUNET_YES);
  GNUNET_CONTAINER_bloomfilter_remove (filter, key);
  return GNUNET_NO;
}
예제 #10
0
/**
 * We've transmitted the iteration request.  Now get ready to process
 * the results (or handle transmission error).
 *
 * @param cls the 'struct GNUNET_PEERINFO_IteratorContext'
 * @param emsg error message, NULL if transmission worked
 */
static void
iterator_start_receive (void *cls, const char *emsg)
{
  struct GNUNET_PEERINFO_IteratorContext *ic = cls;
  struct GNUNET_PEERINFO_Handle *h = ic->h;
  GNUNET_PEERINFO_Processor cb;
  void *cb_cls;

  ic->ac = NULL;
  if (NULL != emsg)
  {
    cb = ic->callback;
    cb_cls = ic->callback_cls;
    GNUNET_PEERINFO_iterate_cancel (ic);
    reconnect (h);
    if (NULL != cb)
      cb (cb_cls, NULL, NULL, emsg);
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
       "PEERINFO");
  ic->in_receive = GNUNET_YES;
  if (GNUNET_NO == h->in_receive)
  {
    h->in_receive = GNUNET_YES;
    GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h,
			   GNUNET_TIME_absolute_get_remaining (ic->timeout));
  }
}
/**
 * If possible, write a shutdown message to the target
 * buffer and destroy the client connection.
 *
 * @param cls the "struct GNUNET_CLIENT_Connection" to destroy
 * @param size number of bytes available in buf
 * @param buf NULL on error, otherwise target buffer
 * @return number of bytes written to buf
 */
static size_t
write_shutdown (void *cls, size_t size, void *buf)
{
  struct GNUNET_MessageHeader *msg;
  struct ShutdownContext *shutdown_ctx = cls;

  if (size < sizeof (struct GNUNET_MessageHeader))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
		  _("Failed to transmit shutdown request to client.\n"));
      shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
      GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
      GNUNET_free (shutdown_ctx);
      return 0;			/* client disconnected */
    }

  GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
			 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
  shutdown_ctx->cancel_task =
    GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
				  (shutdown_ctx->timeout),
				  &service_shutdown_cancel, shutdown_ctx);
  msg = (struct GNUNET_MessageHeader *) buf;
  msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
  return sizeof (struct GNUNET_MessageHeader);
}
/**
 * Task that looks at the 'retry_heap' and transmits all of the requests
 * on the heap that are ready for transmission.  Then re-schedules
 * itself (unless the heap is empty).
 *
 * @param cls unused
 * @param tc scheduler context
 */
static void
transmit_next_request_task (void *cls,
                            const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct ClientQueryRecord *cqr;
  struct GNUNET_TIME_Relative delay;

  retry_task = GNUNET_SCHEDULER_NO_TASK;
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
    return;
  while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap)))
  {
    cqr->hnode = NULL;
    delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time);
    if (delay.rel_value_us > 0)
    {
      cqr->hnode =
          GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
                                        cqr->retry_time.abs_value_us);
      retry_task =
          GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task,
                                        NULL);
      return;
    }
    transmit_request (cqr);
    cqr->hnode =
        GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
                                      cqr->retry_time.abs_value_us);
  }
}
예제 #13
0
파일: client.c 프로젝트: muggenhor/GNUnet
/**
 * Function called to notify a client about the socket
 * begin ready to queue the message.  @a buf will be
 * NULL and @a size zero if the socket was closed for
 * writing in the meantime.
 *
 * @param cls closure of type `struct TransmitGetResponseContext *`
 * @param size number of bytes available in @a buf
 * @param buf where the callee should write the message
 * @return number of bytes written to @a buf
 */
static size_t
transmit_for_response (void *cls,
		       size_t size,
		       void *buf)
{
  struct TransmitGetResponseContext *tc = cls;
  uint16_t msize;

  tc->client->tag = NULL;
  msize = ntohs (tc->hdr->size);
  if (NULL == buf)
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Could not submit request, not expecting to receive a response.\n");
    if (NULL != tc->rn)
      tc->rn (tc->rn_cls, NULL);
    GNUNET_free (tc);
    return 0;
  }
  GNUNET_assert (size >= msize);
  memcpy (buf, tc->hdr, msize);
  GNUNET_CLIENT_receive (tc->client,
                         tc->rn,
                         tc->rn_cls,
                         GNUNET_TIME_absolute_get_remaining (tc->timeout));
  GNUNET_free (tc);
  return msize;
}
예제 #14
0
파일: client.c 프로젝트: muggenhor/GNUnet
/**
 * Send the 'TEST' message to the service.  If successful, prepare to
 * receive the reply.
 *
 * @param cls the `struct GNUNET_CLIENT_TestHandle` of the test
 * @param size number of bytes available in @a buf
 * @param buf where to write the message
 * @return number of bytes written to @a buf
 */
static size_t
write_test (void *cls, size_t size, void *buf)
{
  struct GNUNET_CLIENT_TestHandle *th = cls;
  struct GNUNET_MessageHeader *msg;

  th->th = NULL;
  if (size < sizeof (struct GNUNET_MessageHeader))
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Failed to transmit TEST request.\n");
    service_test_report (th, GNUNET_NO);
    return 0;                   /* client disconnected */
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Transmitting `%s' request.\n",
       "TEST");
  msg = (struct GNUNET_MessageHeader *) buf;
  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
  GNUNET_CLIENT_receive (th->client,
			 &confirm_handler, th,
                         GNUNET_TIME_absolute_get_remaining
                         (th->test_deadline));
  return sizeof (struct GNUNET_MessageHeader);
}
예제 #15
0
/**
 * Receive data from the given connection.  Note that this function will
 * call "receiver" asynchronously using the scheduler.  It will
 * "immediately" return.  Note that there MUST only be one active
 * receive call per connection at any given point in time (so do not
 * call receive again until the receiver callback has been invoked).
 *
 * @param connection connection handle
 * @param max maximum number of bytes to read
 * @param timeout maximum amount of time to wait
 * @param receiver function to call with received data
 * @param receiver_cls closure for receiver
 */
void
GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max,
                           struct GNUNET_TIME_Relative timeout,
                           GNUNET_CONNECTION_Receiver receiver,
                           void *receiver_cls)
{
  GNUNET_assert ((GNUNET_SCHEDULER_NO_TASK == connection->read_task) &&
                 (NULL == connection->receiver));
  GNUNET_assert (NULL != receiver);
  connection->receiver = receiver;
  connection->receiver_cls = receiver_cls;
  connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
  connection->max = max;
  if (NULL != connection->sock)
  {
    connection->read_task =
      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
                                     (connection->receive_timeout), connection->sock,
                                     &receive_ready, connection);
    return;
  }
  if ((NULL == connection->dns_active) && (NULL == connection->ap_head))
  {
    connection->receiver = NULL;
    receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
    return;
  }
}
예제 #16
0
/**
 * Request a list of running services.
 *
 * @param h handle to ARM
 * @param timeout how long to wait before failing for good
 * @param cont callback to invoke after request is sent or is not sent
 * @param cont_cls closure for callback
 */
void
GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h,
                                 struct GNUNET_TIME_Relative timeout,
                                 GNUNET_ARM_ServiceListCallback cont,
                                 void *cont_cls)
{
  struct ARMControlMessage *cm;
  struct GNUNET_ARM_Message *msg;

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Requesting LIST from ARM service with timeout: %s\n",
       GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES));
  cm = GNUNET_new (struct ARMControlMessage);
  cm->h = h;
  cm->list_cont = cont;
  cm->cont_cls = cont_cls;
  cm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
  msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message));
  msg->header.size = htons (sizeof (struct GNUNET_ARM_Message));
  msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST);
  msg->reserved = htonl (0);
  cm->msg = msg;
  GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
                                    h->control_pending_tail, cm);
  cm->timeout_task_id =
      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
                                    (cm->timeout), &control_message_timeout, cm);
  trigger_next_request (h, GNUNET_NO);
}
/**
 * Find a peer that would be reasonable for advertising.
 *
 * @param cls closure
 * @param pid identity of a peer
 * @param value 'struct Peer*' for the peer we are considering
 * @return GNUNET_YES (continue iteration)
 */
static int
find_advertisable_hello (void *cls, const struct GNUNET_HashCode * pid, void *value)
{
  struct FindAdvHelloContext *fah = cls;
  struct Peer *pos = value;
  struct GNUNET_TIME_Relative rst_time;
  size_t hs;

  if (pos == fah->peer)
    return GNUNET_YES;
  if (pos->hello == NULL)
    return GNUNET_YES;
  rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
  if (0 == rst_time.rel_value)
  {
    /* time to discard... */
    GNUNET_CONTAINER_bloomfilter_free (pos->filter);
    setup_filter (pos);
  }
  fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv);
  hs = GNUNET_HELLO_size (pos->hello);
  if (hs > fah->max_size)
    return GNUNET_YES;
  if (GNUNET_NO ==
      GNUNET_CONTAINER_bloomfilter_test (pos->filter,
                                         &fah->peer->pid.hashPubKey))
    fah->result = pos;
  return GNUNET_YES;
}
예제 #18
0
/**
 * Calculate when we would like to send the next HELLO to this
 * peer and ask for it.
 *
 * @param cls for which peer to schedule the HELLO
 */
static void
schedule_next_hello (void *cls)
{
  struct Peer *pl = cls;
  struct FindAdvHelloContext fah;
  struct GNUNET_MQ_Envelope *env;
  size_t want;
  struct GNUNET_TIME_Relative delay;
  struct GNUNET_HashCode hc;

  pl->hello_delay_task = NULL;
  GNUNET_assert (NULL != pl->mq);
  /* find applicable HELLOs */
  fah.peer = pl;
  fah.result = NULL;
  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  GNUNET_CONTAINER_multipeermap_iterate (peers,
                                         &find_advertisable_hello,
                                         &fah);
  pl->hello_delay_task =
      GNUNET_SCHEDULER_add_delayed (fah.next_adv,
                                    &schedule_next_hello,
                                    pl);
  if (NULL == fah.result)
    return;
  delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
  if (0 != delay.rel_value_us)
    return;

  want = GNUNET_HELLO_size (fah.result->hello);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Sending HELLO with %u bytes",
	      (unsigned int) want);
  env = GNUNET_MQ_msg_copy (&fah.result->hello->header);
  GNUNET_MQ_send (pl->mq,
		  env);

  /* avoid sending this one again soon */
  GNUNET_CRYPTO_hash (&pl->pid,
		      sizeof (struct GNUNET_PeerIdentity),
		      &hc);
  GNUNET_CONTAINER_bloomfilter_add (fah.result->filter,
				    &hc);

  GNUNET_STATISTICS_update (stats,
			    gettext_noop ("# HELLO messages gossipped"),
			    1,
			    GNUNET_NO);
  /* prepare to send the next one */
  if (NULL != pl->hello_delay_task)
    GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
  pl->next_hello_allowed
    = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
  pl->hello_delay_task
    = GNUNET_SCHEDULER_add_now (&schedule_next_hello,
				pl);
}
/**
 * Schedule a task to try to connect to the specified peer.
 *
 * @param pos peer to connect to
 */
static void
schedule_attempt_connect (struct Peer *pos)
{
  if (GNUNET_SCHEDULER_NO_TASK != pos->attempt_connect_task)
    return;
  pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_connect_attempt),
							    &do_attempt_connect,
							    pos);
}
예제 #20
0
/**
 * Start or stop a service.
 *
 * @param h handle to ARM
 * @param service_name name of the service
 * @param timeout how long to wait before failing for good
 * @param cb callback to invoke when service is ready
 * @param cb_cls closure for callback
 * @param type type of the request
 */
static void
change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
		struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cb,
		void *cb_cls, uint16_t type)
{
  struct ARMControlMessage *cm;
  size_t slen;
  struct GNUNET_ARM_Message *msg;

  slen = strlen (service_name) + 1;
  if (slen + sizeof (struct GNUNET_ARM_Message) >=
      GNUNET_SERVER_MAX_MESSAGE_SIZE)
  {
    GNUNET_break (0);
    if (cb != NULL)
      cb (cb_cls, GNUNET_ARM_REQUEST_TOO_LONG, NULL, 0);
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting %s of service `%s'.\n",
       (GNUNET_MESSAGE_TYPE_ARM_START == type) ? "start" : "termination",
       service_name);
  cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen);
  cm->h = h;
  cm->result_cont = cb;
  cm->cont_cls = cb_cls;
  cm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
  memcpy (&cm[1], service_name, slen);
  msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message) + slen);
  msg->header.size = htons (sizeof (struct GNUNET_ARM_Message) + slen);
  msg->header.type = htons (type);
  msg->reserved = htonl (0);
  memcpy (&msg[1], service_name, slen);
  cm->msg = msg;
  LOG (GNUNET_ERROR_TYPE_DEBUG,
      "Inserting a control message into the queue. Timeout is %s\n",
       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (cm->timeout),
					       GNUNET_NO));
  GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
                                    h->control_pending_tail, cm);
  cm->timeout_task_id =
      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
                                    (cm->timeout), &control_message_timeout, cm);
  trigger_next_request (h, GNUNET_NO);
}
예제 #21
0
/**
 * Function to handle a ring message incoming over cadet
 *
 * @param cls closure, NULL
 * @param channel the channel over which the message arrived
 * @param channel_ctx the channel context, can be NULL
 *                    or point to the `struct Channel`
 * @param message the incoming message
 * @return #GNUNET_OK
 */
static int
handle_cadet_ring_message (void *cls,
                           struct GNUNET_CADET_Channel *channel,
                           void **channel_ctx,
                           const struct GNUNET_MessageHeader *message)
{
  struct Channel *ch = *channel_ctx;
  struct Line *line = ch->line;
  const struct CadetPhoneRingMessage *msg;
  struct GNUNET_MQ_Envelope *env;
  struct ClientPhoneRingMessage *cring;
  struct CadetPhoneRingInfoPS rs;

  msg = (const struct CadetPhoneRingMessage *) message;
  rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
  rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
  rs.line_port = line->line_port;
  rs.target_peer = my_identity;
  rs.expiration_time = msg->expiration_time;

  if (GNUNET_OK !=
      GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
                                  &rs.purpose,
                                  &msg->signature,
                                  &msg->caller_id))
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
  {
    /* ancient call, replay? */
    GNUNET_break_op (0);
    /* Note that our reliance on time here is awkward; better would be
       to use a more complex challenge-response protocol against
       replay attacks.  Left for future work ;-). */
    return GNUNET_SYSERR;
  }
  if (CS_CALLEE_INIT != ch->status)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  GNUNET_CADET_receive_done (channel);
  ch->status = CS_CALLEE_RINGING;
  env = GNUNET_MQ_msg (cring,
                       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
  cring->cid = ch->cid;
  cring->caller_id = msg->caller_id;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sending RING message to client. CID is %u\n",
              (unsigned int) ch->cid);
  GNUNET_MQ_send (line->mq,
                  env);
  return GNUNET_OK;
}
예제 #22
0
/**
 * Test if a given record is expired.
 *
 * @return #GNUNET_YES if the record is expired,
 *         #GNUNET_NO if not
 */
int
GNUNET_GNSRECORD_is_expired (const struct GNUNET_GNSRECORD_Data *rd)
{
  struct GNUNET_TIME_Absolute at;

  if (0 != (rd->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
    return GNUNET_NO;
  at.abs_value_us = rd->expiration_time;
  return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ? GNUNET_YES : GNUNET_NO;
}
예제 #23
0
/**
 * Periodically announce self id in the DHT
 *
 * @param cls closure
 * @param tc task context
 */
static void
announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct GNUNET_HashCode phash;
  const struct GNUNET_HELLO_Message *hello;
  size_t size;
  struct GNUNET_TIME_Absolute expiration;
  struct GNUNET_TIME_Relative retry_time;

  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  {
    announce_id_task = NULL;
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
  /* TODO
   * - Set data expiration in function of X
   * - Adapt X to churn
   */
  hello = GCH_get_mine ();
  if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
  {
    /* Peerinfo gave us no hello yet, try again in a second. */
    announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
                                                     &announce_id, cls);
    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no hello, waiting!\n");
    GNUNET_STATISTICS_update (stats, "# DHT announce skipped (no hello)",
                              1, GNUNET_NO);

    return;
  }
  expiration = GNUNET_HELLO_get_last_expiration (hello);
  retry_time = GNUNET_TIME_absolute_get_remaining (expiration);

  LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
  GNUNET_STATISTICS_update (stats, "# DHT announce",
                            1, GNUNET_NO);
  memset (&phash, 0, sizeof (phash));
  memcpy (&phash, &my_full_id, sizeof (my_full_id));
  GNUNET_DHT_put (dht_handle,   /* DHT handle */
                  &phash,       /* Key to use */
                  dht_replication_level,     /* Replication level */
                  GNUNET_DHT_RO_RECORD_ROUTE
                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
                  size,  /* Size of the data */
                  (const char *) hello, /* Data itself */
                  expiration,  /* Data expiration */
                  retry_time, /* Retry time */
                  NULL,         /* Continuation */
                  NULL);        /* Continuation closure */
  announce_id_task =
      GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
}
예제 #24
0
/**
 * Connection notifies us about failure or success of a transmission
 * request.  Either pass it on to our user or, if possible, retry.
 *
 * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
 * @param size number of bytes available for transmission
 * @param buf where to write them
 * @return number of bytes written to buf
 */
static size_t
client_notify (void *cls, size_t size, void *buf)
{
  struct GNUNET_CLIENT_TransmitHandle *th = cls;
  struct GNUNET_CLIENT_Connection *client = th->client;
  size_t ret;
  struct GNUNET_TIME_Relative delay;

  th->th = NULL;
  client->th = NULL;
  if (NULL == buf)
  {
    delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
    delay.rel_value /= 2;
    if ((GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) ||
        (delay.rel_value < 1))
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "Transmission failed %u times, giving up.\n",
           MAX_ATTEMPTS - th->attempts_left);
      GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL));
      GNUNET_free (th);
      return 0;
    }
    /* auto-retry */
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Failed to connect to `%s', automatically trying again.\n",
         client->service_name);
    if (GNUNET_YES == client->in_receive)
    {
      GNUNET_CONNECTION_receive_cancel (client->connection);
      client->in_receive = GNUNET_NO;
    }    
    GNUNET_CONNECTION_destroy (client->connection);
    client->connection = NULL;
    delay = GNUNET_TIME_relative_min (delay, client->back_off);
    client->back_off =
        GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply
                                  (client->back_off, 2),
                                  GNUNET_TIME_UNIT_SECONDS);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Transmission failed %u times, trying again in %s.\n",
         MAX_ATTEMPTS - th->attempts_left,
         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
    client->th = th;
    th->reconnect_task =
        GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
    return 0;
  }
  GNUNET_assert (size >= th->size);
  ret = th->notify (th->notify_cls, size, buf);
  GNUNET_free (th);
  return ret;
}
/**
 * Check if we have messages for the specified neighbour pending, and
 * if so, check with the transport about sending them out.
 *
 * @param n neighbour to check.
 */
static void
process_queue (struct Neighbour *n)
{
  struct NeighbourMessageEntry *m;

  if (NULL != n->th)
    return;                     /* request already pending */
  m = n->message_head;
  if (NULL == m)
  {
    /* notify sessions that the queue is empty and more messages
     * could thus be queued now */
    GSC_SESSIONS_solicit (&n->peer);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Asking transport for transmission of %u bytes to `%s' in next %s\n",
              (unsigned int) m->size,
              GNUNET_i2s (&n->peer),
              GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (m->deadline),
                                                      GNUNET_NO));
  m->submission_time = GNUNET_TIME_absolute_get ();
  n->th
    = GNUNET_TRANSPORT_notify_transmit_ready (transport,
                                              &n->peer,
                                              m->size,
                                              GNUNET_TIME_absolute_get_remaining (m->deadline),
                                              &transmit_ready,
                                              n);
  if (NULL != n->th)
    return;
  /* message request too large or duplicate request */
  GNUNET_break (0);
  /* discard encrypted message */
  GNUNET_CONTAINER_DLL_remove (n->message_head,
                               n->message_tail,
                               m);
  n->queue_size--;
  GNUNET_free (m);
  process_queue (n);
}
예제 #26
0
/**
 * Process pending requests to the resolver.
 */
static void
process_requests ()
{
    struct GNUNET_RESOLVER_GetMessage *msg;
    char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
    struct GNUNET_RESOLVER_RequestHandle *rh;

    if (NULL == client)
    {
        reconnect ();
        return;
    }
    rh = req_head;
    if (NULL == rh)
    {
        /* nothing to do, release socket really soon if there is nothing
         * else happening... */
        s_task =
            GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
                                          &shutdown_task,
                                          NULL);
        return;
    }
    if (GNUNET_NO != rh->was_transmitted)
        return;                     /* waiting for reply */
    msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
    msg->header.size =
        htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + rh->data_len);
    msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
    msg->direction = htonl (rh->direction);
    msg->af = htonl (rh->af);
    memcpy (&msg[1],
            &rh[1],
            rh->data_len);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Transmitting DNS resolution request to DNS service\n");
    if (GNUNET_OK !=
            GNUNET_CLIENT_transmit_and_get_response (client,
                    &msg->header,
                    GNUNET_TIME_absolute_get_remaining (rh->timeout),
                    GNUNET_YES,
                    &handle_response,
                    rh))
    {
        GNUNET_CLIENT_disconnect (client);
        client = NULL;
        GNUNET_break (0);
        reconnect ();
        return;
    }
    rh->was_transmitted = GNUNET_YES;
}
예제 #27
0
/**
 * Ask the connection to call us once the specified number of bytes
 * are free in the transmission buffer.  May call the notify
 * method immediately if enough space is available.
 *
 * @param connection connection
 * @param size number of bytes to send
 * @param timeout after how long should we give up (and call
 *        notify with buf NULL and size 0)?
 * @param notify function to call
 * @param notify_cls closure for notify
 * @return non-NULL if the notify callback was queued,
 *         NULL if we are already going to notify someone else (busy)
 */
struct GNUNET_CONNECTION_TransmitHandle *
GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
                                         size_t size,
                                         struct GNUNET_TIME_Relative timeout,
                                         GNUNET_CONNECTION_TransmitReadyNotify
                                         notify, void *notify_cls)
{
  if (NULL != connection->nth.notify_ready)
  {
    GNUNET_assert (0);
    return NULL;
  }
  GNUNET_assert (NULL != notify);
  GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
  GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
  connection->nth.notify_ready = notify;
  connection->nth.notify_ready_cls = notify_cls;
  connection->nth.connection = connection;
  connection->nth.notify_size = size;
  connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task);
  if ((NULL == connection->sock) && 
      (NULL == connection->ap_head) &&
      (NULL == connection->dns_active))
  {
    if (GNUNET_SCHEDULER_NO_TASK != connection->write_task)
      GNUNET_SCHEDULER_cancel (connection->write_task);
    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error, connection);
    return &connection->nth;
  }
  if (GNUNET_SCHEDULER_NO_TASK != connection->write_task)
    return &connection->nth; /* previous transmission still in progress */
  if (NULL != connection->sock)
  {
    /* connected, try to transmit now */
    LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmission (%p).\n", connection);
    connection->write_task =
        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
                                        (connection->nth.transmit_timeout),
                                        connection->sock, &transmit_ready, connection);
    return &connection->nth;
  }
  /* not yet connected, wait for connection */
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Need to wait to schedule transmission for connection, adding timeout task (%p).\n", connection);
  connection->nth.timeout_task =
    GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, connection);
  return &connection->nth;
}
예제 #28
0
/**
 * Store an item in the datastore.  If the item is already present,
 * the priorities are summed up and the higher expiration time and
 * lower anonymity level is used.
 *
 * @param h handle to the datastore
 * @param rid reservation ID to use (from "reserve"); use 0 if no
 *            prior reservation was made
 * @param key key for the value
 * @param size number of bytes in data
 * @param data content stored
 * @param type type of the content
 * @param priority priority of the content
 * @param anonymity anonymity-level for the content
 * @param replication how often should the content be replicated to other peers?
 * @param expiration expiration time for the content
 * @param queue_priority ranking of this request in the priority queue
 * @param max_queue_size at what queue size should this request be dropped
 *        (if other requests of higher priority are in the queue)
 * @param timeout timeout for the operation
 * @param cont continuation to call when done
 * @param cont_cls closure for cont
 * @return NULL if the entry was not queued, otherwise a handle that can be used to
 *         cancel; note that even if NULL is returned, the callback will be invoked
 *         (or rather, will already have been invoked)
 */
struct GNUNET_DATASTORE_QueueEntry *
GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid,
                      const struct GNUNET_HashCode * key, size_t size,
                      const void *data, enum GNUNET_BLOCK_Type type,
                      uint32_t priority, uint32_t anonymity,
                      uint32_t replication,
                      struct GNUNET_TIME_Absolute expiration,
                      unsigned int queue_priority, unsigned int max_queue_size,
                      struct GNUNET_TIME_Relative timeout,
                      GNUNET_DATASTORE_ContinuationWithStatus cont,
                      void *cont_cls)
{
  struct GNUNET_DATASTORE_QueueEntry *qe;
  struct DataMessage *dm;
  size_t msize;
  union QueueContext qc;

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Asked to put %u bytes of data under key `%s' for %llu ms\n", size,
       GNUNET_h2s (key),
       GNUNET_TIME_absolute_get_remaining (expiration).rel_value);
  msize = sizeof (struct DataMessage) + size;
  GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
  qc.sc.cont = cont;
  qc.sc.cont_cls = cont_cls;
  qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout,
                         &process_status_message, &qc);
  if (qe == NULL)
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for PUT\n");
    return NULL;
  }
  GNUNET_STATISTICS_update (h->stats, gettext_noop ("# PUT requests executed"),
                            1, GNUNET_NO);
  dm = (struct DataMessage *) &qe[1];
  dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_PUT);
  dm->header.size = htons (msize);
  dm->rid = htonl (rid);
  dm->size = htonl ((uint32_t) size);
  dm->type = htonl (type);
  dm->priority = htonl (priority);
  dm->anonymity = htonl (anonymity);
  dm->replication = htonl (replication);
  dm->reserved = htonl (0);
  dm->uid = GNUNET_htonll (0);
  dm->expiration = GNUNET_TIME_absolute_hton (expiration);
  dm->key = *key;
  memcpy (&dm[1], data, size);
  process_queue (h);
  return qe;
}
예제 #29
0
/**
 * This function is called once we either timeout
 * or have data ready to read.
 *
 * @param cls connection to read from
 * @param tc scheduler context
 */
static void
receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct GNUNET_CONNECTION_Handle *connection = cls;
  char buffer[connection->max];
  ssize_t ret;
  GNUNET_CONNECTION_Receiver receiver;

  connection->read_task = GNUNET_SCHEDULER_NO_TASK;
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  {
    /* ignore shutdown request, go again immediately */
    connection->read_task =
        GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
                                       (connection->receive_timeout), connection->sock,
                                       &receive_ready, connection);
    return;
  }
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
  {
    LOG (GNUNET_ERROR_TYPE_DEBUG,
	 "Receive from `%s' encounters error: timeout (%p)\n",
	 GNUNET_a2s (connection->addr, connection->addrlen),
	 GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value,
	 connection);
    signal_receive_timeout (connection);
    return;
  }
  if (NULL == connection->sock)
  {
    /* connect failed for good */
    signal_receive_error (connection, ECONNREFUSED);
    return;
  }
  GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock));
RETRY:
  ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max);
  if (-1 == ret)
  {
    if (EINTR == errno)
      goto RETRY;
    signal_receive_error (connection, errno);
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "receive_ready read %u/%u bytes from `%s' (%p)!\n", (unsigned int) ret,
       connection->max, GNUNET_a2s (connection->addr, connection->addrlen), connection);
  GNUNET_assert (NULL != (receiver = connection->receiver));
  connection->receiver = NULL;
  receiver (connection->receiver_cls, buffer, ret, connection->addr, connection->addrlen, 0);
}
예제 #30
0
/**
 * Callback function for data received from the network.  Note that
 * both "available" and "errCode" would be 0 if the read simply timed out.
 *
 * @param cls closure
 * @param buf pointer to received data
 * @param available number of bytes availabe in "buf",
 *        possibly 0 (on errors)
 * @param addr address of the sender
 * @param addrlen size of addr
 * @param errCode value of errno (on errors receiving)
 */
static void
receive_helper (void *cls, const void *buf, size_t available,
                const struct sockaddr *addr, socklen_t addrlen, int errCode)
{
  struct GNUNET_CLIENT_Connection *client = cls;
  struct GNUNET_TIME_Relative remaining;
  GNUNET_CLIENT_MessageHandler receive_handler;
  void *receive_handler_cls;

  GNUNET_assert (GNUNET_NO == client->msg_complete);
  GNUNET_assert (GNUNET_YES == client->in_receive);
  client->in_receive = GNUNET_NO;
  if ((0 == available) || (NULL == client->connection) || (0 != errCode))
  {
    /* signal timeout! */
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n",
         (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL",
         STRERROR (errCode));
    if (NULL != (receive_handler = client->receiver_handler))
    {
      receive_handler_cls = client->receiver_handler_cls;
      client->receiver_handler = NULL;
      receive_handler (receive_handler_cls, NULL);
    }
    return;
  }
  /* FIXME: optimize for common fast case where buf contains the
   * entire message and we need no copying... */

  /* slow path: append to array */
  if (client->received_size < client->received_pos + available)
    GNUNET_array_grow (client->received_buf, client->received_size,
                       client->received_pos + available);
  memcpy (&client->received_buf[client->received_pos], buf, available);
  client->received_pos += available;
  check_complete (client);
  /* check for timeout */
  remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout);
  if (0 == remaining.rel_value)
  {
    /* signal timeout! */
    if (NULL != client->receiver_handler)
      client->receiver_handler (client->receiver_handler_cls, NULL);
    return;
  }
  /* back to receive -- either for more data or to call callback! */
  GNUNET_CLIENT_receive (client, client->receiver_handler,
                         client->receiver_handler_cls, remaining);
}