26
26
#include < lib/support/logging/CHIPLogging.h>
27
27
#include < platform/CHIPDeviceLayer.h>
28
28
29
+ using namespace chip ;
29
30
using namespace chip ::Dnssd;
30
31
using namespace chip ::Dnssd::Internal;
31
32
32
33
namespace {
33
34
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 ;
35
37
36
38
constexpr DNSServiceFlags kRegisterFlags = kDNSServiceFlagsNoAutoRename ;
37
- constexpr DNSServiceFlags kBrowseFlags = 0 ;
39
+ constexpr DNSServiceFlags kBrowseFlags = kDNSServiceFlagsShareConnection ;
38
40
constexpr DNSServiceFlags kGetAddrInfoFlags = kDNSServiceFlagsTimeout | kDNSServiceFlagsShareConnection ;
39
41
constexpr DNSServiceFlags kResolveFlags = kDNSServiceFlagsShareConnection ;
40
42
constexpr DNSServiceFlags kReconfirmRecordFlags = 0 ;
@@ -49,7 +51,7 @@ uint32_t GetInterfaceId(chip::Inet::InterfaceId interfaceId)
49
51
return interfaceId.IsPresent () ? interfaceId.GetPlatformInterface () : kDNSServiceInterfaceIndexAny ;
50
52
}
51
53
52
- std::string GetHostNameWithDomain (const char * hostname)
54
+ std::string GetHostNameWithLocalDomain (const char * hostname)
53
55
{
54
56
return std::string (hostname) + ' .' + kLocalDot ;
55
57
}
@@ -131,10 +133,70 @@ std::shared_ptr<uint32_t> GetCounterHolder(const char * name)
131
133
namespace chip {
132
134
namespace Dnssd {
133
135
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
+
134
165
Global<MdnsContexts> MdnsContexts::sInstance ;
135
166
136
167
namespace {
137
168
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
+
138
200
static void OnRegister (DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type,
139
201
const char * domain, void * context)
140
202
{
@@ -183,14 +245,24 @@ static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interf
183
245
184
246
CHIP_ERROR Browse (BrowseHandler * sdCtx, uint32_t interfaceId, const char * type)
185
247
{
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 );
189
249
VerifyOrReturnError (kDNSServiceErr_NoError == err, sdCtx->Finalize (err));
190
250
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));
193
257
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
+ }
194
266
CHIP_ERROR Browse (void * context, DnssdBrowseCallback callback, uint32_t interfaceId, const char * type,
195
267
DnssdServiceProtocol protocol, intptr_t * browseIdentifier)
196
268
{
@@ -219,25 +291,52 @@ static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t i
219
291
ReturnOnFailure (MdnsContexts::GetInstance ().Has (sdCtx));
220
292
LogOnFailure (__func__, err);
221
293
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
+ }
222
300
if (kDNSServiceErr_NoError == err)
223
301
{
224
- sdCtx->OnNewAddress (interfaceId, address);
302
+ std::pair<uint32_t , std::string> key = std::make_pair (interfaceId, domainName);
303
+ sdCtx->OnNewAddress (key, address);
225
304
}
226
305
227
306
if (!(flags & kDNSServiceFlagsMoreComing ))
228
307
{
229
308
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
+ }
231
331
}
232
332
}
233
333
234
334
static void GetAddrInfo (ResolveContext * sdCtx)
235
335
{
236
336
auto protocol = sdCtx->protocol ;
237
-
238
337
for (auto & interface : sdCtx->interfaces )
239
338
{
240
- auto interfaceId = interface.first ;
339
+ auto interfaceId = interface.first . first ;
241
340
auto hostname = interface.second .fullyQualifiedDomainName .c_str ();
242
341
auto sdRefCopy = sdCtx->serviceRef ; // Mandatory copy because of kDNSServiceFlagsShareConnection
243
342
auto err = DNSServiceGetAddrInfo (&sdRefCopy, kGetAddrInfoFlags , interfaceId, protocol, hostname, OnGetAddrInfo, sdCtx);
@@ -263,7 +362,14 @@ static void OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t inter
263
362
if (!(flags & kDNSServiceFlagsMoreComing ))
264
363
{
265
364
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
+ }
267
373
}
268
374
}
269
375
@@ -276,8 +382,13 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In
276
382
auto err = DNSServiceCreateConnection (&sdCtx->serviceRef );
277
383
VerifyOrReturnError (kDNSServiceErr_NoError == err, sdCtx->Finalize (err));
278
384
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);
281
392
VerifyOrReturnError (kDNSServiceErr_NoError == err, sdCtx->Finalize (err));
282
393
283
394
auto retval = MdnsContexts::GetInstance ().Add (sdCtx, sdCtx->serviceRef );
@@ -339,7 +450,7 @@ CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCal
339
450
340
451
auto regtype = GetFullTypeWithSubTypes (service);
341
452
auto interfaceId = GetInterfaceId (service->mInterface );
342
- auto hostname = GetHostNameWithDomain (service->mHostName );
453
+ auto hostname = GetHostNameWithLocalDomain (service->mHostName );
343
454
344
455
return Register (context, callback, interfaceId, regtype.c_str (), service->mName , service->mPort , record, service->mAddressType ,
345
456
hostname.c_str ());
@@ -485,7 +596,7 @@ CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress
485
596
486
597
auto interfaceId = interface.GetPlatformInterface ();
487
598
auto rrclass = kDNSServiceClass_IN ;
488
- auto fullname = GetHostNameWithDomain (hostname);
599
+ auto fullname = GetHostNameWithLocalDomain (hostname);
489
600
490
601
uint16_t rrtype;
491
602
uint16_t rdlen;
0 commit comments