/** * 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); }
/** * 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; }