Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2022 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 : #pragma once
18 :
19 : #include <lib/address_resolve/AddressResolve.h>
20 : #include <lib/dnssd/IPAddressSorter.h>
21 : #include <lib/dnssd/Resolver.h>
22 : #include <system/TimeSource.h>
23 : #include <transport/raw/PeerAddress.h>
24 :
25 : namespace chip {
26 : namespace AddressResolve {
27 : namespace Impl {
28 :
29 : inline constexpr uint8_t kNodeLookupResultsLen = CHIP_CONFIG_MDNS_RESOLVE_LOOKUP_RESULTS;
30 :
31 : enum class NodeLookupResult
32 : {
33 : kKeepSearching, // keep the current search active
34 : kLookupError, // final status: error
35 : kLookupSuccess, // final status: success
36 : };
37 :
38 : struct NodeLookupResults
39 : {
40 : ResolveResult results[kNodeLookupResultsLen] = {};
41 : uint8_t count = 0; // number of valid ResolveResult
42 : uint8_t consumed = 0; // number of already read ResolveResult
43 :
44 : bool UpdateResults(const ResolveResult & result, Dnssd::IPAddressSorter::IpScore score);
45 :
46 0 : bool HasValidResult() const { return count > consumed; }
47 :
48 0 : ResolveResult ConsumeResult()
49 : {
50 0 : VerifyOrDie(HasValidResult());
51 0 : return results[consumed++];
52 : }
53 :
54 : #if CHIP_DETAIL_LOGGING
55 : void LogDetail() const
56 : {
57 : for (unsigned i = 0; i < count; i++)
58 : {
59 : char addr_string[Transport::PeerAddress::kMaxToStringSize];
60 : results[i].address.ToString(addr_string);
61 : ChipLogDetail(Discovery, "\t#%d: %s", i + 1, addr_string);
62 : }
63 : }
64 : #endif // CHIP_DETAIL_LOGGING
65 : };
66 :
67 : /// Action to take when some resolve data
68 : /// has been received by an active lookup
69 : class NodeLookupAction
70 : {
71 : public:
72 : NodeLookupAction(const NodeLookupAction & other) { *this = other; }
73 :
74 : NodeLookupAction & operator=(const NodeLookupAction & other)
75 : {
76 : mResultType = other.mResultType;
77 : switch (mResultType)
78 : {
79 : case NodeLookupResult::kLookupError:
80 : mResult.error = other.mResult.error;
81 : break;
82 : case NodeLookupResult::kLookupSuccess:
83 : mResult.result = other.mResult.result;
84 : break;
85 : case NodeLookupResult::kKeepSearching:
86 : // no data is important here
87 : break;
88 : }
89 : return *this;
90 : }
91 :
92 0 : static NodeLookupAction KeepSearching() { return NodeLookupAction(NodeLookupResult::kKeepSearching); }
93 :
94 0 : static NodeLookupAction Error(CHIP_ERROR err)
95 : {
96 0 : NodeLookupAction value(NodeLookupResult::kLookupError);
97 0 : value.mResult.error = err;
98 0 : return value;
99 : }
100 :
101 0 : static NodeLookupAction Success(const AddressResolve::ResolveResult & result)
102 : {
103 0 : NodeLookupAction value(NodeLookupResult::kLookupSuccess);
104 0 : value.mResult.result = result;
105 0 : return value;
106 : }
107 :
108 0 : NodeLookupResult Type() const { return mResultType; }
109 0 : CHIP_ERROR ErrorResult() const { return mResult.error; }
110 0 : const AddressResolve::ResolveResult & ResolveResult() const { return mResult.result; }
111 :
112 : private:
113 0 : NodeLookupAction(NodeLookupResult result) : mResultType(result) {}
114 :
115 : union
116 : {
117 : CHIP_ERROR error;
118 : AddressResolve::ResolveResult result;
119 : } mResult = {};
120 : NodeLookupResult mResultType;
121 : };
122 :
123 : /// An implementation of a node lookup handle
124 : ///
125 : /// Keeps track of time requests as well as the current
126 : /// "best" IPs addresses found.
127 : class NodeLookupHandle : public NodeLookupHandleBase
128 : {
129 : public:
130 29 : const NodeLookupRequest & GetRequest() const { return mRequest; }
131 :
132 : /// Sets up a request for a new lookup.
133 : /// Resets internal state (i.e. best address so far)
134 : void ResetForLookup(System::Clock::Timestamp now, const NodeLookupRequest & request);
135 :
136 : /// Mark that a specific IP address has been found
137 : void LookupResult(const ResolveResult & result);
138 :
139 : /// Called after timeouts or after a series of IP addresses have been
140 : /// marked as found.
141 : ///
142 : /// If sufficient data for a complete address resolution has been gathered,
143 : /// calls the underlying listener `OnNodeAddressResolved` and returns
144 : /// kStopSearching.
145 : ///
146 : /// Returns kKeepSearching if more data is acceptable (keep timeouts and
147 : /// any active searches)
148 : NodeLookupAction NextAction(System::Clock::Timestamp now);
149 :
150 : /// Does the node have any valid lookup result?
151 0 : bool HasLookupResult() const { return mResults.HasValidResult(); }
152 :
153 : /// Return the next valid lookup result.
154 0 : ResolveResult TakeLookupResult() { return mResults.ConsumeResult(); }
155 :
156 : /// Return when the next timer (min or max lookup time) is required to
157 : /// be triggered for this lookup handle
158 : System::Clock::Timeout NextEventTimeout(System::Clock::Timestamp now);
159 :
160 : private:
161 : NodeLookupResults mResults;
162 : NodeLookupRequest mRequest; // active request to process
163 : System::Clock::Timestamp mRequestStartTime;
164 : };
165 :
166 : class Resolver : public ::chip::AddressResolve::Resolver, public Dnssd::OperationalResolveDelegate
167 : {
168 : public:
169 1 : ~Resolver() override = default;
170 :
171 : // AddressResolve::Resolver
172 :
173 : CHIP_ERROR Init(System::Layer * systemLayer) override;
174 : CHIP_ERROR LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle) override;
175 : CHIP_ERROR TryNextResult(Impl::NodeLookupHandle & handle) override;
176 : CHIP_ERROR CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method) override;
177 : void Shutdown() override;
178 :
179 : // Dnssd::OperationalResolveDelegate
180 :
181 : void OnOperationalNodeResolved(const Dnssd::ResolvedNodeData & nodeData) override;
182 : void OnOperationalNodeResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override;
183 :
184 : private:
185 0 : static void OnResolveTimer(System::Layer * layer, void * context) { static_cast<Resolver *>(context)->HandleTimer(); }
186 :
187 : /// Timer on lookup node events: min and max search times.
188 : void HandleTimer();
189 :
190 : /// Sets up a system timer to the next closest timeout on one of the active
191 : /// lookup operations.
192 : ///
193 : /// Any existing timer is cancelled and then OnResolveTimer will be called
194 : /// on the closest event required for an active resolve.
195 : void ReArmTimer();
196 :
197 : /// Handles the 'NextAction' on the given iterator
198 : ///
199 : /// NOTE: may remove `current` from the internal list. Current MUST NOT
200 : /// be used after calling this method.
201 : void HandleAction(IntrusiveList<NodeLookupHandle>::Iterator & current);
202 :
203 : System::Layer * mSystemLayer = nullptr;
204 : Time::TimeSource<Time::Source::kSystem> mTimeSource;
205 : IntrusiveList<NodeLookupHandle> mActiveLookups;
206 : };
207 :
208 : } // namespace Impl
209 : } // namespace AddressResolve
210 : } // namespace chip
|