Many messages generated by an IRC server are sent to multiple
recipients.  Previous versions of ircd used DBuf to store these
messages until they could actually be sent.  The problem with using a
DBuf for this, though, is that there are multiple copies of the same
message hanging around.  Another problem is that there is at least one
strcpy() or equivalent call for each destination the message is sent
to.  A simple solution to this problem is to use messages queues.
This file documents the MsgQ interface for ircd.

The MsgQ interface is loosely based on the API for DBuf.  Although the
structures are vastly different, most calls, including several of the
macros, are similar to certain pieces of the DBuf API.  This made
retrofitting ircd with MsgQ support much simpler.

<struct>
struct MsgCounts {
  int alloc;
  int used;
};

The MsgCounts structure may be used for determining how much memory is
in use by the MsgQ system.  The _alloc_ element is a count of the
total number of structures (of whatever type) that have been
allocated; the _used_ element is a count of how many are actually in
use.  MsgQ never releases any of its allocated memory; instead, it
places unused structures onto a free list.
</struct>

<struct>
struct MsgBuf;

The MsgBuf structure contains the actual message, along with a
reference count and the message's length.  None of its fields are
directly accessible by the application.
</struct>

<struct>
struct MsgQ;

The MsgQ structure is a structure allocated by the application that is
used by the MsgQ system to describe an entire message queue, including
both normal and priority queues.  None of its fields are directly
accessible by the application.
</struct>

<global>
struct MsgCounts msgBufCounts;	/* resource count for struct MsgBuf */

This global variable counts the number of MsgBuf structures that have
been allocated.  This may be used to determine how much memory is in
use by the MsgQ system.
</global>

<global>
struct MsgCounts msgCounts;	/* resource count for struct Msg */

This global variable counts the number of Msg structures that have
been allocated.  The Msg structure describes the link between a queue
and a message.  It is not accessible to the application, and so not
further documented here.
</global>

<function>
unsigned int MsgQLength(struct MsgQ* mq);

This macro returns the number of bytes in a particular user's message
queue.
</function>

<function>
unsigned int MsgQCount(struct MsgQ* mq);

This macro returns the number of messages in a particular user's
message queue.
</function>

<function>
void MsgQClear(struct MsgQ* mq);

This macro simply clears the content of a particular message queue.
NOTE: This macro evaluates its argument twice.
</function>

<function>
void msgq_init(struct MsgQ *mq);

This function initializes a caller-allocated message queue to be
empty.  Calling this function on a message queue with messages in it
WILL RESULT IN A MEMORY LEAK.
</function>

<function>
void msgq_delete(struct MsgQ *mq, unsigned int length);

This function removes the given number of bytes from the message
queue.  If entire messages have been sent, they will be unlinked from
the queue.  The _length_ parameter does not need to correspond to a
given message's length; the MsgQ system is able to deal with messages
that have only partially been sent.
</function>

<function>
int msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
		unsigned int *len);

The msgq_mapiov() function takes a struct MsgQ (specified by the _mq_
parameter) and a caller allocated struct iovec array (specified by the
_iov_ parameter) and maps the contents of the message into the struct
iovec array.  The _count_ parameter must indicate the total number of
elements available for msgq_mapiov() to use.  The _len_ parameter must
be a pointer to an unsigned int, and upon return from the function
will contain the total number of bytes that have been mapped into the
struct iovec array.  This function returns the number of struct iovec
elements that have been filled.  For more information about the
purpose of struct iovec, see your system's man page for the writev()
function.
</function>

<function>
struct MsgBuf *msgq_make(struct Client *dest, const char *format, ...);

This function allocates a struct MsgBuf and calls ircd_vsnprintf()
with the _dest_ and _format_ parameters to fill it in.  Most callers
should use the send_buffer() function (declared in send.h) to attach
the struct MsgBuf to a client's message queue.
</function>

<function>
struct MsgBuf *msgq_vmake(struct Client *dest, const char *format, va_list vl);

This function is identical to msgq_make() except that it takes a
va_list (given by the _vl_ parameter) and calls ircd_vsnprintf() to
format the message.
</function>

<function>
void msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format,
		 ...);

Occasionally a caller is not able to completely compute a message
before calling msgq_make().  When this happens, the msgq_append()
function may be called to append more text onto the struct MsgBuf
specified by the _mb_ parameter.  As with msgq_make(), the _dest_ and
_format_ parameters are passed to ircd_vsnprintf(), along with the
additional arguments.
</function>

<function>
void msgq_clean(struct MsgBuf *mb);

As mentioned above, struct MsgBuf includes a reference count.  When
that reference count reaches zero, the structure is released.  The
reference count is set to 1 by msgq_make() and msgq_vmake().  Once a
given message has been attached to all the queues it needs to be, the
caller should call the msgq_clean() function to decrement this
reference count.  This function will place the struct MsgBuf back onto
the free list if it did not get attached to any message queues.  The
msgq_delete() function calls msgq_clean() internally, so the
application need not call msgq_clean() explicitly afterwards.
</function>

<function>
void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio);

This function is used to attach a given struct MsgBuf, as specified by
the _mb_ parameter, to a given message queue.  The _prio_ parameter,
if non-zero, specifies that the message should be placed on the
priority queue.  This function is called by send_buffer(), defined in
send.h; most applications should call that function, rather than this
one.
</function>

<function>
void msgq_count_memory(size_t *msg_alloc, size_t *msg_used,
		       size_t *msgbuf_alloc, size_t *msgbuf_used);

This function simply takes the counts kept in msgBufCounts and
msgCounts and multiplies them by the appropriate structure sizes,
storing the resulting sizes into its parameters.
</function>

<function>
unsigned int msgq_bufleft(struct MsgBuf *mb);

This function is for use in conjunction with msgq_append().  It
returns the total number of bytes of free storage in the given _mb_.
</function>

<authors>
Kev <klmitch@mit.edu>
</authors>

<changelog>
[2001-6-15 Kev] Initial documentation for the MsgQ functions.
</changelog>
