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