Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mdns: separate query responders for advertisers #7615

Merged
123 changes: 78 additions & 45 deletions src/lib/mdns/Advertiser_ImplMinimalMdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
public ParserDelegate // parses queries
{
public:
AdvertiserMinMdns() : mResponseSender(&GlobalMinimalMdnsServer::Server(), mQueryResponderAllocator.GetQueryResponder())
AdvertiserMinMdns() : mResponseSender(&GlobalMinimalMdnsServer::Server())
{
GlobalMinimalMdnsServer::Instance().SetQueryDelegate(this);
mResponseSender.AddQueryResponder(mQueryResponderAllocatorOperational.GetQueryResponder());
mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissionable.GetQueryResponder());
mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissioner.GetQueryResponder());
}
~AdvertiserMinMdns() {}

Expand Down Expand Up @@ -134,8 +137,13 @@ class AdvertiserMinMdns : public ServiceAdvertiser,

FullQName GetCommisioningTextEntries(const CommissionAdvertisingParameters & params);

static constexpr size_t kMaxRecords = 32;
QueryResponderAllocator<kMaxRecords> mQueryResponderAllocator;
// Max number of records for operational = PTR, SRV, TXT, A, AAAA, no subtypes.
static constexpr size_t kMaxOperationalRecords = 5;
QueryResponderAllocator<kMaxOperationalRecords> mQueryResponderAllocatorOperational;
// Max number of records for commissionable = 7 x PTR (base + 6 sub types - _S, _L, _D, _T, _C, _A), SRV, TXT, A, AAAA
static constexpr size_t kMaxCommissionRecords = 11;
QueryResponderAllocator<kMaxCommissionRecords> mQueryResponderAllocatorCommissionable;
QueryResponderAllocator<kMaxCommissionRecords> mQueryResponderAllocatorCommissioner;

ResponseSender mResponseSender;

Expand Down Expand Up @@ -195,33 +203,36 @@ CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t
/// Stops the advertiser.
CHIP_ERROR AdvertiserMinMdns::StopPublishDevice()
{
mQueryResponderAllocator.Clear();
mQueryResponderAllocatorOperational.Clear();
mQueryResponderAllocatorCommissionable.Clear();
mQueryResponderAllocatorCommissioner.Clear();
return CHIP_NO_ERROR;
}

CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & params)
{
mQueryResponderAllocator.Clear();
// TODO: When multi-admin is enabled, commissionable does not need to be cleared here.
mQueryResponderAllocatorOperational.Clear();
char nameBuffer[64] = "";

/// need to set server name
ReturnErrorOnFailure(MakeInstanceName(nameBuffer, sizeof(nameBuffer), params.GetPeerId()));

FullQName operationalServiceName =
mQueryResponderAllocator.AllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
mQueryResponderAllocatorOperational.AllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
FullQName operationalServerName =
mQueryResponderAllocator.AllocateQName(nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain);
mQueryResponderAllocatorOperational.AllocateQName(nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain);

ReturnErrorOnFailure(MakeHostName(nameBuffer, sizeof(nameBuffer), params.GetMac()));
FullQName serverName = mQueryResponderAllocator.AllocateQName(nameBuffer, kLocalDomain);
FullQName serverName = mQueryResponderAllocatorOperational.AllocateQName(nameBuffer, kLocalDomain);

if ((operationalServiceName.nameCount == 0) || (operationalServerName.nameCount == 0) || (serverName.nameCount == 0))
{
ChipLogError(Discovery, "Failed to allocate QNames.");
return CHIP_ERROR_NO_MEMORY;
}

if (!mQueryResponderAllocator.AddResponder<PtrResponder>(operationalServiceName, operationalServerName)
if (!mQueryResponderAllocatorOperational.AddResponder<PtrResponder>(operationalServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -230,30 +241,31 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters &
return CHIP_ERROR_NO_MEMORY;
}

if (!mQueryResponderAllocator.AddResponder<SrvResponder>(SrvResourceRecord(operationalServerName, serverName, params.GetPort()))
if (!mQueryResponderAllocatorOperational
.AddResponder<SrvResponder>(SrvResourceRecord(operationalServerName, serverName, params.GetPort()))
.SetReportAdditional(serverName)
.IsValid())
{
ChipLogError(Discovery, "Failed to add SRV record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
if (!mQueryResponderAllocator.AddResponder<TxtResponder>(TxtResourceRecord(operationalServerName, mEmptyTextEntries))
if (!mQueryResponderAllocatorOperational.AddResponder<TxtResponder>(TxtResourceRecord(operationalServerName, mEmptyTextEntries))
.SetReportAdditional(serverName)
.IsValid())
{
ChipLogError(Discovery, "Failed to add TXT record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

if (!mQueryResponderAllocator.AddResponder<IPv6Responder>(serverName).IsValid())
if (!mQueryResponderAllocatorOperational.AddResponder<IPv6Responder>(serverName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv6 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

if (params.IsIPv4Enabled())
{
if (!mQueryResponderAllocator.AddResponder<IPv4Responder>(serverName).IsValid())
if (!mQueryResponderAllocatorOperational.AddResponder<IPv4Responder>(serverName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
Expand All @@ -267,30 +279,43 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters &

CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & params)
{
mQueryResponderAllocator.Clear();
// TODO: When multi-admin is enabled, operational does not need to be cleared here.
if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
{
mQueryResponderAllocatorCommissionable.Clear();
}
else
{
mQueryResponderAllocatorCommissioner.Clear();
}

// TODO: need to detect colisions here
char nameBuffer[64] = "";
size_t len = snprintf(nameBuffer, sizeof(nameBuffer), ChipLogFormatX64, GetRandU32(), GetRandU32());
if (len >= sizeof(nameBuffer))
{
return CHIP_ERROR_NO_MEMORY;
}
QueryResponderAllocator<kMaxCommissionRecords> * allocator =
params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode ? &mQueryResponderAllocatorCommissionable
: &mQueryResponderAllocatorCommissioner;
const char * serviceType = params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode
? kCommissionableServiceName
: kCommissionerServiceName;
FullQName serviceName = mQueryResponderAllocator.AllocateQName(serviceType, kCommissionProtocol, kLocalDomain);
FullQName instanceName = mQueryResponderAllocator.AllocateQName(nameBuffer, serviceType, kCommissionProtocol, kLocalDomain);

FullQName serviceName = allocator->AllocateQName(serviceType, kCommissionProtocol, kLocalDomain);
FullQName instanceName = allocator->AllocateQName(nameBuffer, serviceType, kCommissionProtocol, kLocalDomain);

ReturnErrorOnFailure(MakeHostName(nameBuffer, sizeof(nameBuffer), params.GetMac()));
FullQName hostName = mQueryResponderAllocator.AllocateQName(nameBuffer, kLocalDomain);
FullQName hostName = allocator->AllocateQName(nameBuffer, kLocalDomain);

if ((serviceName.nameCount == 0) || (instanceName.nameCount == 0) || (hostName.nameCount == 0))
{
ChipLogError(Discovery, "Failed to allocate QNames.");
return CHIP_ERROR_NO_MEMORY;
}

if (!mQueryResponderAllocator.AddResponder<PtrResponder>(serviceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(serviceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -299,22 +324,22 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
return CHIP_ERROR_NO_MEMORY;
}

if (!mQueryResponderAllocator.AddResponder<SrvResponder>(SrvResourceRecord(instanceName, hostName, params.GetPort()))
if (!allocator->AddResponder<SrvResponder>(SrvResourceRecord(instanceName, hostName, params.GetPort()))
.SetReportAdditional(hostName)
.IsValid())
{
ChipLogError(Discovery, "Failed to add SRV record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
if (!mQueryResponderAllocator.AddResponder<IPv6Responder>(hostName).IsValid())
if (!allocator->AddResponder<IPv6Responder>(hostName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv6 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

if (params.IsIPv4Enabled())
{
if (!mQueryResponderAllocator.AddResponder<IPv4Responder>(hostName).IsValid())
if (!allocator->AddResponder<IPv4Responder>(hostName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
Expand All @@ -325,11 +350,11 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kVendor, params.GetVendorId().Value()));
FullQName vendorServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName vendorServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);

if (!mQueryResponderAllocator.AddResponder<PtrResponder>(vendorServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(vendorServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -343,11 +368,11 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kDeviceType, params.GetDeviceType().Value()));
FullQName vendorServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName vendorServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);

if (!mQueryResponderAllocator.AddResponder<PtrResponder>(vendorServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(vendorServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -363,11 +388,11 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kShort, params.GetShortDiscriminator()));
FullQName shortServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName shortServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(shortServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);

if (!mQueryResponderAllocator.AddResponder<PtrResponder>(shortServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(shortServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -380,10 +405,10 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kLong, params.GetLongDiscriminator()));
FullQName longServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName longServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);
if (!mQueryResponderAllocator.AddResponder<PtrResponder>(longServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(longServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -396,10 +421,10 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kCommissioningMode, params.GetCommissioningMode() ? 1 : 0));
FullQName longServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName longServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);
if (!mQueryResponderAllocator.AddResponder<PtrResponder>(longServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(longServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -413,10 +438,10 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
{
MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
DiscoveryFilter(DiscoveryFilterType::kCommissioningModeFromCommand, 1));
FullQName longServiceName = mQueryResponderAllocator.AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType,
kCommissionProtocol, kLocalDomain);
FullQName longServiceName =
allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);
if (!mQueryResponderAllocator.AddResponder<PtrResponder>(longServiceName, instanceName)
if (!allocator->AddResponder<PtrResponder>(longServiceName, instanceName)
.SetReportAdditional(instanceName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -427,7 +452,7 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters &
}
}

if (!mQueryResponderAllocator.AddResponder<TxtResponder>(TxtResourceRecord(instanceName, GetCommisioningTextEntries(params)))
if (!allocator->AddResponder<TxtResponder>(TxtResourceRecord(instanceName, GetCommisioningTextEntries(params)))
.SetReportAdditional(hostName)
.IsValid())
{
Expand All @@ -454,6 +479,10 @@ FullQName AdvertiserMinMdns::GetCommisioningTextEntries(const CommissionAdvertis
const char * txtFields[kMaxTxtFields];
size_t numTxtFields = 0;

QueryResponderAllocator<kMaxCommissionRecords> * allocator =
params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode ? &mQueryResponderAllocatorCommissionable
: &mQueryResponderAllocatorCommissioner;

char txtVidPid[chip::Mdns::kKeyVendorProductMaxLength + 4];
if (params.GetProductId().HasValue() && params.GetVendorId().HasValue())
{
Expand Down Expand Up @@ -490,7 +519,7 @@ FullQName AdvertiserMinMdns::GetCommisioningTextEntries(const CommissionAdvertis

if (!params.GetVendorId().HasValue())
{
return mQueryResponderAllocator.AllocateQName(txtDiscriminator);
return allocator->AllocateQName(txtDiscriminator);
}

char txtCommissioningMode[chip::Mdns::kKeyCommissioningModeMaxLength + 4];
Expand Down Expand Up @@ -527,11 +556,11 @@ FullQName AdvertiserMinMdns::GetCommisioningTextEntries(const CommissionAdvertis
}
if (numTxtFields == 0)
{
return mQueryResponderAllocator.AllocateQNameFromArray(mEmptyTextEntries, 1);
return allocator->AllocateQNameFromArray(mEmptyTextEntries, 1);
}
else
{
return mQueryResponderAllocator.AllocateQNameFromArray(txtFields, numTxtFields);
return allocator->AllocateQNameFromArray(txtFields, numTxtFields);
}
} // namespace

Expand Down Expand Up @@ -603,7 +632,9 @@ void AdvertiserMinMdns::AdvertiseRecords()
QueryData queryData(QType::PTR, QClass::IN, false /* unicast */);
queryData.SetIsBootAdvertising(true);

mQueryResponderAllocator.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorOperational.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();

CHIP_ERROR err = mResponseSender.Respond(0, queryData, &packetInfo);
if (err != CHIP_NO_ERROR)
Expand All @@ -613,7 +644,9 @@ void AdvertiserMinMdns::AdvertiseRecords()
}

// Once all automatic broadcasts are done, allow immediate replies once.
mQueryResponderAllocator.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorOperational.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
}

AdvertiserMinMdns gAdvertiser;
Expand Down
Loading