Matter SDK Coverage Report
Current view: top level - lib/address_resolve - AddressResolve_DefaultImpl.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 31.0 % 184 57
Test Date: 2025-01-17 19:00:11 Functions: 43.8 % 16 7

            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              : 
      18              : #include <lib/address_resolve/AddressResolve_DefaultImpl.h>
      19              : 
      20              : #include <lib/address_resolve/TracingStructs.h>
      21              : #include <tracing/macros.h>
      22              : 
      23              : namespace chip {
      24              : namespace AddressResolve {
      25              : namespace Impl {
      26              : namespace {
      27              : 
      28              : static constexpr System::Clock::Timeout kInvalidTimeout{ System::Clock::Timeout::max() };
      29              : 
      30              : } // namespace
      31              : 
      32            5 : void NodeLookupHandle::ResetForLookup(System::Clock::Timestamp now, const NodeLookupRequest & request)
      33              : {
      34            5 :     mRequestStartTime = now;
      35            5 :     mRequest          = request;
      36            5 :     mResults          = NodeLookupResults();
      37            5 : }
      38              : 
      39           29 : void NodeLookupHandle::LookupResult(const ResolveResult & result)
      40              : {
      41              :     MATTER_LOG_NODE_DISCOVERED(Tracing::DiscoveryInfoType::kIntermediateResult, &GetRequest().GetPeerId(), &result);
      42              : 
      43           29 :     auto score = Dnssd::IPAddressSorter::ScoreIpAddress(result.address.GetIPAddress(), result.address.GetInterface());
      44           29 :     [[maybe_unused]] bool success = mResults.UpdateResults(result, score);
      45              : 
      46              : #if CHIP_PROGRESS_LOGGING
      47              :     char addr_string[Transport::PeerAddress::kMaxToStringSize];
      48           29 :     result.address.ToString(addr_string);
      49              : 
      50           29 :     const PeerId peerId = GetRequest().GetPeerId();
      51           29 :     if (success)
      52              :     {
      53           24 :         ChipLogProgress(Discovery, "%s: new best score: %u (for " ChipLogFormatPeerId ")", addr_string, to_underlying(score),
      54              :                         ChipLogValuePeerId(peerId));
      55              :     }
      56              :     else
      57              :     {
      58            5 :         ChipLogProgress(Discovery, "%s: score has not improved: %u (for " ChipLogFormatPeerId ")", addr_string,
      59              :                         to_underlying(score), ChipLogValuePeerId(peerId));
      60              :     }
      61              : #endif
      62           29 : }
      63              : 
      64            0 : System::Clock::Timeout NodeLookupHandle::NextEventTimeout(System::Clock::Timestamp now)
      65              : {
      66            0 :     const System::Clock::Timestamp elapsed = now - mRequestStartTime;
      67              : 
      68            0 :     if (elapsed < mRequest.GetMinLookupTime())
      69              :     {
      70            0 :         return mRequest.GetMinLookupTime() - elapsed;
      71              :     }
      72              : 
      73            0 :     if (HasLookupResult())
      74              :     {
      75              :         // We can get here if we got our result before our min lookup time had
      76              :         // elapsed, but time has passed between then and this attempt to re-arm
      77              :         // the timer, such that now we are past our min lookup time.  For
      78              :         // example, this can happen because the timer is a bit delayed in firing
      79              :         // but is now being re-scheduled due to a cancellation of a lookup or
      80              :         // start of a new lookup.  Or it could happen because
      81              :         // OnOperationalNodeResolved got called close to our min lookup time,
      82              :         // and we crossed that line while going through mActiveLookups and
      83              :         // before we got to calling ReArmTimer.
      84              :         //
      85              :         // In this case, we should just fire the timer ASAP, since our min
      86              :         // lookup time has elapsed and we have results.
      87            0 :         return System::Clock::Timeout::zero();
      88              :     }
      89              : 
      90            0 :     if (elapsed < mRequest.GetMaxLookupTime())
      91              :     {
      92            0 :         return mRequest.GetMaxLookupTime() - elapsed;
      93              :     }
      94              : 
      95            0 :     ChipLogError(Discovery, "Unexpected timeout: lookup should have been cleaned already.");
      96            0 :     return System::Clock::Timeout::zero();
      97              : }
      98              : 
      99            0 : NodeLookupAction NodeLookupHandle::NextAction(System::Clock::Timestamp now)
     100              : {
     101            0 :     const System::Clock::Timestamp elapsed = now - mRequestStartTime;
     102              : 
     103            0 :     ChipLogProgress(Discovery, "Checking node lookup status for " ChipLogFormatPeerId " after %lu ms",
     104              :                     ChipLogValuePeerId(mRequest.GetPeerId()), static_cast<unsigned long>(elapsed.count()));
     105              : 
     106              :     // We are still within the minimal search time. Wait for more results.
     107            0 :     if (elapsed < mRequest.GetMinLookupTime())
     108              :     {
     109            0 :         ChipLogProgress(Discovery, "Keeping DNSSD lookup active");
     110            0 :         return NodeLookupAction::KeepSearching();
     111              :     }
     112              : 
     113              :     // Minimal time to search reached. If any IP available, ready to return it.
     114            0 :     if (HasLookupResult())
     115              :     {
     116            0 :         auto result = TakeLookupResult();
     117            0 :         return NodeLookupAction::Success(result);
     118              :     }
     119              : 
     120              :     // Give up if the maximum search time has been reached
     121            0 :     if (elapsed >= mRequest.GetMaxLookupTime())
     122              :     {
     123            0 :         return NodeLookupAction::Error(CHIP_ERROR_TIMEOUT);
     124              :     }
     125              : 
     126            0 :     return NodeLookupAction::KeepSearching();
     127              : }
     128              : 
     129           29 : bool NodeLookupResults::UpdateResults(const ResolveResult & result, const Dnssd::IPAddressSorter::IpScore newScore)
     130              : {
     131           29 :     uint8_t insertAtIndex = 0;
     132           94 :     for (; insertAtIndex < kNodeLookupResultsLen; insertAtIndex++)
     133              :     {
     134           89 :         if (insertAtIndex >= count)
     135              :         {
     136              :             // This is a new entry.
     137           21 :             break;
     138              :         }
     139              : 
     140           68 :         auto & oldAddress = results[insertAtIndex].address;
     141           68 :         auto oldScore     = Dnssd::IPAddressSorter::ScoreIpAddress(oldAddress.GetIPAddress(), oldAddress.GetInterface());
     142           68 :         if (newScore > oldScore)
     143              :         {
     144              :             // This is a score update, it will replace a previous entry.
     145            3 :             break;
     146              :         }
     147              :     }
     148              : 
     149           29 :     if (insertAtIndex == kNodeLookupResultsLen)
     150              :     {
     151            5 :         return false;
     152              :     }
     153              : 
     154              :     // Move the following valid entries one level down.
     155           39 :     for (auto i = count; i > insertAtIndex; i--)
     156              :     {
     157           15 :         if (i >= kNodeLookupResultsLen)
     158              :         {
     159            3 :             continue;
     160              :         }
     161              : 
     162           12 :         results[i] = results[i - 1];
     163              :     }
     164              : 
     165              :     // If the number of valid entries is less than the size of the array there is an additional entry.
     166           24 :     if (count < kNodeLookupResultsLen)
     167              :     {
     168           21 :         count++;
     169              :     }
     170              : 
     171           24 :     auto & updatedResult = results[insertAtIndex];
     172           24 :     updatedResult        = result;
     173           24 :     if (!updatedResult.address.GetIPAddress().IsIPv6LinkLocal())
     174              :     {
     175              :         // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA.
     176              :         // For all other addresses, we should rely on the device's routing table to route messages sent.
     177              :         // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread,
     178              :         // mDNS advertisements are not usually received on the same interface the peer is reachable on.
     179           23 :         updatedResult.address.SetInterface(Inet::InterfaceId::Null());
     180           23 :         ChipLogDetail(Discovery, "Lookup clearing interface for non LL address");
     181              :     }
     182              : 
     183           24 :     return true;
     184              : }
     185              : 
     186            0 : CHIP_ERROR Resolver::LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle)
     187              : {
     188              :     MATTER_LOG_NODE_LOOKUP(&request);
     189              : 
     190            0 :     VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);
     191              : 
     192            0 :     handle.ResetForLookup(mTimeSource.GetMonotonicTimestamp(), request);
     193            0 :     auto & peerId = request.GetPeerId();
     194            0 :     ReturnErrorOnFailure(Dnssd::Resolver::Instance().ResolveNodeId(peerId));
     195            0 :     mActiveLookups.PushBack(&handle);
     196            0 :     ReArmTimer();
     197            0 :     ChipLogProgress(Discovery, "Lookup started for " ChipLogFormatPeerId, ChipLogValuePeerId(peerId));
     198            0 :     return CHIP_NO_ERROR;
     199              : }
     200              : 
     201            0 : CHIP_ERROR Resolver::TryNextResult(Impl::NodeLookupHandle & handle)
     202              : {
     203            0 :     VerifyOrReturnError(!mActiveLookups.Contains(&handle), CHIP_ERROR_INCORRECT_STATE);
     204            0 :     VerifyOrReturnError(handle.HasLookupResult(), CHIP_ERROR_NOT_FOUND);
     205              : 
     206            0 :     auto listener = handle.GetListener();
     207            0 :     auto peerId   = handle.GetRequest().GetPeerId();
     208            0 :     auto result   = handle.TakeLookupResult();
     209              : 
     210              :     MATTER_LOG_NODE_DISCOVERED(Tracing::DiscoveryInfoType::kRetryDifferent, &peerId, &result);
     211              : 
     212            0 :     listener->OnNodeAddressResolved(peerId, result);
     213            0 :     return CHIP_NO_ERROR;
     214              : }
     215              : 
     216            0 : CHIP_ERROR Resolver::CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method)
     217              : {
     218            0 :     VerifyOrReturnError(handle.IsActive(), CHIP_ERROR_INVALID_ARGUMENT);
     219            0 :     mActiveLookups.Remove(&handle);
     220            0 :     Dnssd::Resolver::Instance().NodeIdResolutionNoLongerNeeded(handle.GetRequest().GetPeerId());
     221              : 
     222              :     // Adjust any timing updates.
     223            0 :     ReArmTimer();
     224              : 
     225              :     MATTER_LOG_NODE_DISCOVERY_FAILED(&handle.GetRequest().GetPeerId(), CHIP_ERROR_CANCELLED);
     226              : 
     227            0 :     if (cancel_method == FailureCallback::Call)
     228              :     {
     229            0 :         handle.GetListener()->OnNodeAddressResolutionFailed(handle.GetRequest().GetPeerId(), CHIP_ERROR_CANCELLED);
     230              :     }
     231              : 
     232              :     // TODO: There should be some form of cancel into Dnssd::Resolver::Instance()
     233              :     //       to stop any resolution mechanism if applicable.
     234              :     //
     235              :     // Current code just removes the internal list and any callbacks of resolution will
     236              :     // be ignored. This works from the perspective of the caller of this method,
     237              :     // but may be wasteful by letting dnssd still work in the background.
     238              : 
     239            0 :     return CHIP_NO_ERROR;
     240              : }
     241              : 
     242            1 : CHIP_ERROR Resolver::Init(System::Layer * systemLayer)
     243              : {
     244            1 :     mSystemLayer = systemLayer;
     245            1 :     Dnssd::Resolver::Instance().SetOperationalDelegate(this);
     246            1 :     return CHIP_NO_ERROR;
     247              : }
     248              : 
     249            1 : void Resolver::Shutdown()
     250              : {
     251              :     // mSystemLayer is set in ::Init, so if it's null that means the resolver
     252              :     // has not been initialized or has already been shut down.
     253            1 :     VerifyOrReturn(mSystemLayer != nullptr);
     254              : 
     255            1 :     while (mActiveLookups.begin() != mActiveLookups.end())
     256              :     {
     257            0 :         auto current = mActiveLookups.begin();
     258              : 
     259            0 :         const PeerId peerId     = current->GetRequest().GetPeerId();
     260            0 :         NodeListener * listener = current->GetListener();
     261              : 
     262            0 :         mActiveLookups.Erase(current);
     263              : 
     264              :         MATTER_LOG_NODE_DISCOVERY_FAILED(&peerId, CHIP_ERROR_SHUT_DOWN);
     265              : 
     266            0 :         Dnssd::Resolver::Instance().NodeIdResolutionNoLongerNeeded(peerId);
     267              :         // Failure callback only called after iterator was cleared:
     268              :         // This allows failure handlers to deallocate structures that may
     269              :         // contain the active lookup data as a member (intrusive lists members)
     270            0 :         listener->OnNodeAddressResolutionFailed(peerId, CHIP_ERROR_SHUT_DOWN);
     271              :     }
     272              : 
     273              :     // Re-arm of timer is expected to cancel any active timer as the
     274              :     // internal list of active lookups is empty at this point.
     275            1 :     ReArmTimer();
     276              : 
     277            1 :     mSystemLayer = nullptr;
     278            1 :     Dnssd::Resolver::Instance().SetOperationalDelegate(nullptr);
     279              : }
     280              : 
     281            0 : void Resolver::OnOperationalNodeResolved(const Dnssd::ResolvedNodeData & nodeData)
     282              : {
     283            0 :     auto it = mActiveLookups.begin();
     284            0 :     while (it != mActiveLookups.end())
     285              :     {
     286            0 :         auto current = it;
     287            0 :         it++;
     288            0 :         if (current->GetRequest().GetPeerId() != nodeData.operationalData.peerId)
     289              :         {
     290            0 :             continue;
     291              :         }
     292              : 
     293            0 :         ResolveResult result;
     294              : 
     295            0 :         result.address.SetPort(nodeData.resolutionData.port);
     296            0 :         result.address.SetInterface(nodeData.resolutionData.interfaceId);
     297            0 :         result.mrpRemoteConfig   = nodeData.resolutionData.GetRemoteMRPConfig();
     298            0 :         result.supportsTcpClient = nodeData.resolutionData.supportsTcpClient;
     299            0 :         result.supportsTcpServer = nodeData.resolutionData.supportsTcpServer;
     300              : 
     301            0 :         if (nodeData.resolutionData.isICDOperatingAsLIT.has_value())
     302              :         {
     303            0 :             result.isICDOperatingAsLIT = *(nodeData.resolutionData.isICDOperatingAsLIT);
     304              :         }
     305              : 
     306            0 :         for (size_t i = 0; i < nodeData.resolutionData.numIPs; i++)
     307              :         {
     308              : #if !INET_CONFIG_ENABLE_IPV4
     309              :             if (!nodeData.resolutionData.ipAddress[i].IsIPv6())
     310              :             {
     311              :                 ChipLogError(Discovery, "Skipping IPv4 address during operational resolve.");
     312              :                 continue;
     313              :             }
     314              : #endif
     315            0 :             result.address.SetIPAddress(nodeData.resolutionData.ipAddress[i]);
     316            0 :             current->LookupResult(result);
     317              :         }
     318              : 
     319            0 :         HandleAction(current);
     320              :     }
     321              : 
     322            0 :     ReArmTimer();
     323            0 : }
     324              : 
     325            0 : void Resolver::HandleAction(IntrusiveList<NodeLookupHandle>::Iterator & current)
     326              : {
     327            0 :     const NodeLookupAction action = current->NextAction(mTimeSource.GetMonotonicTimestamp());
     328              : 
     329            0 :     if (action.Type() == NodeLookupResult::kKeepSearching)
     330              :     {
     331              :         // No change in iterator
     332            0 :         return;
     333              :     }
     334              : 
     335              :     // final result, handle either success or failure
     336            0 :     const PeerId peerId     = current->GetRequest().GetPeerId();
     337            0 :     NodeListener * listener = current->GetListener();
     338            0 :     mActiveLookups.Erase(current);
     339              : 
     340            0 :     Dnssd::Resolver::Instance().NodeIdResolutionNoLongerNeeded(peerId);
     341              : 
     342              :     // ensure action is taken AFTER the current current lookup is marked complete
     343              :     // This allows failure handlers to deallocate structures that may
     344              :     // contain the active lookup data as a member (intrusive lists members)
     345            0 :     switch (action.Type())
     346              :     {
     347            0 :     case NodeLookupResult::kLookupError:
     348              :         MATTER_LOG_NODE_DISCOVERY_FAILED(&peerId, action.ErrorResult());
     349            0 :         listener->OnNodeAddressResolutionFailed(peerId, action.ErrorResult());
     350            0 :         break;
     351            0 :     case NodeLookupResult::kLookupSuccess:
     352              :         MATTER_LOG_NODE_DISCOVERED(Tracing::DiscoveryInfoType::kResolutionDone, &peerId, &action.ResolveResult());
     353            0 :         listener->OnNodeAddressResolved(peerId, action.ResolveResult());
     354            0 :         break;
     355            0 :     default:
     356            0 :         ChipLogError(Discovery, "Unexpected lookup state (not success or fail).");
     357            0 :         break;
     358              :     }
     359              : }
     360              : 
     361            0 : void Resolver::HandleTimer()
     362              : {
     363            0 :     auto it = mActiveLookups.begin();
     364            0 :     while (it != mActiveLookups.end())
     365              :     {
     366            0 :         auto current = it;
     367            0 :         it++;
     368              : 
     369            0 :         HandleAction(current);
     370              :     }
     371              : 
     372            0 :     ReArmTimer();
     373            0 : }
     374              : 
     375            0 : void Resolver::OnOperationalNodeResolutionFailed(const PeerId & peerId, CHIP_ERROR error)
     376              : {
     377            0 :     auto it = mActiveLookups.begin();
     378            0 :     while (it != mActiveLookups.end())
     379              :     {
     380            0 :         auto current = it;
     381            0 :         it++;
     382            0 :         if (current->GetRequest().GetPeerId() != peerId)
     383              :         {
     384            0 :             continue;
     385              :         }
     386              : 
     387            0 :         NodeListener * listener = current->GetListener();
     388            0 :         mActiveLookups.Erase(current);
     389              : 
     390            0 :         Dnssd::Resolver::Instance().NodeIdResolutionNoLongerNeeded(peerId);
     391              : 
     392              :         // Failure callback only called after iterator was cleared:
     393              :         // This allows failure handlers to deallocate structures that may
     394              :         // contain the active lookup data as a member (intrusive lists members)
     395            0 :         listener->OnNodeAddressResolutionFailed(peerId, error);
     396              :     }
     397            0 :     ReArmTimer();
     398            0 : }
     399              : 
     400            1 : void Resolver::ReArmTimer()
     401              : {
     402            1 :     mSystemLayer->CancelTimer(&OnResolveTimer, static_cast<void *>(this));
     403              : 
     404            1 :     System::Clock::Timestamp now = mTimeSource.GetMonotonicTimestamp();
     405              : 
     406            1 :     System::Clock::Timeout nextTimeout = kInvalidTimeout;
     407            1 :     for (auto & activeLookup : mActiveLookups)
     408              :     {
     409            0 :         System::Clock::Timeout timeout = activeLookup.NextEventTimeout(now);
     410              : 
     411            0 :         if (timeout < nextTimeout)
     412              :         {
     413            0 :             nextTimeout = timeout;
     414              :         }
     415              :     }
     416              : 
     417            1 :     if (nextTimeout == kInvalidTimeout)
     418              :     {
     419              :         // Generally this is only expected when no active lookups exist
     420            1 :         return;
     421              :     }
     422              : 
     423            0 :     CHIP_ERROR err = mSystemLayer->StartTimer(nextTimeout, &OnResolveTimer, static_cast<void *>(this));
     424            0 :     if (err != CHIP_NO_ERROR)
     425              :     {
     426            0 :         ChipLogError(Discovery, "Timer schedule error %s assumed permanent", err.AsString());
     427              : 
     428              :         // Clear out all active lookups: without timers there is no guarantee of success
     429            0 :         auto it = mActiveLookups.begin();
     430            0 :         while (it != mActiveLookups.end())
     431              :         {
     432            0 :             const PeerId peerId     = it->GetRequest().GetPeerId();
     433            0 :             NodeListener * listener = it->GetListener();
     434              : 
     435            0 :             mActiveLookups.Erase(it);
     436            0 :             it = mActiveLookups.begin();
     437              : 
     438            0 :             Dnssd::Resolver::Instance().NodeIdResolutionNoLongerNeeded(peerId);
     439              :             // Callback only called after active lookup is cleared
     440              :             // This allows failure handlers to deallocate structures that may
     441              :             // contain the active lookup data as a member (intrusive lists members)
     442            0 :             listener->OnNodeAddressResolutionFailed(peerId, err);
     443              :         }
     444              :     }
     445              : }
     446              : 
     447              : } // namespace Impl
     448              : 
     449            2 : Resolver & Resolver::Instance()
     450              : {
     451            2 :     static Impl::Resolver gResolver;
     452            2 :     return gResolver;
     453              : }
     454              : 
     455              : } // namespace AddressResolve
     456              : } // namespace chip
        

Generated by: LCOV version 2.0-1