1 /*
2  *  Copyright (c) 2023, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <openthread/config.h>
30 
31 #include "test_platform.h"
32 #include "test_util.hpp"
33 
34 #include <openthread/dataset_ftd.h>
35 #include <openthread/dns_client.h>
36 #include <openthread/srp_client.h>
37 #include <openthread/srp_server.h>
38 #include <openthread/thread.h>
39 
40 #include "common/arg_macros.hpp"
41 #include "common/array.hpp"
42 #include "common/string.hpp"
43 #include "common/time.hpp"
44 #include "instance/instance.hpp"
45 
46 #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE &&                 \
47     OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE && OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && \
48     OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE &&                                   \
49     !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && !OPENTHREAD_PLATFORM_POSIX
50 #define ENABLE_DNS_TEST 1
51 #else
52 #define ENABLE_DNS_TEST 0
53 #endif
54 
55 #if ENABLE_DNS_TEST
56 
57 using namespace ot;
58 
59 // Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
60 #define Log(...)                                                                                          \
61     printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \
62            (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
63 
64 static constexpr uint16_t kMaxRaSize = 800;
65 
66 static ot::Instance *sInstance;
67 
68 static uint32_t sNow = 0;
69 static uint32_t sAlarmTime;
70 static bool     sAlarmOn = false;
71 
72 static otRadioFrame sRadioTxFrame;
73 static uint8_t      sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
74 static bool         sRadioTxOngoing = false;
75 
76 //----------------------------------------------------------------------------------------------------------------------
77 // Function prototypes
78 
79 void ProcessRadioTxAndTasklets(void);
80 void AdvanceTime(uint32_t aDuration);
81 
82 //----------------------------------------------------------------------------------------------------------------------
83 // `otPlatRadio`
84 
85 extern "C" {
86 
otPlatRadioGetCaps(otInstance *)87 otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; }
88 
otPlatRadioTransmit(otInstance *,otRadioFrame *)89 otError otPlatRadioTransmit(otInstance *, otRadioFrame *)
90 {
91     sRadioTxOngoing = true;
92 
93     return OT_ERROR_NONE;
94 }
95 
otPlatRadioGetTransmitBuffer(otInstance *)96 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; }
97 
98 //----------------------------------------------------------------------------------------------------------------------
99 // `otPlatAlaram`
100 
otPlatAlarmMilliStop(otInstance *)101 void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
102 
otPlatAlarmMilliStartAt(otInstance *,uint32_t aT0,uint32_t aDt)103 void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
104 {
105     sAlarmOn   = true;
106     sAlarmTime = aT0 + aDt;
107 }
108 
otPlatAlarmMilliGetNow(void)109 uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
110 
111 //----------------------------------------------------------------------------------------------------------------------
112 
113 Array<void *, 500> sHeapAllocatedPtrs;
114 
115 #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
otPlatCAlloc(size_t aNum,size_t aSize)116 void *otPlatCAlloc(size_t aNum, size_t aSize)
117 {
118     void *ptr = calloc(aNum, aSize);
119 
120     SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
121 
122     return ptr;
123 }
124 
otPlatFree(void * aPtr)125 void otPlatFree(void *aPtr)
126 {
127     if (aPtr != nullptr)
128     {
129         void **entry = sHeapAllocatedPtrs.Find(aPtr);
130 
131         VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
132         sHeapAllocatedPtrs.Remove(*entry);
133     }
134 
135     free(aPtr);
136 }
137 #endif
138 
139 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)140 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
141 {
142     OT_UNUSED_VARIABLE(aLogLevel);
143     OT_UNUSED_VARIABLE(aLogRegion);
144 
145     va_list args;
146 
147     printf("   ");
148     va_start(args, aFormat);
149     vprintf(aFormat, args);
150     va_end(args);
151     printf("\n");
152 }
153 #endif
154 
155 } // extern "C"
156 
157 //---------------------------------------------------------------------------------------------------------------------
158 
ProcessRadioTxAndTasklets(void)159 void ProcessRadioTxAndTasklets(void)
160 {
161     do
162     {
163         if (sRadioTxOngoing)
164         {
165             sRadioTxOngoing = false;
166             otPlatRadioTxStarted(sInstance, &sRadioTxFrame);
167             otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE);
168         }
169 
170         otTaskletsProcess(sInstance);
171     } while (otTaskletsArePending(sInstance));
172 }
173 
AdvanceTime(uint32_t aDuration)174 void AdvanceTime(uint32_t aDuration)
175 {
176     uint32_t time = sNow + aDuration;
177 
178     Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
179 
180     while (TimeMilli(sAlarmTime) <= TimeMilli(time))
181     {
182         ProcessRadioTxAndTasklets();
183         sNow = sAlarmTime;
184         otPlatAlarmMilliFired(sInstance);
185     }
186 
187     ProcessRadioTxAndTasklets();
188     sNow = time;
189 }
190 
InitTest(void)191 void InitTest(void)
192 {
193     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
194     // Initialize OT instance.
195 
196     sNow      = 0;
197     sAlarmOn  = false;
198     sInstance = static_cast<Instance *>(testInitInstance());
199 
200     memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame));
201     sRadioTxFrame.mPsdu = sRadioTxFramePsdu;
202     sRadioTxOngoing     = false;
203 
204     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
205     // Initialize Border Router and start Thread operation.
206 
207     otOperationalDataset     dataset;
208     otOperationalDatasetTlvs datasetTlvs;
209 
210     SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset));
211     SuccessOrQuit(otDatasetConvertToTlvs(&dataset, &datasetTlvs));
212     SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
213 
214     SuccessOrQuit(otIp6SetEnabled(sInstance, true));
215     SuccessOrQuit(otThreadSetEnabled(sInstance, true));
216 
217     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
218     // Ensure device starts as leader.
219 
220     AdvanceTime(10000);
221 
222     VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER);
223 }
224 
FinalizeTest(void)225 void FinalizeTest(void)
226 {
227     SuccessOrQuit(otIp6SetEnabled(sInstance, false));
228     SuccessOrQuit(otThreadSetEnabled(sInstance, false));
229     // Make sure there is no message/buffer leak
230     VerifyOrQuit(sInstance->Get<MessagePool>().GetFreeBufferCount() ==
231                  sInstance->Get<MessagePool>().GetTotalBufferCount());
232     SuccessOrQuit(otInstanceErasePersistentInfo(sInstance));
233     testFreeInstance(sInstance);
234 }
235 
236 //---------------------------------------------------------------------------------------------------------------------
237 
238 static const char kHostName[]     = "elden";
239 static const char kHostFullName[] = "elden.default.service.arpa.";
240 
241 static const char kService1Name[]      = "_srv._udp";
242 static const char kService1FullName[]  = "_srv._udp.default.service.arpa.";
243 static const char kInstance1Label[]    = "srv-instance";
244 static const char kInstance1FullName[] = "srv-instance._srv._udp.default.service.arpa.";
245 
246 static const char kService2Name[]            = "_game._udp";
247 static const char kService2FullName[]        = "_game._udp.default.service.arpa.";
248 static const char kService2SubTypeFullName[] = "_best._sub._game._udp.default.service.arpa.";
249 static const char kInstance2Label[]          = "last-ninja";
250 static const char kInstance2FullName[]       = "last-ninja._game._udp.default.service.arpa.";
251 
PrepareService1(Srp::Client::Service & aService)252 void PrepareService1(Srp::Client::Service &aService)
253 {
254     static const char          kSub1[]       = "_sub1";
255     static const char          kSub2[]       = "_V1234567";
256     static const char          kSub3[]       = "_XYZWS";
257     static const char         *kSubLabels[]  = {kSub1, kSub2, kSub3, nullptr};
258     static const char          kTxtKey1[]    = "ABCD";
259     static const uint8_t       kTxtValue1[]  = {'a', '0'};
260     static const char          kTxtKey2[]    = "Z0";
261     static const uint8_t       kTxtValue2[]  = {'1', '2', '3'};
262     static const char          kTxtKey3[]    = "D";
263     static const uint8_t       kTxtValue3[]  = {0};
264     static const otDnsTxtEntry kTxtEntries[] = {
265         {kTxtKey1, kTxtValue1, sizeof(kTxtValue1)},
266         {kTxtKey2, kTxtValue2, sizeof(kTxtValue2)},
267         {kTxtKey3, kTxtValue3, sizeof(kTxtValue3)},
268     };
269 
270     memset(&aService, 0, sizeof(aService));
271     aService.mName          = kService1Name;
272     aService.mInstanceName  = kInstance1Label;
273     aService.mSubTypeLabels = kSubLabels;
274     aService.mTxtEntries    = kTxtEntries;
275     aService.mNumTxtEntries = 3;
276     aService.mPort          = 777;
277     aService.mWeight        = 1;
278     aService.mPriority      = 2;
279 }
280 
PrepareService2(Srp::Client::Service & aService)281 void PrepareService2(Srp::Client::Service &aService)
282 {
283     static const char  kSub4[]       = "_best";
284     static const char *kSubLabels2[] = {kSub4, nullptr};
285 
286     memset(&aService, 0, sizeof(aService));
287     aService.mName          = kService2Name;
288     aService.mInstanceName  = kInstance2Label;
289     aService.mSubTypeLabels = kSubLabels2;
290     aService.mTxtEntries    = nullptr;
291     aService.mNumTxtEntries = 0;
292     aService.mPort          = 555;
293     aService.mWeight        = 0;
294     aService.mPriority      = 3;
295 }
296 
ValidateHost(Srp::Server & aServer,const char * aHostName)297 void ValidateHost(Srp::Server &aServer, const char *aHostName)
298 {
299     // Validate that only a host with `aHostName` is
300     // registered on SRP server.
301 
302     const Srp::Server::Host *host;
303     const char              *name;
304 
305     Log("ValidateHost()");
306 
307     host = aServer.GetNextHost(nullptr);
308     VerifyOrQuit(host != nullptr);
309 
310     name = host->GetFullName();
311     Log("Hostname: %s", name);
312 
313     VerifyOrQuit(StringStartsWith(name, aHostName, kStringCaseInsensitiveMatch));
314     VerifyOrQuit(name[strlen(aHostName)] == '.');
315 
316     // Only one host on server
317     VerifyOrQuit(aServer.GetNextHost(host) == nullptr);
318 }
319 
320 //---------------------------------------------------------------------------------------------------------------------
321 
LogServiceInfo(const Dns::Client::ServiceInfo & aInfo)322 void LogServiceInfo(const Dns::Client::ServiceInfo &aInfo)
323 {
324     Log("   TTL: %u", aInfo.mTtl);
325     Log("   Port: %u", aInfo.mPort);
326     Log("   Weight: %u", aInfo.mWeight);
327     Log("   HostName: %s", aInfo.mHostNameBuffer);
328     Log("   HostAddr: %s", AsCoreType(&aInfo.mHostAddress).ToString().AsCString());
329     Log("   TxtDataLength: %u", aInfo.mTxtDataSize);
330     Log("   TxtDataTTL: %u", aInfo.mTxtDataTtl);
331 }
332 
ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode)333 const char *ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode)
334 {
335     static const char *const kServiceModeStrings[] = {
336         "unspec",      // kServiceModeUnspecified     (0)
337         "srv",         // kServiceModeSrv             (1)
338         "txt",         // kServiceModeTxt             (2)
339         "srv_txt",     // kServiceModeSrvTxt          (3)
340         "srv_txt_sep", // kServiceModeSrvTxtSeparate  (4)
341         "srv_txt_opt", // kServiceModeSrvTxtOptimize  (5)
342     };
343 
344     static_assert(Dns::Client::QueryConfig::kServiceModeUnspecified == 0, "Unspecified value is incorrect");
345     static_assert(Dns::Client::QueryConfig::kServiceModeSrv == 1, "Srv value is incorrect");
346     static_assert(Dns::Client::QueryConfig::kServiceModeTxt == 2, "Txt value is incorrect");
347     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxt == 3, "SrvTxt value is incorrect");
348     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate == 4, "SrvTxtSeparate value is incorrect");
349     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize == 5, "SrvTxtOptimize value is incorrect");
350 
351     return kServiceModeStrings[aMode];
352 }
353 
354 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
355 
356 struct BrowseInfo
357 {
ResetBrowseInfo358     void Reset(void) { mCallbackCount = 0; }
359 
360     uint16_t          mCallbackCount;
361     Error             mError;
362     Dns::Name::Buffer mServiceName;
363     uint16_t          mNumInstances;
364 };
365 
366 static BrowseInfo sBrowseInfo;
367 
BrowseCallback(otError aError,const otDnsBrowseResponse * aResponse,void * aContext)368 void BrowseCallback(otError aError, const otDnsBrowseResponse *aResponse, void *aContext)
369 {
370     const Dns::Client::BrowseResponse &response = AsCoreType(aResponse);
371 
372     Log("BrowseCallback");
373     Log("   Error: %s", ErrorToString(aError));
374 
375     VerifyOrQuit(aContext == sInstance);
376 
377     sBrowseInfo.mCallbackCount++;
378     sBrowseInfo.mError = aError;
379 
380     SuccessOrExit(aError);
381 
382     SuccessOrQuit(response.GetServiceName(sBrowseInfo.mServiceName, sizeof(sBrowseInfo.mServiceName)));
383     Log("   ServiceName: %s", sBrowseInfo.mServiceName);
384 
385     for (uint16_t index = 0;; index++)
386     {
387         Dns::Name::LabelBuffer instLabel;
388         Error                  error;
389 
390         error = response.GetServiceInstance(index, instLabel, sizeof(instLabel));
391 
392         if (error == kErrorNotFound)
393         {
394             sBrowseInfo.mNumInstances = index;
395             break;
396         }
397 
398         SuccessOrQuit(error);
399 
400         Log("  %2u) %s", index + 1, instLabel);
401     }
402 
403 exit:
404     return;
405 }
406 
407 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
408 
409 static constexpr uint8_t  kMaxHostAddresses = 10;
410 static constexpr uint16_t kMaxTxtBuffer     = 256;
411 
412 struct ResolveServiceInfo
413 {
ResetResolveServiceInfo414     void Reset(void)
415     {
416         memset(this, 0, sizeof(*this));
417         mInfo.mHostNameBuffer     = mNameBuffer;
418         mInfo.mHostNameBufferSize = sizeof(mNameBuffer);
419         mInfo.mTxtData            = mTxtBuffer;
420         mInfo.mTxtDataSize        = sizeof(mTxtBuffer);
421     };
422 
423     uint16_t                 mCallbackCount;
424     Error                    mError;
425     Dns::Client::ServiceInfo mInfo;
426     Dns::Name::Buffer        mNameBuffer;
427     uint8_t                  mTxtBuffer[kMaxTxtBuffer];
428     Ip6::Address             mHostAddresses[kMaxHostAddresses];
429     uint8_t                  mNumHostAddresses;
430 };
431 
432 static ResolveServiceInfo sResolveServiceInfo;
433 
ServiceCallback(otError aError,const otDnsServiceResponse * aResponse,void * aContext)434 void ServiceCallback(otError aError, const otDnsServiceResponse *aResponse, void *aContext)
435 {
436     const Dns::Client::ServiceResponse &response = AsCoreType(aResponse);
437     Dns::Name::LabelBuffer              instLabel;
438     Dns::Name::Buffer                   serviceName;
439 
440     Log("ServiceCallback");
441     Log("   Error: %s", ErrorToString(aError));
442 
443     VerifyOrQuit(aContext == sInstance);
444 
445     SuccessOrQuit(response.GetServiceName(instLabel, sizeof(instLabel), serviceName, sizeof(serviceName)));
446     Log("   InstLabel: %s", instLabel);
447     Log("   ServiceName: %s", serviceName);
448 
449     sResolveServiceInfo.mCallbackCount++;
450     sResolveServiceInfo.mError = aError;
451 
452     SuccessOrExit(aError);
453     SuccessOrQuit(response.GetServiceInfo(sResolveServiceInfo.mInfo));
454 
455     for (uint8_t index = 0; index < kMaxHostAddresses; index++)
456     {
457         Error    error;
458         uint32_t ttl;
459 
460         error = response.GetHostAddress(sResolveServiceInfo.mInfo.mHostNameBuffer, index,
461                                         sResolveServiceInfo.mHostAddresses[index], ttl);
462 
463         if (error == kErrorNotFound)
464         {
465             sResolveServiceInfo.mNumHostAddresses = index;
466             break;
467         }
468 
469         SuccessOrQuit(error);
470     }
471 
472     LogServiceInfo(sResolveServiceInfo.mInfo);
473     Log("   NumHostAddresses: %u", sResolveServiceInfo.mNumHostAddresses);
474 
475     for (uint8_t index = 0; index < sResolveServiceInfo.mNumHostAddresses; index++)
476     {
477         Log("      %s", sResolveServiceInfo.mHostAddresses[index].ToString().AsCString());
478     }
479 
480 exit:
481     return;
482 }
483 
484 //----------------------------------------------------------------------------------------------------------------------
485 
TestDnsClient(void)486 void TestDnsClient(void)
487 {
488     static constexpr uint8_t kNumAddresses = 2;
489 
490     static const char *const kAddresses[kNumAddresses] = {"2001::beef:cafe", "fd00:1234:5678:9abc::1"};
491 
492     const Dns::Client::QueryConfig::ServiceMode kServiceModes[] = {
493         Dns::Client::QueryConfig::kServiceModeSrv,
494         Dns::Client::QueryConfig::kServiceModeTxt,
495         Dns::Client::QueryConfig::kServiceModeSrvTxt,
496         Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate,
497         Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize,
498     };
499 
500     Array<Ip6::Address, kNumAddresses> addresses;
501     Srp::Server                       *srpServer;
502     Srp::Client                       *srpClient;
503     Srp::Client::Service               service1;
504     Srp::Client::Service               service2;
505     Dns::Client                       *dnsClient;
506     Dns::Client::QueryConfig           queryConfig;
507     Dns::ServiceDiscovery::Server     *dnsServer;
508     uint16_t                           heapAllocations;
509 
510     Log("--------------------------------------------------------------------------------------------");
511     Log("TestDnsClient");
512 
513     InitTest();
514 
515     for (const char *addrString : kAddresses)
516     {
517         otNetifAddress netifAddr;
518 
519         memset(&netifAddr, 0, sizeof(netifAddr));
520         SuccessOrQuit(AsCoreType(&netifAddr.mAddress).FromString(addrString));
521         netifAddr.mPrefixLength  = 64;
522         netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
523         netifAddr.mPreferred     = true;
524         netifAddr.mValid         = true;
525         SuccessOrQuit(otIp6AddUnicastAddress(sInstance, &netifAddr));
526 
527         SuccessOrQuit(addresses.PushBack(AsCoreType(&netifAddr.mAddress)));
528     }
529 
530     srpServer = &sInstance->Get<Srp::Server>();
531     srpClient = &sInstance->Get<Srp::Client>();
532     dnsClient = &sInstance->Get<Dns::Client>();
533     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
534 
535     heapAllocations = sHeapAllocatedPtrs.GetLength();
536 
537     PrepareService1(service1);
538     PrepareService2(service2);
539 
540     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541     // Start SRP server.
542 
543     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
544     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
545 
546     srpServer->SetEnabled(true);
547     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
548 
549     AdvanceTime(10000);
550     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
551 
552     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
553     // Start SRP client.
554 
555     srpClient->EnableAutoStartMode(nullptr, nullptr);
556     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
557 
558     AdvanceTime(2000);
559     VerifyOrQuit(srpClient->IsRunning());
560 
561     SuccessOrQuit(srpClient->SetHostName(kHostName));
562     SuccessOrQuit(srpClient->EnableAutoHostAddress());
563 
564     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
565     // Register two services on SRP.
566 
567     SuccessOrQuit(srpClient->AddService(service1));
568     SuccessOrQuit(srpClient->AddService(service2));
569 
570     AdvanceTime(2 * 1000);
571 
572     VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered);
573     VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered);
574     ValidateHost(*srpServer, kHostName);
575 
576     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
577 
578     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
579     // Check DNS Client's default config
580 
581     VerifyOrQuit(dnsClient->GetDefaultConfig().GetServiceMode() ==
582                  Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
583 
584     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
585     // Validate DNS Client `Browse()`
586 
587     sBrowseInfo.Reset();
588     Log("Browse(%s)", kService1FullName);
589     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
590     AdvanceTime(100);
591     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
592     SuccessOrQuit(sBrowseInfo.mError);
593     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
594 
595     sBrowseInfo.Reset();
596 
597     Log("Browse(%s)", kService2FullName);
598     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
599     AdvanceTime(100);
600     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
601     SuccessOrQuit(sBrowseInfo.mError);
602     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
603 
604     sBrowseInfo.Reset();
605 
606     Log("Browse(%s)", kService2SubTypeFullName);
607     SuccessOrQuit(dnsClient->Browse(kService2SubTypeFullName, BrowseCallback, sInstance));
608     AdvanceTime(100);
609     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
610     SuccessOrQuit(sBrowseInfo.mError);
611     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
612 
613     sBrowseInfo.Reset();
614     Log("Browse() for unknown service");
615     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
616     AdvanceTime(100);
617     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
618     VerifyOrQuit(sBrowseInfo.mError == kErrorNotFound);
619 
620     Log("Issue four parallel `Browse()` at the same time");
621     sBrowseInfo.Reset();
622     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
623     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
624     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
625     SuccessOrQuit(dnsClient->Browse("_unknown2._udp.default.service.arpa.", BrowseCallback, sInstance));
626     AdvanceTime(100);
627     VerifyOrQuit(sBrowseInfo.mCallbackCount == 4);
628 
629     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
630     // Validate DNS Client `ResolveService()` using all service modes
631 
632     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
633     {
634         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
635         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
636             ServiceModeToString(mode));
637 
638         queryConfig.Clear();
639         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
640 
641         sResolveServiceInfo.Reset();
642         SuccessOrQuit(
643             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
644         AdvanceTime(100);
645 
646         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
647         SuccessOrQuit(sResolveServiceInfo.mError);
648 
649         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
650         {
651             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
652             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
653             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
654             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
655 
656             VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
657             VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
658 
659             for (uint8_t index = 0; index < kNumAddresses; index++)
660             {
661                 VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
662             }
663         }
664 
665         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
666         {
667             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
668             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
669         }
670     }
671 
672     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
673 
674     Log("Set TestMode on server to only accept single question");
675     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly);
676 
677     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
678         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
679 
680     queryConfig.Clear();
681     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
682 
683     sResolveServiceInfo.Reset();
684     SuccessOrQuit(
685         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
686     AdvanceTime(200);
687 
688     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
689     SuccessOrQuit(sResolveServiceInfo.mError);
690 
691     // Use `kServiceModeSrvTxt` and check that server does reject two questions.
692 
693     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
694         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt));
695 
696     queryConfig.Clear();
697     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt);
698 
699     sResolveServiceInfo.Reset();
700     SuccessOrQuit(
701         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
702     AdvanceTime(200);
703 
704     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
705     VerifyOrQuit(sResolveServiceInfo.mError != kErrorNone);
706 
707     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
708 
709     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
710     // Validate DNS Client `ResolveService()` using all service modes
711     // when sever does not provide any RR in the addition data section.
712 
713     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
714     {
715         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
716         Log("Set TestMode on server to not include any RR in additional section");
717         dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
718         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
719             ServiceModeToString(mode));
720 
721         queryConfig.Clear();
722         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
723 
724         sResolveServiceInfo.Reset();
725         SuccessOrQuit(
726             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
727         AdvanceTime(100);
728 
729         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
730         SuccessOrQuit(sResolveServiceInfo.mError);
731 
732         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
733         {
734             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
735             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
736             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
737             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
738         }
739 
740         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
741         {
742             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
743             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
744         }
745 
746         // Since server is using `kTestModeEmptyAdditionalSection`, there
747         // should be no AAAA records for host address.
748 
749         VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress).IsUnspecified());
750         VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 0);
751     }
752 
753     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
754 
755     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
756     // Validate DNS Client `ResolveServiceAndHostAddress()` using all service modes
757     // with different TestMode configs on server:
758     // - Normal behavior when server provides AAAA records for host in
759     //   additional section.
760     // - Server provides no records in additional section. We validate that
761     //   client will send separate query to resolve host address.
762 
763     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
764     {
765         for (uint8_t testIter = 0; testIter <= 1; testIter++)
766         {
767             Error error;
768 
769             Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
770 
771             if (testIter == 1)
772             {
773                 Log("Set TestMode on server to not include any RR in additional section");
774                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
775             }
776             else
777             {
778                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
779             }
780 
781             Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
782                 ServiceModeToString(mode));
783 
784             queryConfig.Clear();
785             queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
786 
787             sResolveServiceInfo.Reset();
788             error = dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
789                                                             sInstance, &queryConfig);
790 
791             if (mode == Dns::Client::QueryConfig::kServiceModeTxt)
792             {
793                 Log("ResolveServiceAndHostAddress() with ServiceMode: %s failed correctly", ServiceModeToString(mode));
794                 VerifyOrQuit(error == kErrorInvalidArgs);
795                 continue;
796             }
797 
798             SuccessOrQuit(error);
799 
800             AdvanceTime(100);
801 
802             VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
803             SuccessOrQuit(sResolveServiceInfo.mError);
804 
805             if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
806             {
807                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
808                 VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
809                 VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
810                 VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
811 
812                 VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
813                 VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) ==
814                              sResolveServiceInfo.mHostAddresses[0]);
815 
816                 for (uint8_t index = 0; index < kNumAddresses; index++)
817                 {
818                     VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
819                 }
820             }
821 
822             if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
823             {
824                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
825                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
826             }
827         }
828     }
829 
830     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
831 
832     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
833     Log("Set TestMode on server to not include any RR in additional section AND to only accept single question");
834     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection +
835                            Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly);
836 
837     Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
838         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
839 
840     queryConfig.Clear();
841     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
842 
843     sResolveServiceInfo.Reset();
844     SuccessOrQuit(dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
845                                                           sInstance, &queryConfig));
846 
847     AdvanceTime(100);
848 
849     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
850     SuccessOrQuit(sResolveServiceInfo.mError);
851 
852     VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
853     VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
854     VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
855     VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
856 
857     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
858     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
859 
860     VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
861     VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
862 
863     for (uint8_t index = 0; index < kNumAddresses; index++)
864     {
865         VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
866     }
867 
868     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
869 
870     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
871 
872     Log("Stop DNS-SD server");
873     dnsServer->Stop();
874 
875     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
876         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate));
877 
878     queryConfig.Clear();
879     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate);
880 
881     sResolveServiceInfo.Reset();
882     SuccessOrQuit(
883         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
884     AdvanceTime(25 * 1000);
885 
886     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
887     VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout);
888 
889     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
890 
891     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
892     // Disable SRP server, verify that all heap allocations by SRP server
893     // and/or by DNS Client are freed.
894 
895     Log("Disabling SRP server");
896 
897     srpServer->SetEnabled(false);
898     AdvanceTime(100);
899 
900     VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
901 
902     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
903     // Finalize OT instance and validate all heap allocations are freed.
904 
905     Log("Finalizing OT instance");
906     FinalizeTest();
907 
908     VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty());
909 
910     Log("End of TestDnsClient");
911 }
912 
913 //----------------------------------------------------------------------------------------------------------------------
914 
915 Dns::Name::Buffer sLastSubscribeName;
916 Dns::Name::Buffer sLastUnsubscribeName;
917 
QuerySubscribe(void * aContext,const char * aFullName)918 void QuerySubscribe(void *aContext, const char *aFullName)
919 {
920     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
921 
922     Log("QuerySubscribe(%s)", aFullName);
923 
924     VerifyOrQuit(aContext == sInstance);
925     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
926     strcpy(sLastSubscribeName, aFullName);
927 }
928 
QueryUnsubscribe(void * aContext,const char * aFullName)929 void QueryUnsubscribe(void *aContext, const char *aFullName)
930 {
931     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
932 
933     Log("QueryUnsubscribe(%s)", aFullName);
934 
935     VerifyOrQuit(aContext == sInstance);
936     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
937     strcpy(sLastUnsubscribeName, aFullName);
938 }
939 
TestDnssdServerProxyCallback(void)940 void TestDnssdServerProxyCallback(void)
941 {
942     Srp::Server                   *srpServer;
943     Srp::Client                   *srpClient;
944     Dns::Client                   *dnsClient;
945     Dns::ServiceDiscovery::Server *dnsServer;
946     otDnssdServiceInstanceInfo     instanceInfo;
947 
948     Log("--------------------------------------------------------------------------------------------");
949     Log("TestDnssdServerProxyCallback");
950 
951     InitTest();
952 
953     srpServer = &sInstance->Get<Srp::Server>();
954     srpClient = &sInstance->Get<Srp::Client>();
955     dnsClient = &sInstance->Get<Dns::Client>();
956     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
957 
958     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
959     // Start SRP server.
960 
961     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
962     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
963 
964     srpServer->SetEnabled(true);
965     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
966 
967     AdvanceTime(10000);
968     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
969 
970     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
971     // Start SRP client.
972 
973     srpClient->EnableAutoStartMode(nullptr, nullptr);
974     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
975 
976     AdvanceTime(2000);
977     VerifyOrQuit(srpClient->IsRunning());
978 
979     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
980     // Set the query subscribe/unsubscribe callbacks on server
981 
982     dnsServer->SetQueryCallbacks(QuerySubscribe, QueryUnsubscribe, sInstance);
983 
984     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
985 
986     sLastSubscribeName[0]   = '\0';
987     sLastUnsubscribeName[0] = '\0';
988 
989     sBrowseInfo.Reset();
990     Log("Browse(%s)", kService1FullName);
991     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
992     AdvanceTime(10);
993 
994     VerifyOrQuit(strcmp(sLastSubscribeName, kService1FullName) == 0);
995     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
996 
997     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
998 
999     Log("Invoke subscribe callback");
1000 
1001     memset(&instanceInfo, 0, sizeof(instanceInfo));
1002     instanceInfo.mFullName = kInstance1FullName;
1003     instanceInfo.mHostName = kHostFullName;
1004     instanceInfo.mPort     = 200;
1005 
1006     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1007 
1008     AdvanceTime(10);
1009 
1010     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1011     SuccessOrQuit(sBrowseInfo.mError);
1012     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1013 
1014     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService1FullName) == 0);
1015 
1016     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1017 
1018     sLastSubscribeName[0]   = '\0';
1019     sLastUnsubscribeName[0] = '\0';
1020 
1021     sBrowseInfo.Reset();
1022     Log("Browse(%s)", kService2FullName);
1023     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1024     AdvanceTime(10);
1025 
1026     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1027     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1028 
1029     Log("Invoke subscribe callback for wrong name");
1030 
1031     memset(&instanceInfo, 0, sizeof(instanceInfo));
1032     instanceInfo.mFullName = kInstance1FullName;
1033     instanceInfo.mHostName = kHostFullName;
1034     instanceInfo.mPort     = 200;
1035 
1036     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1037 
1038     AdvanceTime(10);
1039 
1040     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1041 
1042     Log("Invoke subscribe callback for correct name");
1043 
1044     memset(&instanceInfo, 0, sizeof(instanceInfo));
1045     instanceInfo.mFullName = kInstance2FullName;
1046     instanceInfo.mHostName = kHostFullName;
1047     instanceInfo.mPort     = 200;
1048 
1049     dnsServer->HandleDiscoveredServiceInstance(kService2FullName, instanceInfo);
1050 
1051     AdvanceTime(10);
1052 
1053     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1054     SuccessOrQuit(sBrowseInfo.mError);
1055     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1056 
1057     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1058 
1059     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1060 
1061     sLastSubscribeName[0]   = '\0';
1062     sLastUnsubscribeName[0] = '\0';
1063 
1064     sBrowseInfo.Reset();
1065     Log("Browse(%s)", kService2FullName);
1066     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1067     AdvanceTime(10);
1068 
1069     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1070     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1071 
1072     Log("Do not invoke subscribe callback and let query to timeout");
1073 
1074     // Query timeout is set to 6 seconds
1075 
1076     AdvanceTime(5000);
1077 
1078     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1079 
1080     AdvanceTime(2000);
1081 
1082     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1083     SuccessOrQuit(sBrowseInfo.mError);
1084     VerifyOrQuit(sBrowseInfo.mNumInstances == 0);
1085 
1086     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1087 
1088     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1089 
1090     sLastSubscribeName[0]   = '\0';
1091     sLastUnsubscribeName[0] = '\0';
1092 
1093     sBrowseInfo.Reset();
1094     Log("Browse(%s)", kService2FullName);
1095     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1096     AdvanceTime(10);
1097 
1098     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1099     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1100 
1101     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1102 
1103     Log("Do not invoke subscribe callback and stop server");
1104 
1105     dnsServer->Stop();
1106 
1107     AdvanceTime(10);
1108 
1109     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1110     VerifyOrQuit(sBrowseInfo.mError != kErrorNone);
1111 
1112     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1113 
1114     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1115 
1116     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1117     // Finalize OT instance and validate all heap allocations are freed.
1118 
1119     Log("Finalizing OT instance");
1120     FinalizeTest();
1121 
1122     Log("End of TestDnssdServerProxyCallback");
1123 }
1124 
1125 #endif // ENABLE_DNS_TEST
1126 
main(void)1127 int main(void)
1128 {
1129 #if ENABLE_DNS_TEST
1130     TestDnsClient();
1131     TestDnssdServerProxyCallback();
1132     printf("All tests passed\n");
1133 #else
1134     printf("DNS_CLIENT or DSNSSD_SERVER feature is not enabled\n");
1135 #endif
1136 
1137     return 0;
1138 }
1139