/* * Copyright (c) 2023, 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 #include "test_platform.h" #include "test_util.hpp" #include #include #include #include #include "common/arg_macros.hpp" #include "common/array.hpp" #include "common/string.hpp" #include "common/time.hpp" #include "instance/instance.hpp" #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && \ OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE && !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && \ !OPENTHREAD_PLATFORM_POSIX && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION #define ENABLE_ADV_PROXY_TEST 1 #else #define ENABLE_ADV_PROXY_TEST 0 #endif #if ENABLE_ADV_PROXY_TEST using namespace ot; // Logs a message and adds current time (sNow) as "::." #define Log(...) \ printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \ (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__)) static constexpr uint16_t kMaxRaSize = 800; static ot::Instance *sInstance; static uint32_t sNow = 0; static uint32_t sAlarmTime; static bool sAlarmOn = false; static otRadioFrame sRadioTxFrame; static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE]; static bool sRadioTxOngoing = false; //---------------------------------------------------------------------------------------------------------------------- // Function prototypes void ProcessRadioTxAndTasklets(void); void AdvanceTime(uint32_t aDuration); //---------------------------------------------------------------------------------------------------------------------- // `otPlatRadio` extern "C" { otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; } otError otPlatRadioTransmit(otInstance *, otRadioFrame *) { sRadioTxOngoing = true; return OT_ERROR_NONE; } otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; } //---------------------------------------------------------------------------------------------------------------------- // `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; } //---------------------------------------------------------------------------------------------------------------------- // `otPlatDnssd` static constexpr uint16_t kDnssdArraySize = 128; struct DnssdRequest { DnssdRequest(void) = default; DnssdRequest(otPlatDnssdRequestId aId, otPlatDnssdRegisterCallback aCallback) : mId(aId) , mCallback(aCallback) { } otPlatDnssdRequestId mId; otPlatDnssdRegisterCallback mCallback; }; static Array sDnssdRegHostRequests; static Array sDnssdUnregHostRequests; static Array sDnssdRegServiceRequests; static Array sDnssdUnregServiceRequests; static Array sDnssdRegKeyRequests; static Array sDnssdUnregKeyRequests; static bool sDnssdShouldCheckWithClient = true; static Error sDnssdCallbackError = kErrorPending; static otPlatDnssdState sDnssdState = OT_PLAT_DNSSD_READY; static uint16_t sDnssdNumHostAddresses = 0; constexpr uint32_t kInfraIfIndex = 1; otPlatDnssdState otPlatDnssdGetState(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); return sDnssdState; } void otPlatDnssdRegisterService(otInstance *aInstance, const otPlatDnssdService *aService, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdRegisterService(aRequestId: %lu)", ToUlong(aRequestId)); Log(" hostName : %s", aService->mHostName); Log(" serviceInstance: %s", aService->mServiceInstance); Log(" serviceType : %s", aService->mServiceType); Log(" num sub-types : %u", aService->mSubTypeLabelsLength); for (uint16_t index = 0; index < aService->mSubTypeLabelsLength; index++) { Log(" sub-type %-4u : %s", index, aService->mSubTypeLabels[index]); } Log(" TXT data len : %u", aService->mTxtDataLength); Log(" port : %u", aService->mPort); Log(" priority : %u", aService->mPriority); Log(" weight : %u", aService->mWeight); Log(" TTL : %u", aService->mTtl); Log(" Infra-if index : %u", aService->mInfraIfIndex); VerifyOrQuit(aInstance == sInstance); VerifyOrQuit(aService->mInfraIfIndex == kInfraIfIndex); if (sDnssdShouldCheckWithClient) { Srp::Client &srpClient = AsCoreType(aInstance).Get(); bool didFind = false; VerifyOrQuit(StringMatch(srpClient.GetHostInfo().GetName(), aService->mHostName)); didFind = false; for (const Srp::Client::Service &service : srpClient.GetServices()) { if (StringMatch(service.GetInstanceName(), aService->mServiceInstance)) { didFind = true; VerifyOrQuit(StringMatch(service.GetName(), aService->mServiceType)); VerifyOrQuit(service.GetPort() == aService->mPort); VerifyOrQuit(service.GetWeight() == aService->mWeight); VerifyOrQuit(service.GetPriority() == aService->mPriority); VerifyOrQuit(service.HasSubType() == (aService->mSubTypeLabelsLength != 0)); } } VerifyOrQuit(didFind); } SuccessOrQuit(sDnssdRegServiceRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } void otPlatDnssdUnregisterService(otInstance *aInstance, const otPlatDnssdService *aService, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdUnregisterService(aRequestId: %lu)", ToUlong(aRequestId)); Log(" hostName : %s", aService->mHostName); Log(" serviceInstance: %s", aService->mServiceInstance); Log(" serviceName : %s", aService->mServiceType); Log(" Infra-if index : %u", aService->mInfraIfIndex); VerifyOrQuit(aInstance == sInstance); VerifyOrQuit(aService->mInfraIfIndex == kInfraIfIndex); if (sDnssdShouldCheckWithClient) { // Validate the received service info matches one of the services // on SRP client. Srp::Client &srpClient = AsCoreType(aInstance).Get(); bool didFind = false; VerifyOrQuit(StringMatch(srpClient.GetHostInfo().GetName(), aService->mHostName)); for (const Srp::Client::Service &service : srpClient.GetServices()) { if (StringMatch(service.GetInstanceName(), aService->mServiceInstance)) { didFind = true; VerifyOrQuit(StringMatch(service.GetName(), aService->mServiceType)); } } VerifyOrQuit(didFind); } SuccessOrQuit(sDnssdUnregServiceRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } void otPlatDnssdRegisterHost(otInstance *aInstance, const otPlatDnssdHost *aHost, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdRegisterHost(aRequestId: %lu)", ToUlong(aRequestId)); Log(" hostName : %s", aHost->mHostName); Log(" numAddresses : %u", aHost->mAddressesLength); for (uint16_t index = 0; index < aHost->mAddressesLength; index++) { Log(" Address %-4u : %s", index, AsCoreType(&aHost->mAddresses[index]).ToString().AsCString()); } Log(" TTL : %u", aHost->mTtl); Log(" Infra-if index : %u", aHost->mInfraIfIndex); VerifyOrQuit(aInstance == sInstance); VerifyOrQuit(aHost->mInfraIfIndex == kInfraIfIndex); sDnssdNumHostAddresses = aHost->mAddressesLength; if (sDnssdShouldCheckWithClient) { VerifyOrQuit(StringMatch(AsCoreType(aInstance).Get().GetHostInfo().GetName(), aHost->mHostName)); } SuccessOrQuit(sDnssdRegHostRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } void otPlatDnssdUnregisterHost(otInstance *aInstance, const otPlatDnssdHost *aHost, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdUnregisterHost(aRequestId: %lu)", ToUlong(aRequestId)); Log(" hostName : %s", aHost->mHostName); Log(" Infra-if index : %u", aHost->mInfraIfIndex); VerifyOrQuit(sInstance == aInstance); VerifyOrQuit(aHost->mInfraIfIndex == kInfraIfIndex); if (sDnssdShouldCheckWithClient) { VerifyOrQuit(StringMatch(AsCoreType(aInstance).Get().GetHostInfo().GetName(), aHost->mHostName)); } SuccessOrQuit(sDnssdUnregHostRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } void otPlatDnssdRegisterKey(otInstance *aInstance, const otPlatDnssdKey *aKey, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdRegisterKey(aRequestId: %lu)", ToUlong(aRequestId)); Log(" name : %s", aKey->mName); Log(" serviceType : %s", aKey->mServiceType == nullptr ? "(null)" : aKey->mServiceType); Log(" key data-len : %u", aKey->mKeyDataLength); Log(" TTL : %u", aKey->mTtl); VerifyOrQuit(aInstance == sInstance); VerifyOrQuit(aKey->mInfraIfIndex == kInfraIfIndex); if (sDnssdShouldCheckWithClient) { if (aKey->mServiceType == nullptr) { VerifyOrQuit(StringMatch(AsCoreType(aInstance).Get().GetHostInfo().GetName(), aKey->mName)); } else { bool didFind = false; for (const Srp::Client::Service &service : AsCoreType(aInstance).Get().GetServices()) { if (StringMatch(service.GetInstanceName(), aKey->mName)) { didFind = true; VerifyOrQuit(StringMatch(service.GetName(), aKey->mServiceType)); } } VerifyOrQuit(didFind); } } SuccessOrQuit(sDnssdRegKeyRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } void otPlatDnssdUnregisterKey(otInstance *aInstance, const otPlatDnssdKey *aKey, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback) { Log("otPlatDnssdUnregisterKey(aRequestId: %lu)", ToUlong(aRequestId)); Log(" name : %s", aKey->mName); VerifyOrQuit(aInstance == sInstance); VerifyOrQuit(aKey->mInfraIfIndex == kInfraIfIndex); if (sDnssdShouldCheckWithClient) { if (aKey->mServiceType == nullptr) { VerifyOrQuit(StringMatch(AsCoreType(aInstance).Get().GetHostInfo().GetName(), aKey->mName)); } else { bool didFind = false; for (const Srp::Client::Service &service : AsCoreType(aInstance).Get().GetServices()) { if (StringMatch(service.GetInstanceName(), aKey->mName)) { didFind = true; VerifyOrQuit(StringMatch(service.GetName(), aKey->mServiceType)); } } VerifyOrQuit(didFind); } } SuccessOrQuit(sDnssdUnregKeyRequests.PushBack(DnssdRequest(aRequestId, aCallback))); if ((sDnssdCallbackError != kErrorPending) && (aCallback != nullptr)) { aCallback(aInstance, aRequestId, sDnssdCallbackError); } } // Number of times we expect each `otPlatDnssd` request to be called struct DnssdRequestCounts : public Clearable { DnssdRequestCounts(void) { Clear(); } uint16_t mKeyReg; uint16_t mHostReg; uint16_t mServiceReg; uint16_t mKeyUnreg; uint16_t mHostUnreg; uint16_t mServiceUnreg; }; void VerifyDnnsdRequests(const DnssdRequestCounts &aRequestCounts, bool aAllowMoreUnregs = false) { VerifyOrQuit(sDnssdRegKeyRequests.GetLength() == aRequestCounts.mKeyReg); VerifyOrQuit(sDnssdRegHostRequests.GetLength() == aRequestCounts.mHostReg); VerifyOrQuit(sDnssdRegServiceRequests.GetLength() == aRequestCounts.mServiceReg); if (aAllowMoreUnregs) { VerifyOrQuit(sDnssdUnregKeyRequests.GetLength() >= aRequestCounts.mKeyUnreg); VerifyOrQuit(sDnssdUnregHostRequests.GetLength() >= aRequestCounts.mHostUnreg); VerifyOrQuit(sDnssdUnregServiceRequests.GetLength() >= aRequestCounts.mServiceUnreg); } else { VerifyOrQuit(sDnssdUnregKeyRequests.GetLength() == aRequestCounts.mKeyUnreg); VerifyOrQuit(sDnssdUnregHostRequests.GetLength() == aRequestCounts.mHostUnreg); VerifyOrQuit(sDnssdUnregServiceRequests.GetLength() == aRequestCounts.mServiceUnreg); } } //---------------------------------------------------------------------------------------------------------------------- Array 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 #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); va_list args; printf(" "); va_start(args, aFormat); vprintf(aFormat, args); va_end(args); printf("\n"); } #endif } // extern "C" //--------------------------------------------------------------------------------------------------------------------- void ProcessRadioTxAndTasklets(void) { do { if (sRadioTxOngoing) { sRadioTxOngoing = false; otPlatRadioTxStarted(sInstance, &sRadioTxFrame); otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE); } otTaskletsProcess(sInstance); } while (otTaskletsArePending(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)) { ProcessRadioTxAndTasklets(); sNow = sAlarmTime; otPlatAlarmMilliFired(sInstance); } ProcessRadioTxAndTasklets(); sNow = time; } void InitTest(void) { //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Initialize OT instance. sNow = 0; sAlarmOn = false; sInstance = static_cast(testInitInstance()); memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame)); sRadioTxFrame.mPsdu = sRadioTxFramePsdu; sRadioTxOngoing = false; sDnssdShouldCheckWithClient = true; sDnssdState = OT_PLAT_DNSSD_READY; sDnssdCallbackError = kErrorPending; sDnssdRegHostRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregServiceRequests.Clear(); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Initialize Border Router and start Thread operation. otOperationalDataset dataset; otOperationalDatasetTlvs datasetTlvs; SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset)); otDatasetConvertToTlvs(&dataset, &datasetTlvs); SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs)); SuccessOrQuit(otIp6SetEnabled(sInstance, true)); SuccessOrQuit(otThreadSetEnabled(sInstance, true)); // Configure the `Dnssd` module to use `otPlatDnssd` APIs. sInstance->Get().SetUseNativeMdns(false); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Ensure device starts as leader. AdvanceTime(10000); VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER); } void FinalizeTest(void) { SuccessOrQuit(otIp6SetEnabled(sInstance, false)); SuccessOrQuit(otThreadSetEnabled(sInstance, false)); SuccessOrQuit(otInstanceErasePersistentInfo(sInstance)); testFreeInstance(sInstance); } //--------------------------------------------------------------------------------------------------------------------- // SRP Client callback static bool sProcessedClientCallback = false; static Error sLastClientCallbackError = kErrorNone; void HandleSrpClientCallback(otError aError, const otSrpClientHostInfo *aHostInfo, const otSrpClientService *aServices, const otSrpClientService *aRemovedServices, void *aContext) { Log("HandleSrpClientCallback() called with error %s", ErrorToString(aError)); VerifyOrQuit(aContext == sInstance); sProcessedClientCallback = true; sLastClientCallbackError = aError; OT_UNUSED_VARIABLE(aHostInfo); OT_UNUSED_VARIABLE(aServices); OT_UNUSED_VARIABLE(aRemovedServices); } static const char kHostName[] = "awesomehost"; void PrepareService1(Srp::Client::Service &aService) { static const char kServiceName[] = "_srv1._udp"; static const char kInstanceLabel[] = "service1"; static const char kSub1[] = "_sub1"; static const char kSub2[] = "_sub2"; static const char kSub3[] = "_sub3"; static const char *kSubLabels[] = {kSub1, kSub2, kSub3, nullptr}; static const char kTxtKey1[] = "ABCD"; static const uint8_t kTxtValue1[] = {'a', '0'}; static const char kTxtKey2[] = "Z0"; static const uint8_t kTxtValue2[] = {'1', '2', '3'}; static const char kTxtKey3[] = "D"; static const uint8_t kTxtValue3[] = {0}; static const otDnsTxtEntry kTxtEntries[] = { {kTxtKey1, kTxtValue1, sizeof(kTxtValue1)}, {kTxtKey2, kTxtValue2, sizeof(kTxtValue2)}, {kTxtKey3, kTxtValue3, sizeof(kTxtValue3)}, }; memset(&aService, 0, sizeof(aService)); aService.mName = kServiceName; aService.mInstanceName = kInstanceLabel; aService.mSubTypeLabels = kSubLabels; aService.mTxtEntries = kTxtEntries; aService.mNumTxtEntries = 3; aService.mPort = 777; aService.mWeight = 1; aService.mPriority = 2; } void PrepareService2(Srp::Client::Service &aService) { static const char kService2Name[] = "_matter._udp"; static const char kInstance2Label[] = "service2"; static const char kSub4[] = "_44444444"; static const char *kSubLabels2[] = {kSub4, nullptr}; memset(&aService, 0, sizeof(aService)); aService.mName = kService2Name; aService.mInstanceName = kInstance2Label; aService.mSubTypeLabels = kSubLabels2; aService.mTxtEntries = nullptr; aService.mNumTxtEntries = 0; aService.mPort = 555; aService.mWeight = 0; aService.mPriority = 3; } //---------------------------------------------------------------------------------------------------------------------- typedef Dnssd::RequestId RequestId; typedef Dnssd::RequestIdRange RequestIdRange; void ValidateRequestIdRange(const RequestIdRange &aIdRange, RequestId aStart, RequestId aEnd) { RequestId maxId = NumericLimits::kMax; bool shouldContain = false; VerifyOrQuit(!aIdRange.IsEmpty()); for (RequestId id = aStart - 5; id != aEnd + 6; id++) { // `idRange` should contain IDs within range `[aStart, aEnd]` if (id == aStart) { shouldContain = true; } if (id == aEnd + 1) { shouldContain = false; } VerifyOrQuit(aIdRange.Contains(id) == shouldContain); } // Test values that half the range apart for (RequestId id = aStart + maxId / 2 - 10; id != aEnd + maxId / 2 + 10; id++) { VerifyOrQuit(!aIdRange.Contains(id)); } } void TestDnssdRequestIdRange(void) { RequestId maxId = NumericLimits::kMax; RequestIdRange idRange; Log("--------------------------------------------------------------------------------------------"); Log("TestDnssdRequestIdRange"); VerifyOrQuit(idRange.IsEmpty()); idRange.Add(5); ValidateRequestIdRange(idRange, 5, 5); idRange.Remove(4); ValidateRequestIdRange(idRange, 5, 5); idRange.Remove(6); ValidateRequestIdRange(idRange, 5, 5); idRange.Remove(5); VerifyOrQuit(idRange.IsEmpty()); VerifyOrQuit(!idRange.Contains(5)); // Adding and removing multiple IDs idRange.Add(10); idRange.Add(15); ValidateRequestIdRange(idRange, 10, 15); idRange.Add(12); ValidateRequestIdRange(idRange, 10, 15); idRange.Add(15); ValidateRequestIdRange(idRange, 10, 15); idRange.Add(10); ValidateRequestIdRange(idRange, 10, 15); idRange.Add(9); ValidateRequestIdRange(idRange, 9, 15); idRange.Add(16); ValidateRequestIdRange(idRange, 9, 16); idRange.Remove(10); ValidateRequestIdRange(idRange, 9, 16); idRange.Remove(15); ValidateRequestIdRange(idRange, 9, 16); idRange.Remove(8); ValidateRequestIdRange(idRange, 9, 16); idRange.Remove(17); ValidateRequestIdRange(idRange, 9, 16); idRange.Remove(9); ValidateRequestIdRange(idRange, 10, 16); idRange.Remove(16); ValidateRequestIdRange(idRange, 10, 15); idRange.Clear(); VerifyOrQuit(idRange.IsEmpty()); VerifyOrQuit(!idRange.Contains(10)); // Ranges close to roll-over max value idRange.Add(maxId); ValidateRequestIdRange(idRange, maxId, maxId); idRange.Remove(0); ValidateRequestIdRange(idRange, maxId, maxId); idRange.Remove(maxId - 1); ValidateRequestIdRange(idRange, maxId, maxId); idRange.Add(0); ValidateRequestIdRange(idRange, maxId, 0); idRange.Add(maxId - 2); ValidateRequestIdRange(idRange, maxId - 2, 0); idRange.Add(3); ValidateRequestIdRange(idRange, maxId - 2, 3); idRange.Add(3); ValidateRequestIdRange(idRange, maxId - 2, 3); idRange.Remove(4); ValidateRequestIdRange(idRange, maxId - 2, 3); idRange.Remove(maxId - 3); ValidateRequestIdRange(idRange, maxId - 2, 3); idRange.Remove(3); ValidateRequestIdRange(idRange, maxId - 2, 2); idRange.Remove(maxId - 2); ValidateRequestIdRange(idRange, maxId - 1, 2); Log("End of TestDnssdRequestIdRange"); } void TestSrpAdvProxy(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxy"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorNone; // Invoke callback directly from dnssd APIs Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->SetLeaseInterval(180); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a service"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); dnssdCounts.mKeyReg += 2; dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a second service"); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // This time we should only see the new service and its key being // registered as the host is same as before and already registered dnssdCounts.mKeyReg++; dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Wait for longer than lease interval for client to refresh"); sProcessedClientCallback = false; AdvanceTime(181 * 1000); VerifyOrQuit(sProcessedClientCallback); // Validate that adv-proxy does not update any of registration on // DNS-SD platform since there is no change. VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal >= 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == advProxy->GetCounters().mAdvTotal); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add a new on-mesh prefix so to get a new host address"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:abba::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); sProcessedClientCallback = false; AdvanceTime(15 * 1000); // This time we should only see new host registration // since that's the only thing that changes dnssdCounts.mHostReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove the first service on client"); SuccessOrQuit(srpClient->RemoveService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // We should see the service being unregistered // by advertising proxy on DNS-SD platform but its key // remains registered. dnssdCounts.mServiceUnreg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); // Wait for more than lease interval again and make sure // there is no change in DNS-SD platform API calls. sProcessedClientCallback = false; AdvanceTime(181 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Change service 2 on client, remove its sub-type"); SuccessOrQuit(srpClient->ClearService(service2)); PrepareService2(service2); service2.mSubTypeLabels = nullptr; SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // Since the service is now changed, advertising proxy // should update it (re-register it) on DNS-SD APIs. dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove the host on client"); SuccessOrQuit(srpClient->RemoveHostAndServices(/* aShouldRemoveKeyLease */ false)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // We should see the host and service being unregistered // on DNS-SD APIs but keys remain unchanged. dnssdCounts.mHostUnreg++; dnssdCounts.mServiceUnreg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); VerifyOrQuit(service2.GetState() == Srp::Client::kRemoved); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove the host on client again and force an update to be sent to server"); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->RemoveHostAndServices(/* aShouldRemoveKeyLease */ false, /* aSendUnregToServer */ true)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // We should see no changes (no calls) to DNS-SD APIs. VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Re-add service 1 on client and register with server"); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); PrepareService1(service1); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); // We should see one host register and one service register // on DNS-SD APIs. Keys are already registered. dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); // Wait for more than lease interval again and make sure // there is no change in DNS-SD platform API calls. sProcessedClientCallback = false; AdvanceTime(181 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP client and wait for lease time to expire"); srpClient->ClearHostAndServices(); // does not signal removal to server // Since we clear everything on SRP client, we disable // matching the services with client from `otPlatDnssd` // APIs. sDnssdShouldCheckWithClient = false; AdvanceTime(181 * 1000); // Make sure host and service are unregistered. dnssdCounts.mHostUnreg++; dnssdCounts.mServiceUnreg++; VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(!advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == advProxy->GetCounters().mAdvTotal); VerifyOrQuit(advProxy->GetCounters().mAdvTimeout == 0); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 0); VerifyOrQuit(advProxy->GetCounters().mAdvSkipped == 0); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); dnssdCounts.mKeyUnreg += 3; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxy"); } void TestSrpAdvProxyDnssdStateChange(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyDnssdStateChange"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_STOPPED; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorNone; // Invoke callback directly VerifyOrQuit(!advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(!advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->SetLeaseInterval(180); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a services"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a second service"); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); // None of the DNS-SD APIs should be called since its state // `OT_PLAT_DNSSD_STOPPED` (`dnssdCounts` is all zeros). VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Update DNS-SD state and signal that state is changed"); sDnssdState = OT_PLAT_DNSSD_READY; otPlatDnssdStateHandleStateChange(sInstance); AdvanceTime(5); VerifyOrQuit(advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 1); // Now the host and two services should be registered on // DNS-SD platform dnssdCounts.mHostReg++; dnssdCounts.mServiceReg += 2; dnssdCounts.mKeyReg += 3; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Wait for longer than lease interval for client to refresh"); sProcessedClientCallback = false; AdvanceTime(181 * 1000); VerifyOrQuit(sProcessedClientCallback); // Validate that adv-proxy does not update any of registration on // DNS-SD platform since there is no change. VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Update DNS-SD state to `STOPPED` and signal its change"); sDnssdState = OT_PLAT_DNSSD_STOPPED; otPlatDnssdStateHandleStateChange(sInstance); AdvanceTime(5); VerifyOrQuit(!advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 2); // Since DNS-SD platform signal that it is stopped, // there should be no calls to any of APIs. VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Wait for longer than lease interval for client to refresh"); sProcessedClientCallback = false; AdvanceTime(181 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); // The DNS-SD API counters should remain unchanged VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Update DNS-SD state to `READY` and signal its change"); sDnssdState = OT_PLAT_DNSSD_READY; otPlatDnssdStateHandleStateChange(sInstance); AdvanceTime(5); VerifyOrQuit(advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 3); // Check that the host and two services are again registered // on DNS-SD platform by advertising proxy. dnssdCounts.mHostReg++; dnssdCounts.mServiceReg += 2; dnssdCounts.mKeyReg += 3; VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Update DNS-SD state to `STOPPED` and signal its change"); sDnssdState = OT_PLAT_DNSSD_STOPPED; otPlatDnssdStateHandleStateChange(sInstance); AdvanceTime(5); VerifyOrQuit(!advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 4); // Since DNS-SD platform signal that it is stopped, // there should be no calls to any of APIs. VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove the first service on client"); SuccessOrQuit(srpClient->RemoveService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); // No changes to DNS-SD API counters (since it is stopped) VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Update DNS-SD state to `READY` and signal its change #2"); // Since the already removed `service1` is no longer available // on SRP client, we disable checking the services with client // from `otPlatDnssd` APIs. sDnssdShouldCheckWithClient = false; sDnssdState = OT_PLAT_DNSSD_READY; otPlatDnssdStateHandleStateChange(sInstance); AdvanceTime(5); VerifyOrQuit(advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 5); // We should see the host and `service2` registered again. // And all 3 keys (even for removed `service1`) to be // registered. dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 3; VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(!advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mStateChanges == 6); VerifyOrQuit(advProxy->GetCounters().mAdvSkipped > 0); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == (advProxy->GetCounters().mAdvSuccessful + advProxy->GetCounters().mAdvSkipped)); VerifyOrQuit(advProxy->GetCounters().mAdvTimeout == 0); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 0); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); dnssdCounts.mHostUnreg++; dnssdCounts.mServiceUnreg++; dnssdCounts.mKeyUnreg += 3; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyDnssdStateChange"); } void TestSrpAdvProxyDelayedCallback(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; const DnssdRequest *request; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyDelayedCallback"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorPending; // Do not call the callbacks directly Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->SetLeaseInterval(180); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a service, invoke the registration callback after some delay"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(1000); dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 2; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(!sProcessedClientCallback); VerifyOrQuit(srpServer->GetNextHost(nullptr) == nullptr); // Invoke the service and key callbacks first request = &sDnssdRegServiceRequests[0]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegKeyRequests[0]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegKeyRequests[1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(10); VerifyOrQuit(!sProcessedClientCallback); VerifyOrQuit(srpServer->GetNextHost(nullptr) == nullptr); // Invoke the host registration callback next request = &sDnssdRegHostRequests[0]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(10); VerifyOrQuit(srpServer->GetNextHost(nullptr) != nullptr); AdvanceTime(100); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a second service, invoke registration callback with `kErrorDuplicated`"); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1000); VerifyOrQuit(!sProcessedClientCallback); dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); // Invoke the service callback with kErrorDuplicated request = &sDnssdRegServiceRequests[1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorDuplicated); AdvanceTime(100); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorDuplicated); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Try registering service again from client, invoke callback with success"); SuccessOrQuit(srpClient->ClearService(service2)); PrepareService2(service2); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1000); VerifyOrQuit(!sProcessedClientCallback); // We should see a new service registration request. dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 1); // Invoked the service and key callback with success. request = &sDnssdRegKeyRequests[sDnssdRegKeyRequests.GetLength() - 1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegServiceRequests[sDnssdRegServiceRequests.GetLength() - 1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Change the service and register again, but ignore the registration callback"); SuccessOrQuit(srpClient->ClearService(service2)); PrepareService2(service2); service2.mSubTypeLabels = nullptr; SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1000); VerifyOrQuit(!sProcessedClientCallback); // We should see a new service registration request. dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); // Wait for advertising proxy timeout (there will be no callback from // platform) so validate that registration failure is reported to // the SRP client. AdvanceTime(2 * 1000); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError != kErrorNone); VerifyOrQuit(advProxy->GetCounters().mAdvTimeout == 1); // Wait for longer than client retry time. AdvanceTime(3 * 1000); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); // Make sure the host and two services are unregistered // (even though the second service was not successfully // registered yet). VerifyOrQuit(sDnssdRegHostRequests.GetLength() == 1); VerifyOrQuit(sDnssdRegServiceRequests.GetLength() >= 4); VerifyOrQuit(sDnssdRegKeyRequests.GetLength() >= 3); VerifyOrQuit(sDnssdUnregHostRequests.GetLength() == 1); VerifyOrQuit(sDnssdUnregServiceRequests.GetLength() == 2); VerifyOrQuit(sDnssdUnregKeyRequests.GetLength() == 3); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyDelayedCallback"); } void TestSrpAdvProxyReplacedEntries(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; const DnssdRequest *request; uint16_t numServices; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyReplacedEntries"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorPending; // Do not call the callbacks directly Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Set AdvTimeout to 5 minutes on AdvProxy"); // Change the timeout on AvdertisingProxy to 5 minutes // so that we can send multiple SRP updates and create // situations where previous advertisement are replaced. advProxy->SetAdvTimeout(5 * 60 * 1000); VerifyOrQuit(advProxy->GetAdvTimeout() == 5 * 60 * 1000); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a service and do not invoke the registration request callbacks"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(1200); dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 2; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(!sProcessedClientCallback); VerifyOrQuit(srpServer->GetNextHost(nullptr) == nullptr); // SRP client min retry is 1800 msec, we wait for longer // to make sure client retries. AdvanceTime(2000); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); // We should see no new service or host registrations on // DNS-SD platform APIs as the requests should be same // and fully matching the outstanding ones. VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the DNS-SD API callbacks"); request = &sDnssdRegServiceRequests[0]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegHostRequests[0]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); for (uint16_t index = 0; index < 2; index++) { request = &sDnssdRegKeyRequests[index]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); } AdvanceTime(100); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(srpServer->GetNextHost(nullptr) != nullptr); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Check outstanding Adv being replaced"); // Change service 1 SuccessOrQuit(srpClient->ClearService(service1)); PrepareService1(service1); service1.mSubTypeLabels = nullptr; // No sub-types SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(1200); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); // We should see the changed service registered on DNS-SD // platform APIs. dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); // Change service 1 again (add sub-types back). SuccessOrQuit(srpClient->ClearService(service1)); PrepareService1(service1); SuccessOrQuit(srpClient->AddService(service1)); AdvanceTime(1200); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 4); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); // We should see the changed service registered on DNS-SD // platform APIs again. dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the replaced entry DNS-SD API callback"); request = &sDnssdRegServiceRequests[1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); // Since adv is replaced invoking the old registration callback // should not complete it. VerifyOrQuit(!sProcessedClientCallback); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 4); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the new entry DNS-SD API callback"); request = &sDnssdRegServiceRequests[2]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 4); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 4); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); // Make sure the service entry on the SRP server is the // last (most recent) request with three sub-types VerifyOrQuit(srpServer->GetNextHost(nullptr)->GetServices().GetHead() != nullptr); VerifyOrQuit(srpServer->GetNextHost(nullptr)->GetServices().GetHead()->GetNumberOfSubTypes() == 3); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Check replacing Adv being blocked till old Adv is completed"); // Change service 1 and add service 2 SuccessOrQuit(srpClient->ClearService(service1)); PrepareService1(service1); service1.mSubTypeLabels = nullptr; // No sub-types SuccessOrQuit(srpClient->AddService(service1)); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1200); // We should see a new Adv with two new service registrations // on DNS-SD APIs. VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 5); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 4); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); dnssdCounts.mServiceReg += 2; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); // Invoke the key registration callback request = &sDnssdRegKeyRequests[sDnssdRegKeyRequests.GetLength() - 1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); // Now have SRP client send a new SRP update message // just changing `service2`. We clear `servcie1` on client // so it is not included in new SRP update message. SuccessOrQuit(srpClient->ClearService(service1)); SuccessOrQuit(srpClient->ClearService(service2)); PrepareService2(service2); service2.mPort = 2222; // Use a different port number SuccessOrQuit(srpClient->AddService(service2)); AdvanceTime(1200); // We should see the new Adv (total increasing) and // also replacing the outstanding one VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 6); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 4); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 2); // We should see new registration for the changed `service2` dnssdCounts.mServiceReg++; VerifyDnnsdRequests(dnssdCounts); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the callback for new registration replacing old one first"); request = &sDnssdRegServiceRequests[5]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); // This should not change anything, since the new Avd should // be still blocked by the earlier Adv that it replaced. VerifyOrQuit(!sProcessedClientCallback); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 6); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 4); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the callback for replaced Adv services"); request = &sDnssdRegServiceRequests[4]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegServiceRequests[3]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); // This should trigger both Adv to complete. VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 6); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 6); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 2); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); // Make sure the `service2` entry on the SRP server is the // last (most recent) request with new port number. VerifyOrQuit(srpServer->GetNextHost(nullptr)->GetServices().GetHead() != nullptr); numServices = 0; for (const Srp::Server::Service &service : srpServer->GetNextHost(nullptr)->GetServices()) { numServices++; if (StringMatch(service.GetInstanceLabel(), service2.GetInstanceName(), kStringCaseInsensitiveMatch)) { VerifyOrQuit(service.GetPort() == service2.GetPort()); } else if (StringMatch(service.GetInstanceLabel(), service1.GetInstanceName(), kStringCaseInsensitiveMatch)) { // Service 1 was changed to have no sub-types VerifyOrQuit(service.GetPort() == service1.GetPort()); VerifyOrQuit(service.GetNumberOfSubTypes() == 0); } else { VerifyOrQuit(false); // Unexpected extra service on SRP server. } } VerifyOrQuit(numServices == 2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Check replacing Adv being blocked till old Adv is completed when removing services"); // Change and re-add both services so they are both // included in a new SRP update message from client. SuccessOrQuit(srpClient->ClearService(service2)); PrepareService1(service1); PrepareService2(service2); SuccessOrQuit(srpClient->AddService(service1)); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1200); // We should see a new Adv with two new service registrations // on DNS-SD APIs. VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 7); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 6); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 2); dnssdCounts.mServiceReg += 2; VerifyDnnsdRequests(dnssdCounts); // Now have SRP client send a new SRP update message // just removing `service1`. We clear `servcie2` on client // so it is not included in new SRP update message. SuccessOrQuit(srpClient->RemoveService(service1)); SuccessOrQuit(srpClient->ClearService(service2)); AdvanceTime(1200); // We should see a new Adv added replacing the outstanding // one. VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 8); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 6); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 3); dnssdCounts.mServiceUnreg++; VerifyDnnsdRequests(dnssdCounts); // Even though the new SRP update which removed `servcie2` // is already unregistered, it should be blocked by the // earlier Adv. VerifyOrQuit(!sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke the callback for replaced Adv services"); request = &sDnssdRegServiceRequests[6]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); request = &sDnssdRegServiceRequests[7]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(100); // This should trigger both Adv to complete, and first one // should be committed before the second one removing the // `service2`. VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 8); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 8); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 3); VerifyOrQuit(service1.GetState() == Srp::Client::kRemoved); // Check services on server and make sure `service2` // is marked as deleted. VerifyOrQuit(srpServer->GetNextHost(nullptr)->GetServices().GetHead() != nullptr); numServices = 0; for (const Srp::Server::Service &service : srpServer->GetNextHost(nullptr)->GetServices()) { numServices++; if (StringMatch(service.GetInstanceLabel(), service1.GetInstanceName(), kStringCaseInsensitiveMatch)) { VerifyOrQuit(service.IsDeleted()); } else if (StringMatch(service.GetInstanceLabel(), service2.GetInstanceName(), kStringCaseInsensitiveMatch)) { VerifyOrQuit(!service.IsDeleted()); } else { VerifyOrQuit(false); // Unexpected extra service on SRP server. } } VerifyOrQuit(numServices == 2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); sDnssdShouldCheckWithClient = false; // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyReplacedEntries"); } void TestSrpAdvProxyHostWithOffMeshRoutableAddress(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; const DnssdRequest *request; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyHostWithOffMeshRoutableAddress"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorNone; // Invoke callback directly from dnssd APIs Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->SetLeaseInterval(400); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a service"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 2; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sDnssdNumHostAddresses == 0); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register a second service"); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(2 * 1000); dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(!advProxy->IsRunning()); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == advProxy->GetCounters().mAdvTotal); VerifyOrQuit(advProxy->GetCounters().mAdvTimeout == 0); VerifyOrQuit(advProxy->GetCounters().mAdvRejected == 0); VerifyOrQuit(advProxy->GetCounters().mAdvSkipped == 0); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyHostWithOffMeshRoutableAddress"); } void TestSrpAdvProxyRemoveBeforeCommitted(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; const DnssdRequest *request; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyRemoveBeforeCommitted"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorNone; // Do not call the callbacks directly Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register host and one service"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2000); dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 2; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Set AdvTimeout to 5 minutes on AdvProxy"); // Change the timeout on AvdertisingProxy to 5 minutes // so that we can send multiple SRP updates and create // situations where previous advertisement are replaced. advProxy->SetAdvTimeout(5 * 60 * 1000); VerifyOrQuit(advProxy->GetAdvTimeout() == 5 * 60 * 1000); sDnssdCallbackError = kErrorPending; // Do not invoke callback Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove service1 while adding a new service2 and do not invoke callback from DNSSD plat"); SuccessOrQuit(srpClient->RemoveService(service1)); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1000); dnssdCounts.mServiceReg++; dnssdCounts.mServiceUnreg++; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(!sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove host and its services without removing key-lease"); SuccessOrQuit(srpClient->RemoveHostAndServices(/* aShouldRemoveKeyLease */ false)); AdvanceTime(1000); // Proxy will unregister both services again // (to be safe). dnssdCounts.mHostUnreg++; dnssdCounts.mServiceUnreg++; VerifyDnnsdRequests(dnssdCounts, /* aAllowMoreUnregs */ true); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); VerifyOrQuit(!sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Invoke callback for last key registration"); // This should be enough for all `AdvInfo` entries to be finished. request = &sDnssdRegKeyRequests[sDnssdRegKeyRequests.GetLength() - 1]; VerifyOrQuit(request->mCallback != nullptr); request->mCallback(sInstance, request->mId, kErrorNone); AdvanceTime(50); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 3); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); VerifyOrQuit(sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); sDnssdShouldCheckWithClient = false; // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyRemoveBeforeCommitted"); } void TestSrpAdvProxyFullyRemoveBeforeCommitted(void) { NetworkData::OnMeshPrefixConfig prefixConfig; Srp::Server *srpServer; Srp::Client *srpClient; Srp::AdvertisingProxy *advProxy; Srp::Client::Service service1; Srp::Client::Service service2; DnssdRequestCounts dnssdCounts; uint16_t heapAllocations; const DnssdRequest *request; Log("--------------------------------------------------------------------------------------------"); Log("TestSrpAdvProxyFullyRemoveBeforeCommitted"); InitTest(); srpServer = &sInstance->Get(); srpClient = &sInstance->Get(); advProxy = &sInstance->Get(); heapAllocations = sHeapAllocatedPtrs.GetLength(); PrepareService1(service1); PrepareService2(service2); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Add an on-mesh prefix (with SLAAC) to network data"); prefixConfig.Clear(); SuccessOrQuit(AsCoreType(&prefixConfig.mPrefix.mPrefix).FromString("fd00:cafe:beef::")); prefixConfig.mPrefix.mLength = 64; prefixConfig.mStable = true; prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); SuccessOrQuit(otBorderRouterRegister(sInstance)); // Configure Dnssd platform API behavior sDnssdRegHostRequests.Clear(); sDnssdRegServiceRequests.Clear(); sDnssdUnregHostRequests.Clear(); sDnssdUnregServiceRequests.Clear(); sDnssdRegKeyRequests.Clear(); sDnssdUnregKeyRequests.Clear(); sDnssdState = OT_PLAT_DNSSD_READY; sDnssdShouldCheckWithClient = true; sDnssdCallbackError = kErrorNone; // Do not call the callbacks directly Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP server"); SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicast); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); srpServer->SetServiceHandler(nullptr, sInstance); srpServer->SetEnabled(true); VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); AdvanceTime(10000); VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); VerifyOrQuit(advProxy->IsRunning()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Start SRP client"); srpClient->SetCallback(HandleSrpClientCallback, sInstance); srpClient->EnableAutoStartMode(nullptr, nullptr); VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); AdvanceTime(2000); VerifyOrQuit(srpClient->IsRunning()); SuccessOrQuit(srpClient->SetHostName(kHostName)); SuccessOrQuit(srpClient->EnableAutoHostAddress()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Register host and one service"); SuccessOrQuit(srpClient->AddService(service1)); sProcessedClientCallback = false; AdvanceTime(2000); dnssdCounts.mHostReg++; dnssdCounts.mServiceReg++; dnssdCounts.mKeyReg += 2; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 1); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(sProcessedClientCallback); VerifyOrQuit(sLastClientCallbackError == kErrorNone); VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Set AdvTimeout to 5 minutes on AdvProxy"); // Change the timeout on AvdertisingProxy to 5 minutes // so that we can send multiple SRP updates and create // situations where previous advertisement are replaced. advProxy->SetAdvTimeout(5 * 60 * 1000); VerifyOrQuit(advProxy->GetAdvTimeout() == 5 * 60 * 1000); sDnssdCallbackError = kErrorPending; // Do not invoke callback Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove service1 while adding a new service2 and do not invoke callback from DNSSD plat"); SuccessOrQuit(srpClient->RemoveService(service1)); SuccessOrQuit(srpClient->AddService(service2)); sProcessedClientCallback = false; AdvanceTime(1000); dnssdCounts.mServiceReg++; dnssdCounts.mServiceUnreg++; dnssdCounts.mKeyReg++; VerifyDnnsdRequests(dnssdCounts); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 2); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 1); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 0); VerifyOrQuit(!sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Remove host and its services and remove key-lease"); SuccessOrQuit(srpClient->RemoveHostAndServices(/* aShouldRemoveKeyLease */ true)); AdvanceTime(1000); // Proxy should unregister everything. // Keys may be unregistered multiple times. dnssdCounts.mHostUnreg++; dnssdCounts.mServiceUnreg++; dnssdCounts.mKeyUnreg += 3; VerifyDnnsdRequests(dnssdCounts, /* aAllowMoreUnregs */ true); VerifyOrQuit(advProxy->GetCounters().mAdvTotal == 3); VerifyOrQuit(advProxy->GetCounters().mAdvSuccessful == 3); VerifyOrQuit(advProxy->GetCounters().mAdvReplaced == 1); VerifyOrQuit(sProcessedClientCallback); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Disable SRP server"); sDnssdShouldCheckWithClient = false; // Verify that all heap allocations by SRP server // and Advertising Proxy are freed. srpServer->SetEnabled(false); AdvanceTime(100); VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Finalize OT instance and validate all heap allocations are freed"); FinalizeTest(); VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); Log("End of TestSrpAdvProxyFullyRemoveBeforeCommitted"); } #endif // ENABLE_ADV_PROXY_TEST int main(void) { #if ENABLE_ADV_PROXY_TEST TestDnssdRequestIdRange(); TestSrpAdvProxy(); TestSrpAdvProxyDnssdStateChange(); TestSrpAdvProxyDelayedCallback(); TestSrpAdvProxyReplacedEntries(); TestSrpAdvProxyHostWithOffMeshRoutableAddress(); TestSrpAdvProxyRemoveBeforeCommitted(); TestSrpAdvProxyFullyRemoveBeforeCommitted(); printf("All tests passed\n"); #else printf("SRP_ADV_PROXY feature is not enabled\n"); #endif return 0; }