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

Generated by: LCOV version 2.0-1