/**
 * Transmit a message to a particular peer.
 *
 * @param car original request that was queued and then solicited;
 *            this handle will now be 'owned' by the SESSIONS subsystem
 * @param msg message to transmit
 * @param cork is corking allowed?
 * @param priority how important is this message
 */
void
GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
                       const struct GNUNET_MessageHeader *msg,
                       int cork,
                       enum GNUNET_CORE_Priority priority)
{
  struct Session *session;
  struct SessionMessageEntry *sme;
  struct SessionMessageEntry *pos;
  size_t msize;

  session = find_session (&car->target);
  if (NULL == session)
    return;
  msize = ntohs (msg->size);
  sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + msize);
  memcpy (&sme[1], msg, msize);
  sme->size = msize;
  sme->priority = priority;
  if (GNUNET_YES == cork)
    sme->deadline =
        GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_MAX_CORK_DELAY);
  pos = session->sme_head;
  while ( (NULL != pos) &&
          (pos->priority >= sme->priority) )
    pos = pos->next;
  if (NULL == pos)
    GNUNET_CONTAINER_DLL_insert_tail (session->sme_head,
                                      session->sme_tail,
                                      sme);
  else
    GNUNET_CONTAINER_DLL_insert_after (session->sme_head,
                                       session->sme_tail,
                                       pos->prev,
                                       sme);
  try_transmission (session);
}
예제 #2
0
/**
 * Create a new entry for our priority queue (and possibly discard other entires if
 * the queue is getting too long).
 *
 * @param h handle to the datastore
 * @param msize size of the message to queue
 * @param queue_priority priority of the entry
 * @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 response_proc function to call with replies (can be NULL)
 * @param qc client context (NOT a closure for response_proc)
 * @return NULL if the queue is full
 */
static struct GNUNET_DATASTORE_QueueEntry *
make_queue_entry (struct GNUNET_DATASTORE_Handle *h, size_t msize,
                  unsigned int queue_priority, unsigned int max_queue_size,
                  struct GNUNET_TIME_Relative timeout,
                  GNUNET_CLIENT_MessageHandler response_proc,
                  const union QueueContext *qc)
{
  struct GNUNET_DATASTORE_QueueEntry *ret;
  struct GNUNET_DATASTORE_QueueEntry *pos;
  unsigned int c;

  c = 0;
  pos = h->queue_head;
  while ((pos != NULL) && (c < max_queue_size) &&
         (pos->priority >= queue_priority))
  {
    c++;
    pos = pos->next;
  }
  if (c >= max_queue_size)
  {
    GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue overflows"), 1,
                              GNUNET_NO);
    return NULL;
  }
  ret = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_QueueEntry) + msize);
  ret->h = h;
  ret->response_proc = response_proc;
  ret->qc = *qc;
  ret->timeout = GNUNET_TIME_relative_to_absolute (timeout);
  ret->priority = queue_priority;
  ret->max_queue = max_queue_size;
  ret->message_size = msize;
  ret->was_transmitted = GNUNET_NO;
  if (pos == NULL)
  {
    /* append at the tail */
    pos = h->queue_tail;
  }
  else
  {
    pos = pos->prev;
    /* do not insert at HEAD if HEAD query was already
     * transmitted and we are still receiving replies! */
    if ((pos == NULL) && (h->queue_head->was_transmitted))
      pos = h->queue_head;
  }
  c++;
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue entries created"),
                            1, GNUNET_NO);
#endif
  GNUNET_CONTAINER_DLL_insert_after (h->queue_head, h->queue_tail, pos, ret);
  h->queue_size++;
  ret->task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_queue_entry, ret);
  for (pos = ret->next; NULL != pos; pos = pos->next)
  {
    if ((pos->max_queue < h->queue_size) && (pos->was_transmitted == GNUNET_NO))
    {
      GNUNET_assert (pos->response_proc != NULL);
      /* move 'pos' element to head so that it will be
       * killed on 'NULL' call below */
      LOG (GNUNET_ERROR_TYPE_DEBUG, "Dropping request from datastore queue\n");     
      GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, pos);
      GNUNET_CONTAINER_DLL_insert (h->queue_head, h->queue_tail, pos);
      GNUNET_STATISTICS_update (h->stats,
                                gettext_noop
                                ("# Requests dropped from datastore queue"), 1,
                                GNUNET_NO);
      GNUNET_assert (h->queue_head == pos);
      pos->response_proc (h, NULL);
      break;
    }
  }
  return ret;
}