Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include "Resolver.h"
19 :
20 : #include <lib/core/CHIPConfig.h>
21 : #include <lib/dnssd/ActiveResolveAttempts.h>
22 : #include <lib/dnssd/IncrementalResolve.h>
23 : #include <lib/dnssd/MinimalMdnsServer.h>
24 : #include <lib/dnssd/ServiceNaming.h>
25 : #include <lib/dnssd/minimal_mdns/Logging.h>
26 : #include <lib/dnssd/minimal_mdns/Parser.h>
27 : #include <lib/dnssd/minimal_mdns/QueryBuilder.h>
28 : #include <lib/dnssd/minimal_mdns/RecordData.h>
29 : #include <lib/dnssd/minimal_mdns/core/FlatAllocatedQName.h>
30 : #include <lib/support/CHIPMemString.h>
31 : #include <lib/support/logging/CHIPLogging.h>
32 : #include <tracing/macros.h>
33 :
34 : // MDNS servers will receive all broadcast packets over the network.
35 : // Disable 'invalid packet' messages because the are expected and common
36 : // These logs are useful for debug only
37 : #undef MINMDNS_RESOLVER_OVERLY_VERBOSE
38 :
39 : namespace chip {
40 : namespace Dnssd {
41 : namespace {
42 :
43 : constexpr size_t kMdnsMaxPacketSize = 1024;
44 : constexpr uint16_t kMdnsPort = 5353;
45 :
46 : using namespace mdns::Minimal;
47 :
48 : /// Handles processing of minmdns packet data.
49 : ///
50 : /// Can process multiple incremental resolves based on SRV data and allows
51 : /// retrieval of pending (e.g. to ask for AAAA) and complete data items.
52 : ///
53 : class PacketParser : private ParserDelegate
54 : {
55 : public:
56 189 : PacketParser(ActiveResolveAttempts & activeResolves) : mActiveResolves(activeResolves) {}
57 :
58 : /// Goes through the given SRV records within a response packet
59 : /// and sets up data resolution
60 : void ParseSrvRecords(const BytesRange & packet);
61 :
62 : /// Goes through non-SRV records and feeds them through the initialized
63 : /// SRV record parsing.
64 : ///
65 : /// Must be called AFTER ParseSrvRecords has been called.
66 : void ParseNonSrvRecords(Inet::InterfaceId interface, const BytesRange & packet);
67 :
68 12 : IncrementalResolver * ResolverBegin() { return mResolvers; }
69 36 : IncrementalResolver * ResolverEnd() { return mResolvers + kMinMdnsNumParallelResolvers; }
70 :
71 : private:
72 : // ParserDelegate implementation
73 : void OnHeader(ConstHeaderRef & header) override;
74 : void OnQuery(const QueryData & data) override;
75 : void OnResource(ResourceType type, const ResourceData & data) override;
76 :
77 : /// Called IFF data is of SRV type and we are in SRV initialization state
78 : ///
79 : /// Initializes a resolver with the given SRV content as long as
80 : /// inactive resolvers exist.
81 : void ParseSRVResource(const ResourceData & data);
82 :
83 : /// Called IFF parsing state is in RecordParsing
84 : ///
85 : /// Forwards the resource to all active resolvers.
86 : void ParseResource(const ResourceData & data);
87 :
88 : enum class RecordParsingState
89 : {
90 : kIdle,
91 : kSrvInitialization,
92 : kRecordParsing,
93 : };
94 :
95 : static constexpr size_t kMinMdnsNumParallelResolvers = CHIP_CONFIG_MINMDNS_MAX_PARALLEL_RESOLVES;
96 :
97 : // Individual parse set
98 : bool mIsResponse = false;
99 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null();
100 : BytesRange mPacketRange;
101 : RecordParsingState mParsingState = RecordParsingState::kIdle;
102 :
103 : // resolvers kept between parse steps
104 : ActiveResolveAttempts & mActiveResolves;
105 : IncrementalResolver mResolvers[kMinMdnsNumParallelResolvers];
106 : };
107 :
108 24 : void PacketParser::OnHeader(ConstHeaderRef & header)
109 : {
110 24 : mIsResponse = header.GetFlags().IsResponse();
111 :
112 : #ifdef MINMDNS_RESOLVER_OVERLY_VERBOSE
113 : if (header.GetFlags().IsTruncated())
114 : {
115 : // MinMdns does not cache data, so receiving piecewise data does not work
116 : ChipLogError(Discovery, "Truncated responses not supported for address resolution");
117 : }
118 : #endif
119 24 : }
120 :
121 0 : void PacketParser::OnQuery(const QueryData & data)
122 : {
123 : // Ignore queries:
124 : // - unicast answers will include the corresponding query in the answer
125 : // packet, however that is not interesting for the resolver.
126 0 : }
127 :
128 216 : void PacketParser::OnResource(ResourceType type, const ResourceData & data)
129 : {
130 216 : if (!mIsResponse)
131 : {
132 0 : return;
133 : }
134 :
135 216 : switch (mParsingState)
136 : {
137 108 : case RecordParsingState::kSrvInitialization: {
138 108 : if (data.GetType() != QType::SRV)
139 : {
140 96 : return;
141 : }
142 12 : mdns::Minimal::Logging::LogReceivedResource(data);
143 12 : ParseSRVResource(data);
144 12 : break;
145 : }
146 108 : case RecordParsingState::kRecordParsing:
147 108 : if (data.GetType() != QType::SRV)
148 : {
149 : // SRV packets logged during 'SrvInitialization' phase
150 96 : mdns::Minimal::Logging::LogReceivedResource(data);
151 : }
152 108 : ParseResource(data);
153 108 : break;
154 0 : case RecordParsingState::kIdle:
155 0 : ChipLogError(Discovery, "Illegal state: received DNSSD resource while IDLE");
156 0 : break;
157 : }
158 : }
159 :
160 108 : void PacketParser::ParseResource(const ResourceData & data)
161 : {
162 324 : for (auto & resolver : mResolvers)
163 : {
164 216 : if (resolver.IsActive())
165 : {
166 108 : CHIP_ERROR err = resolver.OnRecord(mInterfaceId, data, mPacketRange);
167 :
168 : //
169 : // CHIP_ERROR_NO_MEMORY usually gets returned when we have no more memory available to hold the
170 : // resolved data. This gets emitted fairly frequently in dense environments or when receiving records
171 : // from devices with lots of interfaces. Consequently, don't log that unless we have DNS verbosity
172 : // logging enabled.
173 : //
174 108 : if (err != CHIP_NO_ERROR)
175 : {
176 : #if !CHIP_MINMDNS_HIGH_VERBOSITY
177 0 : if (err != CHIP_ERROR_NO_MEMORY)
178 : #endif
179 0 : ChipLogError(Discovery, "DNSSD parse error: %" CHIP_ERROR_FORMAT, err.Format());
180 : }
181 : }
182 : }
183 :
184 : // Once an IP address is received, stop requesting it.
185 108 : if (data.GetType() == QType::AAAA)
186 : {
187 12 : mActiveResolves.CompleteIpResolution(data.GetName());
188 : }
189 108 : }
190 :
191 12 : void PacketParser::ParseSRVResource(const ResourceData & data)
192 : {
193 12 : SrvRecord srv;
194 12 : if (!srv.Parse(data.GetData(), mPacketRange))
195 : {
196 0 : ChipLogError(Discovery, "Packet data reporter failed to parse SRV record");
197 12 : return;
198 : }
199 :
200 36 : for (auto & resolver : mResolvers)
201 : {
202 24 : if (resolver.IsActive() && (resolver.GetRecordName() == data.GetName()))
203 : {
204 0 : ChipLogDetail(Discovery, "SRV record already actively processed.");
205 0 : return;
206 : }
207 : }
208 :
209 12 : for (auto & resolver : mResolvers)
210 : {
211 12 : if (resolver.IsActive())
212 : {
213 0 : continue;
214 : }
215 :
216 12 : CHIP_ERROR err = resolver.InitializeParsing(data.GetName(), data.GetTtlSeconds(), srv);
217 12 : if (err != CHIP_NO_ERROR)
218 : {
219 : // Receiving records that we do not need to parse is normal:
220 : // MinMDNS may receive all DNSSD packets on the network, only
221 : // interested in a subset that is matter-specific
222 : #ifdef MINMDNS_RESOLVER_OVERLY_VERBOSE
223 : ChipLogError(Discovery, "Could not start SRV record processing: %" CHIP_ERROR_FORMAT, err.Format());
224 : #endif
225 : }
226 :
227 : // Done finding an inactive resolver and attempting to use it.
228 12 : return;
229 : }
230 :
231 : #if CHIP_MINMDNS_HIGH_VERBOSITY
232 : ChipLogError(Discovery, "Insufficient parsers to process all SRV entries.");
233 : #endif
234 : }
235 :
236 12 : void PacketParser::ParseSrvRecords(const BytesRange & packet)
237 : {
238 : MATTER_TRACE_SCOPE("Searching SRV Records", "PacketParser");
239 :
240 12 : mParsingState = RecordParsingState::kSrvInitialization;
241 12 : mPacketRange = packet;
242 :
243 12 : if (!ParsePacket(packet, this))
244 : {
245 0 : ChipLogError(Discovery, "DNSSD packet parsing failed (for SRV records)");
246 : }
247 :
248 12 : mParsingState = RecordParsingState::kIdle;
249 12 : }
250 :
251 12 : void PacketParser::ParseNonSrvRecords(Inet::InterfaceId interface, const BytesRange & packet)
252 : {
253 : MATTER_TRACE_SCOPE("Searching NON-SRV Records", "PacketParser");
254 :
255 12 : mParsingState = RecordParsingState::kRecordParsing;
256 12 : mPacketRange = packet;
257 12 : mInterfaceId = interface;
258 :
259 12 : if (!ParsePacket(packet, this))
260 : {
261 0 : ChipLogError(Discovery, "DNSSD packet parsing failed (for non-srv records)");
262 : }
263 :
264 12 : mParsingState = RecordParsingState::kIdle;
265 12 : }
266 :
267 : class MinMdnsResolver : public Resolver, public MdnsPacketDelegate
268 : {
269 : public:
270 63 : MinMdnsResolver() : mActiveResolves(&chip::System::SystemClock()), mPacketParser(mActiveResolves)
271 : {
272 63 : GlobalMinimalMdnsServer::Instance().SetResponseDelegate(this);
273 63 : }
274 63 : ~MinMdnsResolver() { SetDiscoveryContext(nullptr); }
275 :
276 : //// MdnsPacketDelegate implementation
277 : void OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info) override;
278 :
279 : ///// Resolver implementation
280 : CHIP_ERROR Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager) override;
281 : bool IsInitialized() override;
282 : void Shutdown() override;
283 2 : void SetOperationalDelegate(OperationalResolveDelegate * delegate) override { mOperationalDelegate = delegate; }
284 : CHIP_ERROR ResolveNodeId(const PeerId & peerId) override;
285 : void NodeIdResolutionNoLongerNeeded(const PeerId & peerId) override;
286 : CHIP_ERROR StartDiscovery(DiscoveryType type, DiscoveryFilter filter, DiscoveryContext & context) override;
287 : CHIP_ERROR StopDiscovery(DiscoveryContext & context) override;
288 : CHIP_ERROR ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId) override;
289 :
290 : private:
291 : OperationalResolveDelegate * mOperationalDelegate = nullptr;
292 : DiscoveryContext * mDiscoveryContext = nullptr;
293 : System::Layer * mSystemLayer = nullptr;
294 : ActiveResolveAttempts mActiveResolves;
295 : PacketParser mPacketParser;
296 :
297 : void SetDiscoveryContext(DiscoveryContext * context);
298 : void ScheduleIpAddressResolve(SerializedQNameIterator hostName);
299 :
300 : CHIP_ERROR SendAllPendingQueries();
301 : CHIP_ERROR ScheduleRetries();
302 :
303 : /// Prepare a query for the given schedule attempt
304 : CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt & attempt);
305 :
306 : /// Prepare a query for specific resolve types
307 : CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Browse & data, bool firstSend);
308 : CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Resolve & data, bool firstSend);
309 : CHIP_ERROR BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::IpResolve & data, bool firstSend);
310 :
311 : /// Clear any incremental resolver that is not waiting for a AAAA address.
312 : void ExpireIncrementalResolvers();
313 : void AdvancePendingResolverStates();
314 :
315 : static void RetryCallback(System::Layer *, void * self);
316 :
317 : CHIP_ERROR BrowseNodes(DiscoveryType type, DiscoveryFilter subtype);
318 : template <typename... Args>
319 0 : mdns::Minimal::FullQName CheckAndAllocateQName(Args &&... parts)
320 : {
321 0 : size_t requiredSize = mdns::Minimal::FlatAllocatedQName::RequiredStorageSize(parts...);
322 0 : if (requiredSize > kMaxQnameSize)
323 : {
324 0 : return mdns::Minimal::FullQName();
325 : }
326 0 : return mdns::Minimal::FlatAllocatedQName::Build(qnameStorage, parts...);
327 : }
328 : static constexpr int kMaxQnameSize = 100;
329 : char qnameStorage[kMaxQnameSize];
330 : };
331 :
332 63 : void MinMdnsResolver::SetDiscoveryContext(DiscoveryContext * context)
333 : {
334 63 : if (mDiscoveryContext != nullptr)
335 : {
336 0 : mDiscoveryContext->Release();
337 : }
338 :
339 63 : if (context != nullptr)
340 : {
341 0 : context->Retain();
342 : }
343 :
344 63 : mDiscoveryContext = context;
345 63 : }
346 :
347 0 : void MinMdnsResolver::ScheduleIpAddressResolve(SerializedQNameIterator hostName)
348 : {
349 0 : HeapQName target(hostName);
350 0 : if (!target.IsOk())
351 : {
352 0 : ChipLogError(Discovery, "Memory allocation error for IP address resolution");
353 0 : return;
354 : }
355 0 : mActiveResolves.MarkPending(ActiveResolveAttempts::ScheduledAttempt::IpResolve(std::move(target)));
356 0 : }
357 :
358 12 : void MinMdnsResolver::AdvancePendingResolverStates()
359 : {
360 : MATTER_TRACE_SCOPE("Advance pending resolve states", "MinMdnsResolver");
361 :
362 36 : for (IncrementalResolver * resolver = mPacketParser.ResolverBegin(); resolver != mPacketParser.ResolverEnd(); resolver++)
363 : {
364 24 : if (!resolver->IsActive())
365 : {
366 12 : continue;
367 : }
368 :
369 12 : IncrementalResolver::RequiredInformationFlags missing = resolver->GetMissingRequiredInformation();
370 :
371 12 : if (missing.Has(IncrementalResolver::RequiredInformationBitFlags::kIpAddress))
372 : {
373 0 : if (resolver->IsActiveCommissionParse())
374 : {
375 : // Browse wants IP addresses
376 0 : ScheduleIpAddressResolve(resolver->GetTargetHostName());
377 : }
378 0 : else if (mActiveResolves.ShouldResolveIpAddress(resolver->OperationalParsePeerId()))
379 : {
380 : // Keep searching for IP addresses if an active resolve needs these IP addresses
381 : // otherwise ignore the data (received a SRV record without IP address, however we do not
382 : // seem interested in it. Probably just a device that came online).
383 0 : ScheduleIpAddressResolve(resolver->GetTargetHostName());
384 : }
385 : else
386 : {
387 : // This IP address is not interesting enough to run another discovery
388 0 : resolver->ResetToInactive();
389 : }
390 0 : continue;
391 : }
392 :
393 12 : if (missing.HasAny())
394 : {
395 : // Expect either IP missing (ask for it) or done. Anything else is not handled
396 0 : ChipLogError(Discovery, "Unexpected state: cannot advance resolver with missing information");
397 0 : resolver->ResetToInactive();
398 0 : continue;
399 : }
400 :
401 : // SUCCESS. Call the delegates
402 12 : if (resolver->IsActiveCommissionParse())
403 : {
404 : MATTER_TRACE_SCOPE("Active commissioning delegate call", "MinMdnsResolver");
405 12 : DiscoveredNodeData nodeData;
406 :
407 12 : CHIP_ERROR err = resolver->Take(nodeData);
408 12 : if (err != CHIP_NO_ERROR)
409 : {
410 0 : ChipLogError(Discovery, "Failed to take discovery result: %" CHIP_ERROR_FORMAT, err.Format());
411 0 : continue;
412 : }
413 :
414 : // TODO: Ideally commissioning delegates should be aware of the
415 : // node types they receive, however they are currently not
416 : // so try to help out by only calling the delegate when an
417 : // active browse exists.
418 : //
419 : // This is NOT ok and probably we should have separate comissioner
420 : // or commissionable delegates or pass in a node type argument.
421 12 : bool discoveredNodeIsRelevant = false;
422 :
423 12 : switch (resolver->GetCurrentType())
424 : {
425 0 : case IncrementalResolver::ServiceNameType::kCommissioner:
426 0 : discoveredNodeIsRelevant = mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kCommissionerNode);
427 0 : break;
428 12 : case IncrementalResolver::ServiceNameType::kCommissionable:
429 12 : discoveredNodeIsRelevant = mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kCommissionableNode);
430 12 : break;
431 0 : default:
432 0 : ChipLogError(Discovery, "Unexpected type for browse data parsing");
433 0 : continue;
434 : }
435 :
436 12 : if (discoveredNodeIsRelevant)
437 : {
438 0 : if (mDiscoveryContext != nullptr)
439 : {
440 0 : mDiscoveryContext->OnNodeDiscovered(nodeData);
441 : }
442 : else
443 : {
444 : #if CHIP_MINMDNS_HIGH_VERBOSITY
445 : ChipLogError(Discovery, "No delegate to report commissioning node discovery");
446 : #endif
447 : }
448 : }
449 12 : }
450 0 : else if (resolver->IsActiveOperationalParse())
451 : {
452 : MATTER_TRACE_SCOPE("Active operational delegate call", "MinMdnsResolver");
453 0 : ResolvedNodeData nodeResolvedData;
454 0 : CHIP_ERROR err = resolver->Take(nodeResolvedData);
455 :
456 0 : if (err != CHIP_NO_ERROR)
457 : {
458 0 : ChipLogError(Discovery, "Failed to take NodeData - result: %" CHIP_ERROR_FORMAT, err.Format());
459 0 : continue;
460 : }
461 :
462 0 : if (mActiveResolves.HasBrowseFor(chip::Dnssd::DiscoveryType::kOperational))
463 : {
464 0 : if (mDiscoveryContext != nullptr)
465 : {
466 0 : DiscoveredNodeData nodeData;
467 0 : OperationalNodeBrowseData opNodeData;
468 :
469 0 : opNodeData.peerId = nodeResolvedData.operationalData.peerId;
470 0 : opNodeData.hasZeroTTL = nodeResolvedData.operationalData.hasZeroTTL;
471 0 : nodeData.Set<OperationalNodeBrowseData>(opNodeData);
472 0 : mDiscoveryContext->OnNodeDiscovered(nodeData);
473 0 : }
474 : else
475 : {
476 : #if CHIP_MINMDNS_HIGH_VERBOSITY
477 : ChipLogError(Discovery, "No delegate to report operational node discovery");
478 : #endif
479 : }
480 : }
481 :
482 0 : mActiveResolves.Complete(nodeResolvedData.operationalData.peerId);
483 0 : if (mOperationalDelegate != nullptr)
484 : {
485 0 : mOperationalDelegate->OnOperationalNodeResolved(nodeResolvedData);
486 : }
487 : else
488 : {
489 : #if CHIP_MINMDNS_HIGH_VERBOSITY
490 : ChipLogError(Discovery, "No delegate to report operational node discovery");
491 : #endif
492 : }
493 : }
494 : else
495 : {
496 0 : ChipLogError(Discovery, "Unexpected state: record type unknown");
497 0 : resolver->ResetToInactive();
498 : }
499 : }
500 12 : }
501 :
502 12 : void MinMdnsResolver::OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info)
503 : {
504 : MATTER_TRACE_SCOPE("Received MDNS Packet", "MinMdnsResolver");
505 :
506 : // Fill up any relevant data
507 12 : mPacketParser.ParseSrvRecords(data);
508 12 : mPacketParser.ParseNonSrvRecords(info->Interface, data);
509 :
510 12 : AdvancePendingResolverStates();
511 :
512 12 : ScheduleRetries();
513 12 : }
514 :
515 1 : CHIP_ERROR MinMdnsResolver::Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager)
516 : {
517 : /// Note: we do not double-check the port as we assume the APP will always use
518 : /// the same udpEndPointManager and port for mDNS.
519 1 : mSystemLayer = &udpEndPointManager->SystemLayer();
520 :
521 1 : if (GlobalMinimalMdnsServer::Server().IsListening())
522 : {
523 0 : return CHIP_NO_ERROR;
524 : }
525 :
526 1 : return GlobalMinimalMdnsServer::Instance().StartServer(udpEndPointManager, kMdnsPort);
527 : }
528 :
529 1 : bool MinMdnsResolver::IsInitialized()
530 : {
531 1 : return GlobalMinimalMdnsServer::Server().IsListening();
532 : }
533 :
534 1 : void MinMdnsResolver::Shutdown()
535 : {
536 1 : GlobalMinimalMdnsServer::Instance().ShutdownServer();
537 1 : }
538 :
539 0 : CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Browse & data,
540 : bool firstSend)
541 : {
542 0 : mdns::Minimal::FullQName qname;
543 :
544 0 : switch (data.type)
545 : {
546 0 : case DiscoveryType::kOperational:
547 0 : if (data.filter.type == DiscoveryFilterType::kCompressedFabricId)
548 : {
549 : char subtypeStr[Common::kSubTypeMaxLength + 1];
550 0 : ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
551 0 : qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kOperationalServiceName, kOperationalProtocol,
552 : kLocalDomain);
553 : }
554 : else
555 : {
556 0 : qname = CheckAndAllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
557 : }
558 0 : break;
559 0 : case DiscoveryType::kCommissionableNode:
560 0 : if (data.filter.type == DiscoveryFilterType::kNone)
561 : {
562 0 : qname = CheckAndAllocateQName(kCommissionableServiceName, kCommissionProtocol, kLocalDomain);
563 : }
564 0 : else if (data.filter.type == DiscoveryFilterType::kInstanceName)
565 : {
566 0 : qname = CheckAndAllocateQName(data.filter.instanceName, kCommissionableServiceName, kCommissionProtocol, kLocalDomain);
567 : }
568 : else
569 : {
570 : char subtypeStr[Common::kSubTypeMaxLength + 1];
571 0 : ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
572 0 : qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kCommissionableServiceName, kCommissionProtocol,
573 : kLocalDomain);
574 : }
575 0 : break;
576 0 : case DiscoveryType::kCommissionerNode:
577 0 : if (data.filter.type == DiscoveryFilterType::kNone)
578 : {
579 0 : qname = CheckAndAllocateQName(kCommissionerServiceName, kCommissionProtocol, kLocalDomain);
580 : }
581 : else
582 : {
583 : char subtypeStr[Common::kSubTypeMaxLength + 1];
584 0 : ReturnErrorOnFailure(MakeServiceSubtype(subtypeStr, sizeof(subtypeStr), data.filter));
585 0 : qname = CheckAndAllocateQName(subtypeStr, kSubtypeServiceNamePart, kCommissionerServiceName, kCommissionProtocol,
586 : kLocalDomain);
587 : }
588 0 : break;
589 0 : case DiscoveryType::kUnknown:
590 0 : break;
591 : }
592 :
593 0 : VerifyOrReturnError(qname.nameCount, CHIP_ERROR_NO_MEMORY);
594 :
595 0 : mdns::Minimal::Query query(qname);
596 : query
597 0 : .SetClass(QClass::IN) //
598 0 : .SetType(QType::ANY) //
599 0 : .SetAnswerViaUnicast(firstSend) //
600 : ;
601 :
602 0 : mdns::Minimal::Logging::LogSendingQuery(query);
603 0 : builder.AddQuery(query);
604 :
605 0 : return CHIP_NO_ERROR;
606 : }
607 :
608 0 : CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::Resolve & data,
609 : bool firstSend)
610 : {
611 0 : char nameBuffer[kMaxOperationalServiceNameSize] = "";
612 :
613 : // Node and fabricid are encoded in server names.
614 0 : ReturnErrorOnFailure(MakeInstanceName(nameBuffer, sizeof(nameBuffer), data.peerId));
615 :
616 0 : const char * instanceQName[] = { nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain };
617 0 : Query query(instanceQName);
618 :
619 : query
620 0 : .SetClass(QClass::IN) //
621 0 : .SetType(QType::ANY) //
622 0 : .SetAnswerViaUnicast(firstSend) //
623 : ;
624 :
625 0 : mdns::Minimal::Logging::LogSendingQuery(query);
626 0 : builder.AddQuery(query);
627 :
628 0 : return CHIP_NO_ERROR;
629 : }
630 :
631 0 : CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt::IpResolve & data,
632 : bool firstSend)
633 : {
634 :
635 0 : Query query(data.hostName.Content());
636 :
637 : query
638 0 : .SetClass(QClass::IN) //
639 0 : .SetType(QType::AAAA) //
640 0 : .SetAnswerViaUnicast(firstSend) //
641 : ;
642 :
643 0 : mdns::Minimal::Logging::LogSendingQuery(query);
644 0 : builder.AddQuery(query);
645 :
646 0 : return CHIP_NO_ERROR;
647 : }
648 :
649 0 : CHIP_ERROR MinMdnsResolver::BuildQuery(QueryBuilder & builder, const ActiveResolveAttempts::ScheduledAttempt & attempt)
650 : {
651 0 : if (attempt.IsResolve())
652 : {
653 0 : ReturnErrorOnFailure(BuildQuery(builder, attempt.ResolveData(), attempt.firstSend));
654 : }
655 0 : else if (attempt.IsBrowse())
656 : {
657 0 : ReturnErrorOnFailure(BuildQuery(builder, attempt.BrowseData(), attempt.firstSend));
658 : }
659 0 : else if (attempt.IsIpResolve())
660 : {
661 0 : ReturnErrorOnFailure(BuildQuery(builder, attempt.IpResolveData(), attempt.firstSend));
662 : }
663 : else
664 : {
665 0 : return CHIP_ERROR_INVALID_ARGUMENT;
666 : }
667 :
668 0 : VerifyOrReturnError(builder.Ok(), CHIP_ERROR_INTERNAL);
669 0 : return CHIP_NO_ERROR;
670 : }
671 :
672 0 : CHIP_ERROR MinMdnsResolver::SendAllPendingQueries()
673 : {
674 : while (true)
675 : {
676 0 : std::optional<ActiveResolveAttempts::ScheduledAttempt> resolve = mActiveResolves.NextScheduled();
677 :
678 0 : if (!resolve.has_value())
679 : {
680 0 : break;
681 : }
682 :
683 0 : System::PacketBufferHandle buffer = System::PacketBufferHandle::New(kMdnsMaxPacketSize);
684 0 : VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_NO_MEMORY);
685 :
686 0 : QueryBuilder builder(std::move(buffer));
687 0 : builder.Header().SetMessageId(0);
688 :
689 0 : ReturnErrorOnFailure(BuildQuery(builder, *resolve));
690 :
691 0 : if (resolve->firstSend)
692 : {
693 0 : ReturnErrorOnFailure(GlobalMinimalMdnsServer::Server().BroadcastUnicastQuery(builder.ReleasePacket(), kMdnsPort));
694 : }
695 : else
696 : {
697 0 : ReturnErrorOnFailure(GlobalMinimalMdnsServer::Server().BroadcastSend(builder.ReleasePacket(), kMdnsPort));
698 : }
699 0 : }
700 :
701 0 : ExpireIncrementalResolvers();
702 :
703 0 : return ScheduleRetries();
704 : }
705 :
706 0 : void MinMdnsResolver::ExpireIncrementalResolvers()
707 : {
708 : // once all queries are sent, if any SRV cannot receive AAAA addresses, expire it
709 0 : for (IncrementalResolver * resolver = mPacketParser.ResolverBegin(); resolver != mPacketParser.ResolverEnd(); resolver++)
710 : {
711 0 : if (!resolver->IsActive())
712 : {
713 0 : continue;
714 : }
715 :
716 0 : IncrementalResolver::RequiredInformationFlags missing = resolver->GetMissingRequiredInformation();
717 0 : if (missing.Has(IncrementalResolver::RequiredInformationBitFlags::kIpAddress))
718 : {
719 0 : if (mActiveResolves.IsWaitingForIpResolutionFor(resolver->GetTargetHostName()))
720 : {
721 0 : continue;
722 : }
723 : }
724 :
725 : // mark as expired: not waiting for anything
726 0 : resolver->ResetToInactive();
727 : }
728 0 : }
729 :
730 0 : CHIP_ERROR MinMdnsResolver::StartDiscovery(DiscoveryType type, DiscoveryFilter filter, DiscoveryContext & context)
731 : {
732 : // minmdns currently supports only one discovery context at a time so override the previous context
733 0 : SetDiscoveryContext(&context);
734 :
735 0 : return BrowseNodes(type, filter);
736 : }
737 :
738 0 : CHIP_ERROR MinMdnsResolver::StopDiscovery(DiscoveryContext & context)
739 : {
740 0 : SetDiscoveryContext(nullptr);
741 :
742 0 : return mActiveResolves.CompleteAllBrowses();
743 : }
744 :
745 0 : CHIP_ERROR MinMdnsResolver::ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId)
746 : {
747 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
748 : }
749 :
750 0 : CHIP_ERROR MinMdnsResolver::BrowseNodes(DiscoveryType type, DiscoveryFilter filter)
751 : {
752 0 : mActiveResolves.MarkPending(filter, type);
753 :
754 0 : return SendAllPendingQueries();
755 : }
756 :
757 0 : CHIP_ERROR MinMdnsResolver::ResolveNodeId(const PeerId & peerId)
758 : {
759 0 : mActiveResolves.MarkPending(peerId);
760 :
761 0 : return SendAllPendingQueries();
762 : }
763 :
764 0 : void MinMdnsResolver::NodeIdResolutionNoLongerNeeded(const PeerId & peerId)
765 : {
766 0 : mActiveResolves.NodeIdResolutionNoLongerNeeded(peerId);
767 0 : }
768 :
769 12 : CHIP_ERROR MinMdnsResolver::ScheduleRetries()
770 : {
771 : MATTER_TRACE_SCOPE("Schedule retries", "MinMdnsResolver");
772 :
773 12 : VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);
774 12 : mSystemLayer->CancelTimer(&RetryCallback, this);
775 :
776 12 : std::optional<System::Clock::Timeout> delay = mActiveResolves.GetTimeUntilNextExpectedResponse();
777 :
778 12 : if (!delay.has_value())
779 : {
780 12 : return CHIP_NO_ERROR;
781 : }
782 :
783 0 : return mSystemLayer->StartTimer(*delay, &RetryCallback, this);
784 : }
785 :
786 0 : void MinMdnsResolver::RetryCallback(System::Layer *, void * self)
787 : {
788 0 : reinterpret_cast<MinMdnsResolver *>(self)->SendAllPendingQueries();
789 0 : }
790 :
791 : MinMdnsResolver gResolver;
792 :
793 : } // namespace
794 :
795 : #if CHIP_DNSSD_DEFAULT_MINIMAL
796 :
797 4 : Resolver & GetDefaultResolver()
798 : {
799 4 : return gResolver;
800 : }
801 :
802 : #endif // CHIP_DNSSD_DEFAULT_MINIMAL
803 :
804 : } // namespace Dnssd
805 : } // namespace chip
|