• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/clearable.hpp"
43 #include "common/string.hpp"
44 #include "common/time.hpp"
45 #include "instance/instance.hpp"
46 
47 #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE &&                 \
48     OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE && OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && \
49     OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE &&                                   \
50     !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && !OPENTHREAD_PLATFORM_POSIX
51 #define ENABLE_DNS_TEST 1
52 #else
53 #define ENABLE_DNS_TEST 0
54 #endif
55 
56 #if ENABLE_DNS_TEST
57 
58 using namespace ot;
59 
60 // Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
61 #define Log(...)                                                                                          \
62     printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \
63            (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
64 
65 static constexpr uint16_t kMaxRaSize = 800;
66 
67 static ot::Instance *sInstance;
68 
69 static uint32_t sNow = 0;
70 static uint32_t sAlarmTime;
71 static bool     sAlarmOn = false;
72 
73 static otRadioFrame sRadioTxFrame;
74 static uint8_t      sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
75 static bool         sRadioTxOngoing = false;
76 
77 //----------------------------------------------------------------------------------------------------------------------
78 // Function prototypes
79 
80 void ProcessRadioTxAndTasklets(void);
81 void AdvanceTime(uint32_t aDuration);
82 
83 //----------------------------------------------------------------------------------------------------------------------
84 // `otPlatRadio`
85 
86 extern "C" {
87 
otPlatRadioGetCaps(otInstance *)88 otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; }
89 
otPlatRadioTransmit(otInstance *,otRadioFrame *)90 otError otPlatRadioTransmit(otInstance *, otRadioFrame *)
91 {
92     sRadioTxOngoing = true;
93 
94     return OT_ERROR_NONE;
95 }
96 
otPlatRadioGetTransmitBuffer(otInstance *)97 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; }
98 
99 //----------------------------------------------------------------------------------------------------------------------
100 // `otPlatAlaram`
101 
otPlatAlarmMilliStop(otInstance *)102 void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
103 
otPlatAlarmMilliStartAt(otInstance *,uint32_t aT0,uint32_t aDt)104 void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
105 {
106     sAlarmOn   = true;
107     sAlarmTime = aT0 + aDt;
108 }
109 
otPlatAlarmMilliGetNow(void)110 uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
111 
112 //----------------------------------------------------------------------------------------------------------------------
113 
114 Array<void *, 500> sHeapAllocatedPtrs;
115 
116 #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
otPlatCAlloc(size_t aNum,size_t aSize)117 void *otPlatCAlloc(size_t aNum, size_t aSize)
118 {
119     void *ptr = calloc(aNum, aSize);
120 
121     SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
122 
123     return ptr;
124 }
125 
otPlatFree(void * aPtr)126 void otPlatFree(void *aPtr)
127 {
128     if (aPtr != nullptr)
129     {
130         void **entry = sHeapAllocatedPtrs.Find(aPtr);
131 
132         VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
133         sHeapAllocatedPtrs.Remove(*entry);
134     }
135 
136     free(aPtr);
137 }
138 #endif
139 
140 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)141 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
142 {
143     OT_UNUSED_VARIABLE(aLogLevel);
144     OT_UNUSED_VARIABLE(aLogRegion);
145 
146     va_list args;
147 
148     printf("   ");
149     va_start(args, aFormat);
150     vprintf(aFormat, args);
151     va_end(args);
152     printf("\n");
153 }
154 #endif
155 
156 } // extern "C"
157 
158 //---------------------------------------------------------------------------------------------------------------------
159 
ProcessRadioTxAndTasklets(void)160 void ProcessRadioTxAndTasklets(void)
161 {
162     do
163     {
164         if (sRadioTxOngoing)
165         {
166             sRadioTxOngoing = false;
167             otPlatRadioTxStarted(sInstance, &sRadioTxFrame);
168             otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE);
169         }
170 
171         otTaskletsProcess(sInstance);
172     } while (otTaskletsArePending(sInstance));
173 }
174 
AdvanceTime(uint32_t aDuration)175 void AdvanceTime(uint32_t aDuration)
176 {
177     uint32_t time = sNow + aDuration;
178 
179     Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
180 
181     while (TimeMilli(sAlarmTime) <= TimeMilli(time))
182     {
183         ProcessRadioTxAndTasklets();
184         sNow = sAlarmTime;
185         otPlatAlarmMilliFired(sInstance);
186     }
187 
188     ProcessRadioTxAndTasklets();
189     sNow = time;
190 }
191 
InitTest(void)192 void InitTest(void)
193 {
194     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
195     // Initialize OT instance.
196 
197     sNow      = 0;
198     sAlarmOn  = false;
199     sInstance = static_cast<Instance *>(testInitInstance());
200 
201     memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame));
202     sRadioTxFrame.mPsdu = sRadioTxFramePsdu;
203     sRadioTxOngoing     = false;
204 
205     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
206     // Initialize Border Router and start Thread operation.
207 
208     otOperationalDataset     dataset;
209     otOperationalDatasetTlvs datasetTlvs;
210 
211     SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset));
212     otDatasetConvertToTlvs(&dataset, &datasetTlvs);
213     SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
214 
215     SuccessOrQuit(otIp6SetEnabled(sInstance, true));
216     SuccessOrQuit(otThreadSetEnabled(sInstance, true));
217 
218     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
219     // Ensure device starts as leader.
220 
221     AdvanceTime(10000);
222 
223     VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER);
224 }
225 
FinalizeTest(void)226 void FinalizeTest(void)
227 {
228     AdvanceTime(30 * 1000);
229 
230     SuccessOrQuit(otIp6SetEnabled(sInstance, false));
231     SuccessOrQuit(otThreadSetEnabled(sInstance, false));
232     // Make sure there is no message/buffer leak
233     VerifyOrQuit(sInstance->Get<MessagePool>().GetFreeBufferCount() ==
234                  sInstance->Get<MessagePool>().GetTotalBufferCount());
235     SuccessOrQuit(otInstanceErasePersistentInfo(sInstance));
236     testFreeInstance(sInstance);
237 }
238 
239 //---------------------------------------------------------------------------------------------------------------------
240 
241 static const char kHostName[]     = "elden";
242 static const char kHostFullName[] = "elden.default.service.arpa.";
243 
244 static const char kService1Name[]      = "_srv._udp";
245 static const char kService1FullName[]  = "_srv._udp.default.service.arpa.";
246 static const char kInstance1Label[]    = "srv-instance";
247 static const char kInstance1FullName[] = "srv-instance._srv._udp.default.service.arpa.";
248 
249 static const char kService2Name[]            = "_game._udp";
250 static const char kService2FullName[]        = "_game._udp.default.service.arpa.";
251 static const char kService2SubTypeFullName[] = "_best._sub._game._udp.default.service.arpa.";
252 static const char kInstance2Label[]          = "last-ninja";
253 static const char kInstance2FullName[]       = "last-ninja._game._udp.default.service.arpa.";
254 
PrepareService1(Srp::Client::Service & aService)255 void PrepareService1(Srp::Client::Service &aService)
256 {
257     static const char          kSub1[]       = "_sub1";
258     static const char          kSub2[]       = "_V1234567";
259     static const char          kSub3[]       = "_XYZWS";
260     static const char         *kSubLabels[]  = {kSub1, kSub2, kSub3, nullptr};
261     static const char          kTxtKey1[]    = "ABCD";
262     static const uint8_t       kTxtValue1[]  = {'a', '0'};
263     static const char          kTxtKey2[]    = "Z0";
264     static const uint8_t       kTxtValue2[]  = {'1', '2', '3'};
265     static const char          kTxtKey3[]    = "D";
266     static const uint8_t       kTxtValue3[]  = {0};
267     static const otDnsTxtEntry kTxtEntries[] = {
268         {kTxtKey1, kTxtValue1, sizeof(kTxtValue1)},
269         {kTxtKey2, kTxtValue2, sizeof(kTxtValue2)},
270         {kTxtKey3, kTxtValue3, sizeof(kTxtValue3)},
271     };
272 
273     memset(&aService, 0, sizeof(aService));
274     aService.mName          = kService1Name;
275     aService.mInstanceName  = kInstance1Label;
276     aService.mSubTypeLabels = kSubLabels;
277     aService.mTxtEntries    = kTxtEntries;
278     aService.mNumTxtEntries = 3;
279     aService.mPort          = 777;
280     aService.mWeight        = 1;
281     aService.mPriority      = 2;
282 }
283 
PrepareService2(Srp::Client::Service & aService)284 void PrepareService2(Srp::Client::Service &aService)
285 {
286     static const char  kSub4[]       = "_best";
287     static const char *kSubLabels2[] = {kSub4, nullptr};
288 
289     memset(&aService, 0, sizeof(aService));
290     aService.mName          = kService2Name;
291     aService.mInstanceName  = kInstance2Label;
292     aService.mSubTypeLabels = kSubLabels2;
293     aService.mTxtEntries    = nullptr;
294     aService.mNumTxtEntries = 0;
295     aService.mPort          = 555;
296     aService.mWeight        = 0;
297     aService.mPriority      = 3;
298 }
299 
ValidateHost(Srp::Server & aServer,const char * aHostName)300 void ValidateHost(Srp::Server &aServer, const char *aHostName)
301 {
302     // Validate that only a host with `aHostName` is
303     // registered on SRP server.
304 
305     const Srp::Server::Host *host;
306     const char              *name;
307 
308     Log("ValidateHost()");
309 
310     host = aServer.GetNextHost(nullptr);
311     VerifyOrQuit(host != nullptr);
312 
313     name = host->GetFullName();
314     Log("Hostname: %s", name);
315 
316     VerifyOrQuit(StringStartsWith(name, aHostName, kStringCaseInsensitiveMatch));
317     VerifyOrQuit(name[strlen(aHostName)] == '.');
318 
319     // Only one host on server
320     VerifyOrQuit(aServer.GetNextHost(host) == nullptr);
321 }
322 
323 //---------------------------------------------------------------------------------------------------------------------
324 
LogServiceInfo(const Dns::Client::ServiceInfo & aInfo)325 void LogServiceInfo(const Dns::Client::ServiceInfo &aInfo)
326 {
327     Log("   TTL: %u", aInfo.mTtl);
328     Log("   Port: %u", aInfo.mPort);
329     Log("   Weight: %u", aInfo.mWeight);
330     Log("   HostName: %s", aInfo.mHostNameBuffer);
331     Log("   HostAddr: %s", AsCoreType(&aInfo.mHostAddress).ToString().AsCString());
332     Log("   TxtDataLength: %u", aInfo.mTxtDataSize);
333     Log("   TxtDataTTL: %u", aInfo.mTxtDataTtl);
334 }
335 
ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode)336 const char *ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode)
337 {
338     static const char *const kServiceModeStrings[] = {
339         "unspec",      // kServiceModeUnspecified     (0)
340         "srv",         // kServiceModeSrv             (1)
341         "txt",         // kServiceModeTxt             (2)
342         "srv_txt",     // kServiceModeSrvTxt          (3)
343         "srv_txt_sep", // kServiceModeSrvTxtSeparate  (4)
344         "srv_txt_opt", // kServiceModeSrvTxtOptimize  (5)
345     };
346 
347     static_assert(Dns::Client::QueryConfig::kServiceModeUnspecified == 0, "Unspecified value is incorrect");
348     static_assert(Dns::Client::QueryConfig::kServiceModeSrv == 1, "Srv value is incorrect");
349     static_assert(Dns::Client::QueryConfig::kServiceModeTxt == 2, "Txt value is incorrect");
350     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxt == 3, "SrvTxt value is incorrect");
351     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate == 4, "SrvTxtSeparate value is incorrect");
352     static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize == 5, "SrvTxtOptimize value is incorrect");
353 
354     return kServiceModeStrings[aMode];
355 }
356 
357 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
358 
359 static constexpr uint16_t kMaxAddresses = 10;
360 
361 struct AddressInfo
362 {
ResetAddressInfo363     void Reset(void) { ClearAllBytes(*this); }
364 
365     uint16_t          mCallbackCount;
366     Error             mError;
367     Dns::Name::Buffer mHostName;
368     Ip6::Address      mHostAddresses[kMaxAddresses];
369     uint8_t           mNumHostAddresses;
370 };
371 
372 static AddressInfo sAddressInfo;
373 
AddressCallback(otError aError,const otDnsAddressResponse * aResponse,void * aContext)374 void AddressCallback(otError aError, const otDnsAddressResponse *aResponse, void *aContext)
375 {
376     const Dns::Client::AddressResponse &response = AsCoreType(aResponse);
377 
378     Log("AddressCallback");
379     Log("   Error: %s", ErrorToString(aError));
380 
381     VerifyOrQuit(aContext == sInstance);
382 
383     sAddressInfo.mCallbackCount++;
384     sAddressInfo.mError = aError;
385 
386     SuccessOrExit(aError);
387 
388     SuccessOrQuit(response.GetHostName(sAddressInfo.mHostName, sizeof(sAddressInfo.mHostName)));
389     Log("   HostName: %s", sAddressInfo.mHostName);
390 
391     for (uint16_t index = 0;; index++)
392     {
393         Error    error;
394         uint32_t ttl;
395 
396         VerifyOrQuit(index < kMaxAddresses);
397 
398         error = response.GetAddress(index, sAddressInfo.mHostAddresses[index], ttl);
399 
400         if (error == kErrorNotFound)
401         {
402             sAddressInfo.mNumHostAddresses = index;
403             break;
404         }
405 
406         SuccessOrQuit(error);
407 
408         Log("  %2u) %s ttl:%lu", index + 1, sAddressInfo.mHostAddresses[index].ToString().AsCString(), ToUlong(ttl));
409     }
410 
411 exit:
412     return;
413 }
414 
415 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
416 
417 struct BrowseInfo
418 {
ResetBrowseInfo419     void Reset(void) { mCallbackCount = 0; }
420 
421     uint16_t          mCallbackCount;
422     Error             mError;
423     Dns::Name::Buffer mServiceName;
424     uint16_t          mNumInstances;
425 };
426 
427 static BrowseInfo sBrowseInfo;
428 
BrowseCallback(otError aError,const otDnsBrowseResponse * aResponse,void * aContext)429 void BrowseCallback(otError aError, const otDnsBrowseResponse *aResponse, void *aContext)
430 {
431     const Dns::Client::BrowseResponse &response = AsCoreType(aResponse);
432 
433     Log("BrowseCallback");
434     Log("   Error: %s", ErrorToString(aError));
435 
436     VerifyOrQuit(aContext == sInstance);
437 
438     sBrowseInfo.mCallbackCount++;
439     sBrowseInfo.mError = aError;
440 
441     SuccessOrExit(aError);
442 
443     SuccessOrQuit(response.GetServiceName(sBrowseInfo.mServiceName, sizeof(sBrowseInfo.mServiceName)));
444     Log("   ServiceName: %s", sBrowseInfo.mServiceName);
445 
446     for (uint16_t index = 0;; index++)
447     {
448         Dns::Name::LabelBuffer instLabel;
449         Error                  error;
450 
451         error = response.GetServiceInstance(index, instLabel, sizeof(instLabel));
452 
453         if (error == kErrorNotFound)
454         {
455             sBrowseInfo.mNumInstances = index;
456             break;
457         }
458 
459         SuccessOrQuit(error);
460 
461         Log("  %2u) %s", index + 1, instLabel);
462     }
463 
464 exit:
465     return;
466 }
467 
468 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
469 
470 static constexpr uint8_t  kMaxHostAddresses = 10;
471 static constexpr uint16_t kMaxTxtBuffer     = 256;
472 
473 struct ResolveServiceInfo
474 {
ResetResolveServiceInfo475     void Reset(void)
476     {
477         memset(this, 0, sizeof(*this));
478         mInfo.mHostNameBuffer     = mNameBuffer;
479         mInfo.mHostNameBufferSize = sizeof(mNameBuffer);
480         mInfo.mTxtData            = mTxtBuffer;
481         mInfo.mTxtDataSize        = sizeof(mTxtBuffer);
482     };
483 
484     uint16_t                 mCallbackCount;
485     Error                    mError;
486     Dns::Client::ServiceInfo mInfo;
487     Dns::Name::Buffer        mNameBuffer;
488     uint8_t                  mTxtBuffer[kMaxTxtBuffer];
489     Ip6::Address             mHostAddresses[kMaxHostAddresses];
490     uint8_t                  mNumHostAddresses;
491 };
492 
493 static ResolveServiceInfo sResolveServiceInfo;
494 
ServiceCallback(otError aError,const otDnsServiceResponse * aResponse,void * aContext)495 void ServiceCallback(otError aError, const otDnsServiceResponse *aResponse, void *aContext)
496 {
497     const Dns::Client::ServiceResponse &response = AsCoreType(aResponse);
498     Dns::Name::LabelBuffer              instLabel;
499     Dns::Name::Buffer                   serviceName;
500 
501     Log("ServiceCallback");
502     Log("   Error: %s", ErrorToString(aError));
503 
504     VerifyOrQuit(aContext == sInstance);
505 
506     SuccessOrQuit(response.GetServiceName(instLabel, sizeof(instLabel), serviceName, sizeof(serviceName)));
507     Log("   InstLabel: %s", instLabel);
508     Log("   ServiceName: %s", serviceName);
509 
510     sResolveServiceInfo.mCallbackCount++;
511     sResolveServiceInfo.mError = aError;
512 
513     SuccessOrExit(aError);
514     SuccessOrQuit(response.GetServiceInfo(sResolveServiceInfo.mInfo));
515 
516     for (uint8_t index = 0; index < kMaxHostAddresses; index++)
517     {
518         Error    error;
519         uint32_t ttl;
520 
521         error = response.GetHostAddress(sResolveServiceInfo.mInfo.mHostNameBuffer, index,
522                                         sResolveServiceInfo.mHostAddresses[index], ttl);
523 
524         if (error == kErrorNotFound)
525         {
526             sResolveServiceInfo.mNumHostAddresses = index;
527             break;
528         }
529 
530         SuccessOrQuit(error);
531     }
532 
533     LogServiceInfo(sResolveServiceInfo.mInfo);
534     Log("   NumHostAddresses: %u", sResolveServiceInfo.mNumHostAddresses);
535 
536     for (uint8_t index = 0; index < sResolveServiceInfo.mNumHostAddresses; index++)
537     {
538         Log("      %s", sResolveServiceInfo.mHostAddresses[index].ToString().AsCString());
539     }
540 
541 exit:
542     return;
543 }
544 
545 //----------------------------------------------------------------------------------------------------------------------
546 
TestDnsClient(void)547 void TestDnsClient(void)
548 {
549     static constexpr uint8_t kNumAddresses = 2;
550 
551     static const char *const kAddresses[kNumAddresses] = {"2001::beef:cafe", "fd00:1234:5678:9abc::1"};
552 
553     const Dns::Client::QueryConfig::ServiceMode kServiceModes[] = {
554         Dns::Client::QueryConfig::kServiceModeSrv,
555         Dns::Client::QueryConfig::kServiceModeTxt,
556         Dns::Client::QueryConfig::kServiceModeSrvTxt,
557         Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate,
558         Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize,
559     };
560 
561     Array<Ip6::Address, kNumAddresses>      addresses;
562     NetworkData::ExternalRouteConfig        routeConfig;
563     Srp::Server                            *srpServer;
564     Srp::Client                            *srpClient;
565     Srp::Client::Service                    service1;
566     Srp::Client::Service                    service2;
567     Dns::Client                            *dnsClient;
568     Dns::Client::QueryConfig                queryConfig;
569     Dns::ServiceDiscovery::Server          *dnsServer;
570     Dns::ServiceDiscovery::Server::Counters oldServerCounters;
571     Dns::ServiceDiscovery::Server::Counters newServerCounters;
572     uint16_t                                heapAllocations;
573 
574     Log("--------------------------------------------------------------------------------------------");
575     Log("TestDnsClient");
576 
577     InitTest();
578 
579     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
580     Log("Add a route prefix (with NAT64 flag) to network data");
581 
582     routeConfig.Clear();
583     SuccessOrQuit(AsCoreType(&routeConfig.mPrefix.mPrefix).FromString("64:ff9b::"));
584     routeConfig.mPrefix.mLength = 96;
585     routeConfig.mPreference     = NetworkData::kRoutePreferenceMedium;
586     routeConfig.mNat64          = true;
587     routeConfig.mStable         = true;
588 
589     SuccessOrQuit(otBorderRouterAddRoute(sInstance, &routeConfig));
590     SuccessOrQuit(otBorderRouterRegister(sInstance));
591 
592     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
593     Log("Add addresses on Thread netif");
594 
595     for (const char *addrString : kAddresses)
596     {
597         otNetifAddress netifAddr;
598 
599         memset(&netifAddr, 0, sizeof(netifAddr));
600         SuccessOrQuit(AsCoreType(&netifAddr.mAddress).FromString(addrString));
601         netifAddr.mPrefixLength  = 64;
602         netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
603         netifAddr.mPreferred     = true;
604         netifAddr.mValid         = true;
605         SuccessOrQuit(otIp6AddUnicastAddress(sInstance, &netifAddr));
606 
607         SuccessOrQuit(addresses.PushBack(AsCoreType(&netifAddr.mAddress)));
608     }
609 
610     srpServer = &sInstance->Get<Srp::Server>();
611     srpClient = &sInstance->Get<Srp::Client>();
612     dnsClient = &sInstance->Get<Dns::Client>();
613     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
614 
615     heapAllocations = sHeapAllocatedPtrs.GetLength();
616 
617     PrepareService1(service1);
618     PrepareService2(service2);
619 
620     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
621     // Start SRP server.
622 
623     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
624     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
625 
626     srpServer->SetEnabled(true);
627     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
628 
629     AdvanceTime(10000);
630     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
631 
632     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
633     // Start SRP client.
634 
635     srpClient->EnableAutoStartMode(nullptr, nullptr);
636     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
637 
638     AdvanceTime(2000);
639     VerifyOrQuit(srpClient->IsRunning());
640 
641     SuccessOrQuit(srpClient->SetHostName(kHostName));
642     SuccessOrQuit(srpClient->EnableAutoHostAddress());
643 
644     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
645     // Register two services on SRP.
646 
647     SuccessOrQuit(srpClient->AddService(service1));
648     SuccessOrQuit(srpClient->AddService(service2));
649 
650     AdvanceTime(2 * 1000);
651 
652     VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered);
653     VerifyOrQuit(service2.GetState() == Srp::Client::kRegistered);
654     ValidateHost(*srpServer, kHostName);
655 
656     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
657 
658     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
659     // Check DNS Client's default config
660 
661     VerifyOrQuit(dnsClient->GetDefaultConfig().GetServiceMode() ==
662                  Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
663 
664     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
665     // Validate DNS Client `ResolveAddress()`
666 
667     sAddressInfo.Reset();
668     Log("ResolveAddress(%s)", kHostFullName);
669     SuccessOrQuit(dnsClient->ResolveAddress(kHostFullName, AddressCallback, sInstance));
670     AdvanceTime(100);
671     VerifyOrQuit(sAddressInfo.mCallbackCount == 1);
672     SuccessOrQuit(sAddressInfo.mError);
673     VerifyOrQuit(sAddressInfo.mNumHostAddresses == GetArrayLength(kAddresses));
674 
675     for (uint8_t index = 0; index < sAddressInfo.mNumHostAddresses; index++)
676     {
677         VerifyOrQuit(addresses.Contains(sAddressInfo.mHostAddresses[index]));
678     }
679 
680     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
681     // Validate DNS Client `ResolveIp4Address()`
682 
683     sAddressInfo.Reset();
684     Log("ResolveIp4Address(%s)", kHostFullName);
685     SuccessOrQuit(dnsClient->ResolveIp4Address(kHostFullName, AddressCallback, sInstance));
686     AdvanceTime(100);
687     VerifyOrQuit(sAddressInfo.mCallbackCount == 1);
688     SuccessOrQuit(sAddressInfo.mError);
689     VerifyOrQuit(sAddressInfo.mNumHostAddresses == 0);
690 
691     sAddressInfo.Reset();
692     Log("ResolveIp4Address(%s)", "badname");
693     SuccessOrQuit(dnsClient->ResolveIp4Address("badname", AddressCallback, sInstance));
694     AdvanceTime(100);
695     VerifyOrQuit(sAddressInfo.mCallbackCount == 1);
696     VerifyOrQuit(sAddressInfo.mError != kErrorNone);
697 
698     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
699     // Validate DNS Client `Browse()`
700 
701     sBrowseInfo.Reset();
702     Log("Browse(%s)", kService1FullName);
703     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
704     AdvanceTime(100);
705     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
706     SuccessOrQuit(sBrowseInfo.mError);
707     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
708 
709     sBrowseInfo.Reset();
710 
711     Log("Browse(%s)", kService2FullName);
712     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
713     AdvanceTime(100);
714     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
715     SuccessOrQuit(sBrowseInfo.mError);
716     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
717 
718     sBrowseInfo.Reset();
719 
720     Log("Browse(%s)", kService2SubTypeFullName);
721     SuccessOrQuit(dnsClient->Browse(kService2SubTypeFullName, BrowseCallback, sInstance));
722     AdvanceTime(100);
723     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
724     SuccessOrQuit(sBrowseInfo.mError);
725     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
726 
727     sBrowseInfo.Reset();
728     Log("Browse() for unknown service");
729     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
730     AdvanceTime(100);
731     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
732     VerifyOrQuit(sBrowseInfo.mError == kErrorNotFound);
733 
734     Log("Issue four parallel `Browse()` at the same time");
735     sBrowseInfo.Reset();
736     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
737     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
738     SuccessOrQuit(dnsClient->Browse("_unknown._udp.default.service.arpa.", BrowseCallback, sInstance));
739     SuccessOrQuit(dnsClient->Browse("_unknown2._udp.default.service.arpa.", BrowseCallback, sInstance));
740     AdvanceTime(100);
741     VerifyOrQuit(sBrowseInfo.mCallbackCount == 4);
742 
743     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
744     // Validate DNS Client `ResolveService()` using all service modes
745 
746     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
747     {
748         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
749         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
750             ServiceModeToString(mode));
751 
752         queryConfig.Clear();
753         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
754 
755         sResolveServiceInfo.Reset();
756         SuccessOrQuit(
757             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
758         AdvanceTime(100);
759 
760         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
761         SuccessOrQuit(sResolveServiceInfo.mError);
762 
763         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
764         {
765             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
766             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
767             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
768             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
769 
770             VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
771             VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
772 
773             for (uint8_t index = 0; index < kNumAddresses; index++)
774             {
775                 VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
776             }
777         }
778 
779         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
780         {
781             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
782             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
783         }
784     }
785 
786     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
787 
788     Log("Set TestMode on server to reject multi-question queries and send error");
789     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery);
790 
791     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
792         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
793 
794     queryConfig.Clear();
795     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
796 
797     sResolveServiceInfo.Reset();
798     SuccessOrQuit(
799         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
800     AdvanceTime(200);
801 
802     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
803     SuccessOrQuit(sResolveServiceInfo.mError);
804 
805     // Use `kServiceModeSrvTxt` and check that server does reject two questions.
806 
807     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
808         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt));
809 
810     queryConfig.Clear();
811     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt);
812 
813     sResolveServiceInfo.Reset();
814     SuccessOrQuit(
815         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
816     AdvanceTime(200);
817 
818     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
819     VerifyOrQuit(sResolveServiceInfo.mError != kErrorNone);
820 
821     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
822 
823     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
824 
825     Log("Set TestMode on server to ignore multi-question queries (send no response)");
826     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeIgnoreMultiQuestionQuery);
827 
828     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
829         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
830 
831     queryConfig.Clear();
832     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
833 
834     sResolveServiceInfo.Reset();
835     SuccessOrQuit(
836         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
837 
838     AdvanceTime(10 * 1000); // Wait longer than client response timeout.
839 
840     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
841     SuccessOrQuit(sResolveServiceInfo.mError);
842 
843     // Use `kServiceModeSrvTxt` and check that server does ignore two questions.
844 
845     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
846         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt));
847 
848     queryConfig.Clear();
849     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxt);
850 
851     sResolveServiceInfo.Reset();
852     SuccessOrQuit(
853         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
854 
855     // Wait for the client to time out after exhausting all retry attempts, and
856     // ensure that a `kErrorResponseTimeout` error is reported.
857 
858     AdvanceTime(45 * 1000);
859 
860     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
861     VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout);
862 
863     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
864 
865     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
866     // Validate DNS Client `ResolveService()` using all service modes
867     // when sever does not provide any RR in the addition data section.
868 
869     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
870     {
871         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
872         Log("Set TestMode on server to not include any RR in additional section");
873         dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
874         Log("ResolveService(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
875             ServiceModeToString(mode));
876 
877         queryConfig.Clear();
878         queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
879 
880         sResolveServiceInfo.Reset();
881         SuccessOrQuit(
882             dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
883         AdvanceTime(100);
884 
885         VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
886         SuccessOrQuit(sResolveServiceInfo.mError);
887 
888         if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
889         {
890             VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
891             VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
892             VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
893             VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
894         }
895 
896         if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
897         {
898             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
899             VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
900         }
901 
902         // Since server is using `kTestModeEmptyAdditionalSection`, there
903         // should be no AAAA records for host address.
904 
905         VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress).IsUnspecified());
906         VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 0);
907     }
908 
909     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
910 
911     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
912     // Validate DNS Client `ResolveServiceAndHostAddress()` using all service modes
913     // with different TestMode configs on server:
914     // - Normal behavior when server provides AAAA records for host in
915     //   additional section.
916     // - Server provides no records in additional section. We validate that
917     //   client will send separate query to resolve host address.
918 
919     for (Dns::Client::QueryConfig::ServiceMode mode : kServiceModes)
920     {
921         for (uint8_t testIter = 0; testIter <= 1; testIter++)
922         {
923             Error error;
924 
925             Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
926 
927             if (testIter == 1)
928             {
929                 Log("Set TestMode on server to not include any RR in additional section");
930                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection);
931             }
932             else
933             {
934                 dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
935             }
936 
937             Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
938                 ServiceModeToString(mode));
939 
940             queryConfig.Clear();
941             queryConfig.mServiceMode = static_cast<otDnsServiceMode>(mode);
942 
943             sResolveServiceInfo.Reset();
944             error = dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
945                                                             sInstance, &queryConfig);
946 
947             if (mode == Dns::Client::QueryConfig::kServiceModeTxt)
948             {
949                 Log("ResolveServiceAndHostAddress() with ServiceMode: %s failed correctly", ServiceModeToString(mode));
950                 VerifyOrQuit(error == kErrorInvalidArgs);
951                 continue;
952             }
953 
954             SuccessOrQuit(error);
955 
956             AdvanceTime(100);
957 
958             VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
959             SuccessOrQuit(sResolveServiceInfo.mError);
960 
961             if (mode != Dns::Client::QueryConfig::kServiceModeTxt)
962             {
963                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
964                 VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
965                 VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
966                 VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
967 
968                 VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
969                 VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) ==
970                              sResolveServiceInfo.mHostAddresses[0]);
971 
972                 for (uint8_t index = 0; index < kNumAddresses; index++)
973                 {
974                     VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
975                 }
976             }
977 
978             if (mode != Dns::Client::QueryConfig::kServiceModeSrv)
979             {
980                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
981                 VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
982             }
983         }
984     }
985 
986     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
987 
988     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
989     Log("Set TestMode on server to not include any RR in additional section AND to only accept single question");
990     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection +
991                            Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery);
992 
993     Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName,
994         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize));
995 
996     queryConfig.Clear();
997     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
998 
999     oldServerCounters = dnsServer->GetCounters();
1000 
1001     sResolveServiceInfo.Reset();
1002     SuccessOrQuit(dnsClient->ResolveServiceAndHostAddress(kInstance1Label, kService1FullName, ServiceCallback,
1003                                                           sInstance, &queryConfig));
1004 
1005     AdvanceTime(100);
1006 
1007     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
1008     SuccessOrQuit(sResolveServiceInfo.mError);
1009 
1010     VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
1011     VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
1012     VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
1013     VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
1014 
1015     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
1016     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
1017 
1018     VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == kNumAddresses);
1019     VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == sResolveServiceInfo.mHostAddresses[0]);
1020 
1021     for (uint8_t index = 0; index < kNumAddresses; index++)
1022     {
1023         VerifyOrQuit(addresses.Contains(sResolveServiceInfo.mHostAddresses[index]));
1024     }
1025 
1026     newServerCounters = dnsServer->GetCounters();
1027 
1028     Log("Validate (using server counter) that client first tried to query SRV/TXT together and failed");
1029     Log("and then send separate queries (for SRV, TXT and AAAA)");
1030     Log("  Total : %2u -> %2u", oldServerCounters.GetTotalQueries(), newServerCounters.GetTotalQueries());
1031     Log("  Failed: %2u -> %2u", oldServerCounters.GetTotalFailedQueries(), newServerCounters.GetTotalFailedQueries());
1032 
1033     VerifyOrQuit(newServerCounters.GetTotalFailedQueries() == 1 + oldServerCounters.GetTotalFailedQueries());
1034     VerifyOrQuit(newServerCounters.GetTotalQueries() == 4 + oldServerCounters.GetTotalQueries());
1035 
1036     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1037     Log("Resolve service again now using `kServiceModeSrvTxtOptimize` as default config");
1038     Log("Client should already know that server is not capable of handling multi-question query");
1039 
1040     queryConfig.Clear();
1041     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize);
1042 
1043     dnsClient->SetDefaultConfig(queryConfig);
1044 
1045     Log("ResolveService(%s,%s)", kInstance1Label, kService1FullName);
1046 
1047     oldServerCounters = dnsServer->GetCounters();
1048 
1049     sResolveServiceInfo.Reset();
1050     SuccessOrQuit(dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, nullptr));
1051 
1052     AdvanceTime(100);
1053 
1054     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
1055     SuccessOrQuit(sResolveServiceInfo.mError);
1056 
1057     VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl != 0);
1058     VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == service1.mPort);
1059     VerifyOrQuit(sResolveServiceInfo.mInfo.mWeight == service1.mWeight);
1060     VerifyOrQuit(strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, kHostFullName) == 0);
1061 
1062     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl != 0);
1063     VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize != 0);
1064 
1065     newServerCounters = dnsServer->GetCounters();
1066 
1067     Log("Client should already know that server is not capable of handling multi-question query");
1068     Log("Check server counters to validate that client did send separate queries for TXT and SRV");
1069     Log("  Total : %2u -> %2u", oldServerCounters.GetTotalQueries(), newServerCounters.GetTotalQueries());
1070     Log("  Failed: %2u -> %2u", oldServerCounters.GetTotalFailedQueries(), newServerCounters.GetTotalFailedQueries());
1071 
1072     VerifyOrQuit(newServerCounters.GetTotalFailedQueries() == oldServerCounters.GetTotalFailedQueries());
1073     VerifyOrQuit(newServerCounters.GetTotalQueries() == 2 + oldServerCounters.GetTotalQueries());
1074 
1075     dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled);
1076 
1077     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1078 
1079     Log("Stop DNS-SD server");
1080     dnsServer->Stop();
1081 
1082     Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName,
1083         ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate));
1084 
1085     queryConfig.Clear();
1086     queryConfig.mServiceMode = static_cast<otDnsServiceMode>(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate);
1087 
1088     sResolveServiceInfo.Reset();
1089     SuccessOrQuit(
1090         dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig));
1091     AdvanceTime(25 * 1000);
1092 
1093     VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1);
1094     VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout);
1095 
1096     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1097 
1098     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1099     // Disable SRP server, verify that all heap allocations by SRP server
1100     // and/or by DNS Client are freed.
1101 
1102     Log("Disabling SRP server");
1103 
1104     srpServer->SetEnabled(false);
1105     AdvanceTime(100);
1106 
1107     VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
1108 
1109     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1110     // Finalize OT instance and validate all heap allocations are freed.
1111 
1112     Log("Finalizing OT instance");
1113     FinalizeTest();
1114 
1115     VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty());
1116 
1117     Log("End of TestDnsClient");
1118 }
1119 
1120 //----------------------------------------------------------------------------------------------------------------------
1121 
1122 Dns::Name::Buffer sLastSubscribeName;
1123 Dns::Name::Buffer sLastUnsubscribeName;
1124 
QuerySubscribe(void * aContext,const char * aFullName)1125 void QuerySubscribe(void *aContext, const char *aFullName)
1126 {
1127     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
1128 
1129     Log("QuerySubscribe(%s)", aFullName);
1130 
1131     VerifyOrQuit(aContext == sInstance);
1132     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
1133     strcpy(sLastSubscribeName, aFullName);
1134 }
1135 
QueryUnsubscribe(void * aContext,const char * aFullName)1136 void QueryUnsubscribe(void *aContext, const char *aFullName)
1137 {
1138     uint16_t length = StringLength(aFullName, Dns::Name::kMaxNameSize);
1139 
1140     Log("QueryUnsubscribe(%s)", aFullName);
1141 
1142     VerifyOrQuit(aContext == sInstance);
1143     VerifyOrQuit(length < Dns::Name::kMaxNameSize);
1144     strcpy(sLastUnsubscribeName, aFullName);
1145 }
1146 
TestDnssdServerProxyCallback(void)1147 void TestDnssdServerProxyCallback(void)
1148 {
1149     Srp::Server                   *srpServer;
1150     Srp::Client                   *srpClient;
1151     Dns::Client                   *dnsClient;
1152     Dns::ServiceDiscovery::Server *dnsServer;
1153     otDnssdServiceInstanceInfo     instanceInfo;
1154 
1155     Log("--------------------------------------------------------------------------------------------");
1156     Log("TestDnssdServerProxyCallback");
1157 
1158     InitTest();
1159 
1160     srpServer = &sInstance->Get<Srp::Server>();
1161     srpClient = &sInstance->Get<Srp::Client>();
1162     dnsClient = &sInstance->Get<Dns::Client>();
1163     dnsServer = &sInstance->Get<Dns::ServiceDiscovery::Server>();
1164 
1165     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1166     // Start SRP server.
1167 
1168     SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast));
1169     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled);
1170 
1171     srpServer->SetEnabled(true);
1172     VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled);
1173 
1174     AdvanceTime(10000);
1175     VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning);
1176 
1177     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1178     // Start SRP client.
1179 
1180     srpClient->EnableAutoStartMode(nullptr, nullptr);
1181     VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
1182 
1183     AdvanceTime(2000);
1184     VerifyOrQuit(srpClient->IsRunning());
1185 
1186     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1187     // Set the query subscribe/unsubscribe callbacks on server
1188 
1189     dnsServer->SetQueryCallbacks(QuerySubscribe, QueryUnsubscribe, sInstance);
1190 
1191     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1192 
1193     sLastSubscribeName[0]   = '\0';
1194     sLastUnsubscribeName[0] = '\0';
1195 
1196     sBrowseInfo.Reset();
1197     Log("Browse(%s)", kService1FullName);
1198     SuccessOrQuit(dnsClient->Browse(kService1FullName, BrowseCallback, sInstance));
1199     AdvanceTime(10);
1200 
1201     VerifyOrQuit(strcmp(sLastSubscribeName, kService1FullName) == 0);
1202     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1203 
1204     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1205 
1206     Log("Invoke subscribe callback");
1207 
1208     memset(&instanceInfo, 0, sizeof(instanceInfo));
1209     instanceInfo.mFullName = kInstance1FullName;
1210     instanceInfo.mHostName = kHostFullName;
1211     instanceInfo.mPort     = 200;
1212 
1213     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1214 
1215     AdvanceTime(10);
1216 
1217     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1218     SuccessOrQuit(sBrowseInfo.mError);
1219     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1220 
1221     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService1FullName) == 0);
1222 
1223     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1224 
1225     sLastSubscribeName[0]   = '\0';
1226     sLastUnsubscribeName[0] = '\0';
1227 
1228     sBrowseInfo.Reset();
1229     Log("Browse(%s)", kService2FullName);
1230     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1231     AdvanceTime(10);
1232 
1233     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1234     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1235 
1236     Log("Invoke subscribe callback for wrong name");
1237 
1238     memset(&instanceInfo, 0, sizeof(instanceInfo));
1239     instanceInfo.mFullName = kInstance1FullName;
1240     instanceInfo.mHostName = kHostFullName;
1241     instanceInfo.mPort     = 200;
1242 
1243     dnsServer->HandleDiscoveredServiceInstance(kService1FullName, instanceInfo);
1244 
1245     AdvanceTime(10);
1246 
1247     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1248 
1249     Log("Invoke subscribe callback for correct name");
1250 
1251     memset(&instanceInfo, 0, sizeof(instanceInfo));
1252     instanceInfo.mFullName = kInstance2FullName;
1253     instanceInfo.mHostName = kHostFullName;
1254     instanceInfo.mPort     = 200;
1255 
1256     dnsServer->HandleDiscoveredServiceInstance(kService2FullName, instanceInfo);
1257 
1258     AdvanceTime(10);
1259 
1260     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1261     SuccessOrQuit(sBrowseInfo.mError);
1262     VerifyOrQuit(sBrowseInfo.mNumInstances == 1);
1263 
1264     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1265 
1266     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1267 
1268     sLastSubscribeName[0]   = '\0';
1269     sLastUnsubscribeName[0] = '\0';
1270 
1271     sBrowseInfo.Reset();
1272     Log("Browse(%s)", kService2FullName);
1273     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1274     AdvanceTime(10);
1275 
1276     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1277     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1278 
1279     Log("Do not invoke subscribe callback and let query to timeout");
1280 
1281     // Query timeout is set to 6 seconds
1282 
1283     AdvanceTime(5000);
1284 
1285     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1286 
1287     AdvanceTime(2000);
1288 
1289     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1290     SuccessOrQuit(sBrowseInfo.mError);
1291     VerifyOrQuit(sBrowseInfo.mNumInstances == 0);
1292 
1293     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1294 
1295     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1296 
1297     sLastSubscribeName[0]   = '\0';
1298     sLastUnsubscribeName[0] = '\0';
1299 
1300     sBrowseInfo.Reset();
1301     Log("Browse(%s)", kService2FullName);
1302     SuccessOrQuit(dnsClient->Browse(kService2FullName, BrowseCallback, sInstance));
1303     AdvanceTime(10);
1304 
1305     VerifyOrQuit(strcmp(sLastSubscribeName, kService2FullName) == 0);
1306     VerifyOrQuit(strcmp(sLastUnsubscribeName, "") == 0);
1307 
1308     VerifyOrQuit(sBrowseInfo.mCallbackCount == 0);
1309 
1310     Log("Do not invoke subscribe callback and stop server");
1311 
1312     dnsServer->Stop();
1313 
1314     AdvanceTime(10);
1315 
1316     VerifyOrQuit(sBrowseInfo.mCallbackCount == 1);
1317     VerifyOrQuit(sBrowseInfo.mError != kErrorNone);
1318 
1319     VerifyOrQuit(strcmp(sLastUnsubscribeName, kService2FullName) == 0);
1320 
1321     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
1322 
1323     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1324     // Finalize OT instance and validate all heap allocations are freed.
1325 
1326     Log("Finalizing OT instance");
1327     FinalizeTest();
1328 
1329     Log("End of TestDnssdServerProxyCallback");
1330 }
1331 
1332 #endif // ENABLE_DNS_TEST
1333 
main(void)1334 int main(void)
1335 {
1336 #if ENABLE_DNS_TEST
1337     TestDnsClient();
1338     TestDnssdServerProxyCallback();
1339     printf("All tests passed\n");
1340 #else
1341     printf("DNS_CLIENT or DSNSSD_SERVER feature is not enabled\n");
1342 #endif
1343 
1344     return 0;
1345 }
1346