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

Generated by: LCOV version 2.0-1