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