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: Allow multiple operational advertisements #8610

Merged
merged 18 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 73 additions & 18 deletions src/lib/mdns/Advertiser_ImplMinimalMdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
AdvertiserMinMdns() : mResponseSender(&GlobalMinimalMdnsServer::Server())
{
GlobalMinimalMdnsServer::Instance().SetQueryDelegate(this);
mResponseSender.AddQueryResponder(mQueryResponderAllocatorOperational.GetQueryResponder());
for (auto & allocator : mQueryResponderAllocatorOperational)
{
mResponseSender.AddQueryResponder(allocator.GetQueryResponder());
}
mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissionable.GetQueryResponder());
mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissioner.GetQueryResponder());
}
Expand Down Expand Up @@ -139,13 +142,17 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
FullQName GetCommisioningTextEntries(const CommissionAdvertisingParameters & params);

// Max number of records for operational = PTR, SRV, TXT, A, AAAA, no subtypes.
static constexpr size_t kMaxOperationalRecords = 5;
QueryResponderAllocator<kMaxOperationalRecords> mQueryResponderAllocatorOperational;
static constexpr size_t kMaxOperationalRecords = 5;
static constexpr size_t kMaxOperationalNetworks = 5;
QueryResponderAllocator<kMaxOperationalRecords> mQueryResponderAllocatorOperational[kMaxOperationalNetworks];
// 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;

QueryResponderAllocator<kMaxOperationalRecords> * FindOperationalAllocator(const FullQName & qname);
QueryResponderAllocator<kMaxOperationalRecords> * FindEmptyOperationalAllocator();

ResponseSender mResponseSender;
uint32_t mCommissionInstanceName1;
uint32_t mCommissionInstanceName2;
Expand Down Expand Up @@ -209,36 +216,79 @@ CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t
/// Stops the advertiser.
CHIP_ERROR AdvertiserMinMdns::StopPublishDevice()
{
mQueryResponderAllocatorOperational.Clear();
for (auto & allocator : mQueryResponderAllocatorOperational)
{
allocator.Clear();
}
mQueryResponderAllocatorCommissionable.Clear();
mQueryResponderAllocatorCommissioner.Clear();
return CHIP_NO_ERROR;
}

QueryResponderAllocator<AdvertiserMinMdns::kMaxOperationalRecords> *
AdvertiserMinMdns::FindOperationalAllocator(const FullQName & qname)
{
for (auto & allocator : mQueryResponderAllocatorOperational)
{
if (allocator.GetResponder(QType::SRV, qname) != nullptr)
{
return &allocator;
}
}
return nullptr;
}

QueryResponderAllocator<AdvertiserMinMdns::kMaxOperationalRecords> * AdvertiserMinMdns::FindEmptyOperationalAllocator()
{
for (auto & allocator : mQueryResponderAllocatorOperational)
{
if (allocator.IsEmpty())
{
return &allocator;
}
}
return nullptr;
}

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

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

QNamePart nameCheckParts[] = { nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain };
FullQName nameCheck = FullQName(nameCheckParts);
QueryResponderAllocator<AdvertiserMinMdns::kMaxOperationalRecords> * operationalAllocator = FindOperationalAllocator(nameCheck);
cecille marked this conversation as resolved.
Show resolved Hide resolved
if (operationalAllocator != nullptr)
{
operationalAllocator->Clear();
}
else
{
operationalAllocator = FindEmptyOperationalAllocator();
if (operationalAllocator == nullptr)
{
ChipLogError(Discovery, "Failed to find an open operational allocator");
return CHIP_ERROR_NO_MEMORY;
}
}

FullQName operationalServiceName =
mQueryResponderAllocatorOperational.AllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
operationalAllocator->AllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
FullQName operationalServerName =
mQueryResponderAllocatorOperational.AllocateQName(nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain);
operationalAllocator->AllocateQName(nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain);

ReturnErrorOnFailure(MakeHostName(nameBuffer, sizeof(nameBuffer), params.GetMac()));
FullQName serverName = mQueryResponderAllocatorOperational.AllocateQName(nameBuffer, kLocalDomain);
FullQName serverName = operationalAllocator->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 (!mQueryResponderAllocatorOperational.AddResponder<PtrResponder>(operationalServiceName, operationalServerName)
if (!operationalAllocator->AddResponder<PtrResponder>(operationalServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
Expand All @@ -247,31 +297,30 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters &
return CHIP_ERROR_NO_MEMORY;
}

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

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

if (params.IsIPv4Enabled())
{
if (!mQueryResponderAllocatorOperational.AddResponder<IPv4Responder>(serverName).IsValid())
if (!operationalAllocator->AddResponder<IPv4Responder>(serverName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
Expand Down Expand Up @@ -650,7 +699,10 @@ void AdvertiserMinMdns::AdvertiseRecords()
QueryData queryData(QType::PTR, QClass::IN, false /* unicast */);
queryData.SetIsBootAdvertising(true);

mQueryResponderAllocatorOperational.GetQueryResponder()->ClearBroadcastThrottle();
for (auto & allocator : mQueryResponderAllocatorOperational)
{
allocator.GetQueryResponder()->ClearBroadcastThrottle();
}
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();

Expand All @@ -662,7 +714,10 @@ void AdvertiserMinMdns::AdvertiseRecords()
}

// Once all automatic broadcasts are done, allow immediate replies once.
mQueryResponderAllocatorOperational.GetQueryResponder()->ClearBroadcastThrottle();
for (auto & allocator : mQueryResponderAllocatorOperational)
{
allocator.GetQueryResponder()->ClearBroadcastThrottle();
}
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
}
Expand Down
78 changes: 54 additions & 24 deletions src/lib/mdns/Advertiser_ImplMinimalMdnsAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ class QueryResponderAllocator
public:
QueryResponderAllocator()
{
for (size_t i = 0; i < kMaxRecords; i++)
for (auto & responder : mAllocatedResponders)
{
mAllocatedResponders[i] = nullptr;
responder = nullptr;
}
for (size_t i = 0; i < kMaxAllocatedQNameData; i++)
for (auto & name : mAllocatedQNameParts)
{
mAllocatedQNameParts[i] = nullptr;
name = nullptr;
}
}
~QueryResponderAllocator() { Clear(); }
Expand Down Expand Up @@ -84,25 +84,55 @@ class QueryResponderAllocator
mQueryResponder.Init();

// Free all allocated data
for (size_t i = 0; i < kMaxRecords; i++)
for (auto & responder : mAllocatedResponders)
{
if (mAllocatedResponders[i] != nullptr)
if (responder != nullptr)
{
chip::Platform::Delete(mAllocatedResponders[i]);
mAllocatedResponders[i] = nullptr;
chip::Platform::Delete(responder);
responder = nullptr;
}
}

for (size_t i = 0; i < kMaxAllocatedQNameData; i++)
for (auto & name : mAllocatedQNameParts)
{
if (mAllocatedQNameParts[i] != nullptr)
if (name != nullptr)
{
chip::Platform::MemoryFree(mAllocatedQNameParts[i]);
mAllocatedQNameParts[i] = nullptr;
chip::Platform::MemoryFree(name);
name = nullptr;
}
}
}
mdns::Minimal::QueryResponder<kMaxRecords + 1> * GetQueryResponder() { return &mQueryResponder; }
const mdns::Minimal::RecordResponder * GetResponder(const mdns::Minimal::QType & qtype,
const mdns::Minimal::FullQName & qname) const
{
for (auto & responder : mAllocatedResponders)
{
if (responder != nullptr && responder->GetQType() == qtype && responder->GetQName() == qname)
{
return responder;
}
}
return nullptr;
}
bool IsEmpty() const
{
for (auto & responder : mAllocatedResponders)
{
if (responder != nullptr)
{
return false;
}
}
for (auto & name : mAllocatedQNameParts)
{
if (name != nullptr)
{
return false;
}
}
return true;
}

protected:
// For testing.
Expand All @@ -118,45 +148,45 @@ class QueryResponderAllocator
// The QueryResponder needs 1 extra space to hold the record for itself.
mdns::Minimal::QueryResponder<kMaxRecords + 1> mQueryResponder;

mdns::Minimal::QueryResponderSettings AddAllocatedResponder(mdns::Minimal::RecordResponder * responder)
mdns::Minimal::QueryResponderSettings AddAllocatedResponder(mdns::Minimal::RecordResponder * newResponder)
{
if (responder == nullptr)
if (newResponder == nullptr)
{
ChipLogError(Discovery, "Responder memory allocation failed");
return mdns::Minimal::QueryResponderSettings(); // failed
}

for (size_t i = 0; i < kMaxRecords; i++)
for (auto & responder : mAllocatedResponders)
{
if (mAllocatedResponders[i] != nullptr)
if (responder != nullptr)
{
continue;
}

mAllocatedResponders[i] = responder;
return mQueryResponder.AddResponder(mAllocatedResponders[i]);
responder = newResponder;
return mQueryResponder.AddResponder(responder);
}

Platform::Delete(responder);
Platform::Delete(newResponder);
ChipLogError(Discovery, "Failed to find free slot for adding a responder");
return mdns::Minimal::QueryResponderSettings();
}

void * AllocateQNameSpace(size_t size)
{
for (size_t i = 0; i < kMaxAllocatedQNameData; i++)
for (auto & name : mAllocatedQNameParts)
{
if (mAllocatedQNameParts[i] != nullptr)
if (name != nullptr)
{
continue;
}

mAllocatedQNameParts[i] = chip::Platform::MemoryAlloc(size);
if (mAllocatedQNameParts[i] == nullptr)
name = chip::Platform::MemoryAlloc(size);
if (name == nullptr)
{
ChipLogError(Discovery, "QName memory allocation failed");
}
return mAllocatedQNameParts[i];
return name;
}
ChipLogError(Discovery, "Failed to find free slot for adding a qname");
return nullptr;
Expand Down
25 changes: 25 additions & 0 deletions src/lib/mdns/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import("//build_overrides/chip.gni")
import("//build_overrides/nlunit_test.gni")
import("${chip_root}/src/platform/device.gni")

source_set("platform_header") {
Expand Down Expand Up @@ -58,3 +59,27 @@ static_library("mdns") {
assert(false, "Unknown mDNS advertiser implementation.")
}
}

static_library("minimal_mdns_tests") {
cecille marked this conversation as resolved.
Show resolved Hide resolved
public_deps = [
":platform_header",
"${chip_root}/src/lib/core",
"${chip_root}/src/lib/support",
]
defines = [ "MDNS_MINIMAL_TEST_SERVER=true" ]
sources = [
"Advertiser.h",
"Advertiser_ImplMinimalMdns.cpp",
"MinimalMdnsServer.cpp",
"MinimalMdnsServer.h",
"Resolver.h",
"ServiceNaming.cpp",
"ServiceNaming.h",
"TxtFields.cpp",
"TxtFields.h",
]
public_deps += [
"${chip_root}/src/lib/mdns/minimal",
"${nlunit_test_root}:nlunit-test",
]
}
7 changes: 7 additions & 0 deletions src/lib/mdns/MinimalMdnsServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/

#include <mdns/minimal/Server.h>
#ifdef MDNS_MINIMAL_TEST_SERVER
cecille marked this conversation as resolved.
Show resolved Hide resolved
#include <mdns/minimal/tests/CheckOnlyServer.h>
#endif

namespace chip {
namespace Mdns {
Expand Down Expand Up @@ -71,7 +74,11 @@ class GlobalMinimalMdnsServer : public mdns::Minimal::ServerDelegate
public:
static constexpr size_t kMaxEndPoints = 30;

#ifdef MDNS_MINIMAL_TEST_SERVER
using ServerType = mdns::Minimal::test::CheckOnlyServer;
#else
using ServerType = mdns::Minimal::Server<kMaxEndPoints>;
#endif

GlobalMinimalMdnsServer() { mServer.SetDelegate(this); }

Expand Down
4 changes: 1 addition & 3 deletions src/lib/mdns/ServiceNaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ uint8_t HexToInt(char c)

CHIP_ERROR MakeInstanceName(char * buffer, size_t bufferLen, const PeerId & peerId)
{
constexpr size_t kServiceNameLen = 16 + 1 + 16; // 2 * 64-bit value in HEX + hyphen

ReturnErrorCodeIf(bufferLen <= kServiceNameLen, CHIP_ERROR_BUFFER_TOO_SMALL);
ReturnErrorCodeIf(bufferLen <= kOperationalServiceNamePrefix, CHIP_ERROR_BUFFER_TOO_SMALL);

NodeId nodeId = peerId.GetNodeId();
FabricId fabricId = peerId.GetFabricId();
Expand Down
Loading