Matter SDK Coverage Report
Current view: top level - messaging - ReliableMessageMgr.cpp (source / functions) Coverage Total Hit
Test: SHA:09f6fdf93a7e847a42518c076e487f336877a722 Lines: 95.0 % 221 210
Test Date: 2025-06-07 07:10:33 Functions: 100.0 % 33 33

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       3              :  *    All rights reserved.
       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              : /**
      19              :  *    @file
      20              :  *      This file implements the CHIP reliable message protocol.
      21              :  *
      22              :  */
      23              : 
      24              : #include <errno.h>
      25              : #include <inttypes.h>
      26              : 
      27              : #include <app/icd/server/ICDServerConfig.h>
      28              : #include <lib/support/BitFlags.h>
      29              : #include <lib/support/CHIPFaultInjection.h>
      30              : #include <lib/support/CodeUtils.h>
      31              : #include <lib/support/logging/CHIPLogging.h>
      32              : #include <messaging/ErrorCategory.h>
      33              : #include <messaging/ExchangeMessageDispatch.h>
      34              : #include <messaging/ExchangeMgr.h>
      35              : #include <messaging/Flags.h>
      36              : #include <messaging/ReliableMessageContext.h>
      37              : #include <messaging/ReliableMessageMgr.h>
      38              : #include <platform/ConnectivityManager.h>
      39              : #include <tracing/metric_event.h>
      40              : 
      41              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      42              : #include <app/icd/server/ICDConfigurationData.h> // nogncheck
      43              : #include <app/icd/server/ICDNotifier.h>          // nogncheck
      44              : #endif
      45              : 
      46              : using namespace chip::System::Clock::Literals;
      47              : 
      48              : namespace chip {
      49              : namespace Messaging {
      50              : 
      51              : System::Clock::Timeout ReliableMessageMgr::sAdditionalMRPBackoffTime = CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST;
      52              : 
      53        12646 : ReliableMessageMgr::RetransTableEntry::RetransTableEntry(ReliableMessageContext * rc) :
      54        12646 :     ec(*rc->GetExchangeContext()), nextRetransTime(0), sendCount(0)
      55              : {
      56        12646 :     ec->SetWaitingForAck(true);
      57        12646 : }
      58              : 
      59        12646 : ReliableMessageMgr::RetransTableEntry::~RetransTableEntry()
      60              : {
      61        12646 :     ec->SetWaitingForAck(false);
      62        12646 : }
      63              : 
      64          431 : ReliableMessageMgr::ReliableMessageMgr(ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & contextPool) :
      65          431 :     mContextPool(contextPool), mSystemLayer(nullptr)
      66          431 : {}
      67              : 
      68          431 : ReliableMessageMgr::~ReliableMessageMgr() {}
      69              : 
      70          369 : void ReliableMessageMgr::Init(chip::System::Layer * systemLayer)
      71              : {
      72          369 :     mSystemLayer = systemLayer;
      73          369 : }
      74              : 
      75          369 : void ReliableMessageMgr::Shutdown()
      76              : {
      77          369 :     StopTimer();
      78              : 
      79              :     // Clear the retransmit table
      80          369 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
      81            8 :         mRetransTable.ReleaseObject(entry);
      82            8 :         return Loop::Continue;
      83              :     });
      84              : 
      85          369 :     mSystemLayer = nullptr;
      86          369 : }
      87              : 
      88        38040 : void ReliableMessageMgr::TicklessDebugDumpRetransTable(const char * log)
      89              : {
      90              : #if defined(RMP_TICKLESS_DEBUG)
      91              :     ChipLogDetail(ExchangeManager, "%s", log);
      92              : 
      93              :     mRetransTable.ForEachActiveObject([&](auto * entry) {
      94              :         ChipLogDetail(ExchangeManager,
      95              :                       "EC:" ChipLogFormatExchange " MessageCounter:" ChipLogFormatMessageCounter
      96              :                       " NextRetransTimeCtr: 0x" ChipLogFormatX64,
      97              :                       ChipLogValueExchange(&entry->ec.Get()), entry->retainedBuf.GetMessageCounter(),
      98              :                       ChipLogValueX64(entry->nextRetransTime.count()));
      99              :         return Loop::Continue;
     100              :     });
     101              : #endif
     102        38040 : }
     103              : 
     104              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     105        25229 : void ReliableMessageMgr::NotifyMessageSendAnalytics(const RetransTableEntry & entry, const SessionHandle & sessionHandle,
     106              :                                                     const ReliableMessageAnalyticsDelegate::EventType & eventType)
     107              : {
     108              :     // For now we only support sending analytics for messages being sent over an established CASE session.
     109        25229 :     if (!mAnalyticsDelegate || !sessionHandle->IsSecureSession())
     110              :     {
     111        25217 :         return;
     112              :     }
     113              : 
     114           14 :     auto secureSession = sessionHandle->AsSecureSession();
     115           14 :     if (!secureSession->IsCASESession())
     116              :     {
     117            2 :         return;
     118              :     }
     119              : 
     120           12 :     uint32_t messageCounter                               = entry.retainedBuf.GetMessageCounter();
     121           12 :     auto fabricIndex                                      = sessionHandle->GetFabricIndex();
     122           12 :     auto destination                                      = secureSession->GetPeerNodeId();
     123           12 :     ReliableMessageAnalyticsDelegate::TransmitEvent event = { .nodeId      = destination,
     124              :                                                               .fabricIndex = fabricIndex,
     125              :                                                               .sessionType =
     126              :                                                                   ReliableMessageAnalyticsDelegate::SessionType::kEstablishedCase,
     127           12 :                                                               .eventType      = eventType,
     128           12 :                                                               .messageCounter = messageCounter };
     129              : 
     130           12 :     if (eventType == ReliableMessageAnalyticsDelegate::EventType::kRetransmission)
     131              :     {
     132            8 :         event.retransmissionCount = entry.sendCount;
     133              :     }
     134           12 :     if (eventType == ReliableMessageAnalyticsDelegate::EventType::kAcknowledged)
     135              :     {
     136            1 :         auto now           = System::SystemClock().GetMonotonicTimestamp();
     137            1 :         event.ackLatencyMs = now - entry.initialSentTime;
     138              :     }
     139              : 
     140           12 :     mAnalyticsDelegate->OnTransmitEvent(event);
     141              : }
     142              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     143              : 
     144           93 : void ReliableMessageMgr::ExecuteActions()
     145              : {
     146           93 :     System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp();
     147              : 
     148              : #if defined(RMP_TICKLESS_DEBUG)
     149              :     ChipLogDetail(ExchangeManager, "ReliableMessageMgr::ExecuteActions at 0x" ChipLogFormatX64 "ms", ChipLogValueX64(now.count()));
     150              : #endif
     151              : 
     152           93 :     ExecuteForAllContext([&](ReliableMessageContext * rc) {
     153          144 :         if (rc->IsAckPending())
     154              :         {
     155            0 :             if (rc->mNextAckTime <= now)
     156              :             {
     157              : #if defined(RMP_TICKLESS_DEBUG)
     158              :                 ChipLogDetail(ExchangeManager, "ReliableMessageMgr::ExecuteActions sending ACK %p", rc);
     159              : #endif
     160            0 :                 rc->SendStandaloneAckMessage();
     161              :             }
     162              :         }
     163          144 :     });
     164              : 
     165              :     // Retransmit / cancel anything in the retrans table whose retrans timeout has expired
     166           93 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
     167          123 :         if (entry->nextRetransTime > now)
     168           27 :             return Loop::Continue;
     169              : 
     170           96 :         VerifyOrDie(!entry->retainedBuf.IsNull());
     171              : 
     172              :         // Don't check whether the session in the exchange is valid, because when the session is released, the retrans entry is
     173              :         // cleared inside ExchangeContext::OnSessionReleased, so the session must be valid if the entry exists.
     174           96 :         auto session      = entry->ec->GetSessionHandle();
     175           96 :         uint8_t sendCount = entry->sendCount;
     176              : #if CHIP_ERROR_LOGGING || CHIP_PROGRESS_LOGGING
     177           96 :         uint32_t messageCounter = entry->retainedBuf.GetMessageCounter();
     178           96 :         auto fabricIndex        = session->GetFabricIndex();
     179           96 :         auto destination        = kUndefinedNodeId;
     180           96 :         if (session->IsSecureSession())
     181              :         {
     182           93 :             destination = session->AsSecureSession()->GetPeerNodeId();
     183              :         }
     184              : #endif // CHIP_ERROR_LOGGING || CHIP_DETAIL_LOGGING
     185              : 
     186           96 :         if (sendCount == CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS)
     187              :         {
     188              :             // Make sure our exchange stays alive until we are done working with it.
     189           14 :             ExchangeHandle ec(entry->ec);
     190              : 
     191           14 :             ChipLogError(ExchangeManager,
     192              :                          "<<%d [E:" ChipLogFormatExchange " S:%u M:" ChipLogFormatMessageCounter
     193              :                          "] (%s) Msg Retransmission to %u:" ChipLogFormatX64 " failure (max retries:%d)",
     194              :                          sendCount + 1, ChipLogValueExchange(&entry->ec.Get()), session->SessionIdForLogging(), messageCounter,
     195              :                          Transport::GetSessionTypeString(session), fabricIndex, ChipLogValueX64(destination),
     196              :                          CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS);
     197              : 
     198              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     199           14 :             NotifyMessageSendAnalytics(*entry, session, ReliableMessageAnalyticsDelegate::EventType::kFailed);
     200              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     201              : 
     202              :             // If the exchange is expecting a response, it will handle sending
     203              :             // this notification once it detects that it has not gotten a
     204              :             // response.  Otherwise, we need to do it.
     205           14 :             if (!ec->IsResponseExpected())
     206              :             {
     207            4 :                 if (session->IsSecureSession() && session->AsSecureSession()->IsCASESession())
     208              :                 {
     209            3 :                     session->AsSecureSession()->MarkAsDefunct();
     210              :                 }
     211            4 :                 session->NotifySessionHang();
     212              :             }
     213              : 
     214              :             // Do not StartTimer, we will schedule the timer at the end of the timer handler.
     215           14 :             mRetransTable.ReleaseObject(entry);
     216              : 
     217           14 :             return Loop::Continue;
     218           14 :         }
     219              : 
     220           82 :         entry->sendCount++;
     221              : 
     222           82 :         ChipLogProgress(ExchangeManager,
     223              :                         "<<%d [E:" ChipLogFormatExchange " S:%u M:" ChipLogFormatMessageCounter
     224              :                         "] (%s) Msg Retransmission to %u:" ChipLogFormatX64,
     225              :                         entry->sendCount, ChipLogValueExchange(&entry->ec.Get()), session->SessionIdForLogging(), messageCounter,
     226              :                         Transport::GetSessionTypeString(session), fabricIndex, ChipLogValueX64(destination));
     227              :         MATTER_LOG_METRIC(Tracing::kMetricDeviceRMPRetryCount, entry->sendCount);
     228              : 
     229           82 :         SendFromRetransTable(entry);
     230              : 
     231           82 :         return Loop::Continue;
     232           96 :     });
     233              : 
     234           93 :     TicklessDebugDumpRetransTable("ReliableMessageMgr::ExecuteActions Dumping mRetransTable entries after processing");
     235           93 : }
     236              : 
     237           93 : void ReliableMessageMgr::Timeout(System::Layer * aSystemLayer, void * aAppState)
     238              : {
     239           93 :     ReliableMessageMgr * manager = reinterpret_cast<ReliableMessageMgr *>(aAppState);
     240              : 
     241           93 :     VerifyOrDie((aSystemLayer != nullptr) && (manager != nullptr));
     242              : 
     243              : #if defined(RMP_TICKLESS_DEBUG)
     244              :     ChipLogDetail(ExchangeManager, "ReliableMessageMgr::Timeout");
     245              : #endif
     246              : 
     247              :     // Execute any actions that are due this tick
     248           93 :     manager->ExecuteActions();
     249              : 
     250              :     // Calculate next physical wakeup
     251           93 :     manager->StartTimer();
     252           93 : }
     253              : 
     254        12646 : CHIP_ERROR ReliableMessageMgr::AddToRetransTable(ReliableMessageContext * rc, RetransTableEntry ** rEntry)
     255              : {
     256        12646 :     VerifyOrReturnError(!rc->IsWaitingForAck(), CHIP_ERROR_INCORRECT_STATE);
     257              : 
     258        12646 :     *rEntry = mRetransTable.CreateObject(rc);
     259        12646 :     if (*rEntry == nullptr)
     260              :     {
     261            0 :         ChipLogError(ExchangeManager, "mRetransTable Already Full");
     262            0 :         return CHIP_ERROR_RETRANS_TABLE_FULL;
     263              :     }
     264              : 
     265        12646 :     return CHIP_NO_ERROR;
     266              : }
     267              : 
     268       110788 : System::Clock::Timeout ReliableMessageMgr::GetBackoff(System::Clock::Timeout baseInterval, uint8_t sendCount,
     269              :                                                       bool computeMaxPossible)
     270              : {
     271              :     // See section "4.11.8. Parameters and Constants" for the parameters below:
     272              :     // MRP_BACKOFF_JITTER = 0.25
     273       110788 :     constexpr uint32_t MRP_BACKOFF_JITTER_BASE = 1024;
     274              :     // MRP_BACKOFF_MARGIN = 1.1
     275       110788 :     constexpr uint32_t MRP_BACKOFF_MARGIN_NUMERATOR   = 1127;
     276       110788 :     constexpr uint32_t MRP_BACKOFF_MARGIN_DENOMINATOR = 1024;
     277              :     // MRP_BACKOFF_BASE = 1.6
     278       110788 :     constexpr uint32_t MRP_BACKOFF_BASE_NUMERATOR   = 16;
     279       110788 :     constexpr uint32_t MRP_BACKOFF_BASE_DENOMINATOR = 10;
     280       110788 :     constexpr int MRP_BACKOFF_THRESHOLD             = 1;
     281              : 
     282              :     // Implement `i = MRP_BACKOFF_MARGIN * i` from section "4.12.2.1. Retransmissions", where:
     283              :     //   i == interval
     284       110788 :     System::Clock::Milliseconds64 interval = baseInterval;
     285       110788 :     interval *= MRP_BACKOFF_MARGIN_NUMERATOR;
     286       110788 :     interval /= MRP_BACKOFF_MARGIN_DENOMINATOR;
     287              : 
     288              :     // Implement:
     289              :     //   mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD)) * (1.0 + random(0,1) * MRP_BACKOFF_JITTER)
     290              :     // from section "4.12.2.1. Retransmissions", where:
     291              :     //   i == interval
     292              :     //   n == sendCount
     293              : 
     294              :     // 1. Calculate exponent `max(0,n−MRP_BACKOFF_THRESHOLD)`
     295       110788 :     int exponent = sendCount - MRP_BACKOFF_THRESHOLD;
     296       110788 :     if (exponent < 0)
     297        32248 :         exponent = 0; // Enforce floor
     298       110788 :     if (exponent > 4)
     299           12 :         exponent = 4; // Enforce reasonable maximum after 5 tries
     300              : 
     301              :     // 2. Calculate `mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD))`
     302       110788 :     uint32_t backoffNum   = 1;
     303       110788 :     uint32_t backoffDenom = 1;
     304              : 
     305       228648 :     for (int i = 0; i < exponent; i++)
     306              :     {
     307       117860 :         backoffNum *= MRP_BACKOFF_BASE_NUMERATOR;
     308       117860 :         backoffDenom *= MRP_BACKOFF_BASE_DENOMINATOR;
     309              :     }
     310              : 
     311       110788 :     System::Clock::Milliseconds64 mrpBackoffTime = interval * backoffNum / backoffDenom;
     312              : 
     313              :     // 3. Calculate `mrpBackoffTime *= (1.0 + random(0,1) * MRP_BACKOFF_JITTER)`
     314       110788 :     uint32_t jitter = MRP_BACKOFF_JITTER_BASE + (computeMaxPossible ? UINT8_MAX : Crypto::GetRandU8());
     315       110788 :     mrpBackoffTime  = mrpBackoffTime * jitter / MRP_BACKOFF_JITTER_BASE;
     316              : 
     317              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     318              :     // Implement:
     319              :     //   "An ICD sender SHOULD increase t to also account for its own sleepy interval
     320              :     //   required to receive the acknowledgment"
     321              :     mrpBackoffTime += ICDConfigurationData::GetInstance().GetFastPollingInterval();
     322              : #endif
     323              : 
     324       110788 :     mrpBackoffTime += sAdditionalMRPBackoffTime;
     325              : 
     326       110788 :     return std::chrono::duration_cast<System::Clock::Timeout>(mrpBackoffTime);
     327              : }
     328              : 
     329        12641 : void ReliableMessageMgr::StartRetransmision(RetransTableEntry * entry)
     330              : {
     331        12641 :     CalculateNextRetransTime(*entry);
     332              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     333        12641 :     entry->initialSentTime = System::SystemClock().GetMonotonicTimestamp();
     334        12641 :     NotifyMessageSendAnalytics(*entry, entry->ec->GetSessionHandle(), ReliableMessageAnalyticsDelegate::EventType::kInitialSend);
     335              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     336        12641 :     StartTimer();
     337        12641 : }
     338              : 
     339        12510 : bool ReliableMessageMgr::CheckAndRemRetransTable(ReliableMessageContext * rc, uint32_t ackMessageCounter)
     340              : {
     341        12510 :     bool removed = false;
     342        12510 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
     343        30606 :         if (entry->ec->GetReliableMessageContext() == rc && entry->retainedBuf.GetMessageCounter() == ackMessageCounter)
     344              :         {
     345              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     346        12492 :             auto session = entry->ec->GetSessionHandle();
     347        12492 :             NotifyMessageSendAnalytics(*entry, session, ReliableMessageAnalyticsDelegate::EventType::kAcknowledged);
     348              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     349              : 
     350              :             // Clear the entry from the retransmision table.
     351        12492 :             ClearRetransTable(*entry);
     352              : 
     353        12492 :             ChipLogDetail(ExchangeManager,
     354              :                           "Rxd Ack; Removing MessageCounter:" ChipLogFormatMessageCounter
     355              :                           " from Retrans Table on exchange " ChipLogFormatExchange,
     356              :                           ackMessageCounter, ChipLogValueExchange(rc->GetExchangeContext()));
     357        12492 :             removed = true;
     358        12492 :             return Loop::Break;
     359        12492 :         }
     360        18114 :         return Loop::Continue;
     361              :     });
     362              : 
     363        12510 :     return removed;
     364              : }
     365              : 
     366           82 : CHIP_ERROR ReliableMessageMgr::SendFromRetransTable(RetransTableEntry * entry)
     367              : {
     368           82 :     if (!entry->ec->HasSessionHandle())
     369              :     {
     370              :         // Using same error message for all errors to reduce code size.
     371            0 :         ChipLogError(ExchangeManager,
     372              :                      "Crit-err %" CHIP_ERROR_FORMAT " when sending CHIP MessageCounter:" ChipLogFormatMessageCounter
     373              :                      " on exchange " ChipLogFormatExchange ", send tries: %d",
     374              :                      CHIP_ERROR_INCORRECT_STATE.Format(), entry->retainedBuf.GetMessageCounter(),
     375              :                      ChipLogValueExchange(&entry->ec.Get()), entry->sendCount);
     376            0 :         ClearRetransTable(*entry);
     377            0 :         return CHIP_ERROR_INCORRECT_STATE;
     378              :     }
     379              : 
     380           82 :     auto * sessionManager = entry->ec->GetExchangeMgr()->GetSessionManager();
     381           82 :     CHIP_ERROR err        = sessionManager->SendPreparedMessage(entry->ec->GetSessionHandle(), entry->retainedBuf);
     382           82 :     err                   = MapSendError(err, entry->ec->GetExchangeId(), entry->ec->IsInitiator());
     383              : 
     384           82 :     if (err == CHIP_NO_ERROR)
     385              :     {
     386           82 :         CalculateNextRetransTime(*entry);
     387              : 
     388              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     389              :         app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
     390              : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     391              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     392           82 :         NotifyMessageSendAnalytics(*entry, entry->ec->GetSessionHandle(),
     393          164 :                                    ReliableMessageAnalyticsDelegate::EventType::kRetransmission);
     394              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     395              : #if CHIP_CONFIG_RESOLVE_PEER_ON_FIRST_TRANSMIT_FAILURE
     396              :         const ExchangeManager * exchangeMgr = entry->ec->GetExchangeMgr();
     397              :         // TODO: investigate why in ReliableMessageMgr::CheckResendApplicationMessageWithPeerExchange unit test released exchange
     398              :         // context with mExchangeMgr==nullptr is used.
     399              :         if (exchangeMgr)
     400              :         {
     401              :             // After the first failure notify session manager to refresh device data
     402              :             if (entry->sendCount == 1 && mSessionUpdateDelegate != nullptr && entry->ec->GetSessionHandle()->IsSecureSession() &&
     403              :                 entry->ec->GetSessionHandle()->AsSecureSession()->IsCASESession())
     404              :             {
     405              :                 ChipLogDetail(ExchangeManager, "Notify session manager to update peer address");
     406              :                 mSessionUpdateDelegate->UpdatePeerAddress(entry->ec->GetSessionHandle()->GetPeer());
     407              :             }
     408              :         }
     409              : #endif // CHIP_CONFIG_RESOLVE_PEER_ON_FIRST_TRANSMIT_FAILURE
     410              :     }
     411              :     else
     412              :     {
     413              :         // Remove from table
     414              :         // Using same error message for all errors to reduce code size.
     415            0 :         ChipLogError(ExchangeManager,
     416              :                      "Crit-err %" CHIP_ERROR_FORMAT " when sending CHIP MessageCounter:" ChipLogFormatMessageCounter
     417              :                      " on exchange " ChipLogFormatExchange ", send tries: %d",
     418              :                      err.Format(), entry->retainedBuf.GetMessageCounter(), ChipLogValueExchange(&entry->ec.Get()),
     419              :                      entry->sendCount);
     420              : 
     421            0 :         ClearRetransTable(*entry);
     422              :     }
     423           82 :     return err;
     424              : }
     425              : 
     426          252 : void ReliableMessageMgr::ClearRetransTable(ReliableMessageContext * rc)
     427              : {
     428          252 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
     429          225 :         if (entry->ec->GetReliableMessageContext() == rc)
     430              :         {
     431          127 :             ClearRetransTable(*entry);
     432          127 :             return Loop::Break;
     433              :         }
     434           98 :         return Loop::Continue;
     435              :     });
     436          252 : }
     437              : 
     438        12624 : void ReliableMessageMgr::ClearRetransTable(RetransTableEntry & entry)
     439              : {
     440        12624 :     mRetransTable.ReleaseObject(&entry);
     441              :     // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
     442        12624 :     StartTimer();
     443        12624 : }
     444              : 
     445        37947 : void ReliableMessageMgr::StartTimer()
     446              : {
     447              :     // When do we need to next wake up to send an ACK?
     448        37947 :     System::Clock::Timestamp nextWakeTime = System::Clock::Timestamp::max();
     449              : 
     450        37947 :     ExecuteForAllContext([&](ReliableMessageContext * rc) {
     451       231331 :         if (rc->IsAckPending() && rc->mNextAckTime < nextWakeTime)
     452              :         {
     453        14993 :             nextWakeTime = rc->mNextAckTime;
     454              :         }
     455       231331 :     });
     456              : 
     457              :     // When do we need to next wake up for ReliableMessageProtocol retransmit?
     458        37947 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
     459       138198 :         if (entry->nextRetransTime < nextWakeTime)
     460              :         {
     461        27314 :             nextWakeTime = entry->nextRetransTime;
     462              :         }
     463       138198 :         return Loop::Continue;
     464              :     });
     465              : 
     466        37947 :     StopTimer();
     467              : 
     468        37947 :     if (nextWakeTime != System::Clock::Timestamp::max())
     469              :     {
     470        36001 :         const System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp();
     471        36001 :         const auto nextWakeDelay           = (nextWakeTime > now) ? nextWakeTime - now : 0_ms;
     472              : 
     473              : #if defined(RMP_TICKLESS_DEBUG)
     474              :         ChipLogDetail(ExchangeManager,
     475              :                       "ReliableMessageMgr::StartTimer at 0x" ChipLogFormatX64 "ms wake at 0x" ChipLogFormatX64
     476              :                       "ms (in 0x" ChipLogFormatX64 "ms)",
     477              :                       ChipLogValueX64(now.count()), ChipLogValueX64(nextWakeTime.count()), ChipLogValueX64(nextWakeDelay.count()));
     478              : #endif
     479        36001 :         VerifyOrDie(mSystemLayer->StartTimer(nextWakeDelay, Timeout, this) == CHIP_NO_ERROR);
     480              :     }
     481              :     else
     482              :     {
     483              : #if defined(RMP_TICKLESS_DEBUG)
     484              :         ChipLogDetail(ExchangeManager, "ReliableMessageMgr skipped timer");
     485              : #endif
     486              :     }
     487              : 
     488        37947 :     TicklessDebugDumpRetransTable("ReliableMessageMgr::StartTimer Dumping mRetransTable entries after setting wakeup times");
     489        37947 : }
     490              : 
     491        38322 : void ReliableMessageMgr::StopTimer()
     492              : {
     493        38322 :     mSystemLayer->CancelTimer(Timeout, this);
     494        38322 : }
     495              : 
     496            2 : void ReliableMessageMgr::RegisterSessionUpdateDelegate(SessionUpdateDelegate * sessionUpdateDelegate)
     497              : {
     498            2 :     mSessionUpdateDelegate = sessionUpdateDelegate;
     499            2 : }
     500              : 
     501              : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     502            4 : void ReliableMessageMgr::RegisterAnalyticsDelegate(ReliableMessageAnalyticsDelegate * analyticsDelegate)
     503              : {
     504            4 :     mAnalyticsDelegate = analyticsDelegate;
     505            4 : }
     506              : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
     507              : 
     508        12727 : CHIP_ERROR ReliableMessageMgr::MapSendError(CHIP_ERROR error, uint16_t exchangeId, bool isInitiator)
     509              : {
     510        12727 :     if (
     511              : #if CHIP_SYSTEM_CONFIG_USE_LWIP
     512              :         error == System::MapErrorLwIP(ERR_MEM)
     513              : #else
     514        12727 :         error == CHIP_ERROR_POSIX(ENOBUFS)
     515              : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
     516              :     )
     517              :     {
     518              :         // sendmsg on BSD-based systems never blocks, no matter how the
     519              :         // socket is configured, and will return ENOBUFS in situation in
     520              :         // which Linux, for example, blocks.
     521              :         //
     522              :         // This is typically a transient situation, so we pretend like this
     523              :         // packet drop happened somewhere on the network instead of inside
     524              :         // sendmsg and will just resend it in the normal MRP way later.
     525              :         //
     526              :         // Similarly, on LwIP an ERR_MEM on send indicates a likely
     527              :         // temporary lack of TX buffers.
     528            0 :         ChipLogError(ExchangeManager, "Ignoring transient send error: %" CHIP_ERROR_FORMAT " on exchange " ChipLogFormatExchangeId,
     529              :                      error.Format(), ChipLogValueExchangeId(exchangeId, isInitiator));
     530            0 :         error = CHIP_NO_ERROR;
     531              :     }
     532              : 
     533        12727 :     return error;
     534              : }
     535              : 
     536          740 : void ReliableMessageMgr::SetAdditionalMRPBackoffTime(const Optional<System::Clock::Timeout> & additionalTime)
     537              : {
     538          740 :     sAdditionalMRPBackoffTime = additionalTime.ValueOr(CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST);
     539          740 : }
     540              : 
     541        12723 : void ReliableMessageMgr::CalculateNextRetransTime(RetransTableEntry & entry)
     542              : {
     543        12723 :     System::Clock::Timeout baseTimeout = System::Clock::Timeout(0);
     544        12723 :     const auto sessionHandle           = entry.ec->GetSessionHandle();
     545              : 
     546              :     // Check if we have received at least one application-level message
     547        12723 :     if (entry.ec->HasReceivedAtLeastOneMessage())
     548              :     {
     549              :         // If we have received at least one message, assume peer is active and use ActiveRetransTimeout
     550        10390 :         baseTimeout = sessionHandle->GetRemoteMRPConfig().mActiveRetransTimeout;
     551              :     }
     552              :     else
     553              :     {
     554              :         // If we haven't received at least one message
     555              :         // Choose active/idle timeout from PeerActiveMode of session per 4.11.2.1. Retransmissions.
     556         2333 :         baseTimeout = sessionHandle->GetMRPBaseTimeout();
     557              :     }
     558              : 
     559        12723 :     System::Clock::Timeout backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry.sendCount);
     560        12723 :     entry.nextRetransTime          = System::SystemClock().GetMonotonicTimestamp() + backoff;
     561              : 
     562              : #if CHIP_PROGRESS_LOGGING
     563        12723 :     const auto config       = sessionHandle->GetRemoteMRPConfig();
     564        12723 :     uint32_t messageCounter = entry.retainedBuf.GetMessageCounter();
     565        12723 :     auto fabricIndex        = sessionHandle->GetFabricIndex();
     566        12723 :     auto destination        = kUndefinedNodeId;
     567        12723 :     bool peerIsActive       = false;
     568              : 
     569        12723 :     if (sessionHandle->IsSecureSession())
     570              :     {
     571        12637 :         peerIsActive = sessionHandle->AsSecureSession()->IsPeerActive();
     572        12637 :         destination  = sessionHandle->AsSecureSession()->GetPeerNodeId();
     573              :     }
     574           86 :     else if (sessionHandle->IsUnauthenticatedSession())
     575              :     {
     576           86 :         peerIsActive = sessionHandle->AsUnauthenticatedSession()->IsPeerActive();
     577              :     }
     578              : 
     579        12723 :     ChipLogProgress(ExchangeManager,
     580              :                     "??%d [E:" ChipLogFormatExchange " S:%u M:" ChipLogFormatMessageCounter
     581              :                     "] (%s) Msg Retransmission to %u:" ChipLogFormatX64 " scheduled for %" PRIu32
     582              :                     "ms from now [State:%s II:%" PRIu32 " AI:%" PRIu32 " AT:%u]",
     583              :                     entry.sendCount + 1, ChipLogValueExchange(&entry.ec.Get()), sessionHandle->SessionIdForLogging(),
     584              :                     messageCounter, Transport::GetSessionTypeString(sessionHandle), fabricIndex, ChipLogValueX64(destination),
     585              :                     backoff.count(), peerIsActive ? "Active" : "Idle", config.mIdleRetransTimeout.count(),
     586              :                     config.mActiveRetransTimeout.count(), config.mActiveThresholdTime.count());
     587              : #endif // CHIP_PROGRESS_LOGGING
     588        12723 : }
     589              : 
     590              : #if CHIP_CONFIG_TEST
     591       197097 : int ReliableMessageMgr::TestGetCountRetransTable()
     592              : {
     593       197097 :     int count = 0;
     594       197097 :     mRetransTable.ForEachActiveObject([&](auto * entry) {
     595       199944 :         count++;
     596       199944 :         return Loop::Continue;
     597              :     });
     598       197097 :     return count;
     599              : }
     600              : #endif // CHIP_CONFIG_TEST
     601              : 
     602              : } // namespace Messaging
     603              : } // namespace chip
        

Generated by: LCOV version 2.0-1