@@ -332,7 +332,7 @@ CHIP_ERROR MdnsAvahi::Init(DnssdAsyncReturnCallback initCallback, DnssdAsyncRetu
332
332
333
333
VerifyOrExit (initCallback != nullptr , error = CHIP_ERROR_INVALID_ARGUMENT);
334
334
VerifyOrExit (errorCallback != nullptr , error = CHIP_ERROR_INVALID_ARGUMENT);
335
- VerifyOrExit (mClient == nullptr && mGroup == nullptr , error = CHIP_ERROR_INCORRECT_STATE);
335
+ VerifyOrExit (mClient == nullptr && mPublishedGroups . empty () , error = CHIP_ERROR_INCORRECT_STATE);
336
336
mInitCallback = initCallback;
337
337
mErrorCallback = errorCallback;
338
338
mAsyncReturnContext = context;
@@ -346,11 +346,7 @@ CHIP_ERROR MdnsAvahi::Init(DnssdAsyncReturnCallback initCallback, DnssdAsyncRetu
346
346
347
347
void MdnsAvahi::Shutdown ()
348
348
{
349
- if (mGroup )
350
- {
351
- avahi_entry_group_free (mGroup );
352
- mGroup = nullptr ;
353
- }
349
+ StopPublish ();
354
350
if (mClient )
355
351
{
356
352
avahi_client_free (mClient );
@@ -361,19 +357,11 @@ void MdnsAvahi::Shutdown()
361
357
CHIP_ERROR MdnsAvahi::SetHostname (const char * hostname)
362
358
{
363
359
CHIP_ERROR error = CHIP_NO_ERROR;
364
- int avahiRet;
365
360
366
361
VerifyOrExit (mClient != nullptr , error = CHIP_ERROR_INCORRECT_STATE);
367
- avahiRet = avahi_client_set_host_name (mClient , hostname);
368
- if (avahiRet == AVAHI_ERR_ACCESS_DENIED)
369
- {
370
- ChipLogError (DeviceLayer, " Cannot set hostname on this system, continue anyway..." );
371
- }
372
- else if (avahiRet != AVAHI_OK && avahiRet != AVAHI_ERR_NO_CHANGE)
373
- {
374
- error = CHIP_ERROR_INTERNAL;
375
- }
376
-
362
+ // Note: we do no longer set the primary hostname here, as other services
363
+ // on the platform might not be happy with the matter mandated hostname.
364
+ // Instead, we'll establish our own hostname when needed (see PublishService())
377
365
exit :
378
366
return error;
379
367
}
@@ -390,16 +378,8 @@ void MdnsAvahi::HandleClientState(AvahiClient * client, AvahiClientState state)
390
378
case AVAHI_CLIENT_S_RUNNING:
391
379
ChipLogProgress (DeviceLayer, " Avahi client registered" );
392
380
mClient = client;
393
- mGroup = avahi_entry_group_new (client, HandleGroupState, this );
394
- if (mGroup == nullptr )
395
- {
396
- ChipLogError (DeviceLayer, " Failed to create avahi group: %s" , avahi_strerror (avahi_client_errno (client)));
397
- mInitCallback (mAsyncReturnContext , CHIP_ERROR_OPEN_FAILED);
398
- }
399
- else
400
- {
401
- mInitCallback (mAsyncReturnContext , CHIP_NO_ERROR);
402
- }
381
+ // no longer create groups here, but on a by-service basis in PublishService()
382
+ mInitCallback (mAsyncReturnContext , CHIP_NO_ERROR);
403
383
break ;
404
384
case AVAHI_CLIENT_FAILURE:
405
385
ChipLogError (DeviceLayer, " Avahi client failure" );
@@ -408,22 +388,8 @@ void MdnsAvahi::HandleClientState(AvahiClient * client, AvahiClientState state)
408
388
case AVAHI_CLIENT_S_COLLISION:
409
389
case AVAHI_CLIENT_S_REGISTERING:
410
390
ChipLogProgress (DeviceLayer, " Avahi re-register required" );
411
- if (mGroup != nullptr )
412
- {
413
- avahi_entry_group_reset (mGroup );
414
- avahi_entry_group_free (mGroup );
415
- }
416
- mGroup = avahi_entry_group_new (client, HandleGroupState, this );
417
- mPublishedServices .clear ();
418
- if (mGroup == nullptr )
419
- {
420
- ChipLogError (DeviceLayer, " Failed to create avahi group: %s" , avahi_strerror (avahi_client_errno (client)));
421
- mErrorCallback (mAsyncReturnContext , CHIP_ERROR_OPEN_FAILED);
422
- }
423
- else
424
- {
425
- mErrorCallback (mAsyncReturnContext , CHIP_ERROR_FORCED_RESET);
426
- }
391
+ StopPublish ();
392
+ mErrorCallback (mAsyncReturnContext , CHIP_ERROR_FORCED_RESET);
427
393
break ;
428
394
case AVAHI_CLIENT_CONNECTING:
429
395
ChipLogProgress (DeviceLayer, " Avahi connecting" );
@@ -449,7 +415,7 @@ void MdnsAvahi::HandleGroupState(AvahiEntryGroup * group, AvahiEntryGroupState s
449
415
break ;
450
416
case AVAHI_ENTRY_GROUP_FAILURE:
451
417
ChipLogError (DeviceLayer, " Avahi group internal failure %s" ,
452
- avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (mGroup ))));
418
+ avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (group ))));
453
419
mErrorCallback (mAsyncReturnContext , CHIP_ERROR_INTERNAL);
454
420
break ;
455
421
case AVAHI_ENTRY_GROUP_UNCOMMITED:
@@ -462,50 +428,130 @@ CHIP_ERROR MdnsAvahi::PublishService(const DnssdService & service, DnssdPublishC
462
428
{
463
429
std::ostringstream keyBuilder;
464
430
std::string key;
465
- std::string type = GetFullType (service.mType , service.mProtocol );
466
- CHIP_ERROR error = CHIP_NO_ERROR;
467
- AvahiStringList * text = nullptr ;
431
+ std::string type = GetFullType (service.mType , service.mProtocol );
432
+ std::string matterHostname;
433
+ CHIP_ERROR error = CHIP_NO_ERROR;
434
+ AvahiStringList * text = nullptr ;
435
+ AvahiEntryGroup * group = nullptr ;
436
+ const char * mainHostname = nullptr ;
468
437
AvahiIfIndex interface =
469
438
service.mInterface .IsPresent () ? static_cast <AvahiIfIndex>(service.mInterface .GetPlatformInterface ()) : AVAHI_IF_UNSPEC;
439
+ AvahiProtocol protocol = ToAvahiProtocol (service.mAddressType );
470
440
471
441
keyBuilder << service.mName << " ." << type << service.mPort << " ." << interface;
472
442
key = keyBuilder.str ();
473
443
ChipLogProgress (DeviceLayer, " PublishService %s" , key.c_str ());
474
-
475
- if (mPublishedServices . find (key) == mPublishedServices .end ())
444
+ auto publishedgroups_it = mPublishedGroups . find (key);
445
+ if (publishedgroups_it != mPublishedGroups .end ())
476
446
{
477
- SuccessOrExit (error = MakeAvahiStringListFromTextEntries (service.mTextEntries , service.mTextEntrySize , &text));
478
-
479
- mPublishedServices .emplace (key);
480
- VerifyOrExit (avahi_entry_group_add_service_strlst (mGroup , interface, ToAvahiProtocol (service.mAddressType ),
481
- static_cast <AvahiPublishFlags>(0 ), service.mName , type.c_str (), nullptr ,
482
- nullptr , service.mPort , text) == 0 ,
483
- error = CHIP_ERROR_INTERNAL);
484
- for (size_t i = 0 ; i < service.mSubTypeSize ; i++)
447
+ // same service was already published, we need to de-publish it first
448
+ int avahiRet = avahi_entry_group_free (publishedgroups_it->second );
449
+ if (avahiRet != AVAHI_OK)
485
450
{
486
- std::ostringstream sstream;
451
+ ChipLogError (DeviceLayer, " Cannot remove avahi group: %s" , avahi_strerror (avahiRet));
452
+ ExitNow (error = CHIP_ERROR_INTERNAL);
453
+ }
454
+ mPublishedGroups .erase (publishedgroups_it);
455
+ }
487
456
488
- sstream << service.mSubTypes [i] << " ._sub." << type;
457
+ // create fresh group
458
+ group = avahi_entry_group_new (mClient , HandleGroupState, this );
459
+ VerifyOrExit (group != nullptr , error = CHIP_ERROR_INTERNAL);
489
460
490
- VerifyOrExit (avahi_entry_group_add_service_subtype (mGroup , interface, ToAvahiProtocol (service.mAddressType ),
491
- static_cast <AvahiPublishFlags>(0 ), service.mName , type.c_str (),
492
- nullptr , sstream.str ().c_str ()) == 0 ,
493
- error = CHIP_ERROR_INTERNAL);
494
- }
461
+ // establish the host name (separately from avahi's default host name that the platform might have,
462
+ // unless it matches the matter hostname)
463
+ mainHostname = avahi_client_get_host_name (mClient );
464
+ if (strcmp (mainHostname, service.mHostName ) == 0 )
465
+ {
466
+ // main host name is correct, we can use it
467
+ matterHostname = std::string (mainHostname) + " .local" ;
495
468
}
496
469
else
497
470
{
498
- SuccessOrExit (error = MakeAvahiStringListFromTextEntries (service.mTextEntries , service.mTextEntrySize , &text));
471
+ // we need to establish a matter hostname separately from the platform's default hostname
472
+ char b[chip::Inet::IPAddress::kMaxStringLength ];
473
+ SuccessOrExit (error = service.mInterface .GetInterfaceName (b, chip::Inet::IPAddress::kMaxStringLength ));
474
+ ChipLogDetail (DeviceLayer, " Using addresses from interface id=%d name=%s" , service.mInterface .GetPlatformInterface (), b);
475
+ matterHostname = std::string (service.mHostName ) + " .local" ;
476
+ // find addresses to publish
477
+ for (chip::Inet::InterfaceAddressIterator addr_it; addr_it.HasCurrent (); addr_it.Next ())
478
+ {
479
+ // only specific interface?
480
+ if (service.mInterface .IsPresent () && addr_it.GetInterfaceId () != service.mInterface )
481
+ {
482
+ continue ;
483
+ }
484
+ if (addr_it.IsUp ())
485
+ {
486
+ if (addr_it.IsLoopback ())
487
+ {
488
+ // do not advertise loopback interface addresses
489
+ continue ;
490
+ }
491
+ chip::Inet::IPAddress addr;
492
+ if ((addr_it.GetAddress (addr) == CHIP_NO_ERROR) &&
493
+ ((service.mAddressType == chip::Inet::IPAddressType::kAny ) ||
494
+ (addr.IsIPv6 () && service.mAddressType == chip::Inet::IPAddressType::kIPv6 )
495
+ #if INET_CONFIG_ENABLE_IPV4
496
+ || (addr.IsIPv4 () && service.mAddressType == chip::Inet::IPAddressType::kIPv4 )
497
+ #endif
498
+ ))
499
+ {
500
+ VerifyOrExit (addr.ToString (b) != nullptr , error = CHIP_ERROR_INTERNAL);
501
+ AvahiAddress a;
502
+ VerifyOrExit (avahi_address_parse (b, AVAHI_PROTO_UNSPEC, &a) != nullptr , error = CHIP_ERROR_INTERNAL);
503
+ AvahiIfIndex thisinterface = static_cast <AvahiIfIndex>(addr_it.GetInterfaceId ().GetPlatformInterface ());
504
+ // Note: NO_REVERSE publish flag is needed because otherwise we can't have more than one hostname
505
+ // for reverse resolving IP addresses back to hostnames
506
+ VerifyOrExit (avahi_entry_group_add_address (group, // group
507
+ thisinterface, // interface
508
+ ToAvahiProtocol (addr.Type ()), // protocol
509
+ AVAHI_PUBLISH_NO_REVERSE, // publish flags
510
+ matterHostname.c_str (), // hostname
511
+ &a // address
512
+ ) == 0 ,
513
+ error = CHIP_ERROR_INTERNAL);
514
+ }
515
+ }
516
+ }
517
+ }
499
518
500
- VerifyOrExit (avahi_entry_group_update_service_txt_strlst (mGroup , interface, ToAvahiProtocol (service.mAddressType ),
501
- static_cast <AvahiPublishFlags>(0 ), service.mName , type.c_str (),
502
- nullptr , text) == 0 ,
519
+ // create the service
520
+ SuccessOrExit (error = MakeAvahiStringListFromTextEntries (service.mTextEntries , service.mTextEntrySize , &text));
521
+
522
+ VerifyOrExit (avahi_entry_group_add_service_strlst (group, interface, protocol, // group, interface, protocol
523
+ static_cast <AvahiPublishFlags>(0 ), // publish flags
524
+ service.mName , // service name
525
+ type.c_str (), // type
526
+ nullptr , // domain
527
+ matterHostname.c_str (), // host
528
+ service.mPort , // port
529
+ text) == 0 , // TXT records StringList
530
+ error = CHIP_ERROR_INTERNAL);
531
+
532
+ // add the subtypes
533
+ for (size_t i = 0 ; i < service.mSubTypeSize ; i++)
534
+ {
535
+ std::ostringstream sstream;
536
+
537
+ sstream << service.mSubTypes [i] << " ._sub." << type;
538
+
539
+ VerifyOrExit (avahi_entry_group_add_service_subtype (group, interface, protocol, static_cast <AvahiPublishFlags>(0 ),
540
+ service.mName , type.c_str (), nullptr , sstream.str ().c_str ()) == 0 ,
503
541
error = CHIP_ERROR_INTERNAL);
504
542
}
543
+ VerifyOrExit (avahi_entry_group_commit (group) == 0 , error = CHIP_ERROR_INTERNAL);
505
544
506
- VerifyOrExit (avahi_entry_group_commit (mGroup ) == 0 , error = CHIP_ERROR_INTERNAL);
545
+ // group is now published, pass it to the service map
546
+ mPublishedGroups [key] = group;
547
+ group = nullptr ;
507
548
508
549
exit :
550
+ if (group != nullptr )
551
+ {
552
+ avahi_entry_group_free (group);
553
+ }
554
+
509
555
if (text != nullptr )
510
556
{
511
557
avahi_string_list_free (text);
@@ -521,6 +567,8 @@ CHIP_ERROR MdnsAvahi::PublishService(const DnssdService & service, DnssdPublishC
521
567
}
522
568
else
523
569
{
570
+ ChipLogError (DeviceLayer, " PublishService failed: %s" ,
571
+ mClient ? avahi_strerror (avahi_client_errno (mClient )) : " no mClient" );
524
572
callback (context, nullptr , nullptr , error);
525
573
}
526
574
@@ -530,12 +578,19 @@ CHIP_ERROR MdnsAvahi::PublishService(const DnssdService & service, DnssdPublishC
530
578
CHIP_ERROR MdnsAvahi::StopPublish ()
531
579
{
532
580
CHIP_ERROR error = CHIP_NO_ERROR;
533
- mPublishedServices .clear ();
534
- if (mGroup )
581
+ for (const auto & group : mPublishedGroups )
535
582
{
536
- VerifyOrExit (avahi_entry_group_reset (mGroup ) == 0 , error = CHIP_ERROR_INTERNAL);
583
+ if (group.second )
584
+ {
585
+ int avahiRet = avahi_entry_group_free (group.second );
586
+ if (avahiRet != AVAHI_OK)
587
+ {
588
+ ChipLogError (DeviceLayer, " Error freeing avahi group: %s" , avahi_strerror (avahiRet));
589
+ error = CHIP_ERROR_INTERNAL;
590
+ }
591
+ }
537
592
}
538
- exit :
593
+ mPublishedGroups . clear ();
539
594
return error;
540
595
}
541
596
0 commit comments