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