blob: ac6d7dd8d1f4d0b1cfb85cf479e819e702fb66f4 [file] [log] [blame]
/*
*
* 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 <lib/address_resolve/AddressResolve.h>
#include <lib/dnssd/IPAddressSorter.h>
#include <lib/dnssd/Resolver.h>
#include <system/TimeSource.h>
#include <transport/raw/PeerAddress.h>
namespace chip {
namespace AddressResolve {
namespace Impl {
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<Resolver *>(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<NodeLookupHandle>::Iterator & current);
System::Layer * mSystemLayer = nullptr;
Time::TimeSource<Time::Source::kSystem> mTimeSource;
IntrusiveList<NodeLookupHandle> mActiveLookups;
};
} // namespace Impl
} // namespace AddressResolve
} // namespace chip