Skip to content

Commit cc576dc

Browse files
nivi-applerestyled-commitsksperling-apple
authored
Dnssd changes to browse and resolve using open thread domain along wi… (#32631)
* Dnssd changes to browse and resolve using open thread domain along with the local domain * Add checks for empty domain * Restyled by clang-format * Update src/platform/Darwin/DnssdImpl.cpp Co-authored-by: Karsten Sperling <[email protected]> * Addressed review comments * Restyled by clang-format --------- Co-authored-by: Restyled.io <[email protected]> Co-authored-by: Karsten Sperling <[email protected]>
1 parent 03531f7 commit cc576dc

File tree

3 files changed

+171
-40
lines changed

3 files changed

+171
-40
lines changed

src/platform/Darwin/DnssdContexts.cpp

+32-20
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ namespace {
3030

3131
constexpr uint8_t kDnssdKeyMaxSize = 32;
3232
constexpr uint8_t kDnssdTxtRecordMaxEntries = 20;
33-
constexpr char kLocalDot[] = "local.";
34-
35-
bool IsLocalDomain(const char * domain)
36-
{
37-
return strcmp(kLocalDot, domain) == 0;
38-
}
3933

4034
std::string GetHostNameWithoutDomain(const char * hostnameWithDomain)
4135
{
@@ -252,6 +246,7 @@ void MdnsContexts::Delete(GenericContext * context)
252246
{
253247
DNSServiceRefDeallocate(context->serviceRef);
254248
}
249+
255250
chip::Platform::Delete(context);
256251
}
257252

@@ -388,7 +383,6 @@ void BrowseContext::OnBrowseAdd(const char * name, const char * type, const char
388383
ChipLogProgress(Discovery, "Mdns: %s name: %s, type: %s, domain: %s, interface: %" PRIu32, __func__, StringOrNullMarker(name),
389384
StringOrNullMarker(type), StringOrNullMarker(domain), interfaceId);
390385

391-
VerifyOrReturn(IsLocalDomain(domain));
392386
auto service = GetService(name, type, protocol, interfaceId);
393387
services.push_back(service);
394388
}
@@ -399,7 +393,6 @@ void BrowseContext::OnBrowseRemove(const char * name, const char * type, const c
399393
StringOrNullMarker(type), StringOrNullMarker(domain), interfaceId);
400394

401395
VerifyOrReturn(name != nullptr);
402-
VerifyOrReturn(IsLocalDomain(domain));
403396

404397
services.erase(std::remove_if(services.begin(), services.end(),
405398
[name, type, interfaceId](const DnssdService & service) {
@@ -443,8 +436,6 @@ void BrowseWithDelegateContext::OnBrowseAdd(const char * name, const char * type
443436
ChipLogProgress(Discovery, "Mdns: %s name: %s, type: %s, domain: %s, interface: %" PRIu32, __func__, StringOrNullMarker(name),
444437
StringOrNullMarker(type), StringOrNullMarker(domain), interfaceId);
445438

446-
VerifyOrReturn(IsLocalDomain(domain));
447-
448439
auto delegate = static_cast<DnssdBrowseDelegate *>(context);
449440
auto service = GetService(name, type, protocol, interfaceId);
450441
delegate->OnBrowseAdd(service);
@@ -456,7 +447,6 @@ void BrowseWithDelegateContext::OnBrowseRemove(const char * name, const char * t
456447
StringOrNullMarker(type), StringOrNullMarker(domain), interfaceId);
457448

458449
VerifyOrReturn(name != nullptr);
459-
VerifyOrReturn(IsLocalDomain(domain));
460450

461451
auto delegate = static_cast<DnssdBrowseDelegate *>(context);
462452
auto service = GetService(name, type, protocol, interfaceId);
@@ -536,7 +526,17 @@ void ResolveContext::DispatchSuccess()
536526

537527
for (auto interfaceIndex : priorityInterfaceIndices)
538528
{
539-
if (TryReportingResultsForInterfaceIndex(static_cast<uint32_t>(interfaceIndex)))
529+
// Try finding interfaces for domains kLocalDot and kOpenThreadDot and delete them.
530+
if (TryReportingResultsForInterfaceIndex(static_cast<uint32_t>(interfaceIndex), std::string(kLocalDot)))
531+
{
532+
if (needDelete)
533+
{
534+
MdnsContexts::GetInstance().Delete(this);
535+
}
536+
return;
537+
}
538+
539+
if (TryReportingResultsForInterfaceIndex(static_cast<uint32_t>(interfaceIndex), std::string(kOpenThreadDot)))
540540
{
541541
if (needDelete)
542542
{
@@ -548,7 +548,7 @@ void ResolveContext::DispatchSuccess()
548548

549549
for (auto & interface : interfaces)
550550
{
551-
if (TryReportingResultsForInterfaceIndex(interface.first))
551+
if (TryReportingResultsForInterfaceIndex(interface.first.first, interface.first.second))
552552
{
553553
break;
554554
}
@@ -560,16 +560,17 @@ void ResolveContext::DispatchSuccess()
560560
}
561561
}
562562

563-
bool ResolveContext::TryReportingResultsForInterfaceIndex(uint32_t interfaceIndex)
563+
bool ResolveContext::TryReportingResultsForInterfaceIndex(uint32_t interfaceIndex, std::string domainName)
564564
{
565565
if (interfaceIndex == 0)
566566
{
567567
// Not actually an interface we have.
568568
return false;
569569
}
570570

571-
auto & interface = interfaces[interfaceIndex];
572-
auto & ips = interface.addresses;
571+
std::pair<uint32_t, std::string> interfaceKey = std::make_pair(interfaceIndex, domainName);
572+
auto & interface = interfaces[interfaceKey];
573+
auto & ips = interface.addresses;
573574

574575
// Some interface may not have any ips, just ignore them.
575576
if (ips.size() == 0)
@@ -596,15 +597,17 @@ bool ResolveContext::TryReportingResultsForInterfaceIndex(uint32_t interfaceInde
596597
return true;
597598
}
598599

599-
CHIP_ERROR ResolveContext::OnNewAddress(uint32_t interfaceId, const struct sockaddr * address)
600+
CHIP_ERROR ResolveContext::OnNewAddress(const std::pair<uint32_t, std::string> interfaceKey, const struct sockaddr * address)
600601
{
601602
// If we don't have any information about this interfaceId, just ignore the
602603
// address, since it won't be usable anyway without things like the port.
603604
// This can happen if "local" is set up as a search domain in the DNS setup
604605
// on the system, because the hostnames we are looking up all end in
605606
// ".local". In other words, we can get regular DNS results in here, not
606607
// just DNS-SD ones.
607-
if (interfaces.find(interfaceId) == interfaces.end())
608+
uint32_t interfaceId = interfaceKey.first;
609+
610+
if (interfaces.find(interfaceKey) == interfaces.end())
608611
{
609612
return CHIP_NO_ERROR;
610613
}
@@ -627,7 +630,7 @@ CHIP_ERROR ResolveContext::OnNewAddress(uint32_t interfaceId, const struct socka
627630
return CHIP_NO_ERROR;
628631
}
629632

630-
interfaces[interfaceId].addresses.push_back(ip);
633+
interfaces[interfaceKey].addresses.push_back(ip);
631634

632635
return CHIP_NO_ERROR;
633636
}
@@ -709,7 +712,16 @@ void ResolveContext::OnNewInterface(uint32_t interfaceId, const char * fullname,
709712
// resolving.
710713
interface.fullyQualifiedDomainName = hostnameWithDomain;
711714

712-
interfaces.insert(std::make_pair(interfaceId, std::move(interface)));
715+
std::string domainFromHostname = GetDomainFromHostName(hostnameWithDomain);
716+
if (domainFromHostname.empty())
717+
{
718+
ChipLogError(Discovery, "Mdns: No domain set in hostname %s", hostnameWithDomain);
719+
return;
720+
}
721+
722+
std::pair<uint32_t, std::string> interfaceKey = std::make_pair(interfaceId, domainFromHostname);
723+
724+
interfaces.insert(std::make_pair(interfaceKey, std::move(interface)));
713725
}
714726

715727
bool ResolveContext::HasInterface()

src/platform/Darwin/DnssdImpl.cpp

+128-17
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@
2626
#include <lib/support/logging/CHIPLogging.h>
2727
#include <platform/CHIPDeviceLayer.h>
2828

29+
using namespace chip;
2930
using namespace chip::Dnssd;
3031
using namespace chip::Dnssd::Internal;
3132

3233
namespace {
3334

34-
constexpr char kLocalDot[] = "local.";
35+
// The extra time in milliseconds that we will wait for the resolution on the open thread domain to complete.
36+
constexpr uint16_t kOpenThreadTimeoutInMsec = 250;
3537

3638
constexpr DNSServiceFlags kRegisterFlags = kDNSServiceFlagsNoAutoRename;
37-
constexpr DNSServiceFlags kBrowseFlags = 0;
39+
constexpr DNSServiceFlags kBrowseFlags = kDNSServiceFlagsShareConnection;
3840
constexpr DNSServiceFlags kGetAddrInfoFlags = kDNSServiceFlagsTimeout | kDNSServiceFlagsShareConnection;
3941
constexpr DNSServiceFlags kResolveFlags = kDNSServiceFlagsShareConnection;
4042
constexpr DNSServiceFlags kReconfirmRecordFlags = 0;
@@ -49,7 +51,7 @@ uint32_t GetInterfaceId(chip::Inet::InterfaceId interfaceId)
4951
return interfaceId.IsPresent() ? interfaceId.GetPlatformInterface() : kDNSServiceInterfaceIndexAny;
5052
}
5153

52-
std::string GetHostNameWithDomain(const char * hostname)
54+
std::string GetHostNameWithLocalDomain(const char * hostname)
5355
{
5456
return std::string(hostname) + '.' + kLocalDot;
5557
}
@@ -131,10 +133,70 @@ std::shared_ptr<uint32_t> GetCounterHolder(const char * name)
131133
namespace chip {
132134
namespace Dnssd {
133135

136+
/**
137+
* @brief Returns the domain name from a given hostname with domain.
138+
* The assumption here is that the hostname comprises of "hostnameWithoutDomain.<domain>."
139+
* The domainName returned from this API is "<domain>."
140+
*
141+
* @param[in] hostname The hostname with domain.
142+
*/
143+
std::string GetDomainFromHostName(const char * hostnameWithDomain)
144+
{
145+
std::string hostname = std::string(hostnameWithDomain);
146+
147+
// Find the last occurence of '.'
148+
size_t last_pos = hostname.find_last_of(".");
149+
if (last_pos != std::string::npos)
150+
{
151+
// Get a substring without last '.'
152+
std::string substring = hostname.substr(0, last_pos);
153+
154+
// Find the last occurence of '.' in the substring created above.
155+
size_t pos = substring.find_last_of(".");
156+
if (pos != std::string::npos)
157+
{
158+
// Return the domain name between the last 2 occurences of '.' including the trailing dot'.'.
159+
return std::string(hostname.substr(pos + 1, last_pos));
160+
}
161+
}
162+
return std::string();
163+
}
164+
134165
Global<MdnsContexts> MdnsContexts::sInstance;
135166

136167
namespace {
137168

169+
/**
170+
* @brief Callback that is called when the timeout for resolving on the kOpenThreadDot domain has expired.
171+
*
172+
* @param[in] systemLayer The system layer.
173+
* @param[in] callbackContext The context passed to the timer callback.
174+
*/
175+
void OpenThreadTimerExpiredCallback(System::Layer * systemLayer, void * callbackContext)
176+
{
177+
ChipLogProgress(Discovery, "Mdns: Timer expired for resolve to complete on the open thread domain.");
178+
auto sdCtx = static_cast<ResolveContext *>(callbackContext);
179+
VerifyOrDie(sdCtx != nullptr);
180+
181+
if (sdCtx->hasOpenThreadTimerStarted)
182+
{
183+
sdCtx->Finalize();
184+
}
185+
}
186+
187+
/**
188+
* @brief Starts a timer to wait for the resolution on the kOpenThreadDot domain to happen.
189+
*
190+
* @param[in] timeoutSeconds The timeout in seconds.
191+
* @param[in] ResolveContext The resolve context.
192+
*/
193+
void StartOpenThreadTimer(uint16_t timeoutInMSecs, ResolveContext * ctx)
194+
{
195+
VerifyOrReturn(ctx != nullptr, ChipLogError(Discovery, "Can't schedule open thread timer since context is null"));
196+
DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds16(timeoutInMSecs), OpenThreadTimerExpiredCallback,
197+
reinterpret_cast<void *>(ctx));
198+
}
199+
138200
static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type,
139201
const char * domain, void * context)
140202
{
@@ -183,14 +245,24 @@ static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interf
183245

184246
CHIP_ERROR Browse(BrowseHandler * sdCtx, uint32_t interfaceId, const char * type)
185247
{
186-
ChipLogProgress(Discovery, "Browsing for: %s", StringOrNullMarker(type));
187-
DNSServiceRef sdRef;
188-
auto err = DNSServiceBrowse(&sdRef, kBrowseFlags, interfaceId, type, kLocalDot, OnBrowse, sdCtx);
248+
auto err = DNSServiceCreateConnection(&sdCtx->serviceRef);
189249
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
190250

191-
return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
192-
}
251+
// We will browse on both the local domain and the open thread domain.
252+
ChipLogProgress(Discovery, "Browsing for: %s on domain %s", StringOrNullMarker(type), kLocalDot);
253+
254+
auto sdRefLocal = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
255+
err = DNSServiceBrowse(&sdRefLocal, kBrowseFlags, interfaceId, type, kLocalDot, OnBrowse, sdCtx);
256+
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
193257

258+
ChipLogProgress(Discovery, "Browsing for: %s on domain %s", StringOrNullMarker(type), kOpenThreadDot);
259+
260+
DNSServiceRef sdRefOpenThread = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
261+
err = DNSServiceBrowse(&sdRefOpenThread, kBrowseFlags, interfaceId, type, kOpenThreadDot, OnBrowse, sdCtx);
262+
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
263+
264+
return MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef);
265+
}
194266
CHIP_ERROR Browse(void * context, DnssdBrowseCallback callback, uint32_t interfaceId, const char * type,
195267
DnssdServiceProtocol protocol, intptr_t * browseIdentifier)
196268
{
@@ -219,25 +291,52 @@ static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t i
219291
ReturnOnFailure(MdnsContexts::GetInstance().Has(sdCtx));
220292
LogOnFailure(__func__, err);
221293

294+
std::string domainName = GetDomainFromHostName(hostname);
295+
if (domainName.empty())
296+
{
297+
ChipLogError(Discovery, "Mdns: Domain name is not set in hostname %s", hostname);
298+
return;
299+
}
222300
if (kDNSServiceErr_NoError == err)
223301
{
224-
sdCtx->OnNewAddress(interfaceId, address);
302+
std::pair<uint32_t, std::string> key = std::make_pair(interfaceId, domainName);
303+
sdCtx->OnNewAddress(key, address);
225304
}
226305

227306
if (!(flags & kDNSServiceFlagsMoreComing))
228307
{
229308
VerifyOrReturn(sdCtx->HasAddress(), sdCtx->Finalize(kDNSServiceErr_BadState));
230-
sdCtx->Finalize();
309+
310+
if (domainName.compare(kOpenThreadDot) == 0)
311+
{
312+
ChipLogProgress(Discovery, "Mdns: Resolve completed on the open thread domain.");
313+
sdCtx->Finalize();
314+
}
315+
else if (domainName.compare(kLocalDot) == 0)
316+
{
317+
ChipLogProgress(
318+
Discovery,
319+
"Mdns: Resolve completed on the local domain. Starting a timer for the open thread resolve to come back");
320+
321+
// Usually the resolution on the local domain is quicker than on the open thread domain. We would like to give the
322+
// resolution on the open thread domain around 250 millisecs more to give it a chance to resolve before finalizing
323+
// the resolution.
324+
if (!sdCtx->hasOpenThreadTimerStarted)
325+
{
326+
// Schedule a timer to allow the resolve on OpenThread domain to complete.
327+
StartOpenThreadTimer(kOpenThreadTimeoutInMsec, sdCtx);
328+
sdCtx->hasOpenThreadTimerStarted = true;
329+
}
330+
}
231331
}
232332
}
233333

234334
static void GetAddrInfo(ResolveContext * sdCtx)
235335
{
236336
auto protocol = sdCtx->protocol;
237-
238337
for (auto & interface : sdCtx->interfaces)
239338
{
240-
auto interfaceId = interface.first;
339+
auto interfaceId = interface.first.first;
241340
auto hostname = interface.second.fullyQualifiedDomainName.c_str();
242341
auto sdRefCopy = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
243342
auto err = DNSServiceGetAddrInfo(&sdRefCopy, kGetAddrInfoFlags, interfaceId, protocol, hostname, OnGetAddrInfo, sdCtx);
@@ -263,7 +362,14 @@ static void OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t inter
263362
if (!(flags & kDNSServiceFlagsMoreComing))
264363
{
265364
VerifyOrReturn(sdCtx->HasInterface(), sdCtx->Finalize(kDNSServiceErr_BadState));
266-
GetAddrInfo(sdCtx);
365+
366+
// If a resolve was not requested on this context, call GetAddrInfo and set the isResolveRequested flag to true.
367+
if (!sdCtx->isResolveRequested)
368+
{
369+
GetAddrInfo(sdCtx);
370+
sdCtx->isResolveRequested = true;
371+
sdCtx->hasOpenThreadTimerStarted = false;
372+
}
267373
}
268374
}
269375

@@ -276,8 +382,13 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In
276382
auto err = DNSServiceCreateConnection(&sdCtx->serviceRef);
277383
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
278384

279-
auto sdRefCopy = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
280-
err = DNSServiceResolve(&sdRefCopy, kResolveFlags, interfaceId, name, type, kLocalDot, OnResolve, sdCtx);
385+
// Similar to browse, will try to resolve using both the local domain and the open thread domain.
386+
auto sdRefLocal = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
387+
err = DNSServiceResolve(&sdRefLocal, kResolveFlags, interfaceId, name, type, kLocalDot, OnResolve, sdCtx);
388+
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
389+
390+
auto sdRefOpenThread = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection
391+
err = DNSServiceResolve(&sdRefOpenThread, kResolveFlags, interfaceId, name, type, kOpenThreadDot, OnResolve, sdCtx);
281392
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
282393

283394
auto retval = MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef);
@@ -339,7 +450,7 @@ CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCal
339450

340451
auto regtype = GetFullTypeWithSubTypes(service);
341452
auto interfaceId = GetInterfaceId(service->mInterface);
342-
auto hostname = GetHostNameWithDomain(service->mHostName);
453+
auto hostname = GetHostNameWithLocalDomain(service->mHostName);
343454

344455
return Register(context, callback, interfaceId, regtype.c_str(), service->mName, service->mPort, record, service->mAddressType,
345456
hostname.c_str());
@@ -485,7 +596,7 @@ CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress
485596

486597
auto interfaceId = interface.GetPlatformInterface();
487598
auto rrclass = kDNSServiceClass_IN;
488-
auto fullname = GetHostNameWithDomain(hostname);
599+
auto fullname = GetHostNameWithLocalDomain(hostname);
489600

490601
uint16_t rrtype;
491602
uint16_t rdlen;

0 commit comments

Comments
 (0)