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