blob: 0a615fef4d62fb6b42c2de4c04c8ff400ca2f82f [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Resolver.h"
#include <lib/core/CHIPConfig.h>
#include <lib/dnssd/ActiveResolveAttempts.h>
#include <lib/dnssd/IncrementalResolve.h>
#include <lib/dnssd/MinimalMdnsServer.h>
#include <lib/dnssd/ServiceNaming.h>
#include <lib/dnssd/minimal_mdns/Logging.h>
#include <lib/dnssd/minimal_mdns/Parser.h>
#include <lib/dnssd/minimal_mdns/QueryBuilder.h>
#include <lib/dnssd/minimal_mdns/RecordData.h>
#include <lib/dnssd/minimal_mdns/core/FlatAllocatedQName.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/logging/CHIPLogging.h>
#include <tracing/macros.h>
// MDNS servers will receive all broadcast packets over the network.
// Disable 'invalid packet' messages because the are expected and common
// These logs are useful for debug only
#undef MINMDNS_RESOLVER_OVERLY_VERBOSE
namespace chip {
namespace Dnssd {
namespace {
constexpr size_t kMdnsMaxPacketSize = 1024;
constexpr uint16_t kMdnsPort = 5353;
using namespace mdns::Minimal;
/// Handles processing of minmdns packet data.
///
/// Can process multiple incremental resolves based on SRV data and allows
/// retrieval of pending (e.g. to ask for AAAA) and complete data items.
///
class PacketParser : private ParserDelegate
{
public:
PacketParser(ActiveResolveAttempts & activeResolves) : mActiveResolves(activeResolves) {}
/// Goes through the given SRV records within a response packet
/// and sets up data resolution
void ParseSrvRecords(const BytesRange & packet);
/// Goes through non-SRV records and feeds them through the initialized
/// SRV record parsing.
///
/// Must be called AFTER ParseSrvRecords has been called.
void ParseNonSrvRecords(Inet::InterfaceId interface, const BytesRange & packet);
IncrementalResolver * ResolverBegin() { return mResolvers; }
IncrementalResolver * ResolverEnd() { return mResolvers + kMinMdnsNumParallelResolvers; }
private:
// ParserDelegate implementation
void OnHeader(ConstHeaderRef & header) override;
void OnQuery(const QueryData & data) override;
void OnResource(ResourceType type, const ResourceData & data) override;
/// Called IFF data is of SRV type and we are in SRV initialization state
///
/// Initializes a resolver with the given SRV content as long as
/// inactive resolvers exist.
void ParseSRVResource(const ResourceData & data);
/// Called IFF parsing state is in RecordParsing
///
/// Forwards the resource to all active resolvers.
void ParseResource(const ResourceData & data);
enum class RecordParsingState
{
kIdle,
kSrvInitialization,
kRecordParsing,
};
static constexpr size_t kMinMdnsNumParallelResolvers = CHIP_CONFIG_MINMDNS_MAX_PARALLEL_RESOLVES;
// Individual parse set
bool mIsResponse = false;
Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null();
BytesRange mPacketRange;
RecordParsingState mParsingState = RecordParsingState::kIdle;
// resolvers kept between parse steps
ActiveResolveAttempts & mActiveResolves;
IncrementalResolver mResolvers[kMinMdnsNumParallelResolvers];
};
void PacketParser::OnHeader(ConstHeaderRef & header)
{
mIsResponse = header.GetFlags().IsResponse();
#ifdef MINMDNS_RESOLVER_OVERLY_VERBOSE
if (header.GetFlags().IsTruncated())
{
// MinMdns does not cache data, so receiving piecewise data does not work
ChipLogError(Discovery, "Truncated responses not supported for address resolution");
}
#endif
}
void PacketParser::OnQuery(const QueryData & data)
{
// Ignore queries:
// - unicast answers will include the corresponding query in the answer
// packet, however that is not interesting for the resolver.
}
void PacketParser::OnResource(ResourceType type, const ResourceData & data)
{
if (!mIsResponse)
{
return;
}
switch (mParsingState)
{
case RecordParsingState::kSrvInitialization: {
if (data.GetType() != QType::SRV)
{
return;
}
mdns::Minimal::Logging::LogReceivedResource(data);
ParseSRVResource(data);
break;
}
case RecordParsingState::kRecordParsing:
if (data.GetType() != QType::SRV)
{
// SRV packets logged during 'SrvInitialization' phase
mdns::Minimal::Logging::LogReceivedResource(data);
}
ParseResource(data);
break;
case RecordParsingState::kIdle:
ChipLogError(Discovery, "Illegal state: received DNSSD resource while IDLE");
break;
}
}
void PacketParser::ParseResource(const ResourceData & data)
{
for (auto & resolver : mResolvers)
{
if (resolver.IsActive())
{
CHIP_ERROR err = resolver.OnRecord(mInterfaceId, data, mPacketRange);
//
// CHIP_ERROR_NO_MEMORY usually gets returned when we have no more memory available to hold the
// resolved data. This gets emitted fairly frequently in dense environments or when receiving records
// from devices with lots of interfaces. Consequently, don't log that unless we have DNS verbosity
// logging enabled.
//
if (err != CHIP_NO_ERROR)
{
#if !CHIP_MINMDNS_HIGH_VERBOSITY
if (err != CHIP_ERROR_NO_MEMORY)
#endif
ChipLogError(Discovery, "DNSSD parse error: %" CHIP_ERROR_FORMAT, err.Format());
}
}
}
// Once an IP address is received, stop requesting it.
if (data.GetType() == QType::AAAA)
{
mActiveResolves.CompleteIpResolution(data.GetName());
}
}
void PacketParser::ParseSRVResource(const ResourceData & data)
{
SrvRecord srv;
if (!srv.Parse(data.GetData(), mPacketRange))
{
ChipLogError(Discovery, "Packet data reporter failed to parse SRV record");
return;
}
for (auto & resolver : mResolvers)
{
if (resolver.IsActive() && (resolver.GetRecordName() == data.GetName()))
{
ChipLogDetail(Discovery, "SRV record already actively processed.");
return;
}
}
for (auto & resolver : mResolvers)
{
if (resolver.IsActive())
{
continue;
}
CHIP_ERROR err = resolver.InitializeParsing(data.GetName(), data.GetTtlSeconds(), srv);
if (err != CHIP_NO_ERROR)
{
// Receiving records that we do not need to parse is normal:
// MinMDNS may receive all DNSSD packets on the network, only
// interested in a subset that is matter-specific
#ifdef MINMDNS_RESOLVER_OVERLY_VERBOSE
ChipLogError(Discovery, "Could not start SRV record processing: %" CHIP_ERROR_FORMAT, err.Format());
#endif
}
// Done finding an inactive resolver and attempting to use it.
return;
}
#if CHIP_MINMDNS_HIGH_VERBOSITY
ChipLogError(Discovery, "Insufficient parsers to process all SRV entries.");
#endif
}
void PacketParser::ParseSrvRecords(const BytesRange & packet)
{
MATTER_TRACE_SCOPE("Searching SRV Records", "PacketParser");
mParsingState = RecordParsingState::kSrvInitialization;
mPacketRange = packet;
if (!ParsePacket(packet, this))
{
ChipLogError(Discovery, "DNSSD packet parsing failed (for SRV records)");
}
mParsingState = RecordParsingState::kIdle;
}
void PacketParser::ParseNonSrvRecords(Inet::InterfaceId interface, const BytesRange & packet)
{
MATTER_TRACE_SCOPE("Searching NON-SRV Records", "PacketParser");
mParsingState = RecordParsingState::kRecordParsing;
mPacketRange = packet;
mInterfaceId = interface;
if (!ParsePacket(packet, this))
{
ChipLogError(Discovery, "DNSSD packet parsing failed (for non-srv records)");
}
mParsingState = RecordParsingState::kIdle;
}
class MinMdnsResolver : public Resolver, public MdnsPacketDelegate
{
public:
MinMdnsResolver() : mActiveResolves(&chip::System::SystemClock()), mPacketParser(mActiveResolves)
{
GlobalMinimalMdnsServer::Instance().SetResponseDelegate(this);
}
~MinMdnsResolver() { SetDiscoveryContext(nullptr); }
//// MdnsPacketDelegate implementation
void OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info) override;
///// Resolver implementation
CHIP_ERROR Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager) override;
bool IsInitialized() override;
void Shutdown() override;
void SetOperationalDelegate(OperationalResolveDelegate * delegate) override { mOperationalDelegate = delegate; }
CHIP_ERROR ResolveNodeId(const PeerId & peerId) override;
void NodeIdResolutionNoLongerNeeded(const PeerId & peerId) override;
CHIP_ERROR StartDiscovery(DiscoveryType type, DiscoveryFilter filter, DiscoveryContext & context) override;
CHIP_ERROR StopDiscovery(DiscoveryContext & context) override;
CHIP_ERROR ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId) override;
private:
OperationalResolveDelegate * mOperationalDelegate = nullptr;
DiscoveryContext * mDiscoveryContext = nullptr;
System::Layer * mSystemLayer = nullptr;
ActiveResolveAttempts mActiveResolves;
PacketParser mPacketParser;
void SetDiscoveryContext(DiscoveryContext * context);
void ScheduleIpAddressResolve(SerializedQNameIterator hostName);
CHIP_ERROR SendAllPendingQueries();
CHIP_ERROR ScheduleRetries();
/// Prepare a query for the given schedule attempt
CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt & attempt);
/// Prepare a query for specific resolve types
CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Browse & data, bool firstSend);
CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Resolve & data, bool firstSend);
CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::IpResolve & data, bool firstSend);
/// Clear any incremental resolver that is not waiting for a AAAA address.
void ExpireIncrementalResolvers();
void AdvancePendingResolverStates();
static void RetryCallback(System::Layer *, void * self);
CHIP_ERROR BrowseNodes(DiscoveryType type, DiscoveryFilter subtype);
template <typename... Args>
mdns::Minimal::FullQName CheckAndAllocateQName(Args &&... parts)
{
size_t requiredSize = mdns::Minimal::FlatAllocatedQName::RequiredStorageSize(parts...);
if (requiredSize > kMaxQnameSize)
{
return mdns::Minimal::FullQName();
}
return mdns::Minimal::FlatAllocatedQName::Build(qnameStorage, parts...);
}
static constexpr int kMaxQnameSize = 100;
char qnameStorage[kMaxQnameSize];
};
void MinMdnsResolver::SetDiscoveryContext(DiscoveryContext * context)
{
if (mDiscoveryContext != nullptr)
{
mDiscoveryContext->Release();
}
if (context != nullptr)
{
context->Retain();
}
mDiscoveryContext = context;
}
void MinMdnsResolver::ScheduleIpAddressResolve(SerializedQNameIterator hostName)
{
HeapQName target(hostName);
if (!target.IsOk())
{
ChipLogError(Discovery, "Memory allocation error for IP address resolution");
return;
}
mActiveResolves.MarkPending(ActiveResolveAttempts::ScheduledAttempt::IpResolve(std::move(target)));
}
void MinMdnsResolver::AdvancePendingResolverStates()
{
MATTER_TRACE_SCOPE("Advance pending resolve states", "MinMdnsResolver");
for (IncrementalResolver * resolver = mPacketParser.ResolverBegin(); resolver != mPacketParser.ResolverEnd(); resolver++)
{
if (!resolver->IsActive())
{
continue;
}
IncrementalResolver::RequiredInformationFlags missing = resolver->GetMissingRequiredInformation();
if (missing.Has(IncrementalResolver::RequiredInformationBitFlags::kIpAddress))
{
if (resolver->IsActiveCommissionParse())
{
// Browse wants IP addresses
ScheduleIpAddressResolve(resolver->GetTargetHostName());
}
else if (mActiveResolves.ShouldResolveIpAddress(resolver->OperationalParsePeerId()))
{
// Keep searching for IP addresses if an active resolve needs these IP addresses
// otherwise ignore the data (received a SRV record without IP address, however we do not
// seem interested in it. Probably just a device that came online).
ScheduleIpAddressResolve(resolver->GetTargetHostName());
}
else
{
// This IP address is not interesting enough to run another discovery
resolver->ResetToInactive();
}
continue;
}
if (missing.HasAny())
{
// Expect either IP missing (ask for it) or done. Anything else is not handled
ChipLogError(Discovery, "Unexpected state: cannot advance resolver with missing information");
resolver->ResetToInactive();
continue;
}
// SUCCESS. Call the delegates
if (resolver->IsActiveCommissionParse())
{
MATTER_TRACE_SCOPE("Active commissioning delegate call", "MinMdnsResolver");
DiscoveredNodeData nodeData;
CHIP_ERROR err = resolver->Take(nodeData);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to take discovery result: %" CHIP_ERROR_FORMAT, err.Format());
continue;
}
// TODO: Ideally commissioning delegates should be aware of the
// node types they receive, however they are currently not
// so try to help out by only calling the delegate when an
// active browse exists.
//
// This is NOT ok and probably we should have separate comissioner
// or commissionable delegates or pass in a node type argument.
bool discoveredNodeIsRelevant = false;
switch (resolver->GetCurrentType())
{
case IncrementalResolver::ServiceNameType::kCommissioner:
discoveredNodeIsRelevant = mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kCommissionerNode);
break;
case IncrementalResolver::ServiceNameType::kCommissionable:
discoveredNodeIsRelevant = mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kCommissionableNode);
break;
default:
ChipLogError(Discovery, "Unexpected type for browse data parsing");
continue;
}
if (discoveredNodeIsRelevant)
{
if (mDiscoveryContext != nullptr)
{
mDiscoveryContext->OnNodeDiscovered(nodeData);
}
else
{
#if CHIP_MINMDNS_HIGH_VERBOSITY
ChipLogError(Discovery, "No delegate to report commissioning node discovery");
#endif
}
}
}
else if (resolver->IsActiveOperationalParse())
{
MATTER_TRACE_SCOPE("Active operational delegate call", "MinMdnsResolver");
ResolvedNodeData nodeResolvedData;
CHIP_ERROR err = resolver->Take(nodeResolvedData);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to take NodeData - result: %" CHIP_ERROR_FORMAT, err.Format());
continue;
}
if (mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kOperational))
{
if (mDiscoveryContext != nullptr)
{
DiscoveredNodeData nodeData;
OperationalNodeBrowseData opNodeData;
opNodeData.peerId = nodeResolvedData.operationalData.peerId;
opNodeData.hasZeroTTL = nodeResolvedData.operationalData.hasZeroTTL;
nodeData.Set<OperationalNodeBrowseData>(opNodeData);
mDiscoveryContext->OnNodeDiscovered(nodeData);
}
else
{
#if CHIP_MINMDNS_HIGH_VERBOSITY
ChipLogError(Discovery, "No delegate to report operational node discovery");
#endif
}
}
mActiveResolves.Complete(nodeResolvedData.operationalData.peerId);
if (mOperationalDelegate != nullptr)
{
mOperationalDelegate->OnOperationalNodeResolved(nodeResolvedData);
}
else
{
#if CHIP_MINMDNS_HIGH_VERBOSITY
ChipLogError(Discovery, "No delegate to report operational node discovery");
#endif
}
}
else
{
ChipLogError(Discovery, "Unexpected state: record type unknown");
resolver->ResetToInactive();
}
}
}
void MinMdnsResolver::OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info)
{
MATTER_TRACE_SCOPE("Received MDNS Packet", "MinMdnsResolver");
// Fill up any relevant data
mPacketParser.ParseSrvRecords(data);
mPacketParser.ParseNonSrvRecords(info->Interface, data);
AdvancePendingResolverStates();
ScheduleRetries();
}
CHIP_ERROR MinMdnsResolver::Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager)
{
/// Note: we do not double-check the port as we assume the APP will always use
/// the same udpEndPointManager and port for mDNS.
mSystemLayer = &udpEndPointManager->SystemLayer();
if (GlobalMinimalMdnsServer::Server().IsListening())
{
return CHIP_NO_ERROR;
}
return GlobalMinimalMdnsServer::Instance().StartServer(udpEndPointManager, kMdnsPort);
}
bool MinMdnsResolver::IsInitialized()
{
return GlobalMinimalMdnsServer::Server().IsListening();
}
void MinMdnsResolver::Shutdown()
{
GlobalMinimalMdnsServer::Instance().ShutdownServer();
}
CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Browse & data,
bool firstSend)
{
mdns::Minimal::FullQName qname;
switch (data.type)
{
case DiscoveryType::kOperational:
if (data.filter.type == DiscoveryFilterType::kCompressedFabricId)
{
char subtypeStr[Common::kSubTypeMaxLength + 1];
ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kOperationalServiceName, kOperationalProtocol,
kLocalDomain);
}
else
{
qname = CheckAndAllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
}
break;
case DiscoveryType::kCommissionableNode:
if (data.filter.type == DiscoveryFilterType::kNone)
{
qname = CheckAndAllocateQName(kCommissionableServiceName, kCommissionProtocol, kLocalDomain);
}
else if (data.filter.type == DiscoveryFilterType::kInstanceName)
{
qname = CheckAndAllocateQName(data.filter.instanceName, kCommissionableServiceName, kCommissionProtocol, kLocalDomain);
}
else
{
char subtypeStr[Common::kSubTypeMaxLength + 1];
ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kCommissionableServiceName, kCommissionProtocol,
kLocalDomain);
}
break;
case DiscoveryType::kCommissionerNode:
if (data.filter.type == DiscoveryFilterType::kNone)
{
qname = CheckAndAllocateQName(kCommissionerServiceName, kCommissionProtocol, kLocalDomain);
}
else
{
char subtypeStr[Common::kSubTypeMaxLength + 1];
ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kCommissionerServiceName, kCommissionProtocol,
kLocalDomain);
}
break;
case DiscoveryType::kUnknown:
break;
}
VerifyOrReturnError(qname.nameCount, CHIP_ERROR_NO_MEMORY);
mdns::Minimal::Query query(qname);
query
.SetClass(QClass::IN) //
.SetType(QType::ANY) //
.SetAnswerViaUnicast(firstSend) //
;
mdns::Minimal::Logging::LogSendingQuery(query);
builder.AddQuery(query);
return CHIP_NO_ERROR;
}
CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Resolve & data,
bool firstSend)
{
char nameBuffer[kMaxOperationalServiceNameSize] = "";
// Node and fabricid are encoded in server names.
ReturnErrorOnFailure(MakeInstanceName(nameBuffer, sizeof(nameBuffer), data.peerId));
const char * instanceQName[] = { nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain };
Query query(instanceQName);
query
.SetClass(QClass::IN) //
.SetType(QType::ANY) //
.SetAnswerViaUnicast(firstSend) //
;
mdns::Minimal::Logging::LogSendingQuery(query);
builder.AddQuery(query);
return CHIP_NO_ERROR;
}
CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::IpResolve & data,
bool firstSend)
{
Query query(data.hostName.Content());
query
.SetClass(QClass::IN) //
.SetType(QType::AAAA) //
.SetAnswerViaUnicast(firstSend) //
;
mdns::Minimal::Logging::LogSendingQuery(query);
builder.AddQuery(query);
return CHIP_NO_ERROR;
}
CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt & attempt)
{
if (attempt.IsResolve())
{
ReturnErrorOnFailure(BuildQuery(builder, attempt.ResolveData(), attempt.firstSend));
}
else if (attempt.IsBrowse())
{
ReturnErrorOnFailure(BuildQuery(builder, attempt.BrowseData(), attempt.firstSend));
}
else if (attempt.IsIpResolve())
{
ReturnErrorOnFailure(BuildQuery(builder, attempt.IpResolveData(), attempt.firstSend));
}
else
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
VerifyOrReturnError(builder.Ok(), CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR MinMdnsResolver::SendAllPendingQueries()
{
while (true)
{
std::optional<ActiveResolveAttempts::ScheduledAttempt> resolve = mActiveResolves.NextScheduled();
if (!resolve.has_value())
{
break;
}
System::PacketBufferHandle buffer = System::PacketBufferHandle::New(kMdnsMaxPacketSize);
VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_NO_MEMORY);
QueryBuilder builder(std::move(buffer));
builder.Header().SetMessageId(0);
ReturnErrorOnFailure(BuildQuery(builder, *resolve));
if (resolve->firstSend)
{
ReturnErrorOnFailure(GlobalMinimalMdnsServer::Server().BroadcastUnicastQuery(builder.ReleasePacket(), kMdnsPort));
}
else
{
ReturnErrorOnFailure(GlobalMinimalMdnsServer::Server().BroadcastSend(builder.ReleasePacket(), kMdnsPort));
}
}
ExpireIncrementalResolvers();
return ScheduleRetries();
}
void MinMdnsResolver::ExpireIncrementalResolvers()
{
// once all queries are sent, if any SRV cannot receive AAAA addresses, expire it
for (IncrementalResolver * resolver = mPacketParser.ResolverBegin(); resolver != mPacketParser.ResolverEnd(); resolver++)
{
if (!resolver->IsActive())
{
continue;
}
IncrementalResolver::RequiredInformationFlags missing = resolver->GetMissingRequiredInformation();
if (missing.Has(IncrementalResolver::RequiredInformationBitFlags::kIpAddress))
{
if (mActiveResolves.IsWaitingForIpResolutionFor(resolver->GetTargetHostName()))
{
continue;
}
}
// mark as expired: not waiting for anything
resolver->ResetToInactive();
}
}
CHIP_ERROR MinMdnsResolver::StartDiscovery(DiscoveryType type, DiscoveryFilter filter, DiscoveryContext & context)
{
// minmdns currently supports only one discovery context at a time so override the previous context
SetDiscoveryContext(&context);
return BrowseNodes(type, filter);
}
CHIP_ERROR MinMdnsResolver::StopDiscovery(DiscoveryContext & context)
{
SetDiscoveryContext(nullptr);
return mActiveResolves.CompleteAllBrowses();
}
CHIP_ERROR MinMdnsResolver::ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
CHIP_ERROR MinMdnsResolver::BrowseNodes(DiscoveryType type, DiscoveryFilter filter)
{
mActiveResolves.MarkPending(filter, type);
return SendAllPendingQueries();
}
CHIP_ERROR MinMdnsResolver::ResolveNodeId(const PeerId & peerId)
{
mActiveResolves.MarkPending(peerId);
return SendAllPendingQueries();
}
void MinMdnsResolver::NodeIdResolutionNoLongerNeeded(const PeerId & peerId)
{
mActiveResolves.NodeIdResolutionNoLongerNeeded(peerId);
}
CHIP_ERROR MinMdnsResolver::ScheduleRetries()
{
MATTER_TRACE_SCOPE("Schedule retries", "MinMdnsResolver");
VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);
mSystemLayer->CancelTimer(&RetryCallback, this);
std::optional<System::Clock::Timeout> delay = mActiveResolves.GetTimeUntilNextExpectedResponse();
if (!delay.has_value())
{
return CHIP_NO_ERROR;
}
return mSystemLayer->StartTimer(*delay, &RetryCallback, this);
}
void MinMdnsResolver::RetryCallback(System::Layer *, void * self)
{
reinterpret_cast<MinMdnsResolver *>(self)->SendAllPendingQueries();
}
MinMdnsResolver gResolver;
} // namespace
#if CHIP_DNSSD_DEFAULT_MINIMAL
Resolver & GetDefaultResolver()
{
return gResolver;
}
#endif // CHIP_DNSSD_DEFAULT_MINIMAL
} // namespace Dnssd
} // namespace chip