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
|