blob: 876e3e8ce2b74a20afd08e45b7b2936a3e0baa66 [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for the message buffer pool and message buffers.
*/
#ifndef MESSAGE_HPP_
#define MESSAGE_HPP_
#include <openthread/config.h>
#include "utils/wrap_stdint.h"
#include "utils/wrap_string.h"
#include <openthread/message.h>
#include <openthread/platform/messagepool.h>
#include "openthread-core-config.h"
#include "common/code_utils.hpp"
#include "common/locator.hpp"
#include "mac/mac_frame.hpp"
namespace ot {
/**
* @addtogroup core-message
*
* @brief
* This module includes definitions for the message buffer pool and message buffers.
*
* @{
*
*/
enum
{
kNumBuffers = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS,
kBufferSize = OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE,
};
class Message;
class MessagePool;
class MessageQueue;
class PriorityQueue;
/**
* This structure contains metdata about a Message.
*
*/
struct MessageInfo
{
enum
{
kListAll = 0, ///< Identifies the all messages list (maintained by the MessagePool).
kListInterface = 1, ///< Identifies the list for per-interface message queue.
kNumLists = 2, ///< Number of lists.
};
Message *mNext[kNumLists]; ///< A pointer to the next Message in a doubly linked list.
Message *mPrev[kNumLists]; ///< A pointer to the previous Message in a doubly linked list.
MessagePool *mMessagePool; ///< Identifies the message pool for this message.
union
{
MessageQueue *mMessage; ///< Identifies the message queue (if any) where this message is queued.
PriorityQueue *mPriority; ///< Identifies the priority queue (if any) where this message is queued.
} mQueue; ///< Identifies the queue (if any) where this message is queued.
uint16_t mReserved; ///< Number of header bytes reserved for the message.
uint16_t mLength; ///< Number of bytes within the message.
uint16_t mOffset; ///< A byte offset within the message.
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this.
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
int8_t mInterfaceId; ///< The interface ID.
union
{
uint16_t mPanId; ///< Used for MLE Discover Request and Response messages.
uint8_t mChannel; ///< Used for MLE Announce.
} mPanIdChannel; ///< Used for MLE Discover Request, Response, and Announce messages.
uint8_t mType : 2; ///< Identifies the type of message.
uint8_t mSubType : 4; ///< Identifies the message sub type.
bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required.
bool mLinkSecurity : 1; ///< Indicates whether or not link security is enabled.
uint8_t mPriority : 2; ///< Identifies the message priority level (lower value is higher priority).
bool mInPriorityQ : 1; ///< Indicates whether the message is queued in normal or priority queue.
};
/**
* This class represents a Message buffer.
*
*/
class Buffer : public ::otMessage
{
friend class Message;
public:
/**
* This method returns a pointer to the next message buffer.
*
* @returns A pointer to the next message buffer.
*
*/
class Buffer *GetNextBuffer(void) const { return static_cast<Buffer *>(mNext); }
/**
* This method sets the pointer to the next message buffer.
*
*/
void SetNextBuffer(class Buffer *buf) { mNext = static_cast<otMessage *>(buf); }
private:
/**
* This method returns a pointer to the first byte of data in the first message buffer.
*
* @returns A pointer to the first data byte.
*
*/
uint8_t *GetFirstData(void) { return mBuffer.mHead.mData; }
/**
* This method returns a pointer to the first byte of data in the first message buffer.
*
* @returns A pointer to the first data byte.
*
*/
const uint8_t *GetFirstData(void) const { return mBuffer.mHead.mData; }
/**
* This method returns a pointer to the first data byte of a subsequent message buffer.
*
* @returns A pointer to the first data byte.
*
*/
uint8_t *GetData(void) { return mBuffer.mData; }
/**
* This method returns a pointer to the first data byte of a subsequent message buffer.
*
* @returns A pointer to the first data byte.
*
*/
const uint8_t *GetData(void) const { return mBuffer.mData; }
enum
{
kBufferDataSize = kBufferSize - sizeof(struct otMessage),
kHeadBufferDataSize = kBufferDataSize - sizeof(struct MessageInfo),
};
union
{
struct
{
MessageInfo mInfo;
uint8_t mData[kHeadBufferDataSize];
} mHead;
uint8_t mData[kBufferDataSize];
} mBuffer;
};
/**
* This class represents a message.
*
*/
class Message: public Buffer
{
friend class MessagePool;
friend class MessageQueue;
friend class PriorityQueue;
public:
enum
{
kTypeIp6 = 0, ///< A full uncompressed IPv6 packet
kType6lowpan = 1, ///< A 6lowpan frame
kTypeMacDataPoll = 2, ///< A MAC data poll message
kTypeSupervision = 3, ///< A child supervision frame.
};
enum
{
kSubTypeNone = 0, ///< None
kSubTypeMleAnnounce = 1, ///< MLE Announce
kSubTypeMleDiscoverRequest = 2, ///< MLE Discover Request
kSubTypeMleDiscoverResponse = 3, ///< MLE Discover Response
kSubTypeJoinerEntrust = 4, ///< Joiner Entrust
kSubTypeMplRetransmission = 5, ///< MPL next retransmission message
kSubTypeMleGeneral = 6, ///< General MLE
kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response
kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request
};
enum
{
kPriorityHigh = 0, ///< High priority level.
kPriorityMedium = 1, ///< Medium priority level.
kPriorityLow = 2, ///< Low priority level.
kPriorityVeryLow = 3, ///< Very low priority level.
kNumPriorities = 4, ///< Number of priority levels.
};
/**
* This method frees this message buffer.
*
*/
otError Free(void);
/**
* This method returns a pointer to the next message in the same interface list.
*
* @returns A pointer to the next message in the same interface list or NULL if at the end of the list.
*
*/
Message *GetNext(void) const;
/**
* This method returns the number of bytes in the message.
*
* @returns The number of bytes in the message.
*/
uint16_t GetLength(void) const { return mBuffer.mHead.mInfo.mLength; }
/**
* This method sets the number of bytes in the message.
*
* @param[in] aLength Requested number of bytes in the message.
*
* @retval OT_ERROR_NONE Successfully set the length of the message.
* @retval OT_ERROR_NO_BUFS Failed to grow the size of the message because insufficient buffers were available.
*
*/
otError SetLength(uint16_t aLength);
/**
* This method returns the number of buffers in the message.
*
*/
uint8_t GetBufferCount(void) const;
/**
* This method returns the byte offset within the message.
*
* @returns A byte offset within the message.
*
*/
uint16_t GetOffset(void) const { return mBuffer.mHead.mInfo.mOffset; }
/**
* This method moves the byte offset within the message.
*
* @param[in] aDelta The number of bytes to move the current offset, which may be positive or negative.
*
* @retval OT_ERROR_NONE Successfully moved the byte offset.
* @retval OT_ERROR_INVALID_ARGS The resulting byte offset is not within the existing message.
*
*/
otError MoveOffset(int aDelta);
/**
* This method sets the byte offset within the message.
*
* @param[in] aOffset The number of bytes to move the current offset, which may be positive or negative.
*
* @retval OT_ERROR_NONE Successfully moved the byte offset.
* @retval OT_ERROR_INVALID_ARGS The requested byte offset is not within the existing message.
*
*/
otError SetOffset(uint16_t aOffset);
/**
* This method returns the type of the message.
*
* @returns The type of the message.
*
*/
uint8_t GetType(void) const { return mBuffer.mHead.mInfo.mType; }
/**
* This method sets the message type.
*
* @param[in] aType The message type.
*
*/
void SetType(uint8_t aType) { mBuffer.mHead.mInfo.mType = aType; }
/**
* This method returns the sub type of the message.
*
* @returns The sub type of the message.
*
*/
uint8_t GetSubType(void) const { return mBuffer.mHead.mInfo.mSubType; }
/**
* This method sets the message sub type.
*
* @param[in] aSubType The message sub type.
*
*/
void SetSubType(uint8_t aSubType) { mBuffer.mHead.mInfo.mSubType = aSubType; }
/**
* This method returns whether or not the message is of MLE subtype.
*
* @retval TRUE If message is of MLE subtype.
* @retval FLASE If message is not of MLE subtype.
*
*/
bool IsSubTypeMle(void) const;
/**
* This method returns the message priority level.
*
* @returns The priority level associated with this message.
*
*/
uint8_t GetPriority(void) const { return mBuffer.mHead.mInfo.mPriority; }
/**
* This method sets the messages priority.
* If the message is already queued in a priority queue, changing the priority ensures to
* update the message in the associated queue.
*
* @param[in] aPrority The message priority level.
*
* @retval OT_ERROR_NONE Successfully set the priority for the message.
* @retval OT_ERROR_INVALID_ARGS Priority level is not invalid.
*
*/
otError SetPriority(uint8_t aPriority);
/**
* This method prepends bytes to the front of the message.
*
* On success, this method grows the message by @p aLength bytes.
*
* @param[in] aBuf A pointer to a data buffer.
* @param[in] aLength The number of bytes to prepend.
*
* @retval OT_ERROR_NONE Successfully prepended the bytes.
* @retval OT_ERROR_NO_BUFS Not enough reserved bytes in the message.
*
*/
otError Prepend(const void *aBuf, uint16_t aLength);
/**
* This method removes header bytes from the message.
*
* @param[in] aLength Number of header bytes to remove.
*
* @retval OT_ERROR_NONE Successfully removed header bytes from the message.
*
*/
otError RemoveHeader(uint16_t aLength);
/**
* This method appends bytes to the end of the message.
*
* On success, this method grows the message by @p aLength bytes.
*
* @param[in] aBuf A pointer to a data buffer.
* @param[in] aLength The number of bytes to append.
*
* @retval OT_ERROR_NONE Successfully appended the bytes.
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
*
*/
otError Append(const void *aBuf, uint16_t aLength);
/**
* This method reads bytes from the message.
*
* @param[in] aOffset Byte offset within the message to begin reading.
* @param[in] aLength Number of bytes to read.
* @param[in] aBuf A pointer to a data buffer.
*
* @returns The number of bytes read.
*
*/
uint16_t Read(uint16_t aOffset, uint16_t aLength, void *aBuf) const;
/**
* This method writes bytes to the message.
*
* @param[in] aOffset Byte offset within the message to begin writing.
* @param[in] aLength Number of bytes to write.
* @param[in] aBuf A pointer to a data buffer.
*
* @returns The number of bytes written.
*
*/
int Write(uint16_t aOffset, uint16_t aLength, const void *aBuf);
/**
* This method copies bytes from one message to another.
*
* @param[in] aSourceOffset Byte offset within the source message to begin reading.
* @param[in] aDestinationOffset Byte offset within the destination message to begin writing.
* @param[in] aLength Number of bytes to copy.
* @param[in] aMessage Message to copy to.
*
* @returns The number of bytes copied.
*
*/
int CopyTo(uint16_t aSourceOffset, uint16_t aDestinationOffset, uint16_t aLength, Message &aMessage) const;
/**
* This method creates a copy of the current Message. It allocates the new one
* from the same Message Poll as the original Message and copies @p aLength octets of a payload.
*
* The `Type`, `SubType`, `LinkSecurity` and `Priority` fields on the cloned message are also
* copied from the original one.
*
* @param[in] aLength Number of payload bytes to copy.
*
* @returns A pointer to the message or NULL if insufficient message buffers are available.
*/
Message *Clone(uint16_t aLength) const;
/**
* This method creates a copy of the current Message. It allocates the new one
* from the same Message Poll as the original Message and copies a full payload.
*
* @returns A pointer to the message or NULL if insufficient message buffers are available.
*/
Message *Clone(void) const { return Clone(GetLength()); };
/**
* This method returns the datagram tag used for 6LoWPAN fragmentation.
*
* @returns The 6LoWPAN datagram tag.
*
*/
uint16_t GetDatagramTag(void) const { return mBuffer.mHead.mInfo.mDatagramTag; }
/**
* This method sets the datagram tag used for 6LoWPAN fragmentation.
*
* @param[in] aTag The 6LoWPAN datagram tag.
*
*/
void SetDatagramTag(uint16_t aTag) { mBuffer.mHead.mInfo.mDatagramTag = aTag; }
/**
* This method returns whether or not the message forwarding is scheduled for the child.
*
* @param[in] aChildIndex The index into the child table.
*
* @retval TRUE If the message is scheduled to be forwarded to the child.
* @retval FALSE If the message is not scheduled to be forwarded to the child.
*
*/
bool GetChildMask(uint8_t aChildIndex) const;
/**
* This method unschedules forwarding of the message to the child.
*
* @param[in] aChildIndex The index into the child table.
*
*/
void ClearChildMask(uint8_t aChildIndex);
/**
* This method schedules forwarding of the message to the child.
*
* @param[in] aChildIndex The index into the child table.
*
*/
void SetChildMask(uint8_t aChildIndex);
/**
* This method returns whether or not the message forwarding is scheduled for at least one child.
*
* @retval TRUE If message forwarding is scheduled for at least one child.
* @retval FALSE If message forwarding is not scheduled for any child.
*
*/
bool IsChildPending(void) const;
/**
* This method returns the IEEE 802.15.4 Destination PAN ID.
*
* @note Only use this when sending MLE Discover Request or Response messages.
*
* @returns The IEEE 802.15.4 Destination PAN ID.
*
*/
uint16_t GetPanId(void) const { return mBuffer.mHead.mInfo.mPanIdChannel.mPanId; }
/**
* This method sets the IEEE 802.15.4 Destination PAN ID.
*
* @note Only use this when sending MLE Discover Request or Response messages.
*
* @param[in] aPanId The IEEE 802.15.4 Destination PAN ID.
*
*/
void SetPanId(uint16_t aPanId) { mBuffer.mHead.mInfo.mPanIdChannel.mPanId = aPanId; }
/**
* This method returns the IEEE 802.15.4 Channel to use for transmission.
*
* @note Only use this when sending MLE Announce messages.
*
* @returns The IEEE 802.15.4 Channel to use for transmission.
*
*/
uint8_t GetChannel(void) const { return mBuffer.mHead.mInfo.mPanIdChannel.mChannel; }
/**
* This method sets the IEEE 802.15.4 Channel to use for transmission.
*
* @note Only use this when sending MLE Announce messages.
*
* @param[in] aChannel The IEEE 802.15.4 Channel to use for transmission.
*
*/
void SetChannel(uint8_t aChannel) { mBuffer.mHead.mInfo.mPanIdChannel.mChannel = aChannel; }
/**
* This method returns the timeout used for 6LoWPAN reassembly.
*
* @returns The time remaining in seconds.
*
*/
uint8_t GetTimeout(void) const { return mBuffer.mHead.mInfo.mTimeout; }
/**
* This method sets the timeout used for 6LoWPAN reassembly.
*
* @param[in] aTimeout The timeout value.
*
*/
void SetTimeout(uint8_t aTimeout) { mBuffer.mHead.mInfo.mTimeout = aTimeout; }
/**
* This method returns the interface ID.
*
* @returns The interface ID.
*
*/
int8_t GetInterfaceId(void) const { return mBuffer.mHead.mInfo.mInterfaceId; }
/**
* This method sets the interface ID.
*
* @param[in] aInterfaceId The interface ID value.
*
*/
void SetInterfaceId(int8_t aInterfaceId) { mBuffer.mHead.mInfo.mInterfaceId = aInterfaceId; }
/**
* This method returns whether or not message forwarding is scheduled for direct transmission.
*
* @retval TRUE If message forwarding is scheduled for direct transmission.
* @retval FALSE If message forwarding is not scheduled for direct transmission.
*
*/
bool GetDirectTransmission(void) const { return mBuffer.mHead.mInfo.mDirectTx; }
/**
* This method unschedules forwarding using direct transmission.
*
*/
void ClearDirectTransmission(void) { mBuffer.mHead.mInfo.mDirectTx = false; }
/**
* This method schedules forwarding using direct transmission.
*
*/
void SetDirectTransmission(void) { mBuffer.mHead.mInfo.mDirectTx = true; }
/**
* This method indicates whether or not link security is enabled for the message.
*
* @retval TRUE If link security is enabled.
* @retval FALSE If link security is not enabled.
*
*/
bool IsLinkSecurityEnabled(void) const { return mBuffer.mHead.mInfo.mLinkSecurity; }
/**
* This method sets whether or not link security is enabled for the message.
*
* @param[in] aEnabled TRUE if link security is enabled, FALSE otherwise.
*
*/
void SetLinkSecurityEnabled(bool aEnabled) { mBuffer.mHead.mInfo.mLinkSecurity = aEnabled; }
/**
* This method is used to update a checksum value.
*
* @param[in] aChecksum Initial checksum value.
* @param[in] aOffset Byte offset within the message to begin checksum computation.
* @param[in] aLength Number of bytes to compute the checksum over.
*
* @retval The updated checksum value.
*
*/
uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const;
/**
* This method returns a pointer to the message queue (if any) where this message is queued.
*
* @returns A pointer to the message queue or NULL if not in any message queue.
*
*/
MessageQueue *GetMessageQueue(void) const {
return (!mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mMessage : NULL;
}
private:
/**
* This method returns a pointer to the message pool to which this message belongs
*
* @returns A pointer to the message pool.
*
*/
MessagePool *GetMessagePool(void) const { return mBuffer.mHead.mInfo.mMessagePool; }
/**
* This method sets the message pool this message to which this message belongs.
*
* @param[in] aMessagePool A pointer to the message pool
*
*/
void SetMessagePool(MessagePool *aMessagePool) { mBuffer.mHead.mInfo.mMessagePool = aMessagePool; }
/**
* This method returns `true` if the message is enqueued in any queue (`MessageQueue` or `PriorityQueue`).
*
* @returns `true` if the message is in any queue, `false` otherwise.
*
*/
bool IsInAQueue(void) const { return (mBuffer.mHead.mInfo.mQueue.mMessage != NULL); }
/**
* This method sets the message queue information for the message.
*
* @param[in] aMessageQueue A pointer to the message queue where this message is queued.
*
*/
void SetMessageQueue(MessageQueue *aMessageQueue);
/**
* This method returns a pointer to the priority message queue (if any) where this message is queued.
*
* @returns A pointer to the priority queue or NULL if not in any priority queue.
*
*/
PriorityQueue *GetPriorityQueue(void) const {
return (mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mPriority : NULL;
}
/**
* This method sets the message queue information for the message.
*
* @param[in] aPriorityQueue A pointer to the priority queue where this message is queued.
*
*/
void SetPriorityQueue(PriorityQueue *aPriorityQueue);
/**
* This method returns a reference to the `mNext` pointer for a given list.
*
* @param[in] aList The index to the message list.
*
* @returns A reference to the mNext pointer for the specified list.
*
*/
Message *&Next(uint8_t aList) { return mBuffer.mHead.mInfo.mNext[aList]; }
/**
* This method returns a const reference to the `mNext` pointer for a given list.
*
* @param[in] aList The index to the message list.
*
* @returns A const reference to the mNext pointer for the specified list.
*
*/
Message *const &Next(uint8_t aList) const { return mBuffer.mHead.mInfo.mNext[aList]; }
/**
* This method returns a reference to the `mPrev` pointer for a given list.
*
* @param[in] aList The index to the message list.
*
* @returns A reference to the mPrev pointer for the specified list.
*
*/
Message *&Prev(uint8_t aList) { return mBuffer.mHead.mInfo.mPrev[aList]; }
/**
* This method returns the number of reserved header bytes.
*
* @returns The number of reserved header bytes.
*
*/
uint16_t GetReserved(void) const { return mBuffer.mHead.mInfo.mReserved; }
/**
* This method sets the number of reserved header bytes.
*
* @pram[in] aReservedHeader The number of header bytes to reserve.
*
*/
void SetReserved(uint16_t aReservedHeader) { mBuffer.mHead.mInfo.mReserved = aReservedHeader; }
/**
* This method adds or frees message buffers to meet the requested length.
*
* @param[in] aLength The number of bytes that the message buffer needs to handle.
*
* @retval OT_ERROR_NONE Successfully resized the message.
* @retval OT_ERROR_NO_BUFS Could not grow the message due to insufficient available message buffers.
*
*/
otError ResizeMessage(uint16_t aLength);
};
/**
* This class implements a message queue.
*
*/
class MessageQueue : public otMessageQueue
{
friend class Message;
friend class PriorityQueue;
public:
/**
* This constructor initializes the message queue.
*
*/
MessageQueue(void);
/**
* This method returns a pointer to the first message.
*
* @returns A pointer to the first message.
*
*/
Message *GetHead(void) const;
/**
* This method adds a message to the end of the list.
*
* @param[in] aMessage The message to add.
*
* @retval OT_ERROR_NONE Successfully added the message to the list.
* @retval OT_ERROR_ALREADY The message is already enqueued in a list.
*
*/
otError Enqueue(Message &aMessage);
/**
* This method removes a message from the list.
*
* @param[in] aMessage The message to remove.
*
* @retval OT_ERROR_NONE Successfully removed the message from the list.
* @retval OT_ERROR_NOT_FOUND The message is not enqueued in a list.
*
*/
otError Dequeue(Message &aMessage);
/**
* This method returns the number of messages and buffers enqueued.
*
* @param[out] aMessageCount Returns the number of messages enqueued.
* @param[out] aBufferCount Returns the number of buffers enqueued.
*
*/
void GetInfo(uint16_t &aMessageCount, uint16_t &aBufferCount) const;
private:
/**
* This method returns the tail of the list (last message in the list)
*
* @returns A pointer to the tail of the list.
*
*/
Message *GetTail(void) const { return static_cast<Message *>(mData); }
/**
* This method set the tail of the list.
*
* @param[in] aMessage A pointer to the message to set as new tail.
*
*/
void SetTail(Message *aMessage) { mData = aMessage; }
/**
* This method adds a message to a list.
*
* @param[in] aListId The list to add @p aMessage to.
* @param[in] aMessage The message to add to @p aListId.
*
*/
void AddToList(uint8_t aListId, Message &aMessage);
/**
* This method removes a message from a list.
*
* @param[in] aListId The list to add @p aMessage to.
* @param[in] aMessage The message to add to @p aListId.
*
*/
void RemoveFromList(uint8_t aListId, Message &aMessage);
};
/**
* This class implements a priority queue.
*
*/
class PriorityQueue
{
friend class Message;
friend class MessageQueue;
friend class MessagePool;
public:
/**
* This constructor initializes the priority queue.
*
*/
PriorityQueue(void);
/**
* This method returns a pointer to the first message.
*
* @returns A pointer to the first message.
*
*/
Message *GetHead(void) const;
/**
* This method returns a pointer to the first message for a given priority level.
*
* @param[in] aPriority Priority level.
*
* @returns A pointer to the first message with given priority level or NULL if there is no messages with
* this priority level.
*
*/
Message *GetHeadForPriority(uint8_t aPriority) const;
/**
* This method adds a message to the queue.
*
* @param[in] aMessage The message to add.
*
* @retval OT_ERROR_NONE Successfully added the message to the list.
* @retval OT_ERROR_ALREADY The message is already enqueued in a list.
*
*/
otError Enqueue(Message &aMessage);
/**
* This method removes a message from the list.
*
* @param[in] aMessage The message to remove.
*
* @retval OT_ERROR_NONE Successfully removed the message from the list.
* @retval OT_ERROR_NOT_FOUND The message is not enqueued in a list.
*
*/
otError Dequeue(Message &aMessage);
/**
* This method returns the number of messages and buffers enqueued.
*
* @param[out] aMessageCount Returns the number of messages enqueued.
* @param[out] aBufferCount Returns the number of buffers enqueued.
*
*/
void GetInfo(uint16_t &aMessageCount, uint16_t &aBufferCount) const;
private:
/**
* This method returns the tail of the list (last message in the list)
*
* @returns A pointer to the tail of the list.
*
*/
Message *GetTail(void) const;
/**
* This method adds a message to a list.
*
* @param[in] aListId The list to add @p aMessage to.
* @param[in] aMessage The message to add to @p aListId.
*
*/
void AddToList(uint8_t aListId, Message &aMessage);
/**
* This method removes a message from a list.
*
* @param[in] aListId The list to add @p aMessage to.
* @param[in] aMessage The message to add to @p aListId.
*
*/
void RemoveFromList(uint8_t aListId, Message &aMessage);
/**
* This method decreases (moves back) the given priority while ensuring to wrap from
* priority value 0 back to `kNumPriorities` -1.
*
* @param[in] aPriority A given priority level
*
* @returns Decreased/Moved back priority level
*/
uint8_t PrevPriority(uint8_t aPriority) const {
return (aPriority == 0) ? (Message::kNumPriorities - 1) : (aPriority - 1);
}
/**
* This private method finds the first non-NULL tail starting from the given priority level and moving back.
* It wraps from priority value 0 back to `kNumPriorities` -1.
*
* aStartPriorityLevel Starting priority level.
*
* @returns The first non-NULL tail pointer, or NULL if all the
*
*/
Message *FindFirstNonNullTail(uint8_t aStartPriorityLevel) const;
private:
Message *mTails[Message::kNumPriorities]; ///< Tail pointers associated with different priority levels.
};
/**
* This class represents a message pool
*
*/
class MessagePool: public InstanceLocator
{
friend class Message;
friend class MessageQueue;
friend class PriorityQueue;
public:
/**
* This class represents an iterator for iterating through all queued message from this pool.
*
*/
class Iterator
{
friend class MessagePool;
public:
/**
* This constructor initializes an empty iterator.
*/
Iterator(void) : mMessage(NULL) { }
/**
* This method returns the associated message with the iterator.
*
* @returns A pointer to associated message with this iterator.
*
*/
Message *GetMessage(void) const { return mMessage; }
/**
* This method returns `true` if the iterator is empty (i.e., associated with a NULL message)
*
* @returns `true` if the iterator is empty, `false` otherwise.
*/
bool IsEmpty(void) const { return (mMessage == NULL); }
/**
* This method returns `true` if the iterator has ended (beyond the last message on list).
*
* @returns `true` if the iterator has ended , `false` otherwise.
*/
bool HasEnded(void) const { return IsEmpty(); }
/**
* This method returns a new iterator corresponding to next message on the list.
*
* @returns An iterator corresponding to next message on the list.
*
*/
Iterator GetNext(void) const { return Iterator(Next()); }
/**
* This method returns a new iterator corresponding to previous message on the list.
*
* @returns An iterator corresponding to previous message on the list.
*
*/
Iterator GetPrev(void) const { return Iterator(Prev()); }
/**
* This method moves the current iterator to the next message on the list.
*
* @returns A reference to current iterator.
*
*/
Iterator &GoToNext(void) { mMessage = Next(); return *this; }
/**
* This method moves the current iterator to the previous message on the list.
*
* @returns A reference to current iterator.
*
*/
Iterator &GoToPrev(void) { mMessage = Prev(); return *this; }
private:
Iterator(Message *aMessage) : mMessage(aMessage) { }
Message *Next(void) const;
Message *Prev(void) const;
Message *mMessage;
};
/**
* This constructor initializes the object.
*
*/
MessagePool(otInstance *aInstance);
/**
* This method is used to obtain a new message. The default priority `kDefaultMessagePriority`
* is assigned to the message.
*
* @param[in] aType The message type.
* @param[in] aReserveHeader The number of header bytes to reserve.
*
* @returns A pointer to the message or NULL if no message buffers are available.
*
*/
Message *New(uint8_t aType, uint16_t aReserveHeader);
/**
* This method is used to free a message and return all message buffers to the buffer pool.
*
* @param[in] aMessage The message to free.
*
* @retval OT_ERROR_NONE Successfully freed the message.
* @retval OT_ERROR_INVALID_ARGS The message is already freed.
*
*/
otError Free(Message *aMessage);
/**
* This method returns a pointer to the first message (head) in the all-messages list.
* Messages are sorted based on their priority (head with highest priority) and order by which they are enqueued.
*
* @returns A pointer to the first message.
*
*/
Iterator GetAllMessagesHead(void) const;
/**
* This method returns a pointer to the last message (head) in the all-messages list.
* Messages are sorted based on their priority (head with highest priority) and order by which they are enqueued.
*
* @returns A pointer to the last message.
*
*/
Iterator GetAllMessagesTail(void) const { return Iterator(mAllQueue.GetTail()); }
/**
* This method returns the number of free buffers.
*
* @returns The number of free buffers.
*
*/
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
uint16_t GetFreeBufferCount(void) const { return otPlatMessagePoolNumFreeBuffers(GetInstance()); }
#else
uint16_t GetFreeBufferCount(void) const { return mNumFreeBuffers; }
#endif
private:
enum
{
kDefaultMessagePriority = Message::kPriorityLow,
};
Buffer *NewBuffer(void);
otError FreeBuffers(Buffer *aBuffer);
otError ReclaimBuffers(int aNumBuffers);
PriorityQueue *GetAllMessagesQueue(void) { return &mAllQueue; }
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT == 0
uint16_t mNumFreeBuffers;
Buffer mBuffers[kNumBuffers];
Buffer *mFreeBuffers;
#endif
PriorityQueue mAllQueue;
};
/**
* @}
*
*/
} // namespace ot
#endif // MESSAGE_HPP_