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