/*
This file is part of GNUnet.
Copyright (C) 2012-2017 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Florian Dold
* @file util/mq.c
* @brief general purpose request queue
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#define LOG(kind,...) GNUNET_log_from (kind, "util-mq",__VA_ARGS__)
struct GNUNET_MQ_Envelope
{
/**
* Messages are stored in a linked list.
* Each queue has its own list of envelopes.
*/
struct GNUNET_MQ_Envelope *next;
/**
* Messages are stored in a linked list
* Each queue has its own list of envelopes.
*/
struct GNUNET_MQ_Envelope *prev;
/**
* Actual allocated message header.
* The GNUNET_MQ_Envelope header is allocated at
* the end of the message.
*/
struct GNUNET_MessageHeader *mh;
/**
* Queue the message is queued in, NULL if message is not queued.
*/
struct GNUNET_MQ_Handle *parent_queue;
/**
* Called after the message was sent irrevocably.
*/
GNUNET_SCHEDULER_TaskCallback sent_cb;
/**
* Closure for @e send_cb
*/
void *sent_cls;
/**
* Flags that were set for this envelope by
* #GNUNET_MQ_env_set_options(). Only valid if
* @e have_custom_options is set.
*/
uint64_t flags;
/**
* Additional options buffer set for this envelope by
* #GNUNET_MQ_env_set_options(). Only valid if
* @e have_custom_options is set.
*/
const void *extra;
/**
* Did the application call #GNUNET_MQ_env_set_options()?
*/
int have_custom_options;
};
/**
* Handle to a message queue.
*/
struct GNUNET_MQ_Handle
{
/**
* Handlers array, or NULL if the queue should not receive messages
*/
struct GNUNET_MQ_MessageHandler *handlers;
/**
* Actual implementation of message sending,
* called when a message is added
*/
GNUNET_MQ_SendImpl send_impl;
/**
* Implementation-dependent queue destruction function
*/
GNUNET_MQ_DestroyImpl destroy_impl;
/**
* Implementation-dependent send cancel function
*/
GNUNET_MQ_CancelImpl cancel_impl;
/**
* Implementation-specific state
*/
void *impl_state;
/**
* Callback will be called when an error occurs.
*/
GNUNET_MQ_ErrorHandler error_handler;
/**
* Closure for the error handler.
*/
void *error_handler_cls;
/**
* Task to asynchronously run #impl_send_continue().
*/
struct GNUNET_SCHEDULER_Task *send_task;
/**
* Linked list of messages pending to be sent
*/
struct GNUNET_MQ_Envelope *envelope_head;
/**
* Linked list of messages pending to be sent
*/
struct GNUNET_MQ_Envelope *envelope_tail;
/**
* Message that is currently scheduled to be
* sent. Not the head of the message queue, as the implementation
* needs to know if sending has been already scheduled or not.
*/
struct GNUNET_MQ_Envelope *current_envelope;
/**
* Map of associations, lazily allocated
*/
struct GNUNET_CONTAINER_MultiHashMap32 *assoc_map;
/**
* Functions to call on queue destruction; kept in a DLL.
*/
struct GNUNET_MQ_DestroyNotificationHandle *dnh_head;
/**
* Functions to call on queue destruction; kept in a DLL.
*/
struct GNUNET_MQ_DestroyNotificationHandle *dnh_tail;
/**
* Additional options buffer set for this queue by
* #GNUNET_MQ_set_options(). Default is 0.
*/
const void *default_extra;
/**
* Flags that were set for this queue by
* #GNUNET_MQ_set_options(). Default is 0.
*/
uint64_t default_flags;
/**
* Next id that should be used for the @e assoc_map,
* initialized lazily to a random value together with
* @e assoc_map
*/
uint32_t assoc_id;
/**
* Number of entries we have in the envelope-DLL.
*/
unsigned int queue_length;
/**
* #GNUNET_YES if GNUNET_MQ_impl_evacuate was called.
* FIXME: is this dead?
*/
int evacuate_called;
/**
* #GNUNET_YES if GNUNET_MQ_impl_send_in_flight() was called.
*/
int in_flight;
};
/**
* Call the message message handler that was registered
* for the type of the given message in the given message queue.
*
* This function is indended to be used for the implementation
* of message queues.
*
* @param mq message queue with the handlers
* @param mh message to dispatch
*/
void
GNUNET_MQ_inject_message (<