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