mirror of
https://github.com/espressif/openthread.git
synced 2026-07-10 22:30:21 +00:00
de746129e9
This commit implements response aggregation (RFC 6762 section 6.4) in the mDNS module. If multiple responses are scheduled to be sent, each delayed by a different interval, earlier responses are further delayed to allow aggregation with other responses scheduled to go out a little later. Before preparing a response, we determine the next multicast transmission time that is explicitly after the current time. This is used for response aggregation. As the response is being prepared, different entries can decide whether to extend their answer delay duration if allowed (e.g., probe question answer delay cannot be extended) and possible (not extending the delay beyond the maximum allowed delay). To realize this, the way we track the `AnswerTime` of records is changed. It is now tracked by two variables: `mQueryRxTime` (the receive time of the question triggering the answer) and `mAnswerDelay`. This commit also adds `TestResponseAggregation()` to the `test_mdns` unit test to validate the response aggregation behavior.
7299 lines
253 KiB
C++
7299 lines
253 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 kNumInitalQueries = 3;
|
|
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 (or 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::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 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);
|
|
|
|
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`
|
|
// 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);
|
|
|
|
enum GoodBye : bool // Used to indicate "goodbye" records (with zero TTL)
|
|
{
|
|
kNotGoodBye = false,
|
|
kGoodBye = true,
|
|
};
|
|
|
|
enum DnsMessageType : uint8_t
|
|
{
|
|
kMulticastQuery,
|
|
kMulticastResponse,
|
|
kUnicastResponse,
|
|
kLegacyUnicastResponse,
|
|
};
|
|
|
|
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 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 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));
|
|
}
|
|
};
|
|
|
|
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);
|
|
}
|
|
|
|
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 OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
|
|
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
|
|
{
|
|
OT_UNUSED_VARIABLE(aLogLevel);
|
|
OT_UNUSED_VARIABLE(aLogRegion);
|
|
OT_UNUSED_VARIABLE(aFormat);
|
|
|
|
#if ENABLE_TEST_LOG
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `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);
|
|
|
|
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 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 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 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 anwer 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(400);
|
|
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());
|
|
|
|
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 no probes are sent");
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sConflictCallback.Reset();
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->RegisterHost(host, 1, HandleCallback));
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
|
|
|
|
SuccessOrQuit(mdns->UnregisterHost(host));
|
|
|
|
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 no probes are sent");
|
|
|
|
sRegCallbacks[1].Reset();
|
|
sConflictCallback.Reset();
|
|
sDnsMessages.Clear();
|
|
|
|
SuccessOrQuit(mdns->RegisterService(service, 1, HandleCallback));
|
|
AdvanceTime(5000);
|
|
|
|
VerifyOrQuit(sRegCallbacks[1].mWasCalled);
|
|
VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
|
|
VerifyOrQuit(!sConflictCallback.mWasCalled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
|
|
|
|
SuccessOrQuit(mdns->UnregisterService(service));
|
|
|
|
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;
|
|
};
|
|
|
|
OwningList<BrowseCallback> sBrowseCallbacks;
|
|
OwningList<SrvCallback> sSrvCallbacks;
|
|
OwningList<TxtCallback> sTxtCallbacks;
|
|
OwningList<AddrCallback> sAddrCallbacks;
|
|
|
|
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 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 < kNumInitalQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
|
|
|
|
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.", 120, kInAnswerSection);
|
|
|
|
AdvanceTime(1);
|
|
|
|
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);
|
|
|
|
sBrowseCallbacks.Clear();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
|
Log("Validate initial esquires are still sent and include known-answer");
|
|
|
|
for (uint8_t queryCount = 1; queryCount < kNumInitalQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((1U << (queryCount - 1)) * 1000);
|
|
|
|
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 < kNumInitalQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
|
|
|
|
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(15 * 1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; 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 < kNumInitalQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
|
|
|
|
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(15 * 1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; 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 < kNumInitalQueries; queryCount++)
|
|
{
|
|
sDnsMessages.Clear();
|
|
|
|
AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
|
|
|
|
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(15 * 1000);
|
|
|
|
dnsMsg = sDnsMessages.GetHead();
|
|
|
|
for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; 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 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::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::TestPassiveCache();
|
|
ot::Dns::Multicast::TestLegacyUnicastResponse();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("mDNS feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|