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
|