Matter SDK Coverage Report
Current view: top level - messaging - ReliableMessageMgr.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 94.3 % 192 181
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 31 31

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

Generated by: LCOV version 2.0-1