Skip to content

Commit c715269

Browse files
Support chained buffers in PacketBufferHandle::CloneData() (#5355)
* Support chained buffers in PacketBufferHandle::CloneData() #### Problem It's sometimes useful to clone an entire packet buffer chain (e.g. #5309). (If cloning only a single buffer is necessary, `NewWithData(buffer->Start(), buffer->DataLength(), 0, buffer->ReservedSize())` will do the job.) #### Summary of Changes Support chained buffers in `PacketBufferHandle::CloneData()`. Fixes #5348 - Support CloneData with chained buffers in PacketBufferHandle * Restyled by clang-format * review fix Co-authored-by: Restyled.io <commits@restyled.io>
1 parent a079680 commit c715269

File tree

3 files changed

+114
-13
lines changed

3 files changed

+114
-13
lines changed

src/system/SystemPacketBuffer.cpp

+25-5
Original file line numberDiff line numberDiff line change
@@ -605,14 +605,34 @@ PacketBufferHandle PacketBufferHandle::PopHead()
605605
return PacketBufferHandle(head);
606606
}
607607

608-
PacketBufferHandle PacketBufferHandle::CloneData(uint16_t aAdditionalSize, uint16_t aReservedSize)
608+
PacketBufferHandle PacketBufferHandle::CloneData()
609609
{
610-
if (!mBuffer->Next().IsNull())
610+
PacketBufferHandle cloneHead;
611+
612+
for (PacketBuffer * original = mBuffer; original != nullptr; original = static_cast<PacketBuffer *>(original->next))
611613
{
612-
// We do not clone an entire chain.
613-
return PacketBufferHandle();
614+
uint16_t originalDataSize = original->MaxDataLength();
615+
uint16_t originalReservedSize = original->ReservedSize();
616+
PacketBufferHandle clone = PacketBufferHandle::New(originalDataSize, originalReservedSize);
617+
if (clone.IsNull())
618+
{
619+
return PacketBufferHandle();
620+
}
621+
clone.mBuffer->tot_len = clone.mBuffer->len = original->len;
622+
memcpy(reinterpret_cast<uint8_t *>(clone.mBuffer) + PacketBuffer::kStructureSize,
623+
reinterpret_cast<uint8_t *>(original) + PacketBuffer::kStructureSize, originalDataSize + originalReservedSize);
624+
625+
if (cloneHead.IsNull())
626+
{
627+
cloneHead = std::move(clone);
628+
}
629+
else
630+
{
631+
cloneHead->AddToEnd(std::move(clone));
632+
}
614633
}
615-
return NewWithData(mBuffer->Start(), mBuffer->DataLength(), aAdditionalSize, aReservedSize);
634+
635+
return cloneHead;
616636
}
617637

618638
} // namespace System

src/system/SystemPacketBuffer.h

+3-8
Original file line numberDiff line numberDiff line change
@@ -598,16 +598,11 @@ class DLL_EXPORT PacketBufferHandle
598598
uint16_t aReservedSize = PacketBuffer::kDefaultHeaderReserve);
599599

600600
/**
601-
* Creates a copy of the data in this packet.
601+
* Creates a copy of a packet buffer (or chain).
602602
*
603-
* Does NOT support chained buffers.
604-
*
605-
* @param[in] aAdditionalSize Size of additional application data space after the initial contents.
606-
* @param[in] aReservedSize Number of octets to reserve for protocol headers.
607-
*
608-
* @returns empty handle on allocation failure.
603+
* @returns empty handle on allocation failure. Otherwise, the returned buffer has the same sizes and contents as the original.
609604
*/
610-
PacketBufferHandle CloneData(uint16_t aAdditionalSize = 0, uint16_t aReservedSize = PacketBuffer::kDefaultHeaderReserve);
605+
PacketBufferHandle CloneData();
611606

612607
/**
613608
* Perform an implementation-defined check on the validity of a PacketBufferHandle.

src/system/tests/TestSystemPacketBuffer.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ using ::chip::System::pbuf;
6767
#define TO_LWIP_PBUF(x) (reinterpret_cast<struct pbuf *>(reinterpret_cast<void *>(x)))
6868
#define OF_LWIP_PBUF(x) (reinterpret_cast<PacketBuffer *>(reinterpret_cast<void *>(x)))
6969

70+
namespace {
71+
void ScrambleData(uint8_t * start, uint16_t length)
72+
{
73+
for (uint16_t i = 0; i < length; ++i)
74+
++start[i];
75+
}
76+
} // namespace
77+
7078
/*
7179
* An instance of this class created for the test suite.
7280
* It is a friend class of `PacketBuffer` and `PacketBufferHandle` because some tests
@@ -120,6 +128,7 @@ class PacketBufferTest
120128
static void CheckHandleHold(nlTestSuite * inSuite, void * inContext);
121129
static void CheckHandleAdvance(nlTestSuite * inSuite, void * inContext);
122130
static void CheckHandleRightSize(nlTestSuite * inSuite, void * inContext);
131+
static void CheckHandleCloneData(nlTestSuite * inSuite, void * inContext);
123132
static void CheckPacketBufferWriter(nlTestSuite * inSuite, void * inContext);
124133
static void CheckBuildFreeList(nlTestSuite * inSuite, void * inContext);
125134

@@ -1707,6 +1716,82 @@ void PacketBufferTest::CheckHandleRightSize(nlTestSuite * inSuite, void * inCont
17071716
#endif // CHIP_SYSTEM_PACKETBUFFER_HAS_RIGHT_SIZE
17081717
}
17091718

1719+
void PacketBufferTest::CheckHandleCloneData(nlTestSuite * inSuite, void * inContext)
1720+
{
1721+
struct TestContext * const theContext = static_cast<struct TestContext *>(inContext);
1722+
PacketBufferTest * const test = theContext->test;
1723+
NL_TEST_ASSERT(inSuite, test->mContext == theContext);
1724+
1725+
uint8_t lPayload[2 * PacketBuffer::kMaxSizeWithoutReserve];
1726+
for (size_t i = 0; i < sizeof(lPayload); ++i)
1727+
{
1728+
lPayload[i] = static_cast<uint8_t>(random());
1729+
}
1730+
1731+
for (auto & config_1 : test->configurations)
1732+
{
1733+
for (auto & config_2 : test->configurations)
1734+
{
1735+
if (&config_1 == &config_2)
1736+
{
1737+
continue;
1738+
}
1739+
1740+
test->PrepareTestBuffer(&config_1);
1741+
test->PrepareTestBuffer(&config_2);
1742+
1743+
const uint8_t * payload_1 = lPayload;
1744+
memcpy(config_1.handle->Start(), payload_1, config_1.handle->MaxDataLength());
1745+
config_1.handle->SetDataLength(config_1.handle->MaxDataLength());
1746+
1747+
const uint8_t * payload_2 = lPayload + config_1.handle->MaxDataLength();
1748+
memcpy(config_2.handle->Start(), payload_2, config_2.handle->MaxDataLength());
1749+
config_2.handle->SetDataLength(config_2.handle->MaxDataLength());
1750+
1751+
// Clone single buffer.
1752+
PacketBufferHandle clone_1 = config_1.handle.CloneData();
1753+
NL_TEST_ASSERT(inSuite, !clone_1.IsNull());
1754+
NL_TEST_ASSERT(inSuite, clone_1->DataLength() == config_1.handle->DataLength());
1755+
NL_TEST_ASSERT(inSuite, memcmp(clone_1->Start(), payload_1, clone_1->DataLength()) == 0);
1756+
if (clone_1->DataLength())
1757+
{
1758+
// Verify that modifying the clone does not affect the original.
1759+
ScrambleData(clone_1->Start(), clone_1->DataLength());
1760+
NL_TEST_ASSERT(inSuite, memcmp(clone_1->Start(), payload_1, clone_1->DataLength()) != 0);
1761+
NL_TEST_ASSERT(inSuite, memcmp(config_1.handle->Start(), payload_1, config_1.handle->DataLength()) == 0);
1762+
}
1763+
1764+
// Clone buffer chain.
1765+
config_1.handle->AddToEnd(config_2.handle.Retain());
1766+
NL_TEST_ASSERT(inSuite, config_1.handle->HasChainedBuffer());
1767+
clone_1 = config_1.handle.CloneData();
1768+
PacketBufferHandle clone_1_next = clone_1->Next();
1769+
NL_TEST_ASSERT(inSuite, !clone_1.IsNull());
1770+
NL_TEST_ASSERT(inSuite, clone_1->HasChainedBuffer());
1771+
NL_TEST_ASSERT(inSuite, clone_1->DataLength() == config_1.handle->DataLength());
1772+
NL_TEST_ASSERT(inSuite, clone_1->TotalLength() == config_1.handle->TotalLength());
1773+
NL_TEST_ASSERT(inSuite, clone_1_next->DataLength() == config_2.handle->DataLength());
1774+
NL_TEST_ASSERT(inSuite, memcmp(clone_1->Start(), payload_1, clone_1->DataLength()) == 0);
1775+
NL_TEST_ASSERT(inSuite, memcmp(clone_1_next->Start(), payload_2, clone_1_next->DataLength()) == 0);
1776+
if (clone_1->DataLength())
1777+
{
1778+
ScrambleData(clone_1->Start(), clone_1->DataLength());
1779+
NL_TEST_ASSERT(inSuite, memcmp(clone_1->Start(), payload_1, clone_1->DataLength()) != 0);
1780+
NL_TEST_ASSERT(inSuite, memcmp(config_1.handle->Start(), payload_1, config_1.handle->DataLength()) == 0);
1781+
}
1782+
if (clone_1_next->DataLength())
1783+
{
1784+
ScrambleData(clone_1_next->Start(), clone_1_next->DataLength());
1785+
NL_TEST_ASSERT(inSuite, memcmp(clone_1_next->Start(), payload_2, clone_1_next->DataLength()) != 0);
1786+
NL_TEST_ASSERT(inSuite, memcmp(config_2.handle->Start(), payload_2, config_2.handle->DataLength()) == 0);
1787+
}
1788+
1789+
config_1.handle = nullptr;
1790+
config_2.handle = nullptr;
1791+
}
1792+
}
1793+
}
1794+
17101795
void PacketBufferTest::CheckPacketBufferWriter(nlTestSuite * inSuite, void * inContext)
17111796
{
17121797
struct TestContext * const theContext = static_cast<struct TestContext *>(inContext);
@@ -1773,6 +1858,7 @@ const nlTest sTests[] =
17731858
NL_TEST_DEF("PacketBuffer::HandleHold", PacketBufferTest::CheckHandleHold),
17741859
NL_TEST_DEF("PacketBuffer::HandleAdvance", PacketBufferTest::CheckHandleAdvance),
17751860
NL_TEST_DEF("PacketBuffer::HandleRightSize", PacketBufferTest::CheckHandleRightSize),
1861+
NL_TEST_DEF("PacketBuffer::HandleCloneData", PacketBufferTest::CheckHandleCloneData),
17761862
NL_TEST_DEF("PacketBuffer::PacketBufferWriter", PacketBufferTest::CheckPacketBufferWriter),
17771863

17781864
NL_TEST_SENTINEL()

0 commit comments

Comments
 (0)