/* * * Copyright (c) 2022 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. */ #pragma once #include #include #include #include #include namespace chip { namespace AddressResolve { namespace Impl { inline constexpr uint8_t kNodeLookupResultsLen = CHIP_CONFIG_MDNS_RESOLVE_LOOKUP_RESULTS; enum class NodeLookupResult { kKeepSearching, // keep the current search active kLookupError, // final status: error kLookupSuccess, // final status: success }; struct NodeLookupResults { ResolveResult results[kNodeLookupResultsLen] = {}; uint8_t count = 0; // number of valid ResolveResult uint8_t consumed = 0; // number of already read ResolveResult bool UpdateResults(const ResolveResult & result, Dnssd::IPAddressSorter::IpScore score); bool HasValidResult() const { return count > consumed; } ResolveResult ConsumeResult() { VerifyOrDie(HasValidResult()); return results[consumed++]; } #if CHIP_DETAIL_LOGGING void LogDetail() const { for (unsigned i = 0; i < count; i++) { char addr_string[Transport::PeerAddress::kMaxToStringSize]; results[i].address.ToString(addr_string); ChipLogDetail(Discovery, "\t#%d: %s", i + 1, addr_string); } } #endif // CHIP_DETAIL_LOGGING }; /// Action to take when some resolve data /// has been received by an active lookup class NodeLookupAction { public: NodeLookupAction(const NodeLookupAction & other) { *this = other; } NodeLookupAction & operator=(const NodeLookupAction & other) { mResultType = other.mResultType; switch (mResultType) { case NodeLookupResult::kLookupError: mResult.error = other.mResult.error; break; case NodeLookupResult::kLookupSuccess: mResult.result = other.mResult.result; break; case NodeLookupResult::kKeepSearching: // no data is important here break; } return *this; } static NodeLookupAction KeepSearching() { return NodeLookupAction(NodeLookupResult::kKeepSearching); } static NodeLookupAction Error(CHIP_ERROR err) { NodeLookupAction value(NodeLookupResult::kLookupError); value.mResult.error = err; return value; } static NodeLookupAction Success(const AddressResolve::ResolveResult & result) { NodeLookupAction value(NodeLookupResult::kLookupSuccess); value.mResult.result = result; return value; } NodeLookupResult Type() const { return mResultType; } CHIP_ERROR ErrorResult() const { return mResult.error; } const AddressResolve::ResolveResult & ResolveResult() const { return mResult.result; } private: NodeLookupAction(NodeLookupResult result) : mResultType(result) {} union { CHIP_ERROR error; AddressResolve::ResolveResult result; } mResult = {}; NodeLookupResult mResultType; }; /// An implementation of a node lookup handle /// /// Keeps track of time requests as well as the current /// "best" IPs addresses found. class NodeLookupHandle : public NodeLookupHandleBase { public: const NodeLookupRequest & GetRequest() const { return mRequest; } /// Sets up a request for a new lookup. /// Resets internal state (i.e. best address so far) void ResetForLookup(System::Clock::Timestamp now, const NodeLookupRequest & request); /// Mark that a specific IP address has been found void LookupResult(const ResolveResult & result); /// Called after timeouts or after a series of IP addresses have been /// marked as found. /// /// If sufficient data for a complete address resolution has been gathered, /// calls the underlying listener `OnNodeAddressResolved` and returns /// kStopSearching. /// /// Returns kKeepSearching if more data is acceptable (keep timeouts and /// any active searches) NodeLookupAction NextAction(System::Clock::Timestamp now); /// Does the node have any valid lookup result? bool HasLookupResult() const { return mResults.HasValidResult(); } /// Return the next valid lookup result. ResolveResult TakeLookupResult() { return mResults.ConsumeResult(); } /// Return when the next timer (min or max lookup time) is required to /// be triggered for this lookup handle System::Clock::Timeout NextEventTimeout(System::Clock::Timestamp now); private: NodeLookupResults mResults; NodeLookupRequest mRequest; // active request to process System::Clock::Timestamp mRequestStartTime; }; class Resolver : public ::chip::AddressResolve::Resolver, public Dnssd::OperationalResolveDelegate { public: ~Resolver() override = default; // AddressResolve::Resolver CHIP_ERROR Init(System::Layer * systemLayer) override; CHIP_ERROR LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle) override; CHIP_ERROR TryNextResult(Impl::NodeLookupHandle & handle) override; CHIP_ERROR CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method) override; void Shutdown() override; // Dnssd::OperationalResolveDelegate void OnOperationalNodeResolved(const Dnssd::ResolvedNodeData & nodeData) override; void OnOperationalNodeResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override; private: static void OnResolveTimer(System::Layer * layer, void * context) { static_cast(context)->HandleTimer(); } /// Timer on lookup node events: min and max search times. void HandleTimer(); /// Sets up a system timer to the next closest timeout on one of the active /// lookup operations. /// /// Any existing timer is cancelled and then OnResolveTimer will be called /// on the closest event required for an active resolve. void ReArmTimer(); /// Handles the 'NextAction' on the given iterator /// /// NOTE: may remove `current` from the internal list. Current MUST NOT /// be used after calling this method. void HandleAction(IntrusiveList::Iterator & current); System::Layer * mSystemLayer = nullptr; Time::TimeSource mTimeSource; IntrusiveList mActiveLookups; }; } // namespace Impl } // namespace AddressResolve } // namespace chip