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

Switch minmdns to use a single listening socket #27219

Closed
4 changes: 2 additions & 2 deletions examples/minimal-mdns/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class QuerySplitter
std::vector<std::string> mStorage;
};

void BroadcastPacket(mdns::Minimal::ServerBase * server)
void BroadcastPacket(mdns::Minimal::Server * server)
{
System::PacketBufferHandle buffer = System::PacketBufferHandle::New(kMdnsMaxPacketSize);
VerifyOrDie(!buffer.IsNull());
Expand Down Expand Up @@ -295,7 +295,7 @@ void BroadcastPacket(mdns::Minimal::ServerBase * server)
}
}

mdns::Minimal::Server<20> gMdnsServer;
mdns::Minimal::Server gMdnsServer;

} // namespace

Expand Down
2 changes: 1 addition & 1 deletion examples/minimal-mdns/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class ReplyDelegate : public mdns::Minimal::ServerDelegate, public mdns::Minimal
uint16_t mMessageId = 0;
};

mdns::Minimal::Server<10 /* endpoints */> gMdnsServer;
mdns::Minimal::Server gMdnsServer;

void StopSignalHandler(int signal)
{
Expand Down
170 changes: 79 additions & 91 deletions src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,8 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
/// removes all records by advertising a 0 TTL)
void AdvertiseRecords(BroadcastAdvertiseType type);

/// Determine if advertisement on the specified interface/address is ok given the
/// interfaces on which the mDNS server is listening
bool ShouldAdvertiseOn(const chip::Inet::InterfaceId id, const chip::Inet::IPAddress & addr);
// Clears the internal broadcast throttle
void ResetBroadcastThrottle();

FullQName GetCommissioningTxtEntries(const CommissionAdvertisingParameters & params);
FullQName GetOperationalTxtEntries(OperationalQueryAllocator::Allocator * allocator,
Expand Down Expand Up @@ -300,6 +299,34 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
};
};

/// Finds the first ip address of the given address type on the given interface
CHIP_ERROR GetFirstIpAddress(Inet::InterfaceId interfaceId, Inet::IPAddressType addressType, Inet::IPAddress & address)
{
UniquePtr<IpAddressIterator> allIps = GetAddressPolicy()->GetIpAddressesForEndpoint(interfaceId, addressType);

if (!allIps)
{
return CHIP_ERROR_NOT_FOUND;
}

if (!allIps->Next(address))
{
return CHIP_ERROR_NOT_FOUND;
}

return CHIP_NO_ERROR;
}

void AdvertiserMinMdns::ResetBroadcastThrottle()
{
for (auto & it : mOperationalResponders)
{
it.GetAllocator()->GetQueryResponder()->ClearBroadcastThrottle();
}
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
}

void AdvertiserMinMdns::OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info)
{
#ifdef DETAIL_LOGGING
Expand Down Expand Up @@ -856,35 +883,6 @@ FullQName AdvertiserMinMdns::GetCommissioningTxtEntries(const CommissionAdvertis
return allocator->AllocateQNameFromArray(txtFields, numTxtFields);
}

bool AdvertiserMinMdns::ShouldAdvertiseOn(const chip::Inet::InterfaceId id, const chip::Inet::IPAddress & addr)
{
auto & server = GlobalMinimalMdnsServer::Server();

bool result = false;

server.ForEachEndPoints([&](auto * info) {
if (info->mListenUdp == nullptr)
{
return chip::Loop::Continue;
}

if (info->mInterfaceId != id)
{
return chip::Loop::Continue;
}

if (info->mAddressType != addr.Type())
{
return chip::Loop::Continue;
}

result = true;
return chip::Loop::Break;
});

return result;
}

void AdvertiserMinMdns::AdvertiseRecords(BroadcastAdvertiseType type)
{
ResponseConfiguration responseConfiguration;
Expand All @@ -902,73 +900,63 @@ void AdvertiserMinMdns::AdvertiseRecords(BroadcastAdvertiseType type)

while (allInterfaces->Next(&interfaceId, &addressType))
{
UniquePtr<IpAddressIterator> allIps = GetAddressPolicy()->GetIpAddressesForEndpoint(interfaceId, addressType);
VerifyOrDieWithMsg(allIps != nullptr, Discovery, "Failed to allocate memory for ip addresses.");
chip::Inet::IPPacketInfo packetInfo;

Inet::IPAddress ipAddress;
while (allIps->Next(ipAddress))
{
if (!ShouldAdvertiseOn(interfaceId, ipAddress))
{
continue;
}
packetInfo.Clear();

chip::Inet::IPPacketInfo packetInfo;
// Attempt to get a "Real" IP address since `Type()` on a broadcast address
// always returns IPAddressType::kAny
CHIP_ERROR err = GetFirstIpAddress(interfaceId, addressType, packetInfo.SrcAddress);

packetInfo.Clear();
packetInfo.SrcAddress = ipAddress;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (ipAddress.IsIPv4())
{
BroadcastIpAddresses::GetIpv4Into(packetInfo.DestAddress);
}
else
{
BroadcastIpAddresses::GetIpv6Into(packetInfo.DestAddress);
}
packetInfo.SrcPort = kMdnsPort;
packetInfo.DestPort = kMdnsPort;
packetInfo.Interface = interfaceId;

// Advertise all records
//
// TODO: Consider advertising delta changes.
//
// Current advertisement does not have a concept of "delta" to only
// advertise changes. Current implementation is to always
// 1. advertise TTL=0 (clear all caches)
// 2. advertise available records (with longer TTL)
//
// It would be nice if we could selectively advertise what changes, like
// send TTL=0 for anything removed/about to be removed (and only those),
// then only advertise new items added.
//
// This optimization likely will take more logic and state storage, so
// for now it is not done.
QueryData queryData(QType::PTR, QClass::IN, false /* unicast */);
queryData.SetIsInternalBroadcast(true);

for (auto & it : mOperationalResponders)
{
it.GetAllocator()->GetQueryResponder()->ClearBroadcastThrottle();
}
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
if (err != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to find a suitable IP address to advertise: %" CHIP_ERROR_FORMAT, err.Format());
continue;
}

CHIP_ERROR err = mResponseSender.Respond(0, queryData, &packetInfo, responseConfiguration);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to advertise records: %" CHIP_ERROR_FORMAT, err.Format());
}
#if INET_CONFIG_ENABLE_IPV4
if (addressType == chip::Inet::IPAddressType::kIPv4)
{
BroadcastIpAddresses::GetIpv4Into(packetInfo.DestAddress);
}
else
#endif // INET_CONFIG_ENABLE_IPV4
{
BroadcastIpAddresses::GetIpv6Into(packetInfo.DestAddress);
}
packetInfo.SrcPort = kMdnsPort;
packetInfo.DestPort = kMdnsPort;
packetInfo.Interface = interfaceId;

// Advertise all records
//
// TODO: Consider advertising delta changes.
//
// Current advertisement does not have a concept of "delta" to only
// advertise changes. Current implementation is to always
// 1. advertise TTL=0 (clear all caches)
// 2. advertise available records (with longer TTL)
//
// It would be nice if we could selectively advertise what changes, like
// send TTL=0 for anything removed/about to be removed (and only those),
// then only advertise new items added.
//
// This optimization likely will take more logic and state storage, so
// for now it is not done.
QueryData queryData(QType::PTR, QClass::IN, false /* unicast */);
queryData.SetIsInternalBroadcast(true);

ResetBroadcastThrottle();

err = mResponseSender.Respond(0, queryData, &packetInfo, responseConfiguration);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to advertise records: %" CHIP_ERROR_FORMAT, err.Format());
}
}

// Once all automatic broadcasts are done, allow immediate replies once.
for (auto & it : mOperationalResponders)
{
it.GetAllocator()->GetQueryResponder()->ClearBroadcastThrottle();
}
mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
ResetBroadcastThrottle();
}

AdvertiserMinMdns gAdvertiser;
Expand Down
14 changes: 6 additions & 8 deletions src/lib/dnssd/MinimalMdnsServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ class MdnsPacketDelegate
class GlobalMinimalMdnsServer : public mdns::Minimal::ServerDelegate
{
public:
static constexpr size_t kMaxEndPoints = 30;

using ServerType = mdns::Minimal::Server<kMaxEndPoints>;
using ServerType = mdns::Minimal::Server;

GlobalMinimalMdnsServer();

static GlobalMinimalMdnsServer & Instance();
static mdns::Minimal::ServerBase & Server()
static mdns::Minimal::Server & Server()
{
if (Instance().mReplacementServer != nullptr)
{
Expand Down Expand Up @@ -77,13 +75,13 @@ class GlobalMinimalMdnsServer : public mdns::Minimal::ServerDelegate
}
}

void SetReplacementServer(mdns::Minimal::ServerBase * server) { mReplacementServer = server; }
void SetReplacementServer(mdns::Minimal::Server * server) { mReplacementServer = server; }

private:
ServerType mServer;
mdns::Minimal::ServerBase * mReplacementServer = nullptr;
MdnsPacketDelegate * mQueryDelegate = nullptr;
MdnsPacketDelegate * mResponseDelegate = nullptr;
mdns::Minimal::Server * mReplacementServer = nullptr;
MdnsPacketDelegate * mQueryDelegate = nullptr;
MdnsPacketDelegate * mResponseDelegate = nullptr;
};

} // namespace Dnssd
Expand Down
14 changes: 13 additions & 1 deletion src/lib/dnssd/minimal_mdns/ResponseSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,19 @@ CHIP_ERROR ResponseSender::FlushReply()
else
{
#if CHIP_MINMDNS_HIGH_VERBOSITY
ChipLogDetail(Discovery, "Broadcasting mDns reply for query from %s", srcAddressString);
char interfaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
mSendState.GetSourceInterfaceId().GetInterfaceName(interfaceName, sizeof(interfaceName));

const char * interfaceType =
#if INET_CONFIG_ENABLE_IPV4
mSendState.GetSourceAddress().Type() == chip::Inet::IPAddressType::kIPv4
? "IPv4"
:
#endif // INET_CONFIG_ENABLE_IPV4
(mSendState.GetSourceAddress().Type() == chip::Inet::IPAddressType::kIPv6 ? "IPv6" : "???");

ChipLogDetail(Discovery, "Broadcasting mDns reply for query from %s to %s / %s", srcAddressString, interfaceName,
interfaceType);
#endif
ReturnErrorOnFailure(mServer->BroadcastSend(mResponseBuilder.ReleasePacket(), kMdnsStandardPort,
mSendState.GetSourceInterfaceId(), mSendState.GetSourceAddress().Type()));
Expand Down
6 changes: 3 additions & 3 deletions src/lib/dnssd/minimal_mdns/ResponseSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class ResponseSendingState
class ResponseSender : public ResponderDelegate
{
public:
ResponseSender(ServerBase * server) : mServer(server) {}
ResponseSender(Server * server) : mServer(server) {}

CHIP_ERROR AddQueryResponder(QueryResponderBase * queryResponder);
CHIP_ERROR RemoveQueryResponder(QueryResponderBase * queryResponder);
Expand All @@ -118,13 +118,13 @@ class ResponseSender : public ResponderDelegate
// Implementation of ResponderDelegate
void AddResponse(const ResourceRecord & record) override;

void SetServer(ServerBase * server) { mServer = server; }
void SetServer(Server * server) { mServer = server; }

private:
CHIP_ERROR FlushReply();
CHIP_ERROR PrepareNewReplyPacket();

ServerBase * mServer;
Server * mServer;
QueryResponderPtrPool mResponders = {};

/// Current send state
Expand Down
Loading