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 0 : 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