blob: ffd954a841d8aca781e9859e414851562c5deb88 [file] [log] [blame]
/*
* 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 <openthread/config.h>
#include "test_platform.h"
#include "test_util.hpp"
#include <openthread/dataset_ftd.h>
#include <openthread/srp_client.h>
#include <openthread/srp_server.h>
#include <openthread/thread.h>
#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 "<hours>:<min>:<secs>.<msec>"
#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<DnssdRequest, kDnssdArraySize> sDnssdRegHostRequests;
static Array<DnssdRequest, kDnssdArraySize> sDnssdUnregHostRequests;
static Array<DnssdRequest, kDnssdArraySize> sDnssdRegServiceRequests;
static Array<DnssdRequest, kDnssdArraySize> sDnssdUnregServiceRequests;
static Array<DnssdRequest, kDnssdArraySize> sDnssdRegKeyRequests;
static Array<DnssdRequest, kDnssdArraySize> 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<Srp::Client>();
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<Srp::Client>();
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<Srp::Client>().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<Srp::Client>().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<Srp::Client>().GetHostInfo().GetName(), aKey->mName));
}
else
{
bool didFind = false;
for (const Srp::Client::Service &service : AsCoreType(aInstance).Get<Srp::Client>().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<Srp::Client>().GetHostInfo().GetName(), aKey->mName));
}
else
{
bool didFind = false;
for (const Srp::Client::Service &service : AsCoreType(aInstance).Get<Srp::Client>().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>
{
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<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
#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<Instance *>(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));
SuccessOrQuit(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<Dnssd>().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<RequestId>::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<RequestId>::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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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(5 * 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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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<Srp::Server>();
srpClient = &sInstance->Get<Srp::Client>();
advProxy = &sInstance->Get<Srp::AdvertisingProxy>();
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;
}