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     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     Dns::ServiceDiscovery::Server::Counters oldServerCounters;
509     Dns::ServiceDiscovery::Server::Counters newServerCounters;
510     uint16_t                                heapAllocations;
511 
512     Log("--------------------------------------------------------------------------------------------");
513     Log("TestDnsClient");
514 
515     InitTest();
516 
517     for (const char *addrString : kAddresses)
518     {
519         otNetifAddress netifAddr;
520 
521         memset(&netifAddr, 0, sizeof(netifAddr));
522         SuccessOrQuit(AsCoreType(&netifAddr.mAddress).FromString(addrString));
523         netifAddr.mPrefixLength  = 64;
524         netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
525         netifAddr.mPreferred     = true;
526         netifAddr.mValid         = true;
527         SuccessOrQuit(otIp6AddUnicastAddress(sInstance, &netifAddr));
528 
529         SuccessOrQuit(addresses.PushBack(AsCoreType(&netifAddr.mAddress)));
530     }
531 
532     srpServer = &sInstance->Get<Srp::Server>();
533     srpClient = &sInstance->Get<Srp::Client>();
534     dnsClient = &sInstance->Get<Dns::Client>();
535     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
536 
537     heapAllocations = sHeapAllocatedPtrs.GetLength();
538 
539     PrepareService1(service1);
540     PrepareService2(service2);
541 
542     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
543     // Start SRP server.
544 
545     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
546     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
547 
548     srpServer->SetEnabled(true);
549     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
550 
551     AdvanceTime(10000);
552     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
553 
554     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
555     // Start SRP client.
556 
557     srpClient->EnableAutoStartMode(nullptr, nullptr);
558     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
559 
560     AdvanceTime(2000);
561     VerifyOrQuit(srpClient->IsRunning());
562 
563     SuccessOrQuit(srpClient->SetHostName(kHostName));
564     SuccessOrQuit(srpClient->EnableAutoHostAddress());
565 
566     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
567     // Register two services on SRP.
568 
569     SuccessOrQuit(srpClient->AddService(service1));
570     SuccessOrQuit(srpClient->AddService(service2));
571 
572     AdvanceTime(2 * 1000);
573 
574     VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered);
575     VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered);
576     ValidateHost(*srpServer, kHostName);
577 
578     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
579 
580     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
581     // Check DNS Client's default config
582 
583     VerifyOrQuit(dnsClient->GetDefaultConfig().GetServiceMode() ==
584                  Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
585 
586     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
587     // Validate DNS Client `Browse()`
588 
589     sBrowseInfo.Reset();
590     Log("Browse(%s)", kService1FullName);
591     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
592     AdvanceTime(100);
593     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
594     SuccessOrQuit(sBrowseInfo.mError);
595     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
596 
597     sBrowseInfo.Reset();
598 
599     Log("Browse(%s)", kService2FullName);
600     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
601     AdvanceTime(100);
602     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
603     SuccessOrQuit(sBrowseInfo.mError);
604     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
605 
606     sBrowseInfo.Reset();
607 
608     Log("Browse(%s)", kService2SubTypeFullName);
609     SuccessOrQuit(dnsClient->Browse(kService2SubTypeFullName, BrowseCallback, sInstance));
610     AdvanceTime(100);
611     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
612     SuccessOrQuit(sBrowseInfo.mError);
613     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
614 
615     sBrowseInfo.Reset();
616     Log("Browse() for unknown service");
617     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
618     AdvanceTime(100);
619     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
620     VerifyOrQuit(sBrowseInfo.mError == kErrorNotFound);
621 
622     Log("Issue four parallel `Browse()` at the same time");
623     sBrowseInfo.Reset();
624     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
625     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
626     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
627     SuccessOrQuit(dnsClient->Browse("_unknown2._udp.default.service.arpa.", BrowseCallback, sInstance));
628     AdvanceTime(100);
629     VerifyOrQuit(sBrowseInfo.mCallbackCount == 4);
630 
631     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
632     // Validate DNS Client `ResolveService()` using all service modes
633 
634     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
635     {
636         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
637         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
638             ServiceModeToString(mode));
639 
640         queryConfig.Clear();
641         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
642 
643         sResolveServiceInfo.Reset();
644         SuccessOrQuit(
645             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
646         AdvanceTime(100);
647 
648         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
649         SuccessOrQuit(sResolveServiceInfo.mError);
650 
651         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
652         {
653             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
654             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
655             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
656             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
657 
658             VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
659             VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
660 
661             for (uint8_t index = 0; index < kNumAddresses; index++)
662             {
663                 VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
664             }
665         }
666 
667         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
668         {
669             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
670             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
671         }
672     }
673 
674     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
675 
676     Log("Set TestMode on server to reject multi-question queries and send error");
677     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery);
678 
679     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
680         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
681 
682     queryConfig.Clear();
683     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
684 
685     sResolveServiceInfo.Reset();
686     SuccessOrQuit(
687         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
688     AdvanceTime(200);
689 
690     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
691     SuccessOrQuit(sResolveServiceInfo.mError);
692 
693     // Use `kServiceModeSrvTxt` and check that server does reject two questions.
694 
695     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
696         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt));
697 
698     queryConfig.Clear();
699     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt);
700 
701     sResolveServiceInfo.Reset();
702     SuccessOrQuit(
703         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
704     AdvanceTime(200);
705 
706     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
707     VerifyOrQuit(sResolveServiceInfo.mError != kErrorNone);
708 
709     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
710 
711     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
712 
713     Log("Set TestMode on server to ignore multi-question queries (send no response)");
714     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeIgnoreMultiQuestionQuery);
715 
716     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
717         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
718 
719     queryConfig.Clear();
720     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
721 
722     sResolveServiceInfo.Reset();
723     SuccessOrQuit(
724         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
725 
726     AdvanceTime(10 * 1000); // Wait longer than client response timeout.
727 
728     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
729     SuccessOrQuit(sResolveServiceInfo.mError);
730 
731     // Use `kServiceModeSrvTxt` and check that server does ignore two questions.
732 
733     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
734         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt));
735 
736     queryConfig.Clear();
737     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt);
738 
739     sResolveServiceInfo.Reset();
740     SuccessOrQuit(
741         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
742 
743     // Wait for the client to time out after exhausting all retry attempts, and
744     // ensure that a `kErrorResponseTimeout` error is reported.
745 
746     AdvanceTime(45 * 1000);
747 
748     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
749     VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout);
750 
751     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
752 
753     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
754     // Validate DNS Client `ResolveService()` using all service modes
755     // when sever does not provide any RR in the addition data section.
756 
757     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
758     {
759         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
760         Log("Set TestMode on server to not include any RR in additional section");
761         dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
762         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
763             ServiceModeToString(mode));
764 
765         queryConfig.Clear();
766         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
767 
768         sResolveServiceInfo.Reset();
769         SuccessOrQuit(
770             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
771         AdvanceTime(100);
772 
773         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
774         SuccessOrQuit(sResolveServiceInfo.mError);
775 
776         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
777         {
778             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
779             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
780             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
781             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
782         }
783 
784         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
785         {
786             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
787             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
788         }
789 
790         // Since server is using `kTestModeEmptyAdditionalSection`, there
791         // should be no AAAA records for host address.
792 
793         VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress).IsUnspecified());
794         VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 0);
795     }
796 
797     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
798 
799     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
800     // Validate DNS Client `ResolveServiceAndHostAddress()` using all service modes
801     // with different TestMode configs on server:
802     // - Normal behavior when server provides AAAA records for host in
803     //   additional section.
804     // - Server provides no records in additional section. We validate that
805     //   client will send separate query to resolve host address.
806 
807     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
808     {
809         for (uint8_t testIter = 0; testIter <= 1; testIter++)
810         {
811             Error error;
812 
813             Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
814 
815             if (testIter == 1)
816             {
817                 Log("Set TestMode on server to not include any RR in additional section");
818                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
819             }
820             else
821             {
822                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
823             }
824 
825             Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
826                 ServiceModeToString(mode));
827 
828             queryConfig.Clear();
829             queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
830 
831             sResolveServiceInfo.Reset();
832             error = dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
833                                                             sInstance, &queryConfig);
834 
835             if (mode == Dns::Client::QueryConfig::kServiceModeTxt)
836             {
837                 Log("ResolveServiceAndHostAddress() with ServiceMode: %s failed correctly", ServiceModeToString(mode));
838                 VerifyOrQuit(error == kErrorInvalidArgs);
839                 continue;
840             }
841 
842             SuccessOrQuit(error);
843 
844             AdvanceTime(100);
845 
846             VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
847             SuccessOrQuit(sResolveServiceInfo.mError);
848 
849             if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
850             {
851                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
852                 VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
853                 VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
854                 VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
855 
856                 VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
857                 VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) ==
858                              sResolveServiceInfo.mHostAddresses[0]);
859 
860                 for (uint8_t index = 0; index < kNumAddresses; index++)
861                 {
862                     VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
863                 }
864             }
865 
866             if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
867             {
868                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
869                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
870             }
871         }
872     }
873 
874     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
875 
876     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
877     Log("Set TestMode on server to not include any RR in additional section AND to only accept single question");
878     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection +
879                            Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery);
880 
881     Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
882         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
883 
884     queryConfig.Clear();
885     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
886 
887     oldServerCounters = dnsServer->GetCounters();
888 
889     sResolveServiceInfo.Reset();
890     SuccessOrQuit(dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
891                                                           sInstance, &queryConfig));
892 
893     AdvanceTime(100);
894 
895     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
896     SuccessOrQuit(sResolveServiceInfo.mError);
897 
898     VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
899     VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
900     VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
901     VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
902 
903     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
904     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
905 
906     VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
907     VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
908 
909     for (uint8_t index = 0; index < kNumAddresses; index++)
910     {
911         VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
912     }
913 
914     newServerCounters = dnsServer->GetCounters();
915 
916     Log("Validate (using server counter) that client first tried to query SRV/TXT together and failed");
917     Log("and then send separate queries (for SRV, TXT and AAAA)");
918     Log("  Total : %2u -> %2u", oldServerCounters.GetTotalQueries(), newServerCounters.GetTotalQueries());
919     Log("  Failed: %2u -> %2u", oldServerCounters.GetTotalFailedQueries(), newServerCounters.GetTotalFailedQueries());
920 
921     VerifyOrQuit(newServerCounters.GetTotalFailedQueries() == 1 + oldServerCounters.GetTotalFailedQueries());
922     VerifyOrQuit(newServerCounters.GetTotalQueries() == 4 + oldServerCounters.GetTotalQueries());
923 
924     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
925     Log("Resolve service again now using `kServiceModeSrvTxtOptimize` as default config");
926     Log("Client should already know that server is not capable of handling multi-question query");
927 
928     queryConfig.Clear();
929     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
930 
931     dnsClient->SetDefaultConfig(queryConfig);
932 
933     Log("ResolveService(%s,%s)", kInstance1Label, kService1FullName);
934 
935     oldServerCounters = dnsServer->GetCounters();
936 
937     sResolveServiceInfo.Reset();
938     SuccessOrQuit(dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, nullptr));
939 
940     AdvanceTime(100);
941 
942     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
943     SuccessOrQuit(sResolveServiceInfo.mError);
944 
945     VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
946     VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
947     VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
948     VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
949 
950     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
951     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
952 
953     newServerCounters = dnsServer->GetCounters();
954 
955     Log("Client should already know that server is not capable of handling multi-question query");
956     Log("Check server counters to validate that client did send separate queries for TXT and SRV");
957     Log("  Total : %2u -> %2u", oldServerCounters.GetTotalQueries(), newServerCounters.GetTotalQueries());
958     Log("  Failed: %2u -> %2u", oldServerCounters.GetTotalFailedQueries(), newServerCounters.GetTotalFailedQueries());
959 
960     VerifyOrQuit(newServerCounters.GetTotalFailedQueries() == oldServerCounters.GetTotalFailedQueries());
961     VerifyOrQuit(newServerCounters.GetTotalQueries() == 2 + oldServerCounters.GetTotalQueries());
962 
963     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
964 
965     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
966 
967     Log("Stop DNS-SD server");
968     dnsServer->Stop();
969 
970     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
971         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate));
972 
973     queryConfig.Clear();
974     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate);
975 
976     sResolveServiceInfo.Reset();
977     SuccessOrQuit(
978         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
979     AdvanceTime(25 * 1000);
980 
981     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
982     VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout);
983 
984     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
985 
986     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
987     // Disable SRP server, verify that all heap allocations by SRP server
988     // and/or by DNS Client are freed.
989 
990     Log("Disabling SRP server");
991 
992     srpServer->SetEnabled(false);
993     AdvanceTime(100);
994 
995     VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
996 
997     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
998     // Finalize OT instance and validate all heap allocations are freed.
999 
1000     Log("Finalizing OT instance");
1001     FinalizeTest();
1002 
1003     VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty());
1004 
1005     Log("End of TestDnsClient");
1006 }
1007 
1008 //----------------------------------------------------------------------------------------------------------------------
1009 
1010 Dns::Name::Buffer sLastSubscribeName;
1011 Dns::Name::Buffer sLastUnsubscribeName;
1012 
QuerySubscribe(void * aContext,const char * aFullName)1013 void QuerySubscribe(void *aContext, const char *aFullName)
1014 {
1015     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
1016 
1017     Log("QuerySubscribe(%s)", aFullName);
1018 
1019     VerifyOrQuit(aContext == sInstance);
1020     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
1021     strcpy(sLastSubscribeName, aFullName);
1022 }
1023 
QueryUnsubscribe(void * aContext,const char * aFullName)1024 void QueryUnsubscribe(void *aContext, const char *aFullName)
1025 {
1026     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
1027 
1028     Log("QueryUnsubscribe(%s)", aFullName);
1029 
1030     VerifyOrQuit(aContext == sInstance);
1031     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
1032     strcpy(sLastUnsubscribeName, aFullName);
1033 }
1034 
TestDnssdServerProxyCallback(void)1035 void TestDnssdServerProxyCallback(void)
1036 {
1037     Srp::Server                   *srpServer;
1038     Srp::Client                   *srpClient;
1039     Dns::Client                   *dnsClient;
1040     Dns::ServiceDiscovery::Server *dnsServer;
1041     otDnssdServiceInstanceInfo     instanceInfo;
1042 
1043     Log("--------------------------------------------------------------------------------------------");
1044     Log("TestDnssdServerProxyCallback");
1045 
1046     InitTest();
1047 
1048     srpServer = &sInstance->Get<Srp::Server>();
1049     srpClient = &sInstance->Get<Srp::Client>();
1050     dnsClient = &sInstance->Get<Dns::Client>();
1051     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
1052 
1053     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1054     // Start SRP server.
1055 
1056     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
1057     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
1058 
1059     srpServer->SetEnabled(true);
1060     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
1061 
1062     AdvanceTime(10000);
1063     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
1064 
1065     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1066     // Start SRP client.
1067 
1068     srpClient->EnableAutoStartMode(nullptr, nullptr);
1069     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
1070 
1071     AdvanceTime(2000);
1072     VerifyOrQuit(srpClient->IsRunning());
1073 
1074     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1075     // Set the query subscribe/unsubscribe callbacks on server
1076 
1077     dnsServer->SetQueryCallbacks(QuerySubscribe, QueryUnsubscribe, sInstance);
1078 
1079     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1080 
1081     sLastSubscribeName[0]   = '\0';
1082     sLastUnsubscribeName[0] = '\0';
1083 
1084     sBrowseInfo.Reset();
1085     Log("Browse(%s)", kService1FullName);
1086     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
1087     AdvanceTime(10);
1088 
1089     VerifyOrQuit(strcmp(sLastSubscribeName, kService1FullName) == 0);
1090     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1091 
1092     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1093 
1094     Log("Invoke subscribe callback");
1095 
1096     memset(&instanceInfo, 0, sizeof(instanceInfo));
1097     instanceInfo.mFullName = kInstance1FullName;
1098     instanceInfo.mHostName = kHostFullName;
1099     instanceInfo.mPort     = 200;
1100 
1101     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1102 
1103     AdvanceTime(10);
1104 
1105     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1106     SuccessOrQuit(sBrowseInfo.mError);
1107     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1108 
1109     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService1FullName) == 0);
1110 
1111     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1112 
1113     sLastSubscribeName[0]   = '\0';
1114     sLastUnsubscribeName[0] = '\0';
1115 
1116     sBrowseInfo.Reset();
1117     Log("Browse(%s)", kService2FullName);
1118     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1119     AdvanceTime(10);
1120 
1121     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1122     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1123 
1124     Log("Invoke subscribe callback for wrong name");
1125 
1126     memset(&instanceInfo, 0, sizeof(instanceInfo));
1127     instanceInfo.mFullName = kInstance1FullName;
1128     instanceInfo.mHostName = kHostFullName;
1129     instanceInfo.mPort     = 200;
1130 
1131     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1132 
1133     AdvanceTime(10);
1134 
1135     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1136 
1137     Log("Invoke subscribe callback for correct name");
1138 
1139     memset(&instanceInfo, 0, sizeof(instanceInfo));
1140     instanceInfo.mFullName = kInstance2FullName;
1141     instanceInfo.mHostName = kHostFullName;
1142     instanceInfo.mPort     = 200;
1143 
1144     dnsServer->HandleDiscoveredServiceInstance(kService2FullName, instanceInfo);
1145 
1146     AdvanceTime(10);
1147 
1148     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1149     SuccessOrQuit(sBrowseInfo.mError);
1150     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1151 
1152     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1153 
1154     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1155 
1156     sLastSubscribeName[0]   = '\0';
1157     sLastUnsubscribeName[0] = '\0';
1158 
1159     sBrowseInfo.Reset();
1160     Log("Browse(%s)", kService2FullName);
1161     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1162     AdvanceTime(10);
1163 
1164     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1165     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1166 
1167     Log("Do not invoke subscribe callback and let query to timeout");
1168 
1169     // Query timeout is set to 6 seconds
1170 
1171     AdvanceTime(5000);
1172 
1173     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1174 
1175     AdvanceTime(2000);
1176 
1177     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1178     SuccessOrQuit(sBrowseInfo.mError);
1179     VerifyOrQuit(sBrowseInfo.mNumInstances == 0);
1180 
1181     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1182 
1183     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1184 
1185     sLastSubscribeName[0]   = '\0';
1186     sLastUnsubscribeName[0] = '\0';
1187 
1188     sBrowseInfo.Reset();
1189     Log("Browse(%s)", kService2FullName);
1190     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1191     AdvanceTime(10);
1192 
1193     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1194     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1195 
1196     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1197 
1198     Log("Do not invoke subscribe callback and stop server");
1199 
1200     dnsServer->Stop();
1201 
1202     AdvanceTime(10);
1203 
1204     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1205     VerifyOrQuit(sBrowseInfo.mError != kErrorNone);
1206 
1207     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1208 
1209     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1210 
1211     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1212     // Finalize OT instance and validate all heap allocations are freed.
1213 
1214     Log("Finalizing OT instance");
1215     FinalizeTest();
1216 
1217     Log("End of TestDnssdServerProxyCallback");
1218 }
1219 
1220 #endif // ENABLE_DNS_TEST
1221 
main(void)1222 int main(void)
1223 {
1224 #if ENABLE_DNS_TEST
1225     TestDnsClient();
1226     TestDnssdServerProxyCallback();
1227     printf("All tests passed\n");
1228 #else
1229     printf("DNS_CLIENT or DSNSSD_SERVER feature is not enabled\n");
1230 #endif
1231 
1232     return 0;
1233 }
1234