| /* |
| * 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/dns_client.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_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE && \ |
| OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE && OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && \ |
| OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && \ |
| !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && !OPENTHREAD_PLATFORM_POSIX |
| #define ENABLE_DNS_TEST 1 |
| #else |
| #define ENABLE_DNS_TEST 0 |
| #endif |
| |
| #if ENABLE_DNS_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; } |
| |
| //---------------------------------------------------------------------------------------------------------------------- |
| // `otPlatAlaram` |
| |
| 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; } |
| |
| //---------------------------------------------------------------------------------------------------------------------- |
| |
| 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; |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // 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)); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // 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)); |
| // Make sure there is no message/buffer leak |
| VerifyOrQuit(sInstance->Get<MessagePool>().GetFreeBufferCount() == |
| sInstance->Get<MessagePool>().GetTotalBufferCount()); |
| SuccessOrQuit(otInstanceErasePersistentInfo(sInstance)); |
| testFreeInstance(sInstance); |
| } |
| |
| //--------------------------------------------------------------------------------------------------------------------- |
| |
| static const char kHostName[] = "elden"; |
| static const char kHostFullName[] = "elden.default.service.arpa."; |
| |
| static const char kService1Name[] = "_srv._udp"; |
| static const char kService1FullName[] = "_srv._udp.default.service.arpa."; |
| static const char kInstance1Label[] = "srv-instance"; |
| static const char kInstance1FullName[] = "srv-instance._srv._udp.default.service.arpa."; |
| |
| static const char kService2Name[] = "_game._udp"; |
| static const char kService2FullName[] = "_game._udp.default.service.arpa."; |
| static const char kService2SubTypeFullName[] = "_best._sub._game._udp.default.service.arpa."; |
| static const char kInstance2Label[] = "last-ninja"; |
| static const char kInstance2FullName[] = "last-ninja._game._udp.default.service.arpa."; |
| |
| void PrepareService1(Srp::Client::Service &aService) |
| { |
| static const char kSub1[] = "_sub1"; |
| static const char kSub2[] = "_V1234567"; |
| static const char kSub3[] = "_XYZWS"; |
| 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 = kService1Name; |
| aService.mInstanceName = kInstance1Label; |
| 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 kSub4[] = "_best"; |
| 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; |
| } |
| |
| void ValidateHost(Srp::Server &aServer, const char *aHostName) |
| { |
| // Validate that only a host with `aHostName` is |
| // registered on SRP server. |
| |
| const Srp::Server::Host *host; |
| const char *name; |
| |
| Log("ValidateHost()"); |
| |
| host = aServer.GetNextHost(nullptr); |
| VerifyOrQuit(host != nullptr); |
| |
| name = host->GetFullName(); |
| Log("Hostname: %s", name); |
| |
| VerifyOrQuit(StringStartsWith(name, aHostName, kStringCaseInsensitiveMatch)); |
| VerifyOrQuit(name[strlen(aHostName)] == '.'); |
| |
| // Only one host on server |
| VerifyOrQuit(aServer.GetNextHost(host) == nullptr); |
| } |
| |
| //--------------------------------------------------------------------------------------------------------------------- |
| |
| void LogServiceInfo(const Dns::Client::ServiceInfo &aInfo) |
| { |
| Log(" TTL: %u", aInfo.mTtl); |
| Log(" Port: %u", aInfo.mPort); |
| Log(" Weight: %u", aInfo.mWeight); |
| Log(" HostName: %s", aInfo.mHostNameBuffer); |
| Log(" HostAddr: %s", AsCoreType(&aInfo.mHostAddress).ToString().AsCString()); |
| Log(" TxtDataLength: %u", aInfo.mTxtDataSize); |
| Log(" TxtDataTTL: %u", aInfo.mTxtDataTtl); |
| } |
| |
| const char *ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode) |
| { |
| static const char *const kServiceModeStrings[] = { |
| "unspec", // kServiceModeUnspecified (0) |
| "srv", // kServiceModeSrv (1) |
| "txt", // kServiceModeTxt (2) |
| "srv_txt", // kServiceModeSrvTxt (3) |
| "srv_txt_sep", // kServiceModeSrvTxtSeparate (4) |
| "srv_txt_opt", // kServiceModeSrvTxtOptimize (5) |
| }; |
| |
| static_assert(Dns::Client::QueryConfig::kServiceModeUnspecified == 0, "Unspecified value is incorrect"); |
| static_assert(Dns::Client::QueryConfig::kServiceModeSrv == 1, "Srv value is incorrect"); |
| static_assert(Dns::Client::QueryConfig::kServiceModeTxt == 2, "Txt value is incorrect"); |
| static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxt == 3, "SrvTxt value is incorrect"); |
| static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate == 4, "SrvTxtSeparate value is incorrect"); |
| static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize == 5, "SrvTxtOptimize value is incorrect"); |
| |
| return kServiceModeStrings[aMode]; |
| } |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| struct BrowseInfo |
| { |
| void Reset(void) { mCallbackCount = 0; } |
| |
| uint16_t mCallbackCount; |
| Error mError; |
| Dns::Name::Buffer mServiceName; |
| uint16_t mNumInstances; |
| }; |
| |
| static BrowseInfo sBrowseInfo; |
| |
| void BrowseCallback(otError aError, const otDnsBrowseResponse *aResponse, void *aContext) |
| { |
| const Dns::Client::BrowseResponse &response = AsCoreType(aResponse); |
| |
| Log("BrowseCallback"); |
| Log(" Error: %s", ErrorToString(aError)); |
| |
| VerifyOrQuit(aContext == sInstance); |
| |
| sBrowseInfo.mCallbackCount++; |
| sBrowseInfo.mError = aError; |
| |
| SuccessOrExit(aError); |
| |
| SuccessOrQuit(response.GetServiceName(sBrowseInfo.mServiceName, sizeof(sBrowseInfo.mServiceName))); |
| Log(" ServiceName: %s", sBrowseInfo.mServiceName); |
| |
| for (uint16_t index = 0;; index++) |
| { |
| Dns::Name::LabelBuffer instLabel; |
| Error error; |
| |
| error = response.GetServiceInstance(index, instLabel, sizeof(instLabel)); |
| |
| if (error == kErrorNotFound) |
| { |
| sBrowseInfo.mNumInstances = index; |
| break; |
| } |
| |
| SuccessOrQuit(error); |
| |
| Log(" %2u) %s", index + 1, instLabel); |
| } |
| |
| exit: |
| return; |
| } |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| static constexpr uint8_t kMaxHostAddresses = 10; |
| static constexpr uint16_t kMaxTxtBuffer = 256; |
| |
| struct ResolveServiceInfo |
| { |
| void Reset(void) |
| { |
| memset(this, 0, sizeof(*this)); |
| mInfo.mHostNameBuffer = mNameBuffer; |
| mInfo.mHostNameBufferSize = sizeof(mNameBuffer); |
| mInfo.mTxtData = mTxtBuffer; |
| mInfo.mTxtDataSize = sizeof(mTxtBuffer); |
| }; |
| |
| uint16_t mCallbackCount; |
| Error mError; |
| Dns::Client::ServiceInfo mInfo; |
| Dns::Name::Buffer mNameBuffer; |
| uint8_t mTxtBuffer[kMaxTxtBuffer]; |
| Ip6::Address mHostAddresses[kMaxHostAddresses]; |
| uint8_t mNumHostAddresses; |
| }; |
| |
| static ResolveServiceInfo sResolveServiceInfo; |
| |
| void ServiceCallback(otError aError, const otDnsServiceResponse *aResponse, void *aContext) |
| { |
| const Dns::Client::ServiceResponse &response = AsCoreType(aResponse); |
| Dns::Name::LabelBuffer instLabel; |
| Dns::Name::Buffer serviceName; |
| |
| Log("ServiceCallback"); |
| Log(" Error: %s", ErrorToString(aError)); |
| |
| VerifyOrQuit(aContext == sInstance); |
| |
| SuccessOrQuit(response.GetServiceName(instLabel, sizeof(instLabel), serviceName, sizeof(serviceName))); |
| Log(" InstLabel: %s", instLabel); |
| Log(" ServiceName: %s", serviceName); |
| |
| sResolveServiceInfo.mCallbackCount++; |
| sResolveServiceInfo.mError = aError; |
| |
| SuccessOrExit(aError); |
| SuccessOrQuit(response.GetServiceInfo(sResolveServiceInfo.mInfo)); |
| |
| for (uint8_t index = 0; index < kMaxHostAddresses; index++) |
| { |
| Error error; |
| uint32_t ttl; |
| |
| error = response.GetHostAddress(sResolveServiceInfo.mInfo.mHostNameBuffer, index, |
| sResolveServiceInfo.mHostAddresses[index], ttl); |
| |
| if (error == kErrorNotFound) |
| { |
| sResolveServiceInfo.mNumHostAddresses = index; |
| break; |
| } |
| |
| SuccessOrQuit(error); |
| } |
| |
| LogServiceInfo(sResolveServiceInfo.mInfo); |
| Log(" NumHostAddresses: %u", sResolveServiceInfo.mNumHostAddresses); |
| |
| for (uint8_t index = 0; index < sResolveServiceInfo.mNumHostAddresses; index++) |
| { |
| Log(" %s", sResolveServiceInfo.mHostAddresses[index].ToString().AsCString()); |
| } |
| |
| exit: |
| return; |
| } |
| |
| //---------------------------------------------------------------------------------------------------------------------- |
| |
| void TestDnsClient(void) |
| { |
| static constexpr uint8_t kNumAddresses = 2; |
| |
| static const char *const kAddresses[kNumAddresses] = {"2001::beef:cafe", "fd00:1234:5678:9abc::1"}; |
| |
| const Dns::Client::QueryConfig::ServiceMode kServiceModes[] = { |
| Dns::Client::QueryConfig::kServiceModeSrv, |
| Dns::Client::QueryConfig::kServiceModeTxt, |
| Dns::Client::QueryConfig::kServiceModeSrvTxt, |
| Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate, |
| Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize, |
| }; |
| |
| Array<Ip6::Address, kNumAddresses> addresses; |
| Srp::Server *srpServer; |
| Srp::Client *srpClient; |
| Srp::Client::Service service1; |
| Srp::Client::Service service2; |
| Dns::Client *dnsClient; |
| Dns::Client::QueryConfig queryConfig; |
| Dns::ServiceDiscovery::Server *dnsServer; |
| uint16_t heapAllocations; |
| |
| Log("--------------------------------------------------------------------------------------------"); |
| Log("TestDnsClient"); |
| |
| InitTest(); |
| |
| for (const char *addrString : kAddresses) |
| { |
| otNetifAddress netifAddr; |
| |
| memset(&netifAddr, 0, sizeof(netifAddr)); |
| SuccessOrQuit(AsCoreType(&netifAddr.mAddress).FromString(addrString)); |
| netifAddr.mPrefixLength = 64; |
| netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL; |
| netifAddr.mPreferred = true; |
| netifAddr.mValid = true; |
| SuccessOrQuit(otIp6AddUnicastAddress(sInstance, &netifAddr)); |
| |
| SuccessOrQuit(addresses.PushBack(AsCoreType(&netifAddr.mAddress))); |
| } |
| |
| srpServer = &sInstance->Get<Srp::Server>(); |
| srpClient = &sInstance->Get<Srp::Client>(); |
| dnsClient = &sInstance->Get<Dns::Client>(); |
| dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>(); |
| |
| heapAllocations = sHeapAllocatedPtrs.GetLength(); |
| |
| PrepareService1(service1); |
| PrepareService2(service2); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Start SRP server. |
| |
| SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); |
| VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); |
| |
| srpServer->SetEnabled(true); |
| VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); |
| |
| AdvanceTime(10000); |
| VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Start SRP client. |
| |
| srpClient->EnableAutoStartMode(nullptr, nullptr); |
| VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); |
| |
| AdvanceTime(2000); |
| VerifyOrQuit(srpClient->IsRunning()); |
| |
| SuccessOrQuit(srpClient->SetHostName(kHostName)); |
| SuccessOrQuit(srpClient->EnableAutoHostAddress()); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Register two services on SRP. |
| |
| SuccessOrQuit(srpClient->AddService(service1)); |
| SuccessOrQuit(srpClient->AddService(service2)); |
| |
| AdvanceTime(2 * 1000); |
| |
| VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); |
| VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered); |
| ValidateHost(*srpServer, kHostName); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Check DNS Client's default config |
| |
| VerifyOrQuit(dnsClient->GetDefaultConfig().GetServiceMode() == |
| Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Validate DNS Client `Browse()` |
| |
| sBrowseInfo.Reset(); |
| Log("Browse(%s)", kService1FullName); |
| SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance)); |
| AdvanceTime(100); |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 1); |
| |
| sBrowseInfo.Reset(); |
| |
| Log("Browse(%s)", kService2FullName); |
| SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance)); |
| AdvanceTime(100); |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 1); |
| |
| sBrowseInfo.Reset(); |
| |
| Log("Browse(%s)", kService2SubTypeFullName); |
| SuccessOrQuit(dnsClient->Browse(kService2SubTypeFullName, BrowseCallback, sInstance)); |
| AdvanceTime(100); |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 1); |
| |
| sBrowseInfo.Reset(); |
| Log("Browse() for unknown service"); |
| SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance)); |
| AdvanceTime(100); |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| VerifyOrQuit(sBrowseInfo.mError == kErrorNotFound); |
| |
| Log("Issue four parallel `Browse()` at the same time"); |
| sBrowseInfo.Reset(); |
| SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance)); |
| SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance)); |
| SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance)); |
| SuccessOrQuit(dnsClient->Browse("_unknown2._udp.default.service.arpa.", BrowseCallback, sInstance)); |
| AdvanceTime(100); |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 4); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Validate DNS Client `ResolveService()` using all service modes |
| |
| for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes) |
| { |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(mode)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit( |
| dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); |
| AdvanceTime(100); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| SuccessOrQuit(sResolveServiceInfo.mError); |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeTxt) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight); |
| VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0); |
| |
| VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses); |
| VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]); |
| |
| for (uint8_t index = 0; index < kNumAddresses; index++) |
| { |
| VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index])); |
| } |
| } |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeSrv) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0); |
| } |
| } |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| Log("Set TestMode on server to only accept single question"); |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly); |
| |
| Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit( |
| dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); |
| AdvanceTime(200); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| SuccessOrQuit(sResolveServiceInfo.mError); |
| |
| // Use `kServiceModeSrvTxt` and check that server does reject two questions. |
| |
| Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit( |
| dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); |
| AdvanceTime(200); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| VerifyOrQuit(sResolveServiceInfo.mError != kErrorNone); |
| |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Validate DNS Client `ResolveService()` using all service modes |
| // when sever does not provide any RR in the addition data section. |
| |
| for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes) |
| { |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| Log("Set TestMode on server to not include any RR in additional section"); |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection); |
| Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(mode)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit( |
| dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); |
| AdvanceTime(100); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| SuccessOrQuit(sResolveServiceInfo.mError); |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeTxt) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight); |
| VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0); |
| } |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeSrv) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0); |
| } |
| |
| // Since server is using `kTestModeEmptyAdditionalSection`, there |
| // should be no AAAA records for host address. |
| |
| VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress).IsUnspecified()); |
| VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 0); |
| } |
| |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Validate DNS Client `ResolveServiceAndHostAddress()` using all service modes |
| // with different TestMode configs on server: |
| // - Normal behavior when server provides AAAA records for host in |
| // additional section. |
| // - Server provides no records in additional section. We validate that |
| // client will send separate query to resolve host address. |
| |
| for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes) |
| { |
| for (uint8_t testIter = 0; testIter <= 1; testIter++) |
| { |
| Error error; |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| if (testIter == 1) |
| { |
| Log("Set TestMode on server to not include any RR in additional section"); |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection); |
| } |
| else |
| { |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); |
| } |
| |
| Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(mode)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode); |
| |
| sResolveServiceInfo.Reset(); |
| error = dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback, |
| sInstance, &queryConfig); |
| |
| if (mode == Dns::Client::QueryConfig::kServiceModeTxt) |
| { |
| Log("ResolveServiceAndHostAddress() with ServiceMode: %s failed correctly", ServiceModeToString(mode)); |
| VerifyOrQuit(error == kErrorInvalidArgs); |
| continue; |
| } |
| |
| SuccessOrQuit(error); |
| |
| AdvanceTime(100); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| SuccessOrQuit(sResolveServiceInfo.mError); |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeTxt) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight); |
| VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0); |
| |
| VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses); |
| VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == |
| sResolveServiceInfo.mHostAddresses[0]); |
| |
| for (uint8_t index = 0; index < kNumAddresses; index++) |
| { |
| VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index])); |
| } |
| } |
| |
| if (mode != Dns::Client::QueryConfig::kServiceModeSrv) |
| { |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0); |
| } |
| } |
| } |
| |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| Log("Set TestMode on server to not include any RR in additional section AND to only accept single question"); |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection + |
| Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly); |
| |
| Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit(dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback, |
| sInstance, &queryConfig)); |
| |
| AdvanceTime(100); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| SuccessOrQuit(sResolveServiceInfo.mError); |
| |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight); |
| VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0); |
| |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0); |
| VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0); |
| |
| VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses); |
| VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]); |
| |
| for (uint8_t index = 0; index < kNumAddresses; index++) |
| { |
| VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index])); |
| } |
| |
| dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| Log("Stop DNS-SD server"); |
| dnsServer->Stop(); |
| |
| Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, |
| ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate)); |
| |
| queryConfig.Clear(); |
| queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate); |
| |
| sResolveServiceInfo.Reset(); |
| SuccessOrQuit( |
| dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); |
| AdvanceTime(25 * 1000); |
| |
| VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); |
| VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Disable SRP server, verify that all heap allocations by SRP server |
| // and/or by DNS Client are freed. |
| |
| Log("Disabling SRP server"); |
| |
| srpServer->SetEnabled(false); |
| AdvanceTime(100); |
| |
| VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Finalize OT instance and validate all heap allocations are freed. |
| |
| Log("Finalizing OT instance"); |
| FinalizeTest(); |
| |
| VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); |
| |
| Log("End of TestDnsClient"); |
| } |
| |
| //---------------------------------------------------------------------------------------------------------------------- |
| |
| Dns::Name::Buffer sLastSubscribeName; |
| Dns::Name::Buffer sLastUnsubscribeName; |
| |
| void QuerySubscribe(void *aContext, const char *aFullName) |
| { |
| uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize); |
| |
| Log("QuerySubscribe(%s)", aFullName); |
| |
| VerifyOrQuit(aContext == sInstance); |
| VerifyOrQuit(length < Dns::Name::kMaxNameSize); |
| strcpy(sLastSubscribeName, aFullName); |
| } |
| |
| void QueryUnsubscribe(void *aContext, const char *aFullName) |
| { |
| uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize); |
| |
| Log("QueryUnsubscribe(%s)", aFullName); |
| |
| VerifyOrQuit(aContext == sInstance); |
| VerifyOrQuit(length < Dns::Name::kMaxNameSize); |
| strcpy(sLastUnsubscribeName, aFullName); |
| } |
| |
| void TestDnssdServerProxyCallback(void) |
| { |
| Srp::Server *srpServer; |
| Srp::Client *srpClient; |
| Dns::Client *dnsClient; |
| Dns::ServiceDiscovery::Server *dnsServer; |
| otDnssdServiceInstanceInfo instanceInfo; |
| |
| Log("--------------------------------------------------------------------------------------------"); |
| Log("TestDnssdServerProxyCallback"); |
| |
| InitTest(); |
| |
| srpServer = &sInstance->Get<Srp::Server>(); |
| srpClient = &sInstance->Get<Srp::Client>(); |
| dnsClient = &sInstance->Get<Dns::Client>(); |
| dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>(); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Start SRP server. |
| |
| SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); |
| VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); |
| |
| srpServer->SetEnabled(true); |
| VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); |
| |
| AdvanceTime(10000); |
| VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Start SRP client. |
| |
| srpClient->EnableAutoStartMode(nullptr, nullptr); |
| VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); |
| |
| AdvanceTime(2000); |
| VerifyOrQuit(srpClient->IsRunning()); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Set the query subscribe/unsubscribe callbacks on server |
| |
| dnsServer->SetQueryCallbacks(QuerySubscribe, QueryUnsubscribe, sInstance); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| sLastSubscribeName[0] = '\0'; |
| sLastUnsubscribeName[0] = '\0'; |
| |
| sBrowseInfo.Reset(); |
| Log("Browse(%s)", kService1FullName); |
| SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance)); |
| AdvanceTime(10); |
| |
| VerifyOrQuit(strcmp(sLastSubscribeName, kService1FullName) == 0); |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); |
| |
| Log("Invoke subscribe callback"); |
| |
| memset(&instanceInfo, 0, sizeof(instanceInfo)); |
| instanceInfo.mFullName = kInstance1FullName; |
| instanceInfo.mHostName = kHostFullName; |
| instanceInfo.mPort = 200; |
| |
| dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo); |
| |
| AdvanceTime(10); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 1); |
| |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, kService1FullName) == 0); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| sLastSubscribeName[0] = '\0'; |
| sLastUnsubscribeName[0] = '\0'; |
| |
| sBrowseInfo.Reset(); |
| Log("Browse(%s)", kService2FullName); |
| SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance)); |
| AdvanceTime(10); |
| |
| VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0); |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0); |
| |
| Log("Invoke subscribe callback for wrong name"); |
| |
| memset(&instanceInfo, 0, sizeof(instanceInfo)); |
| instanceInfo.mFullName = kInstance1FullName; |
| instanceInfo.mHostName = kHostFullName; |
| instanceInfo.mPort = 200; |
| |
| dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo); |
| |
| AdvanceTime(10); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); |
| |
| Log("Invoke subscribe callback for correct name"); |
| |
| memset(&instanceInfo, 0, sizeof(instanceInfo)); |
| instanceInfo.mFullName = kInstance2FullName; |
| instanceInfo.mHostName = kHostFullName; |
| instanceInfo.mPort = 200; |
| |
| dnsServer->HandleDiscoveredServiceInstance(kService2FullName, instanceInfo); |
| |
| AdvanceTime(10); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 1); |
| |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| sLastSubscribeName[0] = '\0'; |
| sLastUnsubscribeName[0] = '\0'; |
| |
| sBrowseInfo.Reset(); |
| Log("Browse(%s)", kService2FullName); |
| SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance)); |
| AdvanceTime(10); |
| |
| VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0); |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0); |
| |
| Log("Do not invoke subscribe callback and let query to timeout"); |
| |
| // Query timeout is set to 6 seconds |
| |
| AdvanceTime(5000); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); |
| |
| AdvanceTime(2000); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| SuccessOrQuit(sBrowseInfo.mError); |
| VerifyOrQuit(sBrowseInfo.mNumInstances == 0); |
| |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| sLastSubscribeName[0] = '\0'; |
| sLastUnsubscribeName[0] = '\0'; |
| |
| sBrowseInfo.Reset(); |
| Log("Browse(%s)", kService2FullName); |
| SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance)); |
| AdvanceTime(10); |
| |
| VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0); |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); |
| |
| Log("Do not invoke subscribe callback and stop server"); |
| |
| dnsServer->Stop(); |
| |
| AdvanceTime(10); |
| |
| VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); |
| VerifyOrQuit(sBrowseInfo.mError != kErrorNone); |
| |
| VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Finalize OT instance and validate all heap allocations are freed. |
| |
| Log("Finalizing OT instance"); |
| FinalizeTest(); |
| |
| Log("End of TestDnssdServerProxyCallback"); |
| } |
| |
| #endif // ENABLE_DNS_TEST |
| |
| int main(void) |
| { |
| #if ENABLE_DNS_TEST |
| TestDnsClient(); |
| TestDnssdServerProxyCallback(); |
| printf("All tests passed\n"); |
| #else |
| printf("DNS_CLIENT or DSNSSD_SERVER feature is not enabled\n"); |
| #endif |
| |
| return 0; |
| } |