mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[message] enhance Clone() to support different reserved header size (#12440)
This commit enhances the `Message::Clone()` method to support a custom configuration. This allows callers to specify a different length and reserved header size for the cloned message via the new overload `Clone(uint16_t aLength, uint16_t aReserveHeader)`. The existing `Clone()` overloads have been updated to utilize this new configuration mechanism. Additionally, `Coap::Message::Clone()` methods are updated to align with these changes. A new unit test `TestCloning()` is added to `test_message.cpp` to verify the behavior of `Clone()` with various configurations.
This commit is contained in:
committed by
GitHub
parent
7d10faea6f
commit
ecc57f765c
@@ -690,9 +690,13 @@ exit:
|
||||
return hasSame;
|
||||
}
|
||||
|
||||
Message *Message::Clone(uint16_t aLength) const
|
||||
Message *Message::Clone(void) const { return Clone(GetLength()); }
|
||||
|
||||
Message *Message::Clone(uint16_t aLength) const { return Clone(aLength, GetReserved()); }
|
||||
|
||||
Message *Message::Clone(uint16_t aLength, uint16_t aReserveHeader) const
|
||||
{
|
||||
Message *message = static_cast<Message *>(ot::Message::Clone(aLength));
|
||||
Message *message = static_cast<Message *>(ot::Message::Clone(aLength, aReserveHeader));
|
||||
|
||||
VerifyOrExit(message != nullptr);
|
||||
|
||||
|
||||
@@ -826,11 +826,22 @@ public:
|
||||
*/
|
||||
Error AppendPayloadMarker(void);
|
||||
|
||||
/**
|
||||
* Creates a copy of the message.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies the entire payload. The
|
||||
* `Type`, `SubType`, `LinkSecurity`, `Offset`, and `Priority` fields on the cloned message are also
|
||||
* copied from the original one.
|
||||
*
|
||||
* @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const;
|
||||
|
||||
/**
|
||||
* Creates a copy of this CoAP message.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies @p aLength octets
|
||||
* of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the
|
||||
* of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, and `Priority` fields on the
|
||||
* cloned message are also copied from the original one.
|
||||
*
|
||||
* @param[in] aLength Number of payload bytes to copy.
|
||||
@@ -840,15 +851,17 @@ public:
|
||||
Message *Clone(uint16_t aLength) const;
|
||||
|
||||
/**
|
||||
* Creates a copy of the message.
|
||||
* Creates a copy of the message using a given configuration.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies the entire payload. The
|
||||
* `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the cloned message are also
|
||||
* copied from the original one.
|
||||
* It allocates the new message from the same message pool as the original one. The `Type`, `SubType`,
|
||||
* `LinkSecurity`, `Offset`, and `Priority` fields on the cloned message are copied from the original one.
|
||||
*
|
||||
* @param[in] aLength Number of message bytes to copy.
|
||||
* @param[in] aReserveHeader Number of header bytes to reserve in the new cloned message.
|
||||
*
|
||||
* @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const { return Clone(GetLength()); }
|
||||
Message *Clone(uint16_t aLength, uint16_t aReserveHeader) const;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the next message after this as a `Coap::Message`.
|
||||
|
||||
+28
-24
@@ -785,39 +785,43 @@ void Message::WriteBytesFromMessage(uint16_t aWriteOffset,
|
||||
}
|
||||
}
|
||||
|
||||
Message *Message::Clone(uint16_t aLength) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Message *messageCopy;
|
||||
Settings settings(IsLinkSecurityEnabled() ? kWithLinkSecurity : kNoLinkSecurity, GetPriority());
|
||||
uint16_t offset;
|
||||
Message *Message::Clone(void) const { return Clone(GetLength()); }
|
||||
|
||||
aLength = Min(GetLength(), aLength);
|
||||
messageCopy = Get<MessagePool>().Allocate(GetType(), GetReserved(), settings);
|
||||
VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
|
||||
SuccessOrExit(error = messageCopy->AppendBytesFromMessage(*this, 0, aLength));
|
||||
Message *Message::Clone(uint16_t aLength) const { return Clone(aLength, GetReserved()); }
|
||||
|
||||
Message *Message::Clone(uint16_t aLength, uint16_t aReserveHeader) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Message *clone;
|
||||
LinkSecurityMode linkSecurityMode = IsLinkSecurityEnabled() ? kWithLinkSecurity : kNoLinkSecurity;
|
||||
|
||||
clone = Get<MessagePool>().Allocate(GetType(), aReserveHeader, Settings(linkSecurityMode, GetPriority()));
|
||||
VerifyOrExit(clone != nullptr, error = kErrorNoBufs);
|
||||
|
||||
aLength = Min(aLength, GetLength());
|
||||
|
||||
SuccessOrExit(error = clone->AppendBytesFromMessage(*this, 0, aLength));
|
||||
|
||||
// Copy selected message information.
|
||||
|
||||
offset = Min(GetOffset(), aLength);
|
||||
messageCopy->SetOffset(offset);
|
||||
clone->SetOffset(Min(GetOffset(), aLength));
|
||||
|
||||
messageCopy->SetSubType(GetSubType());
|
||||
messageCopy->SetLoopbackToHostAllowed(IsLoopbackToHostAllowed());
|
||||
messageCopy->SetOrigin(GetOrigin());
|
||||
messageCopy->SetTimestamp(GetTimestamp());
|
||||
messageCopy->SetMeshDest(GetMeshDest());
|
||||
messageCopy->SetPanId(GetPanId());
|
||||
messageCopy->SetChannel(GetChannel());
|
||||
messageCopy->SetRssAverager(GetRssAverager());
|
||||
messageCopy->SetLqiAverager(GetLqiAverager());
|
||||
clone->SetSubType(GetSubType());
|
||||
clone->SetLoopbackToHostAllowed(IsLoopbackToHostAllowed());
|
||||
clone->SetOrigin(GetOrigin());
|
||||
clone->SetTimestamp(GetTimestamp());
|
||||
clone->SetMeshDest(GetMeshDest());
|
||||
clone->SetPanId(GetPanId());
|
||||
clone->SetChannel(GetChannel());
|
||||
clone->SetRssAverager(GetRssAverager());
|
||||
clone->SetLqiAverager(GetLqiAverager());
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
messageCopy->SetTimeSync(IsTimeSync());
|
||||
clone->SetTimeSync(IsTimeSync());
|
||||
#endif
|
||||
|
||||
exit:
|
||||
FreeAndNullMessageOnError(messageCopy, error);
|
||||
return messageCopy;
|
||||
FreeAndNullMessageOnError(clone, error);
|
||||
return clone;
|
||||
}
|
||||
|
||||
Error Message::GetLinkInfo(ThreadLinkInfo &aLinkInfo) const
|
||||
|
||||
@@ -70,6 +70,7 @@ struct otMessage
|
||||
|
||||
namespace ot {
|
||||
|
||||
class UnitTester;
|
||||
template <typename UintType> class CrcCalculator;
|
||||
|
||||
namespace Crypto {
|
||||
@@ -286,6 +287,7 @@ class Message : public otMessage, public Buffer, public GetProvider<Message>
|
||||
friend class MessagePool;
|
||||
friend class MessageQueue;
|
||||
friend class PriorityQueue;
|
||||
friend class ot::UnitTester;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -1093,26 +1095,39 @@ public:
|
||||
/**
|
||||
* Creates a copy of the message.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies @p aLength octets
|
||||
* of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the
|
||||
* cloned message are also copied from the original one.
|
||||
* It allocates the new message from the same message pool as the original one and copies the entire payload. The
|
||||
* `Type`, `SubType`, `LinkSecurity`, `Offset`, 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 `nullptr` if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const;
|
||||
|
||||
/**
|
||||
* Creates a copy of the message.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies @p aLength octets
|
||||
* of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, and `Priority` fields on the cloned message
|
||||
* are also copied from the original one.
|
||||
*
|
||||
* @param[in] aLength Number of message bytes to copy.
|
||||
*
|
||||
* @returns A pointer to the message or nullptr if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(uint16_t aLength) const;
|
||||
|
||||
/**
|
||||
* Creates a copy of the message.
|
||||
* Creates a copy of the message using a given configuration.
|
||||
*
|
||||
* It allocates the new message from the same message pool as the original one and copies the entire payload. The
|
||||
* `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the cloned message are also
|
||||
* copied from the original one.
|
||||
* It allocates the new message from the same message pool as the original one. The `Type`, `SubType`,
|
||||
* `LinkSecurity`, `Offset`, and `Priority` fields on the cloned message are copied from the original one.
|
||||
*
|
||||
* @param[in] aLength Number of message bytes to copy.
|
||||
* @param[in] aReserveHeader Number of header bytes to reserve in the new cloned message.
|
||||
*
|
||||
* @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const { return Clone(GetLength()); }
|
||||
Message *Clone(uint16_t aLength, uint16_t aReserveHeader) const;
|
||||
|
||||
/**
|
||||
* Returns the datagram tag used for 6LoWPAN fragmentation or the identification used for IPv6
|
||||
|
||||
+110
-19
@@ -47,7 +47,6 @@ void TestMessage(uint16_t aReservedLength)
|
||||
MessagePool *messagePool;
|
||||
Message *message;
|
||||
Message *message2;
|
||||
Message *messageCopy;
|
||||
uint8_t writeBuffer[kMaxSize];
|
||||
uint8_t readBuffer[kMaxSize];
|
||||
uint8_t zeroBuffer[kMaxSize];
|
||||
@@ -78,26 +77,8 @@ void TestMessage(uint16_t aReservedLength)
|
||||
VerifyOrQuit(message->Compare(0, readBuffer));
|
||||
VerifyOrQuit(message->GetLength() == kMaxSize);
|
||||
|
||||
// Verify `Clone()` behavior
|
||||
message->SetOffset(15);
|
||||
messageCopy = message->Clone();
|
||||
VerifyOrQuit(messageCopy->GetOffset() == message->GetOffset());
|
||||
SuccessOrQuit(messageCopy->Read(0, readBuffer, kMaxSize));
|
||||
VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0);
|
||||
VerifyOrQuit(messageCopy->CompareBytes(0, readBuffer, kMaxSize));
|
||||
VerifyOrQuit(messageCopy->Compare(0, readBuffer));
|
||||
VerifyOrQuit(messageCopy->GetLength() == kMaxSize);
|
||||
VerifyOrQuit(messageCopy->GetType() == message->GetType());
|
||||
VerifyOrQuit(messageCopy->GetSubType() == message->GetSubType());
|
||||
VerifyOrQuit(messageCopy->IsLinkSecurityEnabled() == message->IsLinkSecurityEnabled());
|
||||
VerifyOrQuit(messageCopy->GetPriority() == message->GetPriority());
|
||||
VerifyOrQuit(messageCopy->IsLoopbackToHostAllowed() == message->IsLoopbackToHostAllowed());
|
||||
VerifyOrQuit(messageCopy->GetOrigin() == message->GetOrigin());
|
||||
VerifyOrQuit(messageCopy->Compare(0, readBuffer));
|
||||
message->SetOffset(0);
|
||||
|
||||
messageCopy->Free();
|
||||
|
||||
for (uint16_t offset = 0; offset < kMaxSize; offset++)
|
||||
{
|
||||
for (uint16_t length = 0; length <= kMaxSize - offset; length++)
|
||||
@@ -359,6 +340,114 @@ void TestMessage(uint16_t aReservedLength)
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
|
||||
class UnitTester
|
||||
{
|
||||
public:
|
||||
static void TestCloning(void)
|
||||
{
|
||||
static constexpr uint16_t kLength = 100;
|
||||
|
||||
Instance *instance;
|
||||
MessagePool *messagePool;
|
||||
Message *message;
|
||||
Message *clone;
|
||||
uint8_t buffer[kLength];
|
||||
|
||||
printf("TestCloning()\n");
|
||||
|
||||
instance = static_cast<Instance *>(testInitInstance());
|
||||
VerifyOrQuit(instance != nullptr);
|
||||
|
||||
messagePool = &instance->Get<MessagePool>();
|
||||
|
||||
// Create a message with specific properties
|
||||
message = messagePool->Allocate(Message::kTypeIp6, /* aReserveHeader */ 60);
|
||||
VerifyOrQuit(message != nullptr);
|
||||
|
||||
Random::NonCrypto::FillBuffer(buffer, sizeof(buffer));
|
||||
SuccessOrQuit(message->Append(buffer));
|
||||
|
||||
VerifyOrQuit(message->GetLength() == kLength);
|
||||
VerifyOrQuit(message->GetType() == Message::kTypeIp6);
|
||||
VerifyOrQuit(message->GetReserved() == 60);
|
||||
|
||||
SuccessOrQuit(message->SetPriority(Message::kPriorityHigh));
|
||||
message->SetOffset(10);
|
||||
message->SetSubType(Message::kSubTypeMle);
|
||||
message->SetLinkSecurityEnabled(true);
|
||||
message->SetLoopbackToHostAllowed(true);
|
||||
message->SetOrigin(Message::kOriginHostUntrusted);
|
||||
|
||||
// Test 1: Default cloning
|
||||
clone = message->Clone();
|
||||
VerifyOrQuit(clone != nullptr);
|
||||
|
||||
VerifyOrQuit(clone->GetLength() == message->GetLength());
|
||||
VerifyOrQuit(clone->GetPriority() == message->GetPriority());
|
||||
VerifyOrQuit(clone->GetReserved() == message->GetReserved());
|
||||
VerifyOrQuit(clone->GetOffset() == message->GetOffset());
|
||||
VerifyOrQuit(clone->GetType() == message->GetType());
|
||||
VerifyOrQuit(clone->GetSubType() == message->GetSubType());
|
||||
VerifyOrQuit(clone->IsLinkSecurityEnabled() == message->IsLinkSecurityEnabled());
|
||||
VerifyOrQuit(clone->IsLoopbackToHostAllowed() == message->IsLoopbackToHostAllowed());
|
||||
VerifyOrQuit(clone->GetOrigin() == message->GetOrigin());
|
||||
VerifyOrQuit(clone->Compare(0, buffer));
|
||||
VerifyOrQuit(clone->CompareBytes(0, buffer, kLength));
|
||||
|
||||
clone->Free();
|
||||
|
||||
// Test 2: Cloning with shorter length
|
||||
clone = message->Clone(kLength / 2);
|
||||
VerifyOrQuit(clone != nullptr);
|
||||
|
||||
VerifyOrQuit(clone->GetLength() == kLength / 2);
|
||||
VerifyOrQuit(clone->GetPriority() == message->GetPriority());
|
||||
VerifyOrQuit(clone->GetReserved() == message->GetReserved());
|
||||
VerifyOrQuit(clone->GetOffset() == 10); // Offset should be preserved if < new length
|
||||
VerifyOrQuit(clone->CompareBytes(0, buffer, kLength / 2));
|
||||
|
||||
clone->Free();
|
||||
|
||||
// Test 3: Cloning with shorter length, offset change
|
||||
message->SetOffset(80);
|
||||
|
||||
clone = message->Clone(kLength / 2);
|
||||
VerifyOrQuit(clone != nullptr);
|
||||
|
||||
VerifyOrQuit(clone->GetLength() == kLength / 2);
|
||||
VerifyOrQuit(clone->GetPriority() == message->GetPriority());
|
||||
VerifyOrQuit(clone->GetReserved() == message->GetReserved());
|
||||
VerifyOrQuit(clone->GetOffset() == 50); // Offset should be updated
|
||||
VerifyOrQuit(clone->CompareBytes(0, buffer, kLength / 2));
|
||||
|
||||
clone->Free();
|
||||
|
||||
// Test 4: Cloning with overridden reserved header size
|
||||
clone = message->Clone(message->GetLength(), 0);
|
||||
VerifyOrQuit(clone != nullptr);
|
||||
|
||||
VerifyOrQuit(clone->GetLength() == message->GetLength());
|
||||
VerifyOrQuit(clone->GetPriority() == message->GetPriority());
|
||||
VerifyOrQuit(clone->GetReserved() == 0);
|
||||
VerifyOrQuit(clone->Compare(0, buffer));
|
||||
|
||||
clone->Free();
|
||||
|
||||
// Test 5: Cloning with all shorter length and different reserved header size
|
||||
clone = message->Clone(kLength / 4, 40);
|
||||
VerifyOrQuit(clone != nullptr);
|
||||
|
||||
VerifyOrQuit(clone->GetLength() == kLength / 4);
|
||||
VerifyOrQuit(clone->GetReserved() == 40);
|
||||
VerifyOrQuit(clone->CompareBytes(0, buffer, kLength / 4));
|
||||
|
||||
clone->Free();
|
||||
|
||||
message->Free();
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
};
|
||||
|
||||
void TestAppender(void)
|
||||
{
|
||||
const uint8_t kData1[] = {0x01, 0x02, 0x03, 0x04};
|
||||
@@ -459,7 +548,9 @@ int main(void)
|
||||
ot::TestMessage(reservedLength);
|
||||
}
|
||||
|
||||
ot::UnitTester::TestCloning();
|
||||
ot::TestAppender();
|
||||
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user