mirror of
https://github.com/espressif/openthread.git
synced 2026-08-11 13:17:48 +00:00
[dns] adding Name::AppendTo() to copy DNS name from one message to another (#6365)
This commit adds `AppendTo()` method in `Dns::Name` class. This method allows appending an already encoded name from one message to another. This is performed by directly copying labels one by one between the messages and does not require an intermediate buffer to read and store the labels or the full name. This commit also updates `test_dns` unit test to cover the behavior of the newly added method.
This commit is contained in:
@@ -100,6 +100,51 @@ Error Header::ResponseCodeToError(Response aResponse)
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Name::AppendTo(Message &aMessage) const
|
||||
{
|
||||
Error error;
|
||||
|
||||
if (IsEmpty())
|
||||
{
|
||||
error = AppendTerminator(aMessage);
|
||||
}
|
||||
else if (IsFromCString())
|
||||
{
|
||||
error = AppendName(GetAsCString(), aMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Name is from a message. Read labels one by one from
|
||||
// `mMessage` and and append each to the `aMessage`.
|
||||
|
||||
LabelIterator iterator(*mMessage, mOffset);
|
||||
|
||||
while (true)
|
||||
{
|
||||
error = iterator.GetNextLabel();
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case kErrorNone:
|
||||
SuccessOrExit(error = iterator.AppendLabel(aMessage));
|
||||
break;
|
||||
|
||||
case kErrorNotFound:
|
||||
// We reached the end of name successfully.
|
||||
error = AppendTerminator(aMessage);
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
|
||||
default:
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Name::AppendLabel(const char *aLabel, Message &aMessage)
|
||||
{
|
||||
return AppendLabel(aLabel, static_cast<uint8_t>(StringLength(aLabel, kMaxLabelSize)), aMessage);
|
||||
@@ -545,6 +590,21 @@ bool Name::LabelIterator::CompareLabel(const LabelIterator &aOtherIterator) cons
|
||||
mLabelLength);
|
||||
}
|
||||
|
||||
Error Name::LabelIterator::AppendLabel(Message &aMessage) const
|
||||
{
|
||||
// This method reads and appends the current label in the iterator
|
||||
// to `aMessage`.
|
||||
|
||||
Error error;
|
||||
|
||||
VerifyOrExit((0 < mLabelLength) && (mLabelLength <= kMaxLabelLength), error = kErrorInvalidArgs);
|
||||
SuccessOrExit(error = aMessage.Append(mLabelLength));
|
||||
error = aMessage.AppendBytesFromMessage(mMessage, mLabelStartOffset, mLabelLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Name::IsSubDomainOf(const char *aName, const char *aDomain)
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
@@ -655,6 +655,24 @@ public:
|
||||
return *mMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method encodes and appends the name to a message.
|
||||
*
|
||||
* If the name is empty (not specified), then root "." is appended to @p aMessage. If the name is from a C string
|
||||
* then the string is checked and appended (similar to static `AppendName(const char *aName, Message &)` method).
|
||||
* If the the name is from a message, then it is read from the message and appended to @p aMessage. Note that in
|
||||
* this case independent of whether the name is compressed or not in its original message, the name is appended
|
||||
* as full (uncompressed) in @p aMessage.
|
||||
*
|
||||
* @param[in] aMessage The message to append to.
|
||||
*
|
||||
* @retval kErrorNone Successfully encoded and appended the name to @p aMessage.
|
||||
* @retval kErrorInvalidArgs Name is not valid.
|
||||
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
Error AppendTo(Message &aMessage) const;
|
||||
|
||||
/**
|
||||
* This static method encodes and appends a single name label to a message.
|
||||
*
|
||||
@@ -1021,6 +1039,7 @@ private:
|
||||
Error ReadLabel(char *aLabelBuffer, uint8_t &aLabelLength, bool aAllowDotCharInLabel) const;
|
||||
bool CompareLabel(const char *&aName, bool aIsSingleLabel) const;
|
||||
bool CompareLabel(const LabelIterator &aOtherIterator) const;
|
||||
Error AppendLabel(Message &aMessage) const;
|
||||
|
||||
const Message &mMessage; // Message to read labels from.
|
||||
uint16_t mLabelStartOffset; // Offset in `mMessage` to the first char of current label text.
|
||||
|
||||
@@ -407,6 +407,7 @@ void TestDnsCompressedName(void)
|
||||
Instance * instance;
|
||||
MessagePool *messagePool;
|
||||
Message * message;
|
||||
Message * message2;
|
||||
uint16_t offset;
|
||||
uint16_t name1Offset;
|
||||
uint16_t name2Offset;
|
||||
@@ -416,6 +417,10 @@ void TestDnsCompressedName(void)
|
||||
char label[kLabelSize];
|
||||
uint8_t labelLength;
|
||||
char name[kNameSize];
|
||||
Dns::Name dnsName1;
|
||||
Dns::Name dnsName2;
|
||||
Dns::Name dnsName3;
|
||||
Dns::Name dnsName4;
|
||||
|
||||
printf("================================================================\n");
|
||||
printf("TestDnsCompressedName()\n");
|
||||
@@ -685,7 +690,44 @@ void TestDnsCompressedName(void)
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message, offset, *message, name1Offset) == kErrorNotFound,
|
||||
"Name::CompareName() did not fail with mismatching name");
|
||||
|
||||
printf("----------------------------------------------------------------\n");
|
||||
printf("Append names from one message to another\n");
|
||||
|
||||
VerifyOrQuit((message2 = messagePool->New(Message::kTypeIp6, 0)) != nullptr, "Message::New failed");
|
||||
|
||||
dnsName1.SetFromMessage(*message, name1Offset);
|
||||
dnsName2.SetFromMessage(*message, name2Offset);
|
||||
dnsName3.SetFromMessage(*message, name3Offset);
|
||||
dnsName4.SetFromMessage(*message, name4Offset);
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(dnsName1.AppendTo(*message2), "Name::AppendTo() failed");
|
||||
SuccessOrQuit(dnsName2.AppendTo(*message2), "Name::AppendTo() failed");
|
||||
SuccessOrQuit(dnsName3.AppendTo(*message2), "Name::AppendTo() failed");
|
||||
SuccessOrQuit(dnsName4.AppendTo(*message2), "Name::AppendTo() failed");
|
||||
|
||||
SuccessOrQuit(message2->Read(0, buffer, message2->GetLength()), "Message::Read() failed");
|
||||
DumpBuffer("message2", buffer, message2->GetLength());
|
||||
|
||||
// Now compare the names one by one in `message2`. Note that
|
||||
// `CompareName()` will update `offset` on success.
|
||||
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message2, offset, dnsName1) == kErrorNone, "Incorrect name after AppendTo()");
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message2, offset, dnsName2) == kErrorNone, "Incorrect name after AppendTo()");
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message2, offset, dnsName3) == kErrorNone, "Incorrect name after AppendTo()");
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message2, offset, dnsName4) == kErrorNone, "Incorrect name after AppendTo()");
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)), "ReadName() failed");
|
||||
printf("- Name1 after `AppendTo()`: \"%s\"\n", name);
|
||||
SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)), "ReadName() failed");
|
||||
printf("- Name2 after `AppendTo()`: \"%s\"\n", name);
|
||||
SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)), "ReadName() failed");
|
||||
printf("- Name3 after `AppendTo()`: \"%s\"\n", name);
|
||||
// `ReadName()` for name-4 will fail due to first label containing dot char.
|
||||
|
||||
message->Free();
|
||||
message2->Free();
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user