mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
2a2d4be953
This commit renames several methods in `Ip6::Address`, `Ip6::InterfaceIdentifier`, `Ip6::Prefix`, and `Ip4::Address` that fully initialize the object from `Set...()` to `Init...()`. This creates a clear semantic distinction in the API: - `Init...()`: Fully (re-)initializing the object. - `Set...()`: Modifies a specific property or a sub-component of the object (e.g., `SetPrefix()`, `SetLocator()`, `SetSubnetId()`). Some examples of renames include: - `SetFromExtAddress()` -> `InitFromExtAddress()` - `SetToLocator()` -> `InitAsLocator()` - `SetToLinkLocalAddress()` -> `InitAsLinkLocalAddress()` - `SetToRoutingLocator()` -> `InitAsRoutingLocator()` - `SetToAnycastLocator()` -> `InitAsAnycastLocator()` - `SetToIp4Mapped()` -> `InitAsIp4Mapped()` All calls to these methods across the codebase have been updated to reflect the new names.
8941 lines
311 KiB
C++
8941 lines
311 KiB
C++
/*
|
|
* Copyright (c) 2024, 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.
|
|
*/
|
|
|
|
#include <openthread/config.h>
|
|
|
|
#include "test_platform.h"
|
|
#include "test_util.hpp"
|
|
|
|
#include "common/arg_macros.hpp"
|
|
#include "common/array.hpp"
|
|
#include "common/as_core_type.hpp"
|
|
#include "common/num_utils.hpp"
|
|
#include "common/owning_list.hpp"
|
|
#include "common/string.hpp"
|
|
#include "common/time.hpp"
|
|
#include "instance/instance.hpp"
|
|
#include "net/dns_dso.hpp"
|
|
#include "net/mdns.hpp"
|
|
|
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
|
|
|
namespace ot {
|
|
namespace Dns {
|
|
namespace Multicast {
|
|
|
|
#define ENABLE_TEST_LOG 1 // Enable to get logs from unit test.
|
|
|
|
// Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
|
|
#if ENABLE_TEST_LOG
|
|
#define Log(...) \
|
|
printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 3600000), (sNow / 60000) % 60, \
|
|
(sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
|
|
#else
|
|
#define Log(...)
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Constants
|
|
|
|
static constexpr uint16_t kClassQueryUnicastFlag = (1U << 15);
|
|
static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
|
|
static constexpr uint16_t kClassMask = 0x7fff;
|
|
static constexpr uint16_t kStringSize = 300;
|
|
static constexpr uint16_t kMaxDataSize = 400;
|
|
static constexpr uint16_t kNumAnnounces = 3;
|
|
static constexpr uint16_t kNumInitialQueries = 15;
|
|
static constexpr uint16_t kNumRefreshQueries = 4;
|
|
static constexpr bool kCacheFlush = true;
|
|
static constexpr uint16_t kMdnsPort = 5353;
|
|
static constexpr uint16_t kEphemeralPort = 49152;
|
|
static constexpr uint16_t kLegacyUnicastMessageId = 1;
|
|
static constexpr uint16_t kMaxLegacyUnicastTtl = 10;
|
|
static constexpr uint32_t kInfraIfIndex = 1;
|
|
|
|
static const char kDeviceIp6Address[] = "fd01::1";
|
|
|
|
class DnsMessage;
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Variables
|
|
|
|
static Instance *sInstance;
|
|
|
|
static uint32_t sNow = 0;
|
|
static uint32_t sAlarmTime;
|
|
static bool sAlarmOn = false;
|
|
|
|
OwningList<DnsMessage> sDnsMessages;
|
|
uint32_t sInfraIfIndex;
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Prototypes
|
|
|
|
static const char *RecordTypeToString(uint16_t aType);
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Types
|
|
|
|
template <typename Type> class Allocatable
|
|
{
|
|
public:
|
|
static Type *Allocate(void)
|
|
{
|
|
void *buf = calloc(1, sizeof(Type));
|
|
|
|
VerifyOrQuit(buf != nullptr);
|
|
return new (buf) Type();
|
|
}
|
|
|
|
void Free(void)
|
|
{
|
|
static_cast<Type *>(this)->~Type();
|
|
free(this);
|
|
}
|
|
};
|
|
|
|
struct DnsName
|
|
{
|
|
Name::Buffer mName;
|
|
|
|
void ParseFrom(const Message &aMessage, uint16_t &aOffset)
|
|
{
|
|
SuccessOrQuit(Name::ReadName(aMessage, aOffset, mName));
|
|
}
|
|
|
|
void CopyFrom(const char *aName)
|
|
{
|
|
if (aName == nullptr)
|
|
{
|
|
mName[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
uint16_t len = StringLength(aName, sizeof(mName));
|
|
|
|
VerifyOrQuit(len < sizeof(mName));
|
|
memcpy(mName, aName, len + 1);
|
|
}
|
|
}
|
|
|
|
const char *AsCString(void) const { return mName; }
|
|
bool Matches(const char *aName) const { return StringMatch(mName, aName, kStringCaseInsensitiveMatch); }
|
|
};
|
|
|
|
typedef String<Name::kMaxNameSize> DnsNameString;
|
|
|
|
struct AddrAndTtl
|
|
{
|
|
bool operator==(const AddrAndTtl &aOther) const { return (mTtl == aOther.mTtl) && (mAddress == aOther.mAddress); }
|
|
|
|
Ip6::Address mAddress;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
struct DnsQuestion : public Allocatable<DnsQuestion>, public LinkedListEntry<DnsQuestion>
|
|
{
|
|
DnsQuestion *mNext;
|
|
DnsName mName;
|
|
uint16_t mType;
|
|
uint16_t mClass;
|
|
bool mUnicastResponse;
|
|
|
|
void ParseFrom(const Message &aMessage, uint16_t &aOffset)
|
|
{
|
|
Question question;
|
|
|
|
mName.ParseFrom(aMessage, aOffset);
|
|
SuccessOrQuit(aMessage.Read(aOffset, question));
|
|
aOffset += sizeof(Question);
|
|
|
|
mNext = nullptr;
|
|
mType = question.GetType();
|
|
mClass = question.GetClass() & kClassMask;
|
|
mUnicastResponse = question.GetClass() & kClassQueryUnicastFlag;
|
|
|
|
Log(" %s %s %s class:%u", mName.AsCString(), RecordTypeToString(mType), mUnicastResponse ? "QU" : "QM",
|
|
mClass);
|
|
}
|
|
|
|
bool Matches(const char *aName) const { return mName.Matches(aName); }
|
|
};
|
|
|
|
struct DnsQuestions : public OwningList<DnsQuestion>
|
|
{
|
|
bool Contains(uint16_t aRrType, const DnsNameString &aFullName, bool aUnicastResponse = false) const
|
|
{
|
|
bool contains = false;
|
|
const DnsQuestion *question = FindMatching(aFullName.AsCString());
|
|
|
|
VerifyOrExit(question != nullptr);
|
|
VerifyOrExit(question->mType == aRrType);
|
|
VerifyOrExit(question->mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(question->mUnicastResponse == aUnicastResponse);
|
|
contains = true;
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool Contains(const DnsNameString &aFullName, bool aUnicastResponse) const
|
|
{
|
|
return Contains(ResourceRecord::kTypeAny, aFullName, aUnicastResponse);
|
|
}
|
|
};
|
|
|
|
enum TtlCheckMode : uint8_t
|
|
{
|
|
kZeroTtl,
|
|
kNonZeroTtl,
|
|
kLegacyUnicastTtl,
|
|
};
|
|
|
|
enum Section : uint8_t
|
|
{
|
|
kInAnswerSection,
|
|
kInAdditionalSection,
|
|
};
|
|
|
|
struct Data : public ot::Data<kWithUint16Length>
|
|
{
|
|
Data(const void *aBuffer, uint16_t aLength) { Init(aBuffer, aLength); }
|
|
|
|
bool Matches(const Array<uint8_t, kMaxDataSize> &aDataArray) const
|
|
{
|
|
return (aDataArray.GetLength() == GetLength()) && MatchesBytesIn(aDataArray.GetArrayBuffer());
|
|
}
|
|
};
|
|
|
|
struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsRecord>
|
|
{
|
|
struct SrvData
|
|
{
|
|
uint16_t mPriority;
|
|
uint16_t mWeight;
|
|
uint16_t mPort;
|
|
DnsName mHostName;
|
|
};
|
|
|
|
union RecordData
|
|
{
|
|
RecordData(void) { memset(this, 0, sizeof(*this)); }
|
|
|
|
Ip6::Address mIp6Address; // For AAAAA
|
|
Ip4::Address mIp4Address; // For A
|
|
SrvData mSrv; // For SRV
|
|
Array<uint8_t, kMaxDataSize> mData; // For TXT or KEY
|
|
DnsName mPtrName; // For PTR
|
|
NsecRecord::TypeBitMap mNsecBitmap; // For NSEC
|
|
};
|
|
|
|
DnsRecord *mNext;
|
|
DnsName mName;
|
|
uint16_t mType;
|
|
uint16_t mClass;
|
|
uint32_t mTtl;
|
|
bool mCacheFlush;
|
|
RecordData mData;
|
|
|
|
bool Matches(const char *aName) const { return mName.Matches(aName); }
|
|
|
|
void ParseFrom(const Message &aMessage, uint16_t &aOffset)
|
|
{
|
|
String<kStringSize> logStr;
|
|
ResourceRecord record;
|
|
uint16_t offset;
|
|
|
|
mName.ParseFrom(aMessage, aOffset);
|
|
SuccessOrQuit(aMessage.Read(aOffset, record));
|
|
aOffset += sizeof(ResourceRecord);
|
|
|
|
mNext = nullptr;
|
|
mType = record.GetType();
|
|
mClass = record.GetClass() & kClassMask;
|
|
mCacheFlush = record.GetClass() & kClassCacheFlushFlag;
|
|
mTtl = record.GetTtl();
|
|
|
|
logStr.Append("%s %s%s cls:%u ttl:%u", mName.AsCString(), RecordTypeToString(mType),
|
|
mCacheFlush ? " cache-flush" : "", mClass, mTtl);
|
|
|
|
offset = aOffset;
|
|
|
|
switch (mType)
|
|
{
|
|
case ResourceRecord::kTypeA:
|
|
VerifyOrQuit(record.GetLength() == sizeof(Ip4::Address));
|
|
SuccessOrQuit(aMessage.Read(offset, mData.mIp4Address));
|
|
logStr.Append(" %s", mData.mIp4Address.ToString().AsCString());
|
|
break;
|
|
|
|
case ResourceRecord::kTypeAaaa:
|
|
VerifyOrQuit(record.GetLength() == sizeof(Ip6::Address));
|
|
SuccessOrQuit(aMessage.Read(offset, mData.mIp6Address));
|
|
logStr.Append(" %s", mData.mIp6Address.ToString().AsCString());
|
|
break;
|
|
|
|
case ResourceRecord::kTypeKey:
|
|
case ResourceRecord::kTypeTxt:
|
|
VerifyOrQuit(record.GetLength() > 0);
|
|
VerifyOrQuit(record.GetLength() < kMaxDataSize);
|
|
mData.mData.SetLength(record.GetLength());
|
|
SuccessOrQuit(aMessage.Read(offset, mData.mData.GetArrayBuffer(), record.GetLength()));
|
|
logStr.Append(" data-len:%u", record.GetLength());
|
|
break;
|
|
|
|
case ResourceRecord::kTypePtr:
|
|
mData.mPtrName.ParseFrom(aMessage, offset);
|
|
VerifyOrQuit(offset - aOffset == record.GetLength());
|
|
logStr.Append(" %s", mData.mPtrName.AsCString());
|
|
break;
|
|
|
|
case ResourceRecord::kTypeSrv:
|
|
{
|
|
SrvRecord srv;
|
|
|
|
offset -= sizeof(ResourceRecord);
|
|
SuccessOrQuit(aMessage.Read(offset, srv));
|
|
offset += sizeof(srv);
|
|
mData.mSrv.mHostName.ParseFrom(aMessage, offset);
|
|
VerifyOrQuit(offset - aOffset == record.GetLength());
|
|
mData.mSrv.mPriority = srv.GetPriority();
|
|
mData.mSrv.mWeight = srv.GetWeight();
|
|
mData.mSrv.mPort = srv.GetPort();
|
|
logStr.Append(" port:%u w:%u prio:%u host:%s", mData.mSrv.mPort, mData.mSrv.mWeight, mData.mSrv.mPriority,
|
|
mData.mSrv.mHostName.AsCString());
|
|
break;
|
|
}
|
|
|
|
case ResourceRecord::kTypeNsec:
|
|
{
|
|
NsecRecord::TypeBitMap &bitmap = mData.mNsecBitmap;
|
|
|
|
SuccessOrQuit(Name::CompareName(aMessage, offset, mName.AsCString()));
|
|
SuccessOrQuit(aMessage.Read(offset, &bitmap, NsecRecord::TypeBitMap::kMinSize));
|
|
VerifyOrQuit(bitmap.GetBlockNumber() == 0);
|
|
VerifyOrQuit(bitmap.GetBitmapLength() <= NsecRecord::TypeBitMap::kMaxLength);
|
|
SuccessOrQuit(aMessage.Read(offset, &bitmap, bitmap.GetSize()));
|
|
|
|
offset += bitmap.GetSize();
|
|
VerifyOrQuit(offset - aOffset == record.GetLength());
|
|
|
|
logStr.Append(" [ ");
|
|
|
|
for (uint16_t type = 0; type < bitmap.GetBitmapLength() * kBitsPerByte; type++)
|
|
{
|
|
if (bitmap.ContainsType(type))
|
|
{
|
|
logStr.Append("%s ", RecordTypeToString(type));
|
|
}
|
|
}
|
|
|
|
logStr.Append("]");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Log(" %s", logStr.AsCString());
|
|
|
|
aOffset += record.GetLength();
|
|
}
|
|
|
|
bool MatchesTtl(TtlCheckMode aTtlCheckMode, uint32_t aTtl) const
|
|
{
|
|
bool matches = false;
|
|
|
|
switch (aTtlCheckMode)
|
|
{
|
|
case kZeroTtl:
|
|
VerifyOrExit(mTtl == 0);
|
|
break;
|
|
case kNonZeroTtl:
|
|
if (aTtl > 0)
|
|
{
|
|
VerifyOrQuit(mTtl == aTtl);
|
|
}
|
|
|
|
VerifyOrExit(mTtl > 0);
|
|
break;
|
|
case kLegacyUnicastTtl:
|
|
VerifyOrQuit(mTtl <= kMaxLegacyUnicastTtl);
|
|
break;
|
|
}
|
|
|
|
matches = true;
|
|
|
|
exit:
|
|
return matches;
|
|
}
|
|
};
|
|
|
|
struct DnsRecords : public OwningList<DnsRecord>
|
|
{
|
|
bool ContainsAaaa(const DnsNameString &aFullName,
|
|
const Ip6::Address &aAddress,
|
|
bool aCacheFlush,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeAaaa) &&
|
|
(record.mData.mIp6Address == aAddress))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsA(const DnsNameString &aFullName,
|
|
const Ip4::Address &aAddress,
|
|
bool aCacheFlush,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeA) &&
|
|
(record.mData.mIp4Address == aAddress))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsKey(const DnsNameString &aFullName,
|
|
const Data &aKeyData,
|
|
bool aCacheFlush,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeKey) &&
|
|
aKeyData.Matches(record.mData.mData))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsSrv(const DnsNameString &aFullName,
|
|
const Core::Service &aService,
|
|
bool aCacheFlush,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
bool contains = false;
|
|
DnsNameString hostName;
|
|
|
|
hostName.Append("%s.local.",
|
|
aService.mHostName != nullptr ? aService.mHostName : sInstance->Get<Core>().GetLocalHostName());
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeSrv))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
VerifyOrExit(record.mData.mSrv.mPort == aService.mPort);
|
|
VerifyOrExit(record.mData.mSrv.mPriority == aService.mPriority);
|
|
VerifyOrExit(record.mData.mSrv.mWeight == aService.mWeight);
|
|
VerifyOrExit(record.mData.mSrv.mHostName.Matches(hostName.AsCString()));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsTxt(const DnsNameString &aFullName,
|
|
const Core::Service &aService,
|
|
bool aCacheFlush,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
static const uint8_t kEmptyTxtData[1] = {0};
|
|
|
|
bool contains = false;
|
|
Data txtData(aService.mTxtData, aService.mTxtDataLength);
|
|
|
|
if ((aService.mTxtData == nullptr) || (aService.mTxtDataLength == 0))
|
|
{
|
|
txtData.Init(kEmptyTxtData, sizeof(kEmptyTxtData));
|
|
}
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeTxt) &&
|
|
txtData.Matches(record.mData.mData))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsPtr(const DnsNameString &aFullName,
|
|
const DnsNameString &aPtrName,
|
|
TtlCheckMode aTtlCheckMode,
|
|
uint32_t aTtl = 0) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypePtr) &&
|
|
(record.mData.mPtrName.Matches(aPtrName.AsCString())))
|
|
{
|
|
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
|
VerifyOrExit(!record.mCacheFlush); // PTR should never use cache-flush
|
|
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
|
contains = true;
|
|
ExitNow();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
|
|
bool ContainsServicesPtr(const DnsNameString &aServiceType) const
|
|
{
|
|
DnsNameString allServices;
|
|
|
|
allServices.Append("_services._dns-sd._udp.local.");
|
|
|
|
return ContainsPtr(allServices, aServiceType, kNonZeroTtl, 0);
|
|
}
|
|
|
|
bool ContainsNsec(const DnsNameString &aFullName, uint16_t aRecordType) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (const DnsRecord &record : *this)
|
|
{
|
|
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeNsec))
|
|
{
|
|
VerifyOrQuit(!contains); // Ensure only one NSEC record
|
|
VerifyOrExit(record.mData.mNsecBitmap.ContainsType(aRecordType));
|
|
contains = true;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return contains;
|
|
}
|
|
};
|
|
|
|
// Bit-flags used in `Validate()` with a `Service` or `LocalHost`
|
|
// to specify which records should be checked in the announce
|
|
// message.
|
|
|
|
typedef uint8_t AnnounceCheckFlags;
|
|
|
|
static constexpr uint8_t kCheckSrv = (1 << 0);
|
|
static constexpr uint8_t kCheckTxt = (1 << 1);
|
|
static constexpr uint8_t kCheckPtr = (1 << 2);
|
|
static constexpr uint8_t kCheckServicesPtr = (1 << 3);
|
|
static constexpr uint8_t kCheckAaaa = (1 << 4);
|
|
static constexpr uint8_t kCheckA = (1 << 5);
|
|
|
|
enum GoodBye : bool // Used to indicate "goodbye" records (with zero TTL)
|
|
{
|
|
kNotGoodBye = false,
|
|
kGoodBye = true,
|
|
};
|
|
|
|
enum DnsMessageType : uint8_t
|
|
{
|
|
kMulticastQuery,
|
|
kMulticastResponse,
|
|
kUnicastResponse,
|
|
kLegacyUnicastResponse,
|
|
};
|
|
|
|
struct LocalHost
|
|
{
|
|
static constexpr uint32_t kTtl = 120;
|
|
static constexpr uint16_t kMaxAddrs = 16;
|
|
|
|
char mName[Name::kMaxNameSize];
|
|
Array<Ip6::Address, kMaxAddrs> mIp6Addrs;
|
|
Array<Ip4::Address, kMaxAddrs> mIp4Addrs;
|
|
};
|
|
|
|
struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMessage>
|
|
{
|
|
DnsMessage *mNext;
|
|
uint32_t mTimestamp;
|
|
DnsMessageType mType;
|
|
Core::AddressInfo mUnicastDest;
|
|
Header mHeader;
|
|
DnsQuestions mQuestions;
|
|
DnsRecords mAnswerRecords;
|
|
DnsRecords mAuthRecords;
|
|
DnsRecords mAdditionalRecords;
|
|
|
|
DnsMessage(void)
|
|
: mNext(nullptr)
|
|
, mTimestamp(sNow)
|
|
{
|
|
}
|
|
|
|
const DnsRecords &RecordsFor(Section aSection) const
|
|
{
|
|
const DnsRecords *records = nullptr;
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
records = &mAnswerRecords;
|
|
break;
|
|
case kInAdditionalSection:
|
|
records = &mAdditionalRecords;
|
|
break;
|
|
}
|
|
|
|
VerifyOrQuit(records != nullptr);
|
|
|
|
return *records;
|
|
}
|
|
|
|
void ParseRecords(const Message &aMessage,
|
|
uint16_t &aOffset,
|
|
uint16_t aNumRecords,
|
|
OwningList<DnsRecord> &aRecords,
|
|
const char *aSectionName)
|
|
{
|
|
if (aNumRecords > 0)
|
|
{
|
|
Log(" %s", aSectionName);
|
|
}
|
|
|
|
for (; aNumRecords > 0; aNumRecords--)
|
|
{
|
|
DnsRecord *record = DnsRecord::Allocate();
|
|
|
|
record->ParseFrom(aMessage, aOffset);
|
|
aRecords.PushAfterTail(*record);
|
|
}
|
|
}
|
|
|
|
void ParseFrom(const Message &aMessage)
|
|
{
|
|
uint16_t offset = 0;
|
|
|
|
SuccessOrQuit(aMessage.Read(offset, mHeader));
|
|
offset += sizeof(Header);
|
|
|
|
Log(" %s id:%u qt:%u t:%u rcode:%u [q:%u ans:%u auth:%u addn:%u]",
|
|
mHeader.GetType() == Header::kTypeQuery ? "Query" : "Response", mHeader.GetMessageId(),
|
|
mHeader.GetQueryType(), mHeader.IsTruncationFlagSet(), mHeader.GetResponseCode(),
|
|
mHeader.GetQuestionCount(), mHeader.GetAnswerCount(), mHeader.GetAuthorityRecordCount(),
|
|
mHeader.GetAdditionalRecordCount());
|
|
|
|
if (mHeader.GetQuestionCount() > 0)
|
|
{
|
|
Log(" Question");
|
|
}
|
|
|
|
for (uint16_t num = mHeader.GetQuestionCount(); num > 0; num--)
|
|
{
|
|
DnsQuestion *question = DnsQuestion::Allocate();
|
|
|
|
question->ParseFrom(aMessage, offset);
|
|
mQuestions.PushAfterTail(*question);
|
|
}
|
|
|
|
ParseRecords(aMessage, offset, mHeader.GetAnswerCount(), mAnswerRecords, "Answer");
|
|
ParseRecords(aMessage, offset, mHeader.GetAuthorityRecordCount(), mAuthRecords, "Authority");
|
|
ParseRecords(aMessage, offset, mHeader.GetAdditionalRecordCount(), mAdditionalRecords, "Additional");
|
|
}
|
|
|
|
void ValidateHeader(DnsMessageType aType,
|
|
uint16_t aQuestionCount,
|
|
uint16_t aAnswerCount,
|
|
uint16_t aAuthCount,
|
|
uint16_t aAdditionalCount) const
|
|
{
|
|
VerifyOrQuit(mType == aType);
|
|
VerifyOrQuit(mHeader.GetQuestionCount() == aQuestionCount);
|
|
VerifyOrQuit(mHeader.GetAnswerCount() == aAnswerCount);
|
|
VerifyOrQuit(mHeader.GetAuthorityRecordCount() == aAuthCount);
|
|
VerifyOrQuit(mHeader.GetAdditionalRecordCount() == aAdditionalCount);
|
|
|
|
if (aType == kUnicastResponse)
|
|
{
|
|
Ip6::Address ip6Address;
|
|
|
|
SuccessOrQuit(ip6Address.FromString(kDeviceIp6Address));
|
|
|
|
VerifyOrQuit(mUnicastDest.mPort == kMdnsPort);
|
|
VerifyOrQuit(mUnicastDest.GetAddress() == ip6Address);
|
|
}
|
|
|
|
if (aType == kLegacyUnicastResponse)
|
|
{
|
|
VerifyOrQuit(mHeader.GetMessageId() == kLegacyUnicastMessageId);
|
|
VerifyOrQuit(mUnicastDest.mPort == kEphemeralPort);
|
|
}
|
|
}
|
|
|
|
static void DetermineFullNameForKey(const Core::Key &aKey, DnsNameString &aFullName)
|
|
{
|
|
if (aKey.mServiceType != nullptr)
|
|
{
|
|
aFullName.Append("%s.%s.local.", aKey.mName, aKey.mServiceType);
|
|
}
|
|
else
|
|
{
|
|
aFullName.Append("%s.local.", aKey.mName);
|
|
}
|
|
}
|
|
|
|
static TtlCheckMode DetermineTtlCheckMode(DnsMessageType aMessageType, bool aIsGoodBye)
|
|
{
|
|
TtlCheckMode ttlCheck;
|
|
|
|
if (aMessageType == kLegacyUnicastResponse)
|
|
{
|
|
ttlCheck = kLegacyUnicastTtl;
|
|
}
|
|
else
|
|
{
|
|
ttlCheck = aIsGoodBye ? kZeroTtl : kNonZeroTtl;
|
|
}
|
|
|
|
return ttlCheck;
|
|
}
|
|
|
|
void ValidateAsProbeFor(const Core::Host &aHost, bool aUnicastResponse) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
fullName.Append("%s.local.", aHost.mHostName);
|
|
VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
|
|
|
|
for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
|
|
{
|
|
VerifyOrQuit(mAuthRecords.ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]), !kCacheFlush,
|
|
kNonZeroTtl, aHost.mTtl));
|
|
}
|
|
}
|
|
|
|
void ValidateAsProbeFor(const LocalHost &aLocalHost, bool aUnicastResponse) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
fullName.Append("%s.local.", aLocalHost.mName);
|
|
VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
|
|
|
|
for (const Ip6::Address &ip6Addr : aLocalHost.mIp6Addrs)
|
|
{
|
|
VerifyOrQuit(mAuthRecords.ContainsAaaa(fullName, ip6Addr, !kCacheFlush, kNonZeroTtl, LocalHost::kTtl));
|
|
}
|
|
|
|
for (const Ip4::Address &ip4Addr : aLocalHost.mIp4Addrs)
|
|
{
|
|
VerifyOrQuit(mAuthRecords.ContainsA(fullName, ip4Addr, !kCacheFlush, kNonZeroTtl, LocalHost::kTtl));
|
|
}
|
|
}
|
|
|
|
void ValidateAsProbeFor(const Core::Service &aService, bool aUnicastResponse) const
|
|
{
|
|
DnsNameString serviceName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
|
|
|
|
VerifyOrQuit(mQuestions.Contains(serviceName, aUnicastResponse));
|
|
|
|
VerifyOrQuit(mAuthRecords.ContainsSrv(serviceName, aService, !kCacheFlush, kNonZeroTtl, aService.mTtl));
|
|
VerifyOrQuit(mAuthRecords.ContainsTxt(serviceName, aService, !kCacheFlush, kNonZeroTtl, aService.mTtl));
|
|
}
|
|
|
|
void ValidateAsProbeFor(const Core::Key &aKey, bool aUnicastResponse) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
DetermineFullNameForKey(aKey, fullName);
|
|
|
|
VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
|
|
VerifyOrQuit(mAuthRecords.ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), !kCacheFlush,
|
|
kNonZeroTtl, aKey.mTtl));
|
|
}
|
|
|
|
void Validate(const Core::Host &aHost, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
|
|
{
|
|
DnsNameString fullName;
|
|
TtlCheckMode ttlCheck;
|
|
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
|
|
|
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
|
|
|
fullName.Append("%s.local.", aHost.mHostName);
|
|
|
|
for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
|
|
{
|
|
VerifyOrQuit(RecordsFor(aSection).ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]),
|
|
cacheFlushSet, ttlCheck, aHost.mTtl));
|
|
}
|
|
|
|
if (!aIsGoodBye && (aSection == kInAnswerSection))
|
|
{
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeAaaa));
|
|
}
|
|
}
|
|
|
|
void Validate(const LocalHost &aLocalHost,
|
|
Section aSection,
|
|
AnnounceCheckFlags aCheckFlags,
|
|
GoodBye aIsGoodBye = kNotGoodBye) const
|
|
{
|
|
DnsNameString fullName;
|
|
TtlCheckMode ttlCheck;
|
|
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
|
|
|
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
|
|
|
fullName.Append("%s.local.", aLocalHost.mName);
|
|
|
|
if (aCheckFlags & kCheckAaaa)
|
|
{
|
|
for (const Ip6::Address &ip6Addr : aLocalHost.mIp6Addrs)
|
|
{
|
|
VerifyOrQuit(
|
|
RecordsFor(aSection).ContainsAaaa(fullName, ip6Addr, cacheFlushSet, ttlCheck, LocalHost::kTtl));
|
|
}
|
|
}
|
|
|
|
if (aCheckFlags & kCheckA)
|
|
{
|
|
for (const Ip4::Address &ip4Addr : aLocalHost.mIp4Addrs)
|
|
{
|
|
VerifyOrQuit(
|
|
RecordsFor(aSection).ContainsA(fullName, ip4Addr, cacheFlushSet, ttlCheck, LocalHost::kTtl));
|
|
}
|
|
}
|
|
|
|
if (!aIsGoodBye && (aSection == kInAnswerSection))
|
|
{
|
|
bool shouldSeeAaaa = (aLocalHost.mIp6Addrs.GetLength() != 0);
|
|
bool shouldSeeA = (aLocalHost.mIp4Addrs.GetLength() != 0);
|
|
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeAaaa) == shouldSeeAaaa);
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeA) == shouldSeeA);
|
|
}
|
|
}
|
|
|
|
void Validate(const Core::Service &aService,
|
|
Section aSection,
|
|
AnnounceCheckFlags aCheckFlags,
|
|
GoodBye aIsGoodBye = kNotGoodBye) const
|
|
{
|
|
DnsNameString serviceName;
|
|
DnsNameString serviceType;
|
|
TtlCheckMode ttlCheck;
|
|
bool checkNsec = false;
|
|
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
|
|
|
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
|
|
|
serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
|
|
serviceType.Append("%s.local.", aService.mServiceType);
|
|
|
|
if (aCheckFlags & kCheckSrv)
|
|
{
|
|
VerifyOrQuit(
|
|
RecordsFor(aSection).ContainsSrv(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
|
|
|
|
checkNsec = true;
|
|
}
|
|
|
|
if (aCheckFlags & kCheckTxt)
|
|
{
|
|
VerifyOrQuit(
|
|
RecordsFor(aSection).ContainsTxt(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
|
|
|
|
checkNsec = true;
|
|
}
|
|
|
|
if (aCheckFlags & kCheckPtr)
|
|
{
|
|
VerifyOrQuit(RecordsFor(aSection).ContainsPtr(serviceType, serviceName, ttlCheck, aService.mTtl));
|
|
}
|
|
|
|
if (aCheckFlags & kCheckServicesPtr)
|
|
{
|
|
VerifyOrQuit(RecordsFor(aSection).ContainsServicesPtr(serviceType));
|
|
}
|
|
|
|
if (!aIsGoodBye && checkNsec && (aSection == kInAnswerSection))
|
|
{
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(serviceName, ResourceRecord::kTypeSrv));
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(serviceName, ResourceRecord::kTypeTxt));
|
|
}
|
|
}
|
|
|
|
void Validate(const Core::Key &aKey, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
|
|
{
|
|
DnsNameString fullName;
|
|
TtlCheckMode ttlCheck;
|
|
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
|
|
|
DetermineFullNameForKey(aKey, fullName);
|
|
|
|
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
|
|
|
VerifyOrQuit(RecordsFor(aSection).ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), cacheFlushSet,
|
|
ttlCheck, aKey.mTtl));
|
|
|
|
if (!aIsGoodBye && (aSection == kInAnswerSection))
|
|
{
|
|
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeKey));
|
|
}
|
|
}
|
|
|
|
void ValidateSubType(const char *aSubLabel, const Core::Service &aService, GoodBye aIsGoodBye = kNotGoodBye) const
|
|
{
|
|
DnsNameString serviceName;
|
|
DnsNameString subServiceType;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
|
|
|
serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
|
|
subServiceType.Append("%s._sub.%s.local.", aSubLabel, aService.mServiceType);
|
|
|
|
VerifyOrQuit(mAnswerRecords.ContainsPtr(subServiceType, serviceName, aIsGoodBye ? kZeroTtl : kNonZeroTtl,
|
|
aService.mTtl));
|
|
}
|
|
|
|
void ValidateAsQueryFor(const Core::Browser &aBrowser) const
|
|
{
|
|
DnsNameString fullServiceType;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
if (aBrowser.mSubTypeLabel == nullptr)
|
|
{
|
|
fullServiceType.Append("%s.local.", aBrowser.mServiceType);
|
|
}
|
|
else
|
|
{
|
|
fullServiceType.Append("%s._sub.%s.local", aBrowser.mSubTypeLabel, aBrowser.mServiceType);
|
|
}
|
|
|
|
VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypePtr, fullServiceType));
|
|
}
|
|
|
|
void ValidateAsQueryFor(const Core::SrvResolver &aResolver) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
fullName.Append("%s.%s.local.", aResolver.mServiceInstance, aResolver.mServiceType);
|
|
|
|
VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeSrv, fullName));
|
|
}
|
|
|
|
void ValidateAsQueryFor(const Core::TxtResolver &aResolver) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
fullName.Append("%s.%s.local.", aResolver.mServiceInstance, aResolver.mServiceType);
|
|
|
|
VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeTxt, fullName));
|
|
}
|
|
|
|
void ValidateAsQueryFor(const Core::AddressResolver &aResolver) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
fullName.Append("%s.local.", aResolver.mHostName);
|
|
|
|
VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeAaaa, fullName));
|
|
}
|
|
|
|
void ValidateAsQueryFor(const Core::RecordQuerier &aQuerier) const
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
|
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
|
|
|
if (aQuerier.mNextLabels == nullptr)
|
|
{
|
|
fullName.Append("%s.local.", aQuerier.mFirstLabel);
|
|
}
|
|
else
|
|
{
|
|
fullName.Append("%s.%s.local.", aQuerier.mFirstLabel, aQuerier.mNextLabels);
|
|
}
|
|
|
|
VerifyOrQuit(mQuestions.Contains(aQuerier.mRecordType, fullName));
|
|
}
|
|
};
|
|
|
|
struct RegCallback
|
|
{
|
|
void Reset(void) { mWasCalled = false; }
|
|
|
|
bool mWasCalled;
|
|
Error mError;
|
|
};
|
|
|
|
static constexpr uint16_t kMaxCallbacks = 8;
|
|
|
|
static RegCallback sRegCallbacks[kMaxCallbacks];
|
|
|
|
static void HandleCallback(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError)
|
|
{
|
|
Log("Register callback - ResuestId:%u Error:%s", aRequestId, otThreadErrorToString(aError));
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aRequestId < kMaxCallbacks);
|
|
|
|
VerifyOrQuit(!sRegCallbacks[aRequestId].mWasCalled);
|
|
|
|
sRegCallbacks[aRequestId].mWasCalled = true;
|
|
sRegCallbacks[aRequestId].mError = aError;
|
|
}
|
|
|
|
static void HandleSuccessCallback(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError)
|
|
{
|
|
HandleCallback(aInstance, aRequestId, aError);
|
|
SuccessOrQuit(aError);
|
|
}
|
|
|
|
struct ConflictCallback
|
|
{
|
|
void Reset(void) { mWasCalled = false; }
|
|
|
|
void Handle(const char *aName, const char *aServiceType)
|
|
{
|
|
VerifyOrQuit(!mWasCalled);
|
|
|
|
mWasCalled = true;
|
|
mName.Clear();
|
|
mName.Append("%s", aName);
|
|
|
|
mHasServiceType = (aServiceType != nullptr);
|
|
VerifyOrExit(mHasServiceType);
|
|
mServiceType.Clear();
|
|
mServiceType.Append("%s", aServiceType);
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
bool mWasCalled;
|
|
bool mHasServiceType;
|
|
DnsNameString mName;
|
|
DnsNameString mServiceType;
|
|
};
|
|
|
|
static ConflictCallback sConflictCallback;
|
|
|
|
static void HandleConflict(otInstance *aInstance, const char *aName, const char *aServiceType)
|
|
{
|
|
Log("Conflict callback - %s %s", aName, (aServiceType == nullptr) ? "" : aServiceType);
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
sConflictCallback.Handle(aName, aServiceType);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Helper functions and methods
|
|
|
|
static const char *RecordTypeToString(uint16_t aType)
|
|
{
|
|
const char *str = "Other";
|
|
|
|
switch (aType)
|
|
{
|
|
case ResourceRecord::kTypeZero:
|
|
str = "ZERO";
|
|
break;
|
|
case ResourceRecord::kTypeA:
|
|
str = "A";
|
|
break;
|
|
case ResourceRecord::kTypeSoa:
|
|
str = "SOA";
|
|
break;
|
|
case ResourceRecord::kTypeCname:
|
|
str = "CNAME";
|
|
break;
|
|
case ResourceRecord::kTypePtr:
|
|
str = "PTR";
|
|
break;
|
|
case ResourceRecord::kTypeTxt:
|
|
str = "TXT";
|
|
break;
|
|
case ResourceRecord::kTypeSig:
|
|
str = "SIG";
|
|
break;
|
|
case ResourceRecord::kTypeKey:
|
|
str = "KEY";
|
|
break;
|
|
case ResourceRecord::kTypeAaaa:
|
|
str = "AAAA";
|
|
break;
|
|
case ResourceRecord::kTypeSrv:
|
|
str = "SRV";
|
|
break;
|
|
case ResourceRecord::kTypeOpt:
|
|
str = "OPT";
|
|
break;
|
|
case ResourceRecord::kTypeNsec:
|
|
str = "NSEC";
|
|
break;
|
|
case ResourceRecord::kTypeAny:
|
|
str = "ANY";
|
|
break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
static void ParseMessage(const Message &aMessage, const Core::AddressInfo *aUnicastDest)
|
|
{
|
|
DnsMessage *msg = DnsMessage::Allocate();
|
|
|
|
msg->ParseFrom(aMessage);
|
|
|
|
switch (msg->mHeader.GetType())
|
|
{
|
|
case Header::kTypeQuery:
|
|
msg->mType = kMulticastQuery;
|
|
VerifyOrQuit(aUnicastDest == nullptr);
|
|
break;
|
|
|
|
case Header::kTypeResponse:
|
|
if (aUnicastDest == nullptr)
|
|
{
|
|
msg->mType = kMulticastResponse;
|
|
}
|
|
else
|
|
{
|
|
msg->mType = (aUnicastDest->mPort == kEphemeralPort) ? kLegacyUnicastResponse : kUnicastResponse;
|
|
msg->mUnicastDest = *aUnicastDest;
|
|
}
|
|
}
|
|
|
|
sDnsMessages.PushAfterTail(*msg);
|
|
}
|
|
|
|
static void SendQuery(const char *aName,
|
|
uint16_t aRecordType,
|
|
uint16_t aRecordClass = ResourceRecord::kClassInternet,
|
|
bool aTruncated = false,
|
|
bool aLegacyUnicastQuery = false)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeQuery);
|
|
header.SetQuestionCount(1);
|
|
|
|
if (aLegacyUnicastQuery)
|
|
{
|
|
header.SetMessageId(kLegacyUnicastMessageId);
|
|
}
|
|
|
|
if (aTruncated)
|
|
{
|
|
header.SetTruncationFlag();
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
SuccessOrQuit(message->Append(Question(aRecordType, aRecordClass)));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = aLegacyUnicastQuery ? kEphemeralPort : kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending query for %s %s", aName, RecordTypeToString(aRecordType));
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendQueryForTwo(const char *aName1,
|
|
uint16_t aRecordType1,
|
|
const char *aName2,
|
|
uint16_t aRecordType2,
|
|
bool aIsLegacyUnicast = false)
|
|
{
|
|
// Send query with two questions.
|
|
|
|
Message *message;
|
|
Header header;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeQuery);
|
|
header.SetQuestionCount(2);
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aName1, *message));
|
|
SuccessOrQuit(message->Append(Question(aRecordType1, ResourceRecord::kClassInternet)));
|
|
SuccessOrQuit(Name::AppendName(aName2, *message));
|
|
SuccessOrQuit(message->Append(Question(aRecordType2, ResourceRecord::kClassInternet)));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = aIsLegacyUnicast ? kEphemeralPort : kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending query for %s %s and %s %s", aName1, RecordTypeToString(aRecordType1), aName2,
|
|
RecordTypeToString(aRecordType2));
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendPtrResponse(const char *aName, const char *aPtrName, uint32_t aTtl, Section aSection)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
PtrRecord ptr;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
header.SetAnswerCount(1);
|
|
break;
|
|
case kInAdditionalSection:
|
|
header.SetAdditionalRecordCount(1);
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
|
|
ptr.Init();
|
|
ptr.SetTtl(aTtl);
|
|
ptr.SetLength(StringLength(aPtrName, Name::kMaxNameSize) + 1);
|
|
SuccessOrQuit(message->Append(ptr));
|
|
SuccessOrQuit(Name::AppendName(aPtrName, *message));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending PTR response for %s with %s, ttl:%lu", aName, aPtrName, ToUlong(aTtl));
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendSrvResponse(const char *aServiceName,
|
|
const char *aHostName,
|
|
uint16_t aPort,
|
|
uint16_t aPriority,
|
|
uint16_t aWeight,
|
|
uint32_t aTtl,
|
|
Section aSection)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
SrvRecord srv;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
header.SetAnswerCount(1);
|
|
break;
|
|
case kInAdditionalSection:
|
|
header.SetAdditionalRecordCount(1);
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aServiceName, *message));
|
|
|
|
srv.Init();
|
|
srv.SetTtl(aTtl);
|
|
srv.SetPort(aPort);
|
|
srv.SetPriority(aPriority);
|
|
srv.SetWeight(aWeight);
|
|
srv.SetLength(sizeof(srv) - sizeof(ResourceRecord) + StringLength(aHostName, Name::kMaxNameSize) + 1);
|
|
SuccessOrQuit(message->Append(srv));
|
|
SuccessOrQuit(Name::AppendName(aHostName, *message));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending SRV response for %s, host:%s, port:%u, ttl:%lu", aServiceName, aHostName, aPort, ToUlong(aTtl));
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendTxtResponse(const char *aServiceName,
|
|
const uint8_t *aTxtData,
|
|
uint16_t aTxtDataLength,
|
|
uint32_t aTtl,
|
|
Section aSection)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
TxtRecord txt;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
header.SetAnswerCount(1);
|
|
break;
|
|
case kInAdditionalSection:
|
|
header.SetAdditionalRecordCount(1);
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aServiceName, *message));
|
|
|
|
txt.Init();
|
|
txt.SetTtl(aTtl);
|
|
txt.SetLength(aTxtDataLength);
|
|
SuccessOrQuit(message->Append(txt));
|
|
SuccessOrQuit(message->AppendBytes(aTxtData, aTxtDataLength));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending TXT response for %s, len:%u, ttl:%lu", aServiceName, aTxtDataLength, ToUlong(aTtl));
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendHostAddrResponse(const char *aHostName,
|
|
AddrAndTtl *aAddrAndTtls,
|
|
uint32_t aNumAddrs,
|
|
bool aCacheFlush,
|
|
Section aSection)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
AaaaRecord record;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
header.SetAnswerCount(aNumAddrs);
|
|
break;
|
|
case kInAdditionalSection:
|
|
header.SetAdditionalRecordCount(aNumAddrs);
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
|
|
record.Init();
|
|
|
|
if (aCacheFlush)
|
|
{
|
|
record.SetClass(record.GetClass() | kClassCacheFlushFlag);
|
|
}
|
|
|
|
Log("Sending AAAA response for %s numAddrs:%u, cach-flush:%u", aHostName, aNumAddrs, aCacheFlush);
|
|
|
|
for (uint32_t index = 0; index < aNumAddrs; index++)
|
|
{
|
|
record.SetTtl(aAddrAndTtls[index].mTtl);
|
|
record.SetAddress(aAddrAndTtls[index].mAddress);
|
|
|
|
SuccessOrQuit(Name::AppendName(aHostName, *message));
|
|
SuccessOrQuit(message->Append(record));
|
|
|
|
Log(" - %s, ttl:%lu", aAddrAndTtls[index].mAddress.ToString().AsCString(), ToUlong(aAddrAndTtls[index].mTtl));
|
|
}
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
struct RecordData
|
|
{
|
|
uint16_t mType;
|
|
const uint8_t *mData;
|
|
uint16_t mLength;
|
|
uint32_t mTtl;
|
|
bool mCacheFlush;
|
|
};
|
|
|
|
static void SendRecordResponse(const char *aName, uint16_t aNumRecords, const RecordData *aRecords)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
ResourceRecord rr;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
header.SetAnswerCount(aNumRecords);
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
|
|
Log("Sending response with %u records", aNumRecords);
|
|
|
|
for (uint16_t index = 0; index < aNumRecords; index++)
|
|
{
|
|
const RecordData &record = aRecords[index];
|
|
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
|
|
rr.Init(record.mType);
|
|
|
|
if (record.mCacheFlush)
|
|
{
|
|
rr.SetClass(rr.GetClass() | kClassCacheFlushFlag);
|
|
}
|
|
|
|
rr.SetTtl(record.mTtl);
|
|
rr.SetLength(record.mLength);
|
|
SuccessOrQuit(message->Append(rr));
|
|
SuccessOrQuit(message->AppendBytes(record.mData, record.mLength));
|
|
|
|
Log(" Record %u (cache-flush:%u) for %s", record.mType, record.mCacheFlush, aName);
|
|
}
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendResponseWithEmptyKey(const char *aName, Section aSection)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
ResourceRecord record;
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeResponse);
|
|
|
|
switch (aSection)
|
|
{
|
|
case kInAnswerSection:
|
|
header.SetAnswerCount(1);
|
|
break;
|
|
case kInAdditionalSection:
|
|
header.SetAdditionalRecordCount(1);
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
|
|
record.Init(ResourceRecord::kTypeKey);
|
|
record.SetTtl(4500);
|
|
record.SetLength(0);
|
|
SuccessOrQuit(message->Append(record));
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending response with empty key for %s", aName);
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
struct KnownAnswer
|
|
{
|
|
const char *mPtrAnswer;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
static void SendPtrQueryWithKnownAnswers(const char *aName, const KnownAnswer *aKnownAnswers, uint16_t aNumAnswers)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
Core::AddressInfo senderAddrInfo;
|
|
uint16_t nameOffset;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeQuery);
|
|
header.SetQuestionCount(1);
|
|
header.SetAnswerCount(aNumAnswers);
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
nameOffset = message->GetLength();
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
SuccessOrQuit(message->Append(Question(ResourceRecord::kTypePtr, ResourceRecord::kClassInternet)));
|
|
|
|
for (uint16_t index = 0; index < aNumAnswers; index++)
|
|
{
|
|
PtrRecord ptr;
|
|
|
|
ptr.Init();
|
|
ptr.SetTtl(aKnownAnswers[index].mTtl);
|
|
ptr.SetLength(StringLength(aKnownAnswers[index].mPtrAnswer, Name::kMaxNameSize) + 1);
|
|
|
|
SuccessOrQuit(Name::AppendPointerLabel(nameOffset, *message));
|
|
SuccessOrQuit(message->Append(ptr));
|
|
SuccessOrQuit(Name::AppendName(aKnownAnswers[index].mPtrAnswer, *message));
|
|
}
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending query for %s PTR with %u known-answers", aName, aNumAnswers);
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
static void SendEmtryPtrQueryWithKnownAnswers(const char *aName, const KnownAnswer *aKnownAnswers, uint16_t aNumAnswers)
|
|
{
|
|
Message *message;
|
|
Header header;
|
|
Core::AddressInfo senderAddrInfo;
|
|
uint16_t nameOffset = 0;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
header.Clear();
|
|
header.SetType(Header::kTypeQuery);
|
|
header.SetAnswerCount(aNumAnswers);
|
|
|
|
SuccessOrQuit(message->Append(header));
|
|
|
|
for (uint16_t index = 0; index < aNumAnswers; index++)
|
|
{
|
|
PtrRecord ptr;
|
|
|
|
ptr.Init();
|
|
ptr.SetTtl(aKnownAnswers[index].mTtl);
|
|
ptr.SetLength(StringLength(aKnownAnswers[index].mPtrAnswer, Name::kMaxNameSize) + 1);
|
|
|
|
if (nameOffset == 0)
|
|
{
|
|
nameOffset = message->GetLength();
|
|
SuccessOrQuit(Name::AppendName(aName, *message));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(Name::AppendPointerLabel(nameOffset, *message));
|
|
}
|
|
|
|
SuccessOrQuit(message->Append(ptr));
|
|
SuccessOrQuit(Name::AppendName(aKnownAnswers[index].mPtrAnswer, *message));
|
|
}
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("Sending empty query with %u known-answers for %s", aNumAnswers, aName);
|
|
|
|
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `otPlatLog`
|
|
|
|
extern "C" {
|
|
|
|
#if ENABLE_TEST_LOG
|
|
|
|
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
|
|
#if OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE
|
|
void otPlatLogOutput(otInstance *, otLogLevel, const char *aLogLine) { printf(" %s\n", aLogLine); }
|
|
#else
|
|
void otPlatLog(otLogLevel, otLogRegion, const char *aFormat, ...)
|
|
{
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#endif // ENABLE_TEST_LOG
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `otPlatAlarm`
|
|
|
|
void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
|
|
|
|
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
|
{
|
|
sAlarmOn = true;
|
|
sAlarmTime = aT0 + aDt;
|
|
}
|
|
|
|
uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// Heap allocation
|
|
|
|
Array<void *, 500> sHeapAllocatedPtrs;
|
|
|
|
#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
|
|
|
|
void *otPlatCAlloc(size_t aNum, size_t aSize)
|
|
{
|
|
void *ptr = calloc(aNum, aSize);
|
|
|
|
SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void otPlatFree(void *aPtr)
|
|
{
|
|
if (aPtr != nullptr)
|
|
{
|
|
void **entry = sHeapAllocatedPtrs.Find(aPtr);
|
|
|
|
VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
|
|
sHeapAllocatedPtrs.Remove(*entry);
|
|
}
|
|
|
|
free(aPtr);
|
|
}
|
|
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `otPlatMdns`
|
|
|
|
otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
|
{
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
sInfraIfIndex = aInfraIfIndex;
|
|
|
|
Log("otPlatMdnsSetListeningEnabled(%s)", aEnable ? "true" : "false");
|
|
|
|
return kErrorNone;
|
|
}
|
|
|
|
void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
|
|
{
|
|
Message &message = AsCoreType(aMessage);
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
VerifyOrQuit(aInfraIfIndex == sInfraIfIndex);
|
|
|
|
Log("otPlatMdnsSendMulticast(msg-len:%u)", message.GetLength());
|
|
ParseMessage(message, nullptr);
|
|
|
|
// Pass the multicast message back.
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
otPlatMdnsHandleReceive(sInstance, aMessage, /* aIsUnicast */ false, &senderAddrInfo);
|
|
}
|
|
|
|
void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
|
|
{
|
|
Message &message = AsCoreType(aMessage);
|
|
const Core::AddressInfo &address = AsCoreType(aAddress);
|
|
Ip6::Address deviceAddress;
|
|
|
|
Log("otPlatMdnsSendUnicast() - [%s]:%u", address.GetAddress().ToString().AsCString(), address.mPort);
|
|
ParseMessage(message, AsCoreTypePtr(aAddress));
|
|
|
|
SuccessOrQuit(deviceAddress.FromString(kDeviceIp6Address));
|
|
|
|
if ((address.GetAddress() == deviceAddress) && (address.mPort == kMdnsPort))
|
|
{
|
|
Core::AddressInfo senderAddrInfo;
|
|
|
|
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
|
|
senderAddrInfo.mPort = kMdnsPort;
|
|
senderAddrInfo.mInfraIfIndex = 0;
|
|
|
|
Log("otPlatMdnsSendUnicast() - unicast msg matches this device address, passing it back");
|
|
otPlatMdnsHandleReceive(sInstance, &message, /* aIsUnicast */ true, &senderAddrInfo);
|
|
}
|
|
else
|
|
{
|
|
message.Free();
|
|
}
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void ProcessTasklets(void)
|
|
{
|
|
while (otTaskletsArePending(sInstance))
|
|
{
|
|
otTaskletsProcess(sInstance);
|
|
}
|
|
}
|
|
|
|
void AdvanceTime(uint32_t aDuration)
|
|
{
|
|
uint32_t time = sNow + aDuration;
|
|
|
|
Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
|
|
|
|
while (TimeMilli(sAlarmTime) <= TimeMilli(time))
|
|
{
|
|
ProcessTasklets();
|
|
sNow = sAlarmTime;
|
|
otPlatAlarmMilliFired(sInstance);
|
|
}
|
|
|
|
ProcessTasklets();
|
|
sNow = time;
|
|
}
|
|
|
|
Core *InitTest(void)
|
|
{
|
|
sNow = 0;
|
|
sAlarmOn = false;
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (RegCallback ®Callbck : sRegCallbacks)
|
|
{
|
|
regCallbck.Reset();
|
|
}
|
|
|
|
sConflictCallback.Reset();
|
|
|
|
sInstance = testInitInstance();
|
|
|
|
VerifyOrQuit(sInstance != nullptr);
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
|
// Disable the Border Agent to prevent its attempt to
|
|
// register the `_meshcop._udp` service from
|
|
// interfering with this test.
|
|
|
|
sInstance->Get<MeshCoP::BorderAgent::Manager>().SetEnabled(false);
|
|
#endif
|
|
|
|
return &sInstance->Get<Core>();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
static const uint8_t kKey1[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
|
static const uint8_t kKey2[] = {0x12, 0x34, 0x56};
|
|
static const uint8_t kKey3[] = {0xaa, 0xbb, 0xcc, 0xdd};
|
|
static const uint8_t kTxtData1[] = {3, 'a', '=', '1', 0};
|
|
static const uint8_t kTxtData2[] = {1, 'b', 0};
|
|
static const uint8_t kEmptyTxtData[] = {0};
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestHostReg(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Ip6::Address hostAddresses[3];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString hostFullName;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestHostReg");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::aaaa"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::bbbb"));
|
|
SuccessOrQuit(hostAddresses[2].FromString("fd00::cccc"));
|
|
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 3;
|
|
host.mTtl = 1500;
|
|
|
|
hostFullName.Append("%s.local.", host.mHostName);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `HostEntry`, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for AAAA record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for non-existing record and validate the response with NSEC");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
|
|
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update number of host addresses and validate new announcements");
|
|
|
|
host.mAddressesLength = 2;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Change the addresses and validate the first announce");
|
|
|
|
host.mAddressesLength = 3;
|
|
|
|
sRegCallbacks[0].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
|
|
AdvanceTime(300);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
Log("Change the address list again before second announce");
|
|
|
|
host.mAddressesLength = 1;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Change `HostEntry` TTL and validate announcements");
|
|
|
|
host.mTtl = 120;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for AAAA record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the host and validate the goodbye announces");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a host with no address (first time)");
|
|
|
|
host.mHostName = "newhost";
|
|
host.mAddresses = nullptr;
|
|
host.mAddressesLength = 0;
|
|
host.mTtl = 1500;
|
|
|
|
sRegCallbacks[2].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 2, HandleSuccessCallback));
|
|
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sRegCallbacks[2].mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the same host now with an address");
|
|
|
|
host.mAddresses = &hostAddresses[0];
|
|
host.mAddressesLength = 1;
|
|
|
|
sRegCallbacks[3].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 3, HandleSuccessCallback));
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sRegCallbacks[3].mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the same host again now with no address");
|
|
|
|
host.mAddressesLength = 0;
|
|
|
|
sRegCallbacks[4].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 4, HandleSuccessCallback));
|
|
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sRegCallbacks[4].mWasCalled);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the same host again now adding an address");
|
|
|
|
host.mAddresses = &hostAddresses[1];
|
|
host.mAddressesLength = 1;
|
|
|
|
sRegCallbacks[5].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 5, HandleSuccessCallback));
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sRegCallbacks[5].mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void ValidateLocalHostAddresses(Core &aMdns, const LocalHost &aLocalHost)
|
|
{
|
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
|
|
|
Core::Iterator *iterator;
|
|
Array<Ip6::Address, LocalHost::kMaxAddrs> ip6Addrs;
|
|
Array<Ip4::Address, LocalHost::kMaxAddrs> ip4Addrs;
|
|
|
|
iterator = aMdns.AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
Log("Verifying local host addresses (%u IPv6 and %u IPv4 addresses)", aLocalHost.mIp6Addrs.GetLength(),
|
|
aLocalHost.mIp4Addrs.GetLength());
|
|
|
|
while (true)
|
|
{
|
|
Error error;
|
|
Core::LocalHostAddress addr;
|
|
|
|
error = aMdns.GetNextLocalHostAddress(*iterator, addr);
|
|
|
|
if (error == kErrorNotFound)
|
|
{
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(error);
|
|
|
|
VerifyOrQuit(addr.mInfraIfIndex == kInfraIfIndex);
|
|
|
|
if (addr.mIsIp6)
|
|
{
|
|
SuccessOrQuit(ip6Addrs.PushBack(AsCoreType(&addr.mAddress.mIp6)));
|
|
Log(" %s", ip6Addrs.Back()->ToString().AsCString());
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(ip4Addrs.PushBack(AsCoreType(&addr.mAddress.mIp4)));
|
|
Log(" %s", ip4Addrs.Back()->ToString().AsCString());
|
|
}
|
|
}
|
|
|
|
aMdns.FreeIterator(*iterator);
|
|
|
|
VerifyOrQuit(ip6Addrs.GetLength() == aLocalHost.mIp6Addrs.GetLength());
|
|
|
|
for (const Ip6::Address &ip6Addr : ip6Addrs)
|
|
{
|
|
VerifyOrQuit(aLocalHost.mIp6Addrs.Contains(ip6Addr));
|
|
}
|
|
|
|
VerifyOrQuit(ip4Addrs.GetLength() == aLocalHost.mIp4Addrs.GetLength());
|
|
|
|
for (const Ip4::Address &ip4Addr : ip4Addrs)
|
|
{
|
|
VerifyOrQuit(aLocalHost.mIp4Addrs.Contains(ip4Addr));
|
|
}
|
|
#else
|
|
OT_UNUSED_VARIABLE(aMdns);
|
|
OT_UNUSED_VARIABLE(aLocalHost);
|
|
#endif
|
|
}
|
|
|
|
void TestLocalHost(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
LocalHost localHost;
|
|
Ip6::Address ip6Address;
|
|
Ip4::Address ip4Address;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString hostFullName;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestLocalHost");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(StringCopy(localHost.mName, mdns->GetLocalHostName()));
|
|
Log("Local host name is \"%s\"", localHost.mName);
|
|
|
|
hostFullName.Append("%s.local.", localHost.mName);
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Add an IP6 address and IP4 address for local host, check probes and announcements");
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::1"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip4Address.FromString("200.1.5.6"));
|
|
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
|
ip6Address.InitAsIp4Mapped(ip4Address);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
AdvanceTime(4);
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(localHost, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for AAAA record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for A record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for non-existing record and validate the response with NSEC");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeKey);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
|
|
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
|
|
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeA));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal a new host IPv6 address is added and validate new announcements");
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::22"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(5);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal new host IPv6 addresses added and removed");
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::22"));
|
|
localHost.mIp6Addrs.Remove(ip6Address);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
|
|
|
// Add then remove the same address quickly
|
|
// It should not be included in the announcements.
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::333"));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
AdvanceTime(1);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::4444"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
Log("Validate the announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(4);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal three new host IPv4 addresses added");
|
|
|
|
SuccessOrQuit(ip4Address.FromString("200.1.5.7"));
|
|
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
|
ip6Address.InitAsIp4Mapped(ip4Address);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip4Address.FromString("200.1.2.100"));
|
|
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
|
ip6Address.InitAsIp4Mapped(ip4Address);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip4Address.FromString("200.1.4.0"));
|
|
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
|
ip6Address.InitAsIp4Mapped(ip4Address);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
Log("Validate the announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(5);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal removal of all host addresses and add them all back");
|
|
|
|
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
|
|
|
|
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
|
|
{
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
|
|
{
|
|
ip6Address.InitAsIp4Mapped(ip4Addr);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
Log("Validate that there are no announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal removal of all addr, add them all back with one extra IPv6 and one extra IPv4 addr");
|
|
|
|
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::5555"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
|
|
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
|
|
{
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
SuccessOrQuit(ip4Address.FromString("200.0.64.13"));
|
|
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
|
|
|
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
|
|
{
|
|
ip6Address.InitAsIp4Mapped(ip4Addr);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
Log("Validate the announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(5);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 8, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal removal of all addresses and add some back");
|
|
|
|
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
|
|
|
|
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
|
|
{
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
Log("Before previous events are processed, signal removal of all addresses again");
|
|
Log("And add them all back without the recently added extra IPv6 and IPv4 addresses");
|
|
|
|
AdvanceTime(1);
|
|
|
|
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
|
|
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
|
|
|
|
localHost.mIp6Addrs.PopBack();
|
|
localHost.mIp4Addrs.PopBack();
|
|
|
|
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
|
|
{
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
|
|
{
|
|
ip6Address.InitAsIp4Mapped(ip4Addr);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
}
|
|
|
|
Log("Validate the announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(5);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 6, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal all host IPv4 addresses are removed, validate goodbye announcements");
|
|
|
|
for (const Ip4::Address &ip4Addr : localHost.mIp4Addrs)
|
|
{
|
|
ip6Address.InitAsIp4Mapped(ip4Addr);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
|
}
|
|
|
|
localHost.mIp4Addrs.Clear();
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(5);
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal removal of an IPv6 host address which was not added earlier");
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:cafe::beef"));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
|
|
|
Log("Validate that there are no announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Signal remove and re-add of the same host IPv6 address quickly");
|
|
|
|
ip6Address = localHost.mIp6Addrs[0];
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
|
AdvanceTime(1);
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
Log("Validate that there are no announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate `SetLocalHostName()`");
|
|
|
|
VerifyOrQuit(mdns->SetLocalHostName("itsme") == kErrorInvalidState);
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(mdns->SetLocalHostName("itsme"));
|
|
VerifyOrQuit(StringMatch(mdns->GetLocalHostName(), "itsme"));
|
|
|
|
localHost.mIp4Addrs.Clear();
|
|
localHost.mIp6Addrs.Clear();
|
|
|
|
SuccessOrQuit(StringCopy(localHost.mName, mdns->GetLocalHostName()));
|
|
Log("Local host name is \"%s\"", localHost.mName);
|
|
|
|
hostFullName.Append("%s.local.", localHost.mName);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Re-enable mDNS module, add 4 new host IPv6 address and validate probe and announcements");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:beef::a"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:beef::b"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:beef::c"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
SuccessOrQuit(ip6Address.FromString("fd00:beef::d"));
|
|
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
|
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
|
|
|
AdvanceTime(4);
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 4, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(localHost, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
ValidateLocalHostAddresses(*mdns, localHost);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestKeyReg(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Key key;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestKeyReg");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
// Run all tests twice. first with key for a host name, followed
|
|
// by key for service instance name.
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
DnsNameString fullName;
|
|
|
|
if (iter == 0)
|
|
{
|
|
Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
|
|
Log("Registering key for 'myhost' host name");
|
|
key.mName = "myhost";
|
|
key.mServiceType = nullptr;
|
|
|
|
fullName.Append("%s.local.", key.mName);
|
|
}
|
|
else
|
|
{
|
|
Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
|
|
Log("Registering key for 'mysrv._srv._udo' service name");
|
|
|
|
key.mName = "mysrv";
|
|
key.mServiceType = "_srv._udp";
|
|
|
|
fullName.Append("%s.%s.local.", key.mName, key.mServiceType);
|
|
}
|
|
|
|
key.mKeyData = kKey1;
|
|
key.mKeyDataLength = sizeof(kKey1);
|
|
key.mTtl = 8000;
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a key record and check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterKey(key, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for KEY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullName.AsCString(), ResourceRecord::kTypeKey);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullName.AsCString(), ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for non-existing record and validate the response with NSEC");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullName.AsCString(), ResourceRecord::kTypeA);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
|
|
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeKey));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Change the TTL");
|
|
|
|
key.mTtl = 0; // Use default
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Change the key");
|
|
|
|
key.mKeyData = kKey2;
|
|
key.mKeyDataLength = sizeof(kKey2);
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the key and validate the goodbye announces");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterKey(key));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
}
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestServiceReg(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Service service;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullServiceName;
|
|
DnsNameString fullServiceType;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestServiceReg");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
service.mHostName = "myhost";
|
|
service.mServiceInstance = "myservice";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 1000;
|
|
|
|
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
fullServiceType.Append("%s.local.", service.mServiceType);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `ServiceEntry`, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for SRV record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for TXT record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for service type and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for `services._dns-sd` and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update service port number and validate new announcements of SRV record");
|
|
|
|
service.mPort = 4567;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update TXT data and validate new announcements of TXT record");
|
|
|
|
service.mTxtData = nullptr;
|
|
service.mTxtDataLength = 0;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update both service and TXT data and validate new announcements of both records");
|
|
|
|
service.mTxtData = kTxtData2;
|
|
service.mTxtDataLength = sizeof(kTxtData2);
|
|
service.mWeight = 0;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update service host name to use local host and validate new announcements of SRV record");
|
|
|
|
service.mHostName = nullptr;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update service host name and validate new announcements of SRV record");
|
|
|
|
service.mHostName = "newhost";
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update TTL and validate new announcements of SRV, TXT and PTR records");
|
|
|
|
service.mTtl = 0;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the service and validate the goodbye announces");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestUnregisterBeforeProbeFinished(void)
|
|
{
|
|
const uint8_t kKey1[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
|
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Core::Service service;
|
|
Core::Key key;
|
|
Ip6::Address hostAddresses[3];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestUnregisterBeforeProbeFinished");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::aaaa"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::bbbb"));
|
|
SuccessOrQuit(hostAddresses[2].FromString("fd00::cccc"));
|
|
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 3;
|
|
host.mTtl = 1500;
|
|
|
|
service.mHostName = "myhost";
|
|
service.mServiceInstance = "myservice";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 1000;
|
|
|
|
key.mName = "mysrv";
|
|
key.mServiceType = "_srv._udp";
|
|
key.mKeyData = kKey1;
|
|
key.mKeyDataLength = sizeof(kKey1);
|
|
key.mTtl = 8000;
|
|
|
|
// Repeat the same test 3 times for host and service and key registration.
|
|
|
|
for (uint8_t iter = 0; iter < 3; iter++)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register an entry, check for the first two probes");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
|
|
switch (iter)
|
|
{
|
|
case 0:
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
break;
|
|
case 1:
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
break;
|
|
case 2:
|
|
SuccessOrQuit(mdns->RegisterKey(key, 0, HandleSuccessCallback));
|
|
break;
|
|
}
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 2; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
switch (iter)
|
|
{
|
|
case 0:
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
|
|
break;
|
|
case 1:
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
break;
|
|
case 2:
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
|
|
break;
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the entry before the last probe and make sure probing stops");
|
|
|
|
switch (iter)
|
|
{
|
|
case 0:
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
break;
|
|
case 1:
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
break;
|
|
case 2:
|
|
SuccessOrQuit(mdns->UnregisterKey(key));
|
|
break;
|
|
}
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
}
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestServiceSubTypeReg(void)
|
|
{
|
|
static const char *const kSubTypes1[] = {"_s1", "_r2", "_vXy", "_last"};
|
|
static const char *const kSubTypes2[] = {"_vxy", "_r1", "_r2", "_zzz"};
|
|
|
|
Core *mdns = InitTest();
|
|
Core::Service service;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullServiceName;
|
|
DnsNameString fullServiceType;
|
|
DnsNameString fullSubServiceType;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestServiceSubTypeReg");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
service.mHostName = "tarnished";
|
|
service.mServiceInstance = "elden";
|
|
service.mServiceType = "_ring._udp";
|
|
service.mSubTypeLabels = kSubTypes1;
|
|
service.mSubTypeLabelsLength = 3;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 6000;
|
|
|
|
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
fullServiceType.Append("%s.local.", service.mServiceType);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `ServiceEntry` with sub-types, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
|
|
for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for SRV record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for TXT record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for service type and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for `services._dns-sd` and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
|
|
|
|
for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query for sub-type `%s` and validate the response", service.mSubTypeLabels[index]);
|
|
|
|
fullSubServiceType.Clear();
|
|
fullSubServiceType.Append("%s._sub.%s", service.mSubTypeLabels[index], fullServiceType.AsCString());
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullSubServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query for non-existing sub-type and validate there is no response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
fullSubServiceType.Clear();
|
|
fullSubServiceType.Append("_none._sub.%s", fullServiceType.AsCString());
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullSubServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(2000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a new sub-type and validate announcements of PTR record for it");
|
|
|
|
service.mSubTypeLabelsLength = 4;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[3], service);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Remove a previous sub-type and validate announcements of its removal");
|
|
|
|
service.mSubTypeLabels++;
|
|
service.mSubTypeLabelsLength = 3;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateSubType(kSubTypes1[0], service, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Update TTL and validate announcement of all records");
|
|
|
|
service.mTtl = 0;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 6, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
|
|
|
|
for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Add and remove sub-types at the same time and check proper announcements");
|
|
|
|
// Registered sub-types: _r2, _vXy, _last
|
|
// New sub-types list : _vxy, _r1, _r2, _zzz
|
|
//
|
|
// Should announce removal of `_last` and addition of
|
|
// `_r1` and `_zzz`. The `_vxy` should match with `_vXy`.
|
|
|
|
service.mSubTypeLabels = kSubTypes2;
|
|
service.mSubTypeLabelsLength = 4;
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 2);
|
|
|
|
dnsMsg->ValidateSubType(kSubTypes1[3], service, kGoodBye);
|
|
dnsMsg->ValidateSubType(kSubTypes2[1], service);
|
|
dnsMsg->ValidateSubType(kSubTypes2[3], service);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the service and validate the goodbye announces for service and its sub-types");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
|
|
for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service, kGoodBye);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestHostOrServiceAndKeyReg(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Core::Service service;
|
|
Core::Key key;
|
|
Ip6::Address hostAddresses[2];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestHostOrServiceAndKeyReg");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::1"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::2"));
|
|
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 2;
|
|
host.mTtl = 5000;
|
|
|
|
key.mKeyData = kKey1;
|
|
key.mKeyDataLength = sizeof(kKey1);
|
|
key.mTtl = 80000;
|
|
|
|
service.mHostName = "myhost";
|
|
service.mServiceInstance = "myservice";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 1000;
|
|
|
|
// Run all test step twice, first time registering host and key,
|
|
// second time registering service and key.
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
if (iter == 0)
|
|
{
|
|
key.mName = host.mHostName;
|
|
key.mServiceType = nullptr;
|
|
}
|
|
else
|
|
{
|
|
key.mName = service.mServiceInstance;
|
|
key.mServiceType = service.mServiceType;
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a %s entry, check the first probe is sent", iter == 0 ? "host" : "service");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
|
|
if (iter == 0)
|
|
{
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
|
|
if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ true);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ true);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `KeyEntry` for same name, check that probes continue");
|
|
|
|
sRegCallbacks[1].Reset();
|
|
SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 1; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(!sRegCallbacks[1].mWasCalled);
|
|
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
|
|
|
|
if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ false);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ false);
|
|
}
|
|
|
|
dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate Announces for both entry and key");
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
}
|
|
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the entry and validate its goodbye announces");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
if (iter == 0)
|
|
{
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the entry again, validate its announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[2].Reset();
|
|
|
|
if (iter == 0)
|
|
{
|
|
SuccessOrQuit(mdns->RegisterHost(host, 2, HandleSuccessCallback));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(mdns->RegisterService(service, 2, HandleSuccessCallback));
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[2].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the key and validate its goodbye announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterKey(key));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
sDnsMessages.Clear();
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the key again, validate its announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[3].Reset();
|
|
SuccessOrQuit(mdns->RegisterKey(key, 3, HandleSuccessCallback));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[3].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister key first, validate two of its goodbye announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->UnregisterKey(key));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < 2; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 1 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("Unregister entry as well");
|
|
|
|
if (iter == 0)
|
|
{
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
}
|
|
|
|
AdvanceTime(15000);
|
|
|
|
for (uint16_t anncCount = 0; anncCount < 4; anncCount++)
|
|
{
|
|
dnsMsg = dnsMsg->GetNext();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
|
|
if (anncCount == 2)
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
|
|
}
|
|
else if (iter == 0)
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
|
|
}
|
|
else
|
|
{
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
}
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestQuery(void)
|
|
{
|
|
static const char *const kSubTypes[] = {"_s", "_r"};
|
|
|
|
Core *mdns = InitTest();
|
|
Core::Host host1;
|
|
Core::Host host2;
|
|
Core::Service service1;
|
|
Core::Service service2;
|
|
Core::Service service3;
|
|
Core::Key key1;
|
|
Core::Key key2;
|
|
Ip6::Address host1Addresses[3];
|
|
Ip6::Address host2Addresses[2];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString host1FullName;
|
|
DnsNameString host2FullName;
|
|
DnsNameString service1FullName;
|
|
DnsNameString service2FullName;
|
|
DnsNameString service3FullName;
|
|
KnownAnswer knownAnswers[2];
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestQuery");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(host1Addresses[0].FromString("fd00::1:aaaa"));
|
|
SuccessOrQuit(host1Addresses[1].FromString("fd00::1:bbbb"));
|
|
SuccessOrQuit(host1Addresses[2].FromString("fd00::1:cccc"));
|
|
host1.mHostName = "host1";
|
|
host1.mAddresses = host1Addresses;
|
|
host1.mAddressesLength = 3;
|
|
host1.mTtl = 1500;
|
|
host1FullName.Append("%s.local.", host1.mHostName);
|
|
|
|
SuccessOrQuit(host2Addresses[0].FromString("fd00::2:eeee"));
|
|
SuccessOrQuit(host2Addresses[1].FromString("fd00::2:ffff"));
|
|
host2.mHostName = "host2";
|
|
host2.mAddresses = host2Addresses;
|
|
host2.mAddressesLength = 2;
|
|
host2.mTtl = 1500;
|
|
host2FullName.Append("%s.local.", host2.mHostName);
|
|
|
|
service1.mHostName = host1.mHostName;
|
|
service1.mServiceInstance = "srv1";
|
|
service1.mServiceType = "_srv._udp";
|
|
service1.mSubTypeLabels = kSubTypes;
|
|
service1.mSubTypeLabelsLength = 2;
|
|
service1.mTxtData = kTxtData1;
|
|
service1.mTxtDataLength = sizeof(kTxtData1);
|
|
service1.mPort = 1111;
|
|
service1.mPriority = 0;
|
|
service1.mWeight = 0;
|
|
service1.mTtl = 1500;
|
|
service1FullName.Append("%s.%s.local.", service1.mServiceInstance, service1.mServiceType);
|
|
|
|
service2.mHostName = host1.mHostName;
|
|
service2.mServiceInstance = "srv2";
|
|
service2.mServiceType = "_tst._tcp";
|
|
service2.mSubTypeLabels = nullptr;
|
|
service2.mSubTypeLabelsLength = 0;
|
|
service2.mTxtData = nullptr;
|
|
service2.mTxtDataLength = 0;
|
|
service2.mPort = 2222;
|
|
service2.mPriority = 2;
|
|
service2.mWeight = 2;
|
|
service2.mTtl = 1500;
|
|
service2FullName.Append("%s.%s.local.", service2.mServiceInstance, service2.mServiceType);
|
|
|
|
service3.mHostName = host2.mHostName;
|
|
service3.mServiceInstance = "srv3";
|
|
service3.mServiceType = "_srv._udp";
|
|
service3.mSubTypeLabels = kSubTypes;
|
|
service3.mSubTypeLabelsLength = 1;
|
|
service3.mTxtData = kTxtData2;
|
|
service3.mTxtDataLength = sizeof(kTxtData2);
|
|
service3.mPort = 3333;
|
|
service3.mPriority = 3;
|
|
service3.mWeight = 3;
|
|
service3.mTtl = 1500;
|
|
service3FullName.Append("%s.%s.local.", service3.mServiceInstance, service3.mServiceType);
|
|
|
|
key1.mName = host2.mHostName;
|
|
key1.mServiceType = nullptr;
|
|
key1.mKeyData = kKey1;
|
|
key1.mKeyDataLength = sizeof(kKey1);
|
|
key1.mTtl = 8000;
|
|
|
|
key2.mName = service3.mServiceInstance;
|
|
key2.mServiceType = service3.mServiceType;
|
|
key2.mKeyData = kKey1;
|
|
key2.mKeyDataLength = sizeof(kKey1);
|
|
key2.mTtl = 8000;
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register 2 hosts and 3 services and 2 keys");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (RegCallback ®Callbck : sRegCallbacks)
|
|
{
|
|
regCallbck.Reset();
|
|
}
|
|
|
|
SuccessOrQuit(mdns->RegisterHost(host1, 0, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterHost(host2, 1, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service1, 2, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service2, 3, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service3, 4, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterKey(key1, 5, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterKey(key2, 6, HandleSuccessCallback));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate probes for all entries");
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint16_t index = 0; index < 7; index++)
|
|
{
|
|
VerifyOrQuit(!sRegCallbacks[index].mWasCalled);
|
|
}
|
|
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 5, /* Ans */ 0, /* Auth */ 13, /* Addnl */ 0);
|
|
|
|
dnsMsg->ValidateAsProbeFor(host1, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(host2, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(service1, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(service2, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(service3, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(key1, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(key2, /* aUnicastRequest */ (probeCount == 0));
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate announcements for all entries");
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
for (uint16_t index = 0; index < 7; index++)
|
|
{
|
|
VerifyOrQuit(sRegCallbacks[index].mWasCalled);
|
|
}
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 21, /* Auth */ 0, /* Addnl */ 5);
|
|
|
|
dnsMsg->Validate(host1, kInAnswerSection);
|
|
dnsMsg->Validate(host2, kInAnswerSection);
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
dnsMsg->Validate(service2, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
dnsMsg->Validate(service2, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
dnsMsg->Validate(key1, kInAnswerSection);
|
|
dnsMsg->Validate(key2, kInAnswerSection);
|
|
|
|
for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1);
|
|
}
|
|
|
|
for (uint16_t index = 0; index < service3.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service3.mSubTypeLabels[index], service3);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query (browse) for `_srv._udp` and validate two answers and additional data");
|
|
|
|
AdvanceTime(2000);
|
|
sDnsMessages.Clear();
|
|
|
|
SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
|
|
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Resend the same query but request a unicast response, validate the response");
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet | kClassQueryUnicastFlag);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kUnicastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
|
|
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Resend the same multicast query and validate that response is not emitted (rate limit)");
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Wait for > 1 second and resend the query and validate that now a response is emitted");
|
|
|
|
SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
|
|
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Browse for sub-type `_s._sub._srv._udp` and validate two answers");
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_s._sub._srv._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
|
|
|
|
dnsMsg->ValidateSubType("_s", service1);
|
|
dnsMsg->ValidateSubType("_s", service3);
|
|
dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
// Send same query again and make sure it is ignored (rate limit).
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_s._sub._srv._udp.local.", ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate that query with `ANY class` instead of `IN class` is responded");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_r._sub._srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassAny);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 5);
|
|
dnsMsg->ValidateSubType("_r", service1);
|
|
dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate that query with other `class` is ignored");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_r._sub._srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassNone);
|
|
|
|
AdvanceTime(2000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate that query for non-registered name is ignored");
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_u._sub._srv._udp.local.", ResourceRecord::kTypeAny);
|
|
SendQuery("host3.local.", ResourceRecord::kTypeAny);
|
|
|
|
AdvanceTime(2000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Query for SRV for `srv1._srv._udp` and validate answer and additional data");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SendQuery("srv1._srv._udp.local.", ResourceRecord::kTypeSrv);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
|
|
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv);
|
|
dnsMsg->Validate(host1, kInAdditionalSection);
|
|
|
|
//--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
// Query with multiple questions
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query with two questions (SRV for service1 and AAAA for host1). Validate response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQueryForTwo("srv1._srv._udp.local.", ResourceRecord::kTypeSrv, "host1.local.", ResourceRecord::kTypeAaaa);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
// Since AAAA record are already present in Answer they should not be appended
|
|
// in Additional anymore (for the SRV query).
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 2);
|
|
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv);
|
|
dnsMsg->Validate(host1, kInAnswerSection);
|
|
|
|
//--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
// Known-answer suppression
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query for `_srv._udp` and include `srv1` as known-answer and validate response");
|
|
|
|
knownAnswers[0].mPtrAnswer = "srv1._srv._udp.local.";
|
|
knownAnswers[0].mTtl = 1500;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 1);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
// Response should include `service3` only
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query again with both services as known-answer, validate no response is emitted");
|
|
|
|
knownAnswers[1].mPtrAnswer = "srv3._srv._udp.local.";
|
|
knownAnswers[1].mTtl = 1500;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 2);
|
|
|
|
AdvanceTime(2000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query for `_srv._udp` and include `srv1` as known-answer and validate response");
|
|
|
|
knownAnswers[0].mPtrAnswer = "srv1._srv._udp.local.";
|
|
knownAnswers[0].mTtl = 1500;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 1);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
// Response should include `service3` only
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Change the TTL for known-answer to less than half of record TTL and validate response");
|
|
|
|
knownAnswers[1].mTtl = 1500 / 2 - 1;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 2);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
// Response should include `service3` only since answer TTL
|
|
// is less than half of registered TTL
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host2, kInAdditionalSection);
|
|
|
|
//--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
// Query during Goodbye announcements
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister `service1` and wait for its two announcements and validate them");
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->UnregisterService(service1));
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces - 1; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
|
|
for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1, kGoodBye);
|
|
}
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for removed `service1` before its final announcement, validate no response");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(1100);
|
|
SendQuery("srv1._srv._udp.local.", ResourceRecord::kTypeSrv);
|
|
|
|
AdvanceTime(200);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for final announcement and validate it
|
|
|
|
AdvanceTime(2000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
|
|
|
|
for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1, kGoodBye);
|
|
}
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestMultiPacket(void)
|
|
{
|
|
static const char *const kSubTypes[] = {"_s1", "_r2", "vxy"};
|
|
|
|
Core *mdns = InitTest();
|
|
Core::Service service;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullServiceName;
|
|
DnsNameString fullServiceType;
|
|
KnownAnswer knownAnswers[2];
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestMultiPacket");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
service.mHostName = "myhost";
|
|
service.mServiceInstance = "mysrv";
|
|
service.mServiceType = "_tst._udp";
|
|
service.mSubTypeLabels = kSubTypes;
|
|
service.mSubTypeLabelsLength = 3;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 2222;
|
|
service.mPriority = 3;
|
|
service.mWeight = 4;
|
|
service.mTtl = 2000;
|
|
|
|
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
fullServiceType.Append("%s.local.", service.mServiceType);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `ServiceEntry` with sub-types, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
|
|
for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
|
|
{
|
|
dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for service type and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query again but mark it as truncated");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
Log("Since message is marked as `truncated`, mDNS should wait at least 400 msec");
|
|
|
|
AdvanceTime(399);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(2000);
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query again as truncated followed-up by a non-matching answer");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
AdvanceTime(10);
|
|
|
|
knownAnswers[0].mPtrAnswer = "other._tst._udp.local.";
|
|
knownAnswers[0].mTtl = 1500;
|
|
|
|
SendEmtryPtrQueryWithKnownAnswers(fullServiceType.AsCString(), knownAnswers, 1);
|
|
|
|
AdvanceTime(1000);
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a PTR query again as truncated now followed-up by matching known-answer");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
AdvanceTime(10);
|
|
|
|
knownAnswers[1].mPtrAnswer = "mysrv._tst._udp.local.";
|
|
knownAnswers[1].mTtl = 1500;
|
|
|
|
SendEmtryPtrQueryWithKnownAnswers(fullServiceType.AsCString(), knownAnswers, 2);
|
|
|
|
Log("We expect no response since the followed-up message contains a matching known-answer");
|
|
AdvanceTime(5000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a truncated query for PTR record for `services._dns-sd`");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
Log("Response should be sent after longer wait time");
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a truncated query for PTR record for `services._dns-sd` folloed by known-aswer");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
AdvanceTime(20);
|
|
knownAnswers[0].mPtrAnswer = "_other._udp.local.";
|
|
knownAnswers[0].mTtl = 4500;
|
|
|
|
SendEmtryPtrQueryWithKnownAnswers("_services._dns-sd._udp.local.", knownAnswers, 1);
|
|
|
|
Log("Response should be sent again due to answer not matching");
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send the same truncated query again but follow-up with a matching known-answer message");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
AdvanceTime(20);
|
|
knownAnswers[1].mPtrAnswer = "_tst._udp.local.";
|
|
knownAnswers[1].mTtl = 4500;
|
|
|
|
SendEmtryPtrQueryWithKnownAnswers("_services._dns-sd._udp.local.", knownAnswers, 2);
|
|
|
|
Log("We expect no response since the followed-up message contains a matching known-answer");
|
|
AdvanceTime(5000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send the same truncated query multiple times to validate msg eviction");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
AdvanceTime(20);
|
|
|
|
SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ true);
|
|
|
|
knownAnswers[1].mPtrAnswer = "_tst._udp.local.";
|
|
knownAnswers[1].mTtl = 4500;
|
|
|
|
SendEmtryPtrQueryWithKnownAnswers("_services._dns-sd._udp.local.", knownAnswers, 2);
|
|
|
|
Log("We expect no response since the followed-up message contains a matching known-answer");
|
|
AdvanceTime(5000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestResponseAggregation(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Service tcpService;
|
|
Core::Service udpService;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullTcpServiceName;
|
|
DnsNameString fullTcpServiceType;
|
|
DnsNameString fullUdpServiceName;
|
|
DnsNameString fullUdpServiceType;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestResponseAggregation");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
tcpService.mHostName = "host";
|
|
tcpService.mServiceInstance = "srv1";
|
|
tcpService.mServiceType = "_matter._tcp";
|
|
tcpService.mSubTypeLabels = nullptr;
|
|
tcpService.mSubTypeLabelsLength = 0;
|
|
tcpService.mTxtData = kTxtData1;
|
|
tcpService.mTxtDataLength = sizeof(kTxtData1);
|
|
tcpService.mPort = 1111;
|
|
tcpService.mPriority = 1;
|
|
tcpService.mWeight = 2;
|
|
tcpService.mTtl = 4500;
|
|
|
|
udpService.mHostName = "host";
|
|
udpService.mServiceInstance = "srv2";
|
|
udpService.mServiceType = "_srv._udp";
|
|
udpService.mSubTypeLabels = nullptr;
|
|
udpService.mSubTypeLabelsLength = 0;
|
|
udpService.mTxtData = kTxtData2;
|
|
udpService.mTxtDataLength = sizeof(kTxtData2);
|
|
udpService.mPort = 2222;
|
|
udpService.mPriority = 6;
|
|
udpService.mWeight = 2;
|
|
udpService.mTtl = 4500;
|
|
|
|
fullTcpServiceName.Append("%s.%s.local.", tcpService.mServiceInstance, tcpService.mServiceType);
|
|
fullTcpServiceType.Append("%s.local.", tcpService.mServiceType);
|
|
|
|
fullUdpServiceName.Append("%s.%s.local.", udpService.mServiceInstance, udpService.mServiceType);
|
|
fullUdpServiceType.Append("%s.local.", udpService.mServiceType);
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("Register a first `ServiceEntry`, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(tcpService, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(tcpService, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(tcpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("Register a second `ServiceEntry`, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(udpService, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(udpService, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(udpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("Send two PTR queries back to back and validate the response is aggregated");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullTcpServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
AdvanceTime(5);
|
|
SendQuery(fullUdpServiceType.AsCString(), ResourceRecord::kTypePtr);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(tcpService, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(tcpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(udpService, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(udpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestQuestionUnicastDisallowed(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Ip6::Address hostAddresses[1];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString hostFullName;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestQuestionUnicastDisallowed");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::1234"));
|
|
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 1;
|
|
host.mTtl = 1500;
|
|
|
|
mdns->SetQuestionUnicastAllowed(false);
|
|
VerifyOrQuit(!mdns->IsQuestionUnicastAllowed());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `HostEntry`, check probes and announcements");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ false);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestTxMessageSizeLimit(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Core::Service service;
|
|
Core::Key hostKey;
|
|
Core::Key serviceKey;
|
|
Ip6::Address hostAddresses[3];
|
|
uint8_t keyData[300];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString hostFullName;
|
|
DnsNameString serviceFullName;
|
|
|
|
memset(keyData, 1, sizeof(keyData));
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestTxMessageSizeLimit");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
|
|
SuccessOrQuit(hostAddresses[2].FromString("fd00::1:cccc"));
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 3;
|
|
host.mTtl = 1500;
|
|
hostFullName.Append("%s.local.", host.mHostName);
|
|
|
|
service.mHostName = host.mHostName;
|
|
service.mServiceInstance = "mysrv";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1111;
|
|
service.mPriority = 0;
|
|
service.mWeight = 0;
|
|
service.mTtl = 1500;
|
|
serviceFullName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
|
|
hostKey.mName = host.mHostName;
|
|
hostKey.mServiceType = nullptr;
|
|
hostKey.mKeyData = keyData;
|
|
hostKey.mKeyDataLength = 300;
|
|
hostKey.mTtl = 8000;
|
|
|
|
serviceKey.mName = service.mServiceInstance;
|
|
serviceKey.mServiceType = service.mServiceType;
|
|
serviceKey.mKeyData = keyData;
|
|
serviceKey.mKeyDataLength = 300;
|
|
serviceKey.mTtl = 8000;
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Set `MaxMessageSize` to 340 and use large key record data to trigger size limit behavior");
|
|
|
|
mdns->SetMaxMessageSize(340);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register host and service and keys for each");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (RegCallback ®Callbck : sRegCallbacks)
|
|
{
|
|
regCallbck.Reset();
|
|
}
|
|
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterKey(hostKey, 2, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterKey(serviceKey, 3, HandleSuccessCallback));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate probes for all entries");
|
|
Log("Probes for host and service should be broken into separate message due to size limit");
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint16_t index = 0; index < 4; index++)
|
|
{
|
|
VerifyOrQuit(!sRegCallbacks[index].mWasCalled);
|
|
}
|
|
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 4, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(hostKey, /* aUnicastRequest */ (probeCount == 0));
|
|
|
|
dnsMsg = dnsMsg->GetNext();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
dnsMsg->ValidateAsProbeFor(serviceKey, /* aUnicastRequest */ (probeCount == 0));
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate announcements for all entries");
|
|
Log("Announces should also be broken into separate message due to size limit");
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
|
|
for (uint16_t index = 0; index < 4; index++)
|
|
{
|
|
VerifyOrQuit(sRegCallbacks[index].mWasCalled);
|
|
}
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
dnsMsg->Validate(hostKey, kInAnswerSection);
|
|
|
|
dnsMsg = dnsMsg->GetNext();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
|
|
dnsMsg->Validate(serviceKey, kInAnswerSection);
|
|
|
|
dnsMsg = dnsMsg->GetNext();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
|
|
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestHostConflict(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Ip6::Address hostAddresses[2];
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString hostFullName;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestHostConflict");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::1"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::2"));
|
|
|
|
host.mHostName = "myhost";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 2;
|
|
host.mTtl = 1500;
|
|
|
|
hostFullName.Append("%s.local.", host.mHostName);
|
|
|
|
// Run the test twice, first run send response with record in Answer section,
|
|
// section run in Additional Data section.
|
|
|
|
sConflictCallback.Reset();
|
|
mdns->SetConflictCallback(HandleConflict);
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `HostEntry`, wait for first probe");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ true);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
|
|
|
|
SendResponseWithEmptyKey(hostFullName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
|
|
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `HostEntry` and respond to probe to trigger conflict");
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
|
|
SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the conflicted `HostEntry` again, and make sure probes are sent");
|
|
|
|
sConflictCallback.Reset();
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(host, kInAnswerSection);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response for host name and validate that conflict is detected and callback is called");
|
|
|
|
SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sConflictCallback.mWasCalled);
|
|
VerifyOrQuit(StringMatch(sConflictCallback.mName.AsCString(), host.mHostName, kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(!sConflictCallback.mHasServiceType);
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestServiceConflict(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Service service;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullServiceName;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestServiceConflict");
|
|
|
|
service.mHostName = "myhost";
|
|
service.mServiceInstance = "myservice";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 1000;
|
|
|
|
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
// Run the test twice, first run send response with record in Answer section,
|
|
// section run in Additional Data section.
|
|
|
|
sConflictCallback.Reset();
|
|
mdns->SetConflictCallback(HandleConflict);
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `ServiceEntry`, wait for first probe");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ true);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
|
|
|
|
SendResponseWithEmptyKey(fullServiceName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
|
|
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
|
|
AdvanceTime(15000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register a `ServiceEntry` and respond to probe to trigger conflict");
|
|
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
|
|
SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register the conflicted `ServiceEntry` again, and make sure probes are sent");
|
|
|
|
sConflictCallback.Reset();
|
|
sRegCallbacks[0].Reset();
|
|
SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
|
|
|
|
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
|
|
AdvanceTime(250);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
|
VerifyOrQuit(sRegCallbacks[0].mWasCalled);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response for service name and validate that conflict is detected and callback is called");
|
|
|
|
SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sConflictCallback.mWasCalled);
|
|
VerifyOrQuit(
|
|
StringMatch(sConflictCallback.mName.AsCString(), service.mServiceInstance, kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(sConflictCallback.mHasServiceType);
|
|
VerifyOrQuit(
|
|
StringMatch(sConflictCallback.mServiceType.AsCString(), service.mServiceType, kStringCaseInsensitiveMatch));
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(20000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//=====================================================================================================================
|
|
// Browser/Resolver tests
|
|
|
|
struct BrowseCallback : public Allocatable<BrowseCallback>, public LinkedListEntry<BrowseCallback>
|
|
{
|
|
BrowseCallback *mNext;
|
|
DnsName mServiceType;
|
|
DnsName mSubTypeLabel;
|
|
DnsName mServiceInstance;
|
|
uint32_t mTtl;
|
|
bool mIsSubType;
|
|
};
|
|
|
|
struct SrvCallback : public Allocatable<SrvCallback>, public LinkedListEntry<SrvCallback>
|
|
{
|
|
SrvCallback *mNext;
|
|
DnsName mServiceInstance;
|
|
DnsName mServiceType;
|
|
DnsName mHostName;
|
|
uint16_t mPort;
|
|
uint16_t mPriority;
|
|
uint16_t mWeight;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
struct TxtCallback : public Allocatable<TxtCallback>, public LinkedListEntry<TxtCallback>
|
|
{
|
|
static constexpr uint16_t kMaxTxtDataLength = 100;
|
|
|
|
template <uint16_t kSize> bool Matches(const uint8_t (&aData)[kSize]) const
|
|
{
|
|
return (mTxtDataLength == kSize) && (memcmp(mTxtData, aData, kSize) == 0);
|
|
}
|
|
|
|
TxtCallback *mNext;
|
|
DnsName mServiceInstance;
|
|
DnsName mServiceType;
|
|
uint8_t mTxtData[kMaxTxtDataLength];
|
|
uint16_t mTxtDataLength;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
struct AddrCallback : public Allocatable<AddrCallback>, public LinkedListEntry<AddrCallback>
|
|
{
|
|
static constexpr uint16_t kMaxNumAddrs = 16;
|
|
|
|
bool Contains(const AddrAndTtl &aAddrAndTtl) const
|
|
{
|
|
bool contains = false;
|
|
|
|
for (uint16_t index = 0; index < mNumAddrs; index++)
|
|
{
|
|
if (mAddrAndTtls[index] == aAddrAndTtl)
|
|
{
|
|
contains = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return contains;
|
|
}
|
|
|
|
bool Matches(const AddrAndTtl *aAddrAndTtls, uint16_t aNumAddrs) const
|
|
{
|
|
bool matches = true;
|
|
|
|
VerifyOrExit(aNumAddrs == mNumAddrs, matches = false);
|
|
|
|
for (uint16_t index = 0; index < mNumAddrs; index++)
|
|
{
|
|
if (!Contains(aAddrAndTtls[index]))
|
|
{
|
|
ExitNow(matches = false);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return matches;
|
|
}
|
|
|
|
AddrCallback *mNext;
|
|
DnsName mHostName;
|
|
AddrAndTtl mAddrAndTtls[kMaxNumAddrs];
|
|
uint16_t mNumAddrs;
|
|
};
|
|
|
|
struct RecordCallback : public Allocatable<RecordCallback>, public LinkedListEntry<RecordCallback>
|
|
{
|
|
static constexpr uint16_t kMaxRecordDataLength = 256;
|
|
|
|
template <uint16_t kSize> bool MatchesData(const uint8_t (&aData)[kSize]) const
|
|
{
|
|
return (mRecordDataLength == kSize) && (memcmp(mRecordData, aData, kSize) == 0);
|
|
}
|
|
|
|
RecordCallback *mNext;
|
|
DnsName mFirstLabel;
|
|
DnsName mNextLabels;
|
|
uint16_t mRecordType;
|
|
uint8_t mRecordData[kMaxRecordDataLength];
|
|
uint16_t mRecordDataLength;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
OwningList<BrowseCallback> sBrowseCallbacks;
|
|
OwningList<SrvCallback> sSrvCallbacks;
|
|
OwningList<TxtCallback> sTxtCallbacks;
|
|
OwningList<AddrCallback> sAddrCallbacks;
|
|
OwningList<RecordCallback> sRecordCallbacks;
|
|
|
|
void HandleBrowseResult(otInstance *aInstance, const otMdnsBrowseResult *aResult)
|
|
{
|
|
BrowseCallback *entry;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aResult != nullptr);
|
|
VerifyOrQuit(aResult->mServiceType != nullptr);
|
|
VerifyOrQuit(aResult->mServiceInstance != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
Log("Browse callback: %s (subtype:%s) -> %s ttl:%lu", aResult->mServiceType,
|
|
aResult->mSubTypeLabel == nullptr ? "(null)" : aResult->mSubTypeLabel, aResult->mServiceInstance,
|
|
ToUlong(aResult->mTtl));
|
|
|
|
entry = BrowseCallback::Allocate();
|
|
VerifyOrQuit(entry != nullptr);
|
|
|
|
entry->mServiceType.CopyFrom(aResult->mServiceType);
|
|
entry->mSubTypeLabel.CopyFrom(aResult->mSubTypeLabel);
|
|
entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
|
|
entry->mTtl = aResult->mTtl;
|
|
entry->mIsSubType = (aResult->mSubTypeLabel != nullptr);
|
|
|
|
sBrowseCallbacks.PushAfterTail(*entry);
|
|
}
|
|
|
|
void HandleBrowseResultAlternate(otInstance *aInstance, const otMdnsBrowseResult *aResult)
|
|
{
|
|
Log("Alternate browse callback is called");
|
|
HandleBrowseResult(aInstance, aResult);
|
|
}
|
|
|
|
void HandleSrvResult(otInstance *aInstance, const otMdnsSrvResult *aResult)
|
|
{
|
|
SrvCallback *entry;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aResult != nullptr);
|
|
VerifyOrQuit(aResult->mServiceInstance != nullptr);
|
|
VerifyOrQuit(aResult->mServiceType != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
if (aResult->mTtl != 0)
|
|
{
|
|
VerifyOrQuit(aResult->mHostName != nullptr);
|
|
|
|
Log("SRV callback: %s %s, host:%s port:%u, prio:%u, weight:%u, ttl:%lu", aResult->mServiceInstance,
|
|
aResult->mServiceType, aResult->mHostName, aResult->mPort, aResult->mPriority, aResult->mWeight,
|
|
ToUlong(aResult->mTtl));
|
|
}
|
|
else
|
|
{
|
|
Log("SRV callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
|
|
}
|
|
|
|
entry = SrvCallback::Allocate();
|
|
VerifyOrQuit(entry != nullptr);
|
|
|
|
entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
|
|
entry->mServiceType.CopyFrom(aResult->mServiceType);
|
|
entry->mHostName.CopyFrom(aResult->mHostName);
|
|
entry->mPort = aResult->mPort;
|
|
entry->mPriority = aResult->mPriority;
|
|
entry->mWeight = aResult->mWeight;
|
|
entry->mTtl = aResult->mTtl;
|
|
|
|
sSrvCallbacks.PushAfterTail(*entry);
|
|
}
|
|
|
|
void HandleSrvResultAlternate(otInstance *aInstance, const otMdnsSrvResult *aResult)
|
|
{
|
|
Log("Alternate SRV callback is called");
|
|
HandleSrvResult(aInstance, aResult);
|
|
}
|
|
|
|
void HandleTxtResult(otInstance *aInstance, const otMdnsTxtResult *aResult)
|
|
{
|
|
TxtCallback *entry;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aResult != nullptr);
|
|
VerifyOrQuit(aResult->mServiceInstance != nullptr);
|
|
VerifyOrQuit(aResult->mServiceType != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
VerifyOrQuit(aResult->mTxtDataLength <= TxtCallback::kMaxTxtDataLength);
|
|
|
|
if (aResult->mTtl != 0)
|
|
{
|
|
VerifyOrQuit(aResult->mTxtData != nullptr);
|
|
|
|
Log("TXT callback: %s %s, len:%u, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType,
|
|
aResult->mTxtDataLength, ToUlong(aResult->mTtl));
|
|
}
|
|
else
|
|
{
|
|
Log("TXT callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
|
|
}
|
|
|
|
entry = TxtCallback::Allocate();
|
|
VerifyOrQuit(entry != nullptr);
|
|
|
|
entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
|
|
entry->mServiceType.CopyFrom(aResult->mServiceType);
|
|
entry->mTxtDataLength = aResult->mTxtDataLength;
|
|
memcpy(entry->mTxtData, aResult->mTxtData, aResult->mTxtDataLength);
|
|
entry->mTtl = aResult->mTtl;
|
|
|
|
sTxtCallbacks.PushAfterTail(*entry);
|
|
}
|
|
|
|
void HandleTxtResultAlternate(otInstance *aInstance, const otMdnsTxtResult *aResult)
|
|
{
|
|
Log("Alternate TXT callback is called");
|
|
HandleTxtResult(aInstance, aResult);
|
|
}
|
|
|
|
void HandleAddrResult(otInstance *aInstance, const otMdnsAddressResult *aResult)
|
|
{
|
|
AddrCallback *entry;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aResult != nullptr);
|
|
VerifyOrQuit(aResult->mHostName != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
VerifyOrQuit(aResult->mAddressesLength <= AddrCallback::kMaxNumAddrs);
|
|
|
|
entry = AddrCallback::Allocate();
|
|
VerifyOrQuit(entry != nullptr);
|
|
|
|
entry->mHostName.CopyFrom(aResult->mHostName);
|
|
entry->mNumAddrs = aResult->mAddressesLength;
|
|
|
|
Log("Addr callback: %s, num:%u", aResult->mHostName, aResult->mAddressesLength);
|
|
|
|
for (uint16_t index = 0; index < aResult->mAddressesLength; index++)
|
|
{
|
|
entry->mAddrAndTtls[index].mAddress = AsCoreType(&aResult->mAddresses[index].mAddress);
|
|
entry->mAddrAndTtls[index].mTtl = aResult->mAddresses[index].mTtl;
|
|
|
|
Log(" - %s, ttl:%lu", entry->mAddrAndTtls[index].mAddress.ToString().AsCString(),
|
|
ToUlong(entry->mAddrAndTtls[index].mTtl));
|
|
}
|
|
|
|
sAddrCallbacks.PushAfterTail(*entry);
|
|
}
|
|
|
|
void HandleAddrResultAlternate(otInstance *aInstance, const otMdnsAddressResult *aResult)
|
|
{
|
|
Log("Alternate addr callback is called");
|
|
HandleAddrResult(aInstance, aResult);
|
|
}
|
|
|
|
void HandleRecordResult(otInstance *aInstance, const otMdnsRecordResult *aResult)
|
|
{
|
|
RecordCallback *entry;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aResult != nullptr);
|
|
VerifyOrQuit(aResult->mFirstLabel != nullptr);
|
|
VerifyOrQuit(aResult->mRecordData != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
VerifyOrQuit(aResult->mRecordDataLength <= RecordCallback::kMaxRecordDataLength);
|
|
|
|
Log("Record callback: %s %s type:%u -> rlen:%u ttl:%lu", aResult->mFirstLabel,
|
|
(aResult->mNextLabels != nullptr) ? aResult->mNextLabels : "(null)", aResult->mRecordType,
|
|
aResult->mRecordDataLength, ToUlong(aResult->mTtl));
|
|
|
|
entry = RecordCallback::Allocate();
|
|
VerifyOrQuit(entry != nullptr);
|
|
|
|
entry->mFirstLabel.CopyFrom(aResult->mFirstLabel);
|
|
entry->mNextLabels.CopyFrom(aResult->mNextLabels);
|
|
entry->mRecordType = aResult->mRecordType;
|
|
entry->mRecordDataLength = aResult->mRecordDataLength;
|
|
memcpy(entry->mRecordData, aResult->mRecordData, aResult->mRecordDataLength);
|
|
entry->mTtl = aResult->mTtl;
|
|
|
|
sRecordCallbacks.PushAfterTail(*entry);
|
|
}
|
|
|
|
void HandleRecordResultAlternate(otInstance *aInstance, const otMdnsRecordResult *aResult)
|
|
{
|
|
Log("Alternate record callback is called");
|
|
HandleRecordResult(aInstance, aResult);
|
|
}
|
|
|
|
uint32_t DetermineQueryWaitTime(uint8_t aQueryCount)
|
|
{
|
|
uint32_t interval = 125;
|
|
|
|
if (aQueryCount == 0)
|
|
{
|
|
interval = 125;
|
|
}
|
|
else if (aQueryCount <= 12)
|
|
{
|
|
interval = (1U << (aQueryCount - 1)) * 1000;
|
|
interval += (interval / 32) + 1;
|
|
}
|
|
else
|
|
{
|
|
interval = 3600 * 1000;
|
|
interval += (interval / 32) + 1;
|
|
}
|
|
|
|
return interval;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestBrowser(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Browser browser;
|
|
Core::Browser browser2;
|
|
const DnsMessage *dnsMsg;
|
|
const BrowseCallback *browseCallback;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestBrowser");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a browser. Validate initial queries.");
|
|
|
|
ClearAllBytes(browser);
|
|
|
|
browser.mServiceType = "_srv._udp";
|
|
browser.mSubTypeLabel = nullptr;
|
|
browser.mInfraIfIndex = kInfraIfIndex;
|
|
browser.mCallback = HandleBrowseResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartBrowser(browser));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(browser);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(browseCallback->mTtl == 120);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send another response. Validate callback result.");
|
|
|
|
AdvanceTime(10000);
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 500, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
|
|
VerifyOrQuit(browseCallback->mTtl == 500);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another browser for the same service and different callback. Validate results.");
|
|
|
|
AdvanceTime(5000);
|
|
|
|
browser2.mServiceType = "_srv._udp";
|
|
browser2.mSubTypeLabel = nullptr;
|
|
browser2.mInfraIfIndex = kInfraIfIndex;
|
|
browser2.mCallback = HandleBrowseResultAlternate;
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartBrowser(browser2));
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(browseCallback != nullptr);
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
|
|
if (browseCallback->mServiceInstance.Matches("awesome"))
|
|
{
|
|
VerifyOrQuit(browseCallback->mTtl == 500);
|
|
}
|
|
else if (browseCallback->mServiceInstance.Matches("mysrv"))
|
|
{
|
|
VerifyOrQuit(browseCallback->mTtl == 120);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(false);
|
|
}
|
|
|
|
browseCallback = browseCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(browseCallback == nullptr);
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start same browser again and check the returned error.");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
VerifyOrQuit(mdns->StartBrowser(browser2) == kErrorAlready);
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a goodbye response. Validate result callback for both browsers.");
|
|
|
|
SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 0, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(browseCallback != nullptr);
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
|
|
VerifyOrQuit(browseCallback->mTtl == 0);
|
|
|
|
browseCallback = browseCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(browseCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with no changes, validate that no callback is invoked.");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second browser.");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopBrowser(browser2));
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check query is sent at 80 percentage of TTL and then respond to it.");
|
|
|
|
// First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
|
|
// We wait for 100 second. Note that 5 seconds already passed in the
|
|
// previous step.
|
|
|
|
AdvanceTime(91 * 1000 - 1);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(4 * 1000 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(browser);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
|
|
AdvanceTime(10);
|
|
|
|
SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
|
|
{
|
|
if (queryCount == 0)
|
|
{
|
|
// First query is expected in 80-82% of TTL, so
|
|
// 80% of 120 = 96.0, 82% of 120 = 98.4
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
}
|
|
else
|
|
{
|
|
// Next query should happen within 3%-5% of TTL
|
|
// from previous query. We wait 3% of TTL here.
|
|
AdvanceTime(3600 - 1);
|
|
}
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for 2% of TTL of 120 which is 2.4 sec.
|
|
|
|
AdvanceTime(2400 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(browser);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout and callback result.");
|
|
|
|
AdvanceTime(6 * 1000);
|
|
|
|
VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(browseCallback->mTtl == 0);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(200 * 1000);
|
|
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a new response and make sure result callback is invoked");
|
|
|
|
SendPtrResponse("_srv._udp.local.", "great._srv._udp.local.", 200, kInAdditionalSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("great"));
|
|
VerifyOrQuit(browseCallback->mTtl == 200);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
AdvanceTime(150 * 1000);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the browser. There is no active browser for this service. Ensure no queries are sent");
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopBrowser(browser));
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyOrQuit(sBrowseCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start browser again. Validate that initial queries are sent again");
|
|
|
|
SuccessOrQuit(mdns->StartBrowser(browser));
|
|
|
|
AdvanceTime(125);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(browser);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response after the first initial query");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 20 * 3600, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(browseCallback->mTtl == 20 * 3600);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate initial queries are still sent and include known-answer");
|
|
|
|
for (uint8_t queryCount = 1; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(browser);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sDnsMessages.Clear();
|
|
AdvanceTime(50 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestSrvResolver(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::SrvResolver resolver;
|
|
Core::SrvResolver resolver2;
|
|
const DnsMessage *dnsMsg;
|
|
const SrvCallback *srvCallback;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestSrvResolver");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a SRV resolver. Validate initial queries.");
|
|
|
|
ClearAllBytes(resolver);
|
|
|
|
resolver.mServiceInstance = "mysrv";
|
|
resolver.mServiceType = "_srv._udp";
|
|
resolver.mInfraIfIndex = kInfraIfIndex;
|
|
resolver.mCallback = HandleSrvResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartSrvResolver(resolver));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 0, 1, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 0);
|
|
VerifyOrQuit(srvCallback->mWeight == 1);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing host name. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 1234, 0, 1, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 0);
|
|
VerifyOrQuit(srvCallback->mWeight == 1);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing port. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
|
|
VerifyOrQuit(srvCallback->mPort == 4567);
|
|
VerifyOrQuit(srvCallback->mPriority == 0);
|
|
VerifyOrQuit(srvCallback->mWeight == 1);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing TTL. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 0, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches(""));
|
|
VerifyOrQuit(srvCallback->mPort == 4567);
|
|
VerifyOrQuit(srvCallback->mPriority == 0);
|
|
VerifyOrQuit(srvCallback->mWeight == 1);
|
|
VerifyOrQuit(srvCallback->mTtl == 0);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing a bunch of things. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with no changes. Validate callback is not invoked.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another resolver for the same service and different callback. Validate results.");
|
|
|
|
ClearAllBytes(resolver2);
|
|
|
|
resolver2.mServiceInstance = "mysrv";
|
|
resolver2.mServiceType = "_srv._udp";
|
|
resolver2.mInfraIfIndex = kInfraIfIndex;
|
|
resolver2.mCallback = HandleSrvResultAlternate;
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(resolver2));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start same resolver again and check the returned error.");
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
VerifyOrQuit(mdns->StartSrvResolver(resolver2) == kErrorAlready);
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check query is sent at 80 percentage of TTL and then respond to it.");
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
|
|
|
|
// First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
|
|
// We wait for 100 second. Note that 5 seconds already passed in the
|
|
// previous step.
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(4 * 1000 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
|
|
AdvanceTime(10);
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
|
|
{
|
|
if (queryCount == 0)
|
|
{
|
|
// First query is expected in 80-82% of TTL, so
|
|
// 80% of 120 = 96.0, 82% of 120 = 98.4
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
}
|
|
else
|
|
{
|
|
// Next query should happen within 3%-5% of TTL
|
|
// from previous query. We wait 3% of TTL here.
|
|
AdvanceTime(3600 - 1);
|
|
}
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for 2% of TTL of 120 which is 2.4 sec.
|
|
|
|
AdvanceTime(2400 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout and callback result.");
|
|
|
|
AdvanceTime(6 * 1000);
|
|
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(srvCallback != nullptr);
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mTtl == 0);
|
|
srvCallback = srvCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(srvCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sSrvCallbacks.Clear();
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(200 * 1000);
|
|
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second resolver");
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopSrvResolver(resolver2));
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a new response and make sure result callback is invoked");
|
|
|
|
SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopSrvResolver(resolver));
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sSrvCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Restart the resolver with more than half of TTL remaining.");
|
|
Log("Ensure cached entry is reported in the result callback and no queries are sent.");
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop and start the resolver again after less than half TTL remaining.");
|
|
Log("Ensure cached entry is still reported in the result callback but queries should be sent");
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopSrvResolver(resolver));
|
|
|
|
AdvanceTime(25 * 1000);
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(srvCallback->mPort == 1234);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 120);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
// Initial query intervals use exponential backoff: 1, 2, 4,
|
|
// 8, ... seconds. Cumulative send times would be 0, 1, 3, 7,
|
|
// 15, 31, ... So within 20 seconds, we should see a total of 5
|
|
// queries.
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount <= 4; queryCount++)
|
|
{
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
dnsMsg = dnsMsg->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestTxtResolver(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::TxtResolver resolver;
|
|
Core::TxtResolver resolver2;
|
|
const DnsMessage *dnsMsg;
|
|
const TxtCallback *txtCallback;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestTxtResolver");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a TXT resolver. Validate initial queries.");
|
|
|
|
ClearAllBytes(resolver);
|
|
|
|
resolver.mServiceInstance = "mysrv";
|
|
resolver.mServiceType = "_srv._udp";
|
|
resolver.mInfraIfIndex = kInfraIfIndex;
|
|
resolver.mCallback = HandleTxtResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartTxtResolver(resolver));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing TXT data. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData2, sizeof(kTxtData2), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData2));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing TXT data to empty. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response changing TTL. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 500, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
|
|
VerifyOrQuit(txtCallback->mTtl == 500);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response with zero TTL. Validate callback result.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 0, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->mTtl == 0);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response. Validate callback result.");
|
|
|
|
sTxtCallbacks.Clear();
|
|
AdvanceTime(100 * 1000);
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with no changes. Validate callback is not invoked.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(100);
|
|
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another resolver for the same service and different callback. Validate results.");
|
|
|
|
resolver2.mServiceInstance = "mysrv";
|
|
resolver2.mServiceType = "_srv._udp";
|
|
resolver2.mInfraIfIndex = kInfraIfIndex;
|
|
resolver2.mCallback = HandleTxtResultAlternate;
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartTxtResolver(resolver2));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start same resolver again and check the returned error.");
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
VerifyOrQuit(mdns->StartTxtResolver(resolver2) == kErrorAlready);
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check query is sent at 80 percentage of TTL and then respond to it.");
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
// First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
|
|
// We wait for 100 second. Note that 5 seconds already passed in the
|
|
// previous step.
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(4 * 1000 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
|
|
AdvanceTime(10);
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
|
|
{
|
|
if (queryCount == 0)
|
|
{
|
|
// First query is expected in 80-82% of TTL, so
|
|
// 80% of 120 = 96.0, 82% of 120 = 98.4
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
}
|
|
else
|
|
{
|
|
// Next query should happen within 3%-5% of TTL
|
|
// from previous query. We wait 3% of TTL here.
|
|
AdvanceTime(3600 - 1);
|
|
}
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for 2% of TTL of 120 which is 2.4 sec.
|
|
|
|
AdvanceTime(2400 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout and callback result.");
|
|
|
|
AdvanceTime(6 * 1000);
|
|
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(txtCallback != nullptr);
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->mTtl == 0);
|
|
txtCallback = txtCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(txtCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sTxtCallbacks.Clear();
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(200 * 1000);
|
|
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second resolver");
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopTxtResolver(resolver2));
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a new response and make sure result callback is invoked");
|
|
|
|
SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopTxtResolver(resolver));
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sTxtCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Restart the resolver with more than half of TTL remaining.");
|
|
Log("Ensure cached entry is reported in the result callback and no queries are sent.");
|
|
|
|
SuccessOrQuit(mdns->StartTxtResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop and start the resolver again after less than half TTL remaining.");
|
|
Log("Ensure cached entry is still reported in the result callback but queries should be sent");
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopTxtResolver(resolver));
|
|
|
|
AdvanceTime(25 * 1000);
|
|
|
|
SuccessOrQuit(mdns->StartTxtResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 120);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
sTxtCallbacks.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
// Initial query intervals use exponential backoff: 1, 2, 4,
|
|
// 8, ... seconds. Cumulative send times would be 0, 1, 3, 7,
|
|
// 15, 31, ... So within 20 seconds, we should see a total of 5
|
|
// queries.
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount <= 4; queryCount++)
|
|
{
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
dnsMsg = dnsMsg->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestIp6AddrResolver(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::AddressResolver resolver;
|
|
Core::AddressResolver resolver2;
|
|
AddrAndTtl addrs[5];
|
|
const DnsMessage *dnsMsg;
|
|
const AddrCallback *addrCallback;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestIp6AddrResolver");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start an IPv6 address resolver. Validate initial queries.");
|
|
|
|
ClearAllBytes(resolver);
|
|
|
|
resolver.mHostName = "myhost";
|
|
resolver.mInfraIfIndex = kInfraIfIndex;
|
|
resolver.mCallback = HandleAddrResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SuccessOrQuit(addrs[0].mAddress.FromString("fd00::1"));
|
|
addrs[0].mTtl = 120;
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 1));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response adding a new address. Validate callback result.");
|
|
|
|
SuccessOrQuit(addrs[1].mAddress.FromString("fd00::2"));
|
|
addrs[1].mTtl = 120;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 2, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 2));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send an updated response adding and removing addresses. Validate callback result.");
|
|
|
|
SuccessOrQuit(addrs[0].mAddress.FromString("fd00::2"));
|
|
SuccessOrQuit(addrs[1].mAddress.FromString("fd00::aa"));
|
|
SuccessOrQuit(addrs[2].mAddress.FromString("fe80::bb"));
|
|
addrs[0].mTtl = 120;
|
|
addrs[1].mTtl = 120;
|
|
addrs[2].mTtl = 120;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 3, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 3));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response without cache flush adding an address. Validate callback result.");
|
|
|
|
SuccessOrQuit(addrs[3].mAddress.FromString("fd00::3"));
|
|
addrs[3].mTtl = 500;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 4));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response without cache flush with existing addresses. Validate that callback is not called.");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", &addrs[2], 2, /* aCachFlush */ false, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response without no changes to the list. Validate that callback is not called");
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAdditionalSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response without cache flush updating TTL of existing address. Validate callback result.");
|
|
|
|
addrs[3].mTtl = 200;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 4));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response without cache flush removing an address (zero TTL). Validate callback result.");
|
|
|
|
addrs[3].mTtl = 0;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 3));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with cache flush removing all addresses. Validate callback result.");
|
|
|
|
addrs[0].mTtl = 0;
|
|
|
|
AdvanceTime(1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 0));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with addresses with different TTL. Validate callback result");
|
|
|
|
SuccessOrQuit(addrs[0].mAddress.FromString("fd00::00"));
|
|
SuccessOrQuit(addrs[1].mAddress.FromString("fd00::11"));
|
|
SuccessOrQuit(addrs[2].mAddress.FromString("fe80::22"));
|
|
SuccessOrQuit(addrs[3].mAddress.FromString("fe80::33"));
|
|
addrs[0].mTtl = 120;
|
|
addrs[1].mTtl = 800;
|
|
addrs[2].mTtl = 2000;
|
|
addrs[3].mTtl = 8000;
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 4));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another resolver for the same host and different callback. Validate results.");
|
|
|
|
resolver2.mHostName = "myhost";
|
|
resolver2.mInfraIfIndex = kInfraIfIndex;
|
|
resolver2.mCallback = HandleAddrResultAlternate;
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(resolver2));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 4));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start same resolver again and check the returned error.");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
VerifyOrQuit(mdns->StartIp6AddressResolver(resolver2) == kErrorAlready);
|
|
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
sDnsMessages.Clear();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check query is sent at 80 percentage of TTL and then respond to it.");
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
// First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
|
|
// We wait for 100 second. Note that 5 seconds already passed in the
|
|
// previous step.
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(4 * 1000 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
|
|
AdvanceTime(10);
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
|
|
{
|
|
if (queryCount == 0)
|
|
{
|
|
// First query is expected in 80-82% of TTL, so
|
|
// 80% of 120 = 96.0, 82% of 120 = 98.4
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
}
|
|
else
|
|
{
|
|
// Next query should happen within 3%-5% of TTL
|
|
// from previous query. We wait 3% of TTL here.
|
|
AdvanceTime(3600 - 1);
|
|
}
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for 2% of TTL of 120 which is 2.4 sec.
|
|
|
|
AdvanceTime(2400 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout of first address (TTL 120) and callback result.");
|
|
|
|
AdvanceTime(6 * 1000);
|
|
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(addrCallback != nullptr);
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(&addrs[1], 3));
|
|
addrCallback = addrCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(addrCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout of next address (TTL 800) and callback result.");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
AdvanceTime((800 - 120) * 1000);
|
|
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(addrCallback != nullptr);
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(&addrs[2], 2));
|
|
addrCallback = addrCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(addrCallback == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sAddrCallbacks.Clear();
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(200 * 1000);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second resolver");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopIp6AddressResolver(resolver2));
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a new response and make sure result callback is invoked");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 1));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sAddrCallbacks.IsEmpty());
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Restart the resolver with more than half of TTL remaining.");
|
|
Log("Ensure cached entry is reported in the result callback and no queries are sent.");
|
|
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 1));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop and start the resolver again after less than half TTL remaining.");
|
|
Log("Ensure cached entry is still reported in the result callback but queries should be sent");
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
|
|
|
|
AdvanceTime(25 * 1000);
|
|
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
|
|
VerifyOrQuit(addrCallback->Matches(addrs, 1));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
sAddrCallbacks.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
// Initial query intervals use exponential backoff: 1, 2, 4,
|
|
// 8, ... seconds. Cumulative send times would be 0, 1, 3, 7,
|
|
// 15, 31, ... So within 20 seconds, we should see a total of 5
|
|
// queries.
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount <= 4; queryCount++)
|
|
{
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(resolver);
|
|
dnsMsg = dnsMsg->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(dnsMsg == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestRecordQuerier(void)
|
|
{
|
|
static constexpr uint8_t kMaxResponseRecords = 4;
|
|
|
|
Core *mdns = InitTest();
|
|
Core::RecordQuerier querier;
|
|
Core::RecordQuerier querier2;
|
|
Core::Iterator *iterator;
|
|
Core::CacheInfo cacheInfo;
|
|
const DnsMessage *dnsMsg;
|
|
const RecordCallback *recordCallback;
|
|
uint16_t heapAllocations;
|
|
RecordData records[kMaxResponseRecords];
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestRecordQuerier");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a record querier. Validate initial queries.");
|
|
|
|
ClearAllBytes(querier);
|
|
|
|
querier.mFirstLabel = "mysrv";
|
|
querier.mNextLabels = "_srv._udp";
|
|
querier.mRecordType = ResourceRecord::kTypeKey;
|
|
querier.mInfraIfIndex = kInfraIfIndex;
|
|
querier.mCallback = HandleRecordResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartRecordQuerier(querier));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(querier);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a second response (without cache-flush). Validate callback result.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey2;
|
|
records[0].mLength = sizeof(kKey2);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another record querier for the same name and record type with different callback.");
|
|
|
|
ClearAllBytes(querier2);
|
|
|
|
querier2.mFirstLabel = "mysrv";
|
|
querier2.mNextLabels = "_srv._udp";
|
|
querier2.mRecordType = ResourceRecord::kTypeKey;
|
|
querier2.mInfraIfIndex = kInfraIfIndex;
|
|
querier2.mCallback = HandleRecordResultAlternate;
|
|
|
|
sRecordCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartRecordQuerier(querier2));
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback result from cache for the new querier");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
|
|
for (uint8_t num = 2; num > 0; num--)
|
|
{
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey2) || recordCallback->MatchesData(kKey1));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
recordCallback = recordCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(recordCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second querier.");
|
|
|
|
SuccessOrQuit(mdns->StopRecordQuerier(querier2));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response (without cache-flush) with one previous record and a new record.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = false;
|
|
|
|
records[1].mType = ResourceRecord::kTypeKey;
|
|
records[1].mData = kKey3;
|
|
records[1].mLength = sizeof(kKey3);
|
|
records[1].mTtl = 120;
|
|
records[1].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 2, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
// Only key3 (which is new) should be reported.
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey3));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(5000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with one record, `key3` (cached-flush) and an extra record of different type");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey3;
|
|
records[0].mLength = sizeof(kKey3);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = true;
|
|
|
|
// The second record is of type TXT, which should be ignored
|
|
// because it doesn't match the `RecordQuerier`. We intentionally
|
|
// use `kKey2` as record data to validate that the record type
|
|
// (TXT) and not just is indeed checked by the mDNS module.
|
|
|
|
records[1].mType = ResourceRecord::kTypeTxt;
|
|
records[1].mData = kKey2;
|
|
records[1].mLength = sizeof(kKey2);
|
|
records[1].mTtl = 120;
|
|
records[1].mCacheFlush = true;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 2, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback result indicating the two other two keys are removed.");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
|
|
for (uint8_t num = 2; num > 0; num--)
|
|
{
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1) || recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 0);
|
|
recordCallback = recordCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(recordCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(500);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response removing key3 and other keys.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 0;
|
|
records[0].mCacheFlush = false;
|
|
|
|
records[1].mType = ResourceRecord::kTypeKey;
|
|
records[1].mData = kKey2;
|
|
records[1].mLength = sizeof(kKey2);
|
|
records[1].mTtl = 0;
|
|
records[1].mCacheFlush = false;
|
|
|
|
records[2].mType = ResourceRecord::kTypeKey;
|
|
records[2].mData = kKey3;
|
|
records[2].mLength = sizeof(kKey3);
|
|
records[2].mTtl = 0;
|
|
records[2].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 3, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback result indicating key3 is now removed.");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey3));
|
|
VerifyOrQuit(recordCallback->mTtl == 0);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response adding two keys");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 500;
|
|
records[0].mCacheFlush = true;
|
|
|
|
records[1].mType = ResourceRecord::kTypeKey;
|
|
records[1].mData = kKey2;
|
|
records[1].mLength = sizeof(kKey2);
|
|
records[1].mTtl = 500;
|
|
records[1].mCacheFlush = true;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 2, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback results");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
|
|
for (uint8_t num = 2; num > 0; num--)
|
|
{
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1) || recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 500);
|
|
recordCallback = recordCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(recordCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(5000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response changing the TTL for key1");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback results indicating key1 TTL change");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
sRecordCallbacks.Clear();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check query is sent at 80 percentage of TTL and then respond to it.");
|
|
|
|
// First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
|
|
// We wait for 100 second. Note that 5 seconds already passed in the
|
|
// previous step.
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
AdvanceTime(4 * 1000 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(querier);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sRecordCallbacks.IsEmpty());
|
|
|
|
AdvanceTime(10);
|
|
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
|
|
{
|
|
if (queryCount == 0)
|
|
{
|
|
// First query is expected in 80-82% of TTL, so
|
|
// 80% of 120 = 96.0, 82% of 120 = 98.4
|
|
|
|
AdvanceTime(96 * 1000 - 1);
|
|
}
|
|
else
|
|
{
|
|
// Next query should happen within 3%-5% of TTL
|
|
// from previous query. We wait 3% of TTL here.
|
|
AdvanceTime(3600 - 1);
|
|
}
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
// Wait for 2% of TTL of 120 which is 2.4 sec.
|
|
|
|
AdvanceTime(2400 + 1);
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(querier);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
|
|
sDnsMessages.Clear();
|
|
VerifyOrQuit(sRecordCallbacks.IsEmpty());
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check TTL timeout and callback result.");
|
|
|
|
AdvanceTime(6 * 1000);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1));
|
|
VerifyOrQuit(recordCallback->mTtl == 0);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the list of `RecordQueier` entries and the cache-info");
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
SuccessOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo));
|
|
VerifyOrQuit(querier2.mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(StringMatch(querier2.mFirstLabel, "mysrv", kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(StringMatch(querier2.mNextLabels, "_srv._udp", kStringCaseInsensitiveMatch));
|
|
|
|
VerifyOrQuit(cacheInfo.mIsActive);
|
|
VerifyOrQuit(cacheInfo.mHasCachedResults);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the record querier");
|
|
|
|
SuccessOrQuit(mdns->StopRecordQuerier(querier));
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(10);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the list of `RecordQueier` entries and cache-info after stop (no longer active)");
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
SuccessOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo));
|
|
VerifyOrQuit(querier2.mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(StringMatch(querier2.mFirstLabel, "mysrv", kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(StringMatch(querier2.mNextLabels, "_srv._udp", kStringCaseInsensitiveMatch));
|
|
|
|
VerifyOrQuit(!cacheInfo.mIsActive);
|
|
VerifyOrQuit(cacheInfo.mHasCachedResults);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the `RecordQuerier` is correctly removed after 'remove timeout' of 7 minutes");
|
|
|
|
AdvanceTime(7 * 60 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestRecordQuerierForAny(void)
|
|
{
|
|
static constexpr uint8_t kMaxResponseRecords = 6;
|
|
|
|
Core *mdns = InitTest();
|
|
Core::RecordQuerier querier;
|
|
Core::RecordQuerier querier2;
|
|
Core::Iterator *iterator;
|
|
Core::CacheInfo cacheInfo;
|
|
const DnsMessage *dnsMsg;
|
|
const RecordCallback *recordCallback;
|
|
uint16_t heapAllocations;
|
|
RecordData records[kMaxResponseRecords];
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestRecordQuerierForAny");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a record querier for ANY record type. Validate initial queries.");
|
|
|
|
ClearAllBytes(querier);
|
|
|
|
querier.mFirstLabel = "mysrv";
|
|
querier.mNextLabels = "_srv._udp";
|
|
querier.mRecordType = ResourceRecord::kTypeAny;
|
|
querier.mInfraIfIndex = kInfraIfIndex;
|
|
querier.mCallback = HandleRecordResult;
|
|
|
|
sDnsMessages.Clear();
|
|
SuccessOrQuit(mdns->StartRecordQuerier(querier));
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitialQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(DetermineQueryWaitTime(queryCount));
|
|
|
|
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
|
|
dnsMsg->ValidateAsQueryFor(querier);
|
|
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
|
}
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response. Validate callback result.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 120;
|
|
records[0].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeKey);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1));
|
|
VerifyOrQuit(recordCallback->mTtl == 120);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a second response for a different record type. Validate callback result.");
|
|
|
|
records[0].mType = ResourceRecord::kTypeTxt;
|
|
records[0].mData = kKey2;
|
|
records[0].mLength = sizeof(kKey2);
|
|
records[0].mTtl = 400;
|
|
records[0].mCacheFlush = true;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 1, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
VerifyOrQuit(recordCallback->mRecordType == ResourceRecord::kTypeTxt);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 400);
|
|
VerifyOrQuit(recordCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a response with multiple record of different types");
|
|
|
|
records[0].mType = ResourceRecord::kTypeKey;
|
|
records[0].mData = kKey1;
|
|
records[0].mLength = sizeof(kKey1);
|
|
records[0].mTtl = 200;
|
|
records[0].mCacheFlush = false;
|
|
|
|
records[1].mType = ResourceRecord::kTypeTxt;
|
|
records[1].mData = kKey2;
|
|
records[1].mLength = sizeof(kKey2);
|
|
records[1].mTtl = 300;
|
|
records[1].mCacheFlush = true;
|
|
|
|
records[2].mType = ResourceRecord::kTypeKey;
|
|
records[2].mData = kKey2;
|
|
records[2].mLength = sizeof(kKey2);
|
|
records[2].mTtl = 200;
|
|
records[2].mCacheFlush = false;
|
|
|
|
records[3].mType = ResourceRecord::kTypeKey;
|
|
records[3].mData = kKey3;
|
|
records[3].mLength = sizeof(kKey3);
|
|
records[3].mTtl = 200;
|
|
records[3].mCacheFlush = false;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SendRecordResponse("mysrv._srv._udp.local.", 4, records);
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
|
|
for (uint8_t num = 4; num > 0; num--)
|
|
{
|
|
VerifyOrQuit(recordCallback != nullptr);
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
|
|
if (recordCallback->mRecordType == ResourceRecord::kTypeTxt)
|
|
{
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 300);
|
|
}
|
|
else if (recordCallback->mRecordType == ResourceRecord::kTypeKey)
|
|
{
|
|
VerifyOrQuit(recordCallback->mTtl == 200);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1) || recordCallback->MatchesData(kKey2) ||
|
|
recordCallback->MatchesData(kKey3));
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(false);
|
|
}
|
|
|
|
recordCallback = recordCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(recordCallback == nullptr);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start another record querier for the same name with different callback.");
|
|
|
|
ClearAllBytes(querier2);
|
|
|
|
querier2.mFirstLabel = "mysrv";
|
|
querier2.mNextLabels = "_srv._udp";
|
|
querier2.mRecordType = ResourceRecord::kTypeAny;
|
|
querier2.mInfraIfIndex = kInfraIfIndex;
|
|
querier2.mCallback = HandleRecordResultAlternate;
|
|
|
|
sRecordCallbacks.Clear();
|
|
SuccessOrQuit(mdns->StartRecordQuerier(querier2));
|
|
|
|
AdvanceTime(1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate callback result from cache for the new querier");
|
|
|
|
VerifyOrQuit(!sRecordCallbacks.IsEmpty());
|
|
recordCallback = sRecordCallbacks.GetHead();
|
|
|
|
for (uint8_t num = 4; num > 0; num--)
|
|
{
|
|
VerifyOrQuit(recordCallback != nullptr);
|
|
VerifyOrQuit(recordCallback->mFirstLabel.Matches("mysrv"));
|
|
VerifyOrQuit(recordCallback->mNextLabels.Matches("_srv._udp"));
|
|
|
|
if (recordCallback->mRecordType == ResourceRecord::kTypeTxt)
|
|
{
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey2));
|
|
VerifyOrQuit(recordCallback->mTtl == 300);
|
|
}
|
|
else if (recordCallback->mRecordType == ResourceRecord::kTypeKey)
|
|
{
|
|
VerifyOrQuit(recordCallback->mTtl == 200);
|
|
VerifyOrQuit(recordCallback->MatchesData(kKey1) || recordCallback->MatchesData(kKey2) ||
|
|
recordCallback->MatchesData(kKey3));
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(false);
|
|
}
|
|
|
|
recordCallback = recordCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(recordCallback == nullptr);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the second querier.");
|
|
|
|
SuccessOrQuit(mdns->StopRecordQuerier(querier2));
|
|
|
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the list of `RecordQueier` entries and the cache-info");
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
SuccessOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo));
|
|
VerifyOrQuit(querier2.mRecordType == ResourceRecord::kTypeAny);
|
|
VerifyOrQuit(StringMatch(querier2.mFirstLabel, "mysrv", kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(StringMatch(querier2.mNextLabels, "_srv._udp", kStringCaseInsensitiveMatch));
|
|
|
|
VerifyOrQuit(cacheInfo.mIsActive);
|
|
VerifyOrQuit(cacheInfo.mHasCachedResults);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Stop the record querier");
|
|
|
|
SuccessOrQuit(mdns->StopRecordQuerier(querier));
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime(10);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the list of `RecordQueier` entries and cache-info after stop (no longer active)");
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
SuccessOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo));
|
|
VerifyOrQuit(querier2.mRecordType == ResourceRecord::kTypeAny);
|
|
VerifyOrQuit(StringMatch(querier2.mFirstLabel, "mysrv", kStringCaseInsensitiveMatch));
|
|
VerifyOrQuit(StringMatch(querier2.mNextLabels, "_srv._udp", kStringCaseInsensitiveMatch));
|
|
|
|
VerifyOrQuit(!cacheInfo.mIsActive);
|
|
VerifyOrQuit(cacheInfo.mHasCachedResults);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Check the `RecordQuerier` is correctly removed after 'remove timeout' of 1 minutes");
|
|
|
|
AdvanceTime(1 * 60 * 1000);
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
iterator = mdns->AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
VerifyOrQuit(mdns->GetNextRecordQuerier(*iterator, querier2, cacheInfo) == kErrorNotFound);
|
|
|
|
mdns->FreeIterator(*iterator);
|
|
|
|
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestPassiveCache(void)
|
|
{
|
|
static const char *const kSubTypes[] = {"_sub1", "_xyzw"};
|
|
|
|
Core *mdns = InitTest();
|
|
Core::Browser browser;
|
|
Core::SrvResolver srvResolver;
|
|
Core::TxtResolver txtResolver;
|
|
Core::AddressResolver addrResolver;
|
|
Core::Host host1;
|
|
Core::Host host2;
|
|
Core::Service service1;
|
|
Core::Service service2;
|
|
Core::Service service3;
|
|
Ip6::Address host1Addresses[3];
|
|
Ip6::Address host2Addresses[2];
|
|
AddrAndTtl host1AddrTtls[3];
|
|
AddrAndTtl host2AddrTtls[2];
|
|
const DnsMessage *dnsMsg;
|
|
BrowseCallback *browseCallback;
|
|
SrvCallback *srvCallback;
|
|
TxtCallback *txtCallback;
|
|
AddrCallback *addrCallback;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestPassiveCache");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(host1Addresses[0].FromString("fd00::1:aaaa"));
|
|
SuccessOrQuit(host1Addresses[1].FromString("fd00::1:bbbb"));
|
|
SuccessOrQuit(host1Addresses[2].FromString("fd00::1:cccc"));
|
|
host1.mHostName = "host1";
|
|
host1.mAddresses = host1Addresses;
|
|
host1.mAddressesLength = 3;
|
|
host1.mTtl = 1500;
|
|
|
|
host1AddrTtls[0].mAddress = host1Addresses[0];
|
|
host1AddrTtls[1].mAddress = host1Addresses[1];
|
|
host1AddrTtls[2].mAddress = host1Addresses[2];
|
|
host1AddrTtls[0].mTtl = host1.mTtl;
|
|
host1AddrTtls[1].mTtl = host1.mTtl;
|
|
host1AddrTtls[2].mTtl = host1.mTtl;
|
|
|
|
SuccessOrQuit(host2Addresses[0].FromString("fd00::2:eeee"));
|
|
SuccessOrQuit(host2Addresses[1].FromString("fd00::2:ffff"));
|
|
host2.mHostName = "host2";
|
|
host2.mAddresses = host2Addresses;
|
|
host2.mAddressesLength = 2;
|
|
host2.mTtl = 1500;
|
|
|
|
host2AddrTtls[0].mAddress = host2Addresses[0];
|
|
host2AddrTtls[1].mAddress = host2Addresses[1];
|
|
host2AddrTtls[0].mTtl = host2.mTtl;
|
|
host2AddrTtls[1].mTtl = host2.mTtl;
|
|
|
|
service1.mHostName = host1.mHostName;
|
|
service1.mServiceInstance = "srv1";
|
|
service1.mServiceType = "_srv._udp";
|
|
service1.mSubTypeLabels = kSubTypes;
|
|
service1.mSubTypeLabelsLength = 2;
|
|
service1.mTxtData = kTxtData1;
|
|
service1.mTxtDataLength = sizeof(kTxtData1);
|
|
service1.mPort = 1111;
|
|
service1.mPriority = 0;
|
|
service1.mWeight = 0;
|
|
service1.mTtl = 1500;
|
|
|
|
service2.mHostName = host1.mHostName;
|
|
service2.mServiceInstance = "srv2";
|
|
service2.mServiceType = "_tst._tcp";
|
|
service2.mSubTypeLabels = nullptr;
|
|
service2.mSubTypeLabelsLength = 0;
|
|
service2.mTxtData = nullptr;
|
|
service2.mTxtDataLength = 0;
|
|
service2.mPort = 2222;
|
|
service2.mPriority = 2;
|
|
service2.mWeight = 2;
|
|
service2.mTtl = 1500;
|
|
|
|
service3.mHostName = host2.mHostName;
|
|
service3.mServiceInstance = "srv3";
|
|
service3.mServiceType = "_srv._udp";
|
|
service3.mSubTypeLabels = kSubTypes;
|
|
service3.mSubTypeLabelsLength = 1;
|
|
service3.mTxtData = kTxtData2;
|
|
service3.mTxtDataLength = sizeof(kTxtData2);
|
|
service3.mPort = 3333;
|
|
service3.mPriority = 3;
|
|
service3.mWeight = 3;
|
|
service3.mTtl = 1500;
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Register 2 hosts and 3 services");
|
|
|
|
SuccessOrQuit(mdns->RegisterHost(host1, 0, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterHost(host2, 1, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service1, 2, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service2, 3, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service3, 4, HandleSuccessCallback));
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a browser for `_srv._udp`, validate callback result");
|
|
|
|
browser.mServiceType = "_srv._udp";
|
|
browser.mSubTypeLabel = nullptr;
|
|
browser.mInfraIfIndex = kInfraIfIndex;
|
|
browser.mCallback = HandleBrowseResult;
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartBrowser(browser));
|
|
|
|
AdvanceTime(350);
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
|
|
for (uint8_t iter = 0; iter < 2; iter++)
|
|
{
|
|
VerifyOrQuit(browseCallback != nullptr);
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(!browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1") ||
|
|
browseCallback->mServiceInstance.Matches("srv3"));
|
|
VerifyOrQuit(browseCallback->mTtl == 1500);
|
|
|
|
browseCallback = browseCallback->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(browseCallback == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start SRV and TXT resolvers for the srv1 and for its host name.");
|
|
Log("Ensure all results are immediately provided from cache.");
|
|
|
|
srvResolver.mServiceInstance = "srv1";
|
|
srvResolver.mServiceType = "_srv._udp";
|
|
srvResolver.mInfraIfIndex = kInfraIfIndex;
|
|
srvResolver.mCallback = HandleSrvResult;
|
|
|
|
txtResolver.mServiceInstance = "srv1";
|
|
txtResolver.mServiceType = "_srv._udp";
|
|
txtResolver.mInfraIfIndex = kInfraIfIndex;
|
|
txtResolver.mCallback = HandleTxtResult;
|
|
|
|
addrResolver.mHostName = "host1";
|
|
addrResolver.mInfraIfIndex = kInfraIfIndex;
|
|
addrResolver.mCallback = HandleAddrResult;
|
|
|
|
sSrvCallbacks.Clear();
|
|
sTxtCallbacks.Clear();
|
|
sAddrCallbacks.Clear();
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
|
|
SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv1"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
|
|
VerifyOrQuit(srvCallback->mPort == 1111);
|
|
VerifyOrQuit(srvCallback->mPriority == 0);
|
|
VerifyOrQuit(srvCallback->mWeight == 0);
|
|
VerifyOrQuit(srvCallback->mTtl == 1500);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv1"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(txtCallback->Matches(kTxtData1));
|
|
VerifyOrQuit(txtCallback->mTtl == 1500);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("host1"));
|
|
VerifyOrQuit(addrCallback->Matches(host1AddrTtls, 3));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
AdvanceTime(400);
|
|
|
|
VerifyOrQuit(sDnsMessages.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start a browser for sub-type service, validate callback result");
|
|
|
|
browser.mServiceType = "_srv._udp";
|
|
browser.mSubTypeLabel = "_xyzw";
|
|
browser.mInfraIfIndex = kInfraIfIndex;
|
|
browser.mCallback = HandleBrowseResult;
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartBrowser(browser));
|
|
|
|
AdvanceTime(350);
|
|
|
|
browseCallback = sBrowseCallbacks.GetHead();
|
|
VerifyOrQuit(browseCallback != nullptr);
|
|
|
|
VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(browseCallback->mIsSubType);
|
|
VerifyOrQuit(browseCallback->mSubTypeLabel.Matches("_xyzw"));
|
|
VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1"));
|
|
VerifyOrQuit(browseCallback->mTtl == 1500);
|
|
VerifyOrQuit(browseCallback->GetNext() == nullptr);
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start SRV and TXT resolvers for `srv2._tst._tcp` service and validate callback result");
|
|
|
|
srvResolver.mServiceInstance = "srv2";
|
|
srvResolver.mServiceType = "_tst._tcp";
|
|
srvResolver.mInfraIfIndex = kInfraIfIndex;
|
|
srvResolver.mCallback = HandleSrvResult;
|
|
|
|
txtResolver.mServiceInstance = "srv2";
|
|
txtResolver.mServiceType = "_tst._tcp";
|
|
txtResolver.mInfraIfIndex = kInfraIfIndex;
|
|
txtResolver.mCallback = HandleTxtResult;
|
|
|
|
sSrvCallbacks.Clear();
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
|
|
SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
|
|
|
|
AdvanceTime(350);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
|
|
VerifyOrQuit(srvCallback->mPort == 2222);
|
|
VerifyOrQuit(srvCallback->mPriority == 2);
|
|
VerifyOrQuit(srvCallback->mWeight == 2);
|
|
VerifyOrQuit(srvCallback->mTtl == 1500);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
|
|
VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
|
|
VerifyOrQuit(txtCallback->mTtl == 1500);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister `srv2._tst._tcp` and validate callback results");
|
|
|
|
sSrvCallbacks.Clear();
|
|
sTxtCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->UnregisterService(service2));
|
|
|
|
AdvanceTime(350);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
|
|
VerifyOrQuit(srvCallback->mTtl == 0);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
VerifyOrQuit(!sTxtCallbacks.IsEmpty());
|
|
txtCallback = sTxtCallbacks.GetHead();
|
|
VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
|
|
VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
|
|
VerifyOrQuit(txtCallback->mTtl == 0);
|
|
VerifyOrQuit(txtCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start an SRV resolver for `srv3._srv._udp` service and validate callback result");
|
|
|
|
srvResolver.mServiceInstance = "srv3";
|
|
srvResolver.mServiceType = "_srv._udp";
|
|
srvResolver.mInfraIfIndex = kInfraIfIndex;
|
|
srvResolver.mCallback = HandleSrvResult;
|
|
|
|
sSrvCallbacks.Clear();
|
|
|
|
SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
|
|
|
|
AdvanceTime(350);
|
|
|
|
VerifyOrQuit(!sSrvCallbacks.IsEmpty());
|
|
srvCallback = sSrvCallbacks.GetHead();
|
|
VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv3"));
|
|
VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
|
|
VerifyOrQuit(srvCallback->mHostName.Matches("host2"));
|
|
VerifyOrQuit(srvCallback->mPort == 3333);
|
|
VerifyOrQuit(srvCallback->mPriority == 3);
|
|
VerifyOrQuit(srvCallback->mWeight == 3);
|
|
VerifyOrQuit(srvCallback->mTtl == 1500);
|
|
VerifyOrQuit(srvCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Start an address resolver for host2 and validate result is immediately reported from cache");
|
|
|
|
addrResolver.mHostName = "host2";
|
|
addrResolver.mInfraIfIndex = kInfraIfIndex;
|
|
addrResolver.mCallback = HandleAddrResult;
|
|
|
|
sAddrCallbacks.Clear();
|
|
SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!sAddrCallbacks.IsEmpty());
|
|
addrCallback = sAddrCallbacks.GetHead();
|
|
VerifyOrQuit(addrCallback->mHostName.Matches("host2"));
|
|
VerifyOrQuit(addrCallback->Matches(host2AddrTtls, 2));
|
|
VerifyOrQuit(addrCallback->GetNext() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
void TestLegacyUnicastResponse(void)
|
|
{
|
|
Core *mdns = InitTest();
|
|
Core::Host host;
|
|
Core::Service service;
|
|
const DnsMessage *dnsMsg;
|
|
uint16_t heapAllocations;
|
|
DnsNameString fullServiceName;
|
|
DnsNameString fullServiceType;
|
|
DnsNameString hostFullName;
|
|
Ip6::Address hostAddresses[2];
|
|
|
|
Log("-------------------------------------------------------------------------------------------");
|
|
Log("TestLegacyUnicastResponse");
|
|
|
|
AdvanceTime(1);
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
|
|
|
SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
|
|
SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
|
|
host.mHostName = "host";
|
|
host.mAddresses = hostAddresses;
|
|
host.mAddressesLength = 2;
|
|
host.mTtl = 1500;
|
|
hostFullName.Append("%s.local.", host.mHostName);
|
|
|
|
service.mHostName = host.mHostName;
|
|
service.mServiceInstance = "myservice";
|
|
service.mServiceType = "_srv._udp";
|
|
service.mSubTypeLabels = nullptr;
|
|
service.mSubTypeLabelsLength = 0;
|
|
service.mTxtData = kTxtData1;
|
|
service.mTxtDataLength = sizeof(kTxtData1);
|
|
service.mPort = 1234;
|
|
service.mPriority = 1;
|
|
service.mWeight = 2;
|
|
service.mTtl = 1000;
|
|
|
|
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
|
|
fullServiceType.Append("%s.local.", service.mServiceType);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
for (RegCallback ®Callbck : sRegCallbacks)
|
|
{
|
|
regCallbck.Reset();
|
|
}
|
|
|
|
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query with two questions (SRV for service1 and AAAA for host). Validate that no response is sent");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQueryForTwo(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, hostFullName.AsCString(),
|
|
ResourceRecord::kTypeAaaa, /* aIsLegacyUnicast */ true);
|
|
|
|
AdvanceTime(200);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for SRV record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ false,
|
|
/* aLegacyUnicastQuery */ true);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 3);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
|
|
dnsMsg->Validate(host, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for TXT record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ false,
|
|
/* aLegacyUnicastQuery */ true);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for ANY record and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ false,
|
|
/* aLegacyUnicastQuery */ true);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 3);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for PTR record for service type and validate the response");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
|
|
/* aTruncated */ false,
|
|
/* aLegacyUnicastQuery */ true);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
|
|
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
|
|
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
|
|
dnsMsg->Validate(host, kInAdditionalSection);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Send a query for non-existing record and validate the response with NSEC");
|
|
|
|
AdvanceTime(2000);
|
|
|
|
sDnsMessages.Clear();
|
|
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA, ResourceRecord::kClassInternet, /* aTruncated */ false,
|
|
/* aLegacyUnicastQuery */ true);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
VerifyOrQuit(dnsMsg != nullptr);
|
|
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
|
|
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
|
|
AdvanceTime(15000);
|
|
|
|
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of test");
|
|
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
} // namespace Multicast
|
|
} // namespace Dns
|
|
} // namespace ot
|
|
|
|
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
|
|
|
int main(void)
|
|
{
|
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
|
ot::Dns::Multicast::TestHostReg();
|
|
ot::Dns::Multicast::TestLocalHost();
|
|
ot::Dns::Multicast::TestKeyReg();
|
|
ot::Dns::Multicast::TestServiceReg();
|
|
ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
|
|
ot::Dns::Multicast::TestServiceSubTypeReg();
|
|
ot::Dns::Multicast::TestHostOrServiceAndKeyReg();
|
|
ot::Dns::Multicast::TestQuery();
|
|
ot::Dns::Multicast::TestMultiPacket();
|
|
ot::Dns::Multicast::TestResponseAggregation();
|
|
ot::Dns::Multicast::TestQuestionUnicastDisallowed();
|
|
ot::Dns::Multicast::TestTxMessageSizeLimit();
|
|
ot::Dns::Multicast::TestHostConflict();
|
|
ot::Dns::Multicast::TestServiceConflict();
|
|
|
|
ot::Dns::Multicast::TestBrowser();
|
|
ot::Dns::Multicast::TestSrvResolver();
|
|
ot::Dns::Multicast::TestTxtResolver();
|
|
ot::Dns::Multicast::TestIp6AddrResolver();
|
|
ot::Dns::Multicast::TestRecordQuerier();
|
|
ot::Dns::Multicast::TestRecordQuerierForAny();
|
|
ot::Dns::Multicast::TestPassiveCache();
|
|
ot::Dns::Multicast::TestLegacyUnicastResponse();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("mDNS feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|