Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / messaging / ReliableMessageMgr.cpp
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 <inttypes.h>
25
26 #include <messaging/ReliableMessageMgr.h>
27
28 #include <messaging/ErrorCategory.h>
29 #include <messaging/Flags.h>
30 #include <messaging/ReliableMessageContext.h>
31 #include <support/BitFlags.h>
32 #include <support/CHIPFaultInjection.h>
33 #include <support/CodeUtils.h>
34 #include <support/logging/CHIPLogging.h>
35
36 namespace chip {
37 namespace Messaging {
38
39 ReliableMessageMgr::RetransTableEntry::RetransTableEntry() : rc(nullptr), nextRetransTimeTick(0), sendCount(0) {}
40
41 ReliableMessageMgr::ReliableMessageMgr(std::array<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & contextPool) :
42     mContextPool(contextPool), mSystemLayer(nullptr), mSessionMgr(nullptr), mCurrentTimerExpiry(0),
43     mTimerIntervalShift(CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT)
44 {}
45
46 ReliableMessageMgr::~ReliableMessageMgr() {}
47
48 void ReliableMessageMgr::Init(chip::System::Layer * systemLayer, SecureSessionMgr * sessionMgr)
49 {
50     mSystemLayer = systemLayer;
51     mSessionMgr  = sessionMgr;
52
53     mTimeStampBase      = System::Timer::GetCurrentEpoch();
54     mCurrentTimerExpiry = 0;
55 }
56
57 void ReliableMessageMgr::Shutdown()
58 {
59     StopTimer();
60
61     mSystemLayer = nullptr;
62     mSessionMgr  = nullptr;
63
64     // Clear the retransmit table
65     for (RetransTableEntry & rEntry : mRetransTable)
66     {
67         ClearRetransTable(rEntry);
68     }
69 }
70
71 uint64_t ReliableMessageMgr::GetTickCounterFromTimePeriod(uint64_t period)
72 {
73     return (period >> mTimerIntervalShift);
74 }
75
76 uint64_t ReliableMessageMgr::GetTickCounterFromTimeDelta(uint64_t newTime)
77 {
78     return GetTickCounterFromTimePeriod(newTime - mTimeStampBase);
79 }
80
81 #if defined(RMP_TICKLESS_DEBUG)
82 void ReliableMessageMgr::TicklessDebugDumpRetransTable(const char * log)
83 {
84     ChipLogProgress(ExchangeManager, log);
85
86     for (RetransTableEntry & entry : mRetransTable)
87     {
88         if (entry.rc)
89         {
90             ChipLogProgress(ExchangeManager, "EC:%04" PRIX16 " MsgId:%08" PRIX32 " NextRetransTimeCtr:%04" PRIX16, entry.rc,
91                             entry.msgId, entry.nextRetransTimeTick);
92         }
93     }
94 }
95 #else
96 void ReliableMessageMgr::TicklessDebugDumpRetransTable(const char * log)
97 {
98     return;
99 }
100 #endif // RMP_TICKLESS_DEBUG
101
102 void ReliableMessageMgr::ExecuteActions()
103 {
104 #if defined(RMP_TICKLESS_DEBUG)
105     ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExecuteActions");
106 #endif
107
108     ExecuteForAllContext([](ReliableMessageContext * rc) {
109         if (rc->IsAckPending())
110         {
111             if (0 == rc->mNextAckTimeTick)
112             {
113 #if defined(RMP_TICKLESS_DEBUG)
114                 ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExecuteActions sending ACK");
115 #endif
116                 // Send the Ack in a SecureChannel::StandaloneAck message
117                 rc->SendStandaloneAckMessage();
118                 rc->SetAckPending(false);
119             }
120         }
121     });
122
123     TicklessDebugDumpRetransTable("ReliableMessageMgr::ExecuteActions Dumping mRetransTable entries before processing");
124
125     // Retransmit / cancel anything in the retrans table whose retrans timeout
126     // has expired
127     for (RetransTableEntry & entry : mRetransTable)
128     {
129         ReliableMessageContext * rc = entry.rc;
130         CHIP_ERROR err              = CHIP_NO_ERROR;
131
132         if (!rc || entry.nextRetransTimeTick != 0)
133             continue;
134
135         uint8_t sendCount = entry.sendCount;
136
137         if (sendCount == rc->mConfig.mMaxRetrans)
138         {
139             err = CHIP_ERROR_MESSAGE_NOT_ACKNOWLEDGED;
140
141             ChipLogError(ExchangeManager, "Failed to Send CHIP MsgId:%08" PRIX32 " sendCount: %" PRIu8 " max retries: %" PRIu8,
142                          entry.retainedBuf.GetMsgId(), sendCount, rc->mConfig.mMaxRetrans);
143
144             // Remove from Table
145             ClearRetransTable(entry);
146         }
147
148         // Resend from Table (if the operation fails, the entry is cleared)
149         if (err == CHIP_NO_ERROR)
150             err = SendFromRetransTable(&entry);
151
152         if (err == CHIP_NO_ERROR)
153         {
154             // If the retransmission was successful, update the passive timer
155             entry.nextRetransTimeTick = static_cast<uint16_t>(rc->GetCurrentRetransmitTimeoutTick());
156 #if !defined(NDEBUG)
157             ChipLogProgress(ExchangeManager, "Retransmit MsgId:%08" PRIX32 " Send Cnt %d", entry.retainedBuf.GetMsgId(),
158                             entry.sendCount);
159 #endif
160         }
161
162         if (err != CHIP_NO_ERROR && rc->mDelegate)
163             rc->mDelegate->OnSendError(err);
164     }
165
166     TicklessDebugDumpRetransTable("ReliableMessageMgr::ExecuteActions Dumping mRetransTable entries after processing");
167 }
168
169 static void TickProceed(uint16_t & time, uint64_t ticks)
170 {
171     if (time >= ticks)
172     {
173         time = static_cast<uint16_t>(time - ticks);
174     }
175     else
176     {
177         time = 0;
178     }
179 }
180
181 void ReliableMessageMgr::ExpireTicks()
182 {
183     uint64_t now = System::Timer::GetCurrentEpoch();
184
185     // Number of full ticks elapsed since last timer processing.  We always round down
186     // to the previous tick.  If we are between tick boundaries, the extra time since the
187     // last virtual tick is not accounted for here (it will be accounted for when resetting
188     // the ReliableMessageProtocol timer)
189     uint64_t deltaTicks = GetTickCounterFromTimeDelta(now);
190
191 #if defined(RMP_TICKLESS_DEBUG)
192     ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExpireTicks at %" PRIu64 ", %" PRIu64 ", %u", now, mTimeStampBase,
193                     deltaTicks);
194 #endif
195
196     ExecuteForAllContext([deltaTicks](ReliableMessageContext * rc) {
197         if (rc->IsAckPending())
198         {
199             // Decrement counter of Ack timestamp by the elapsed timer ticks
200             TickProceed(rc->mNextAckTimeTick, deltaTicks);
201 #if defined(RMP_TICKLESS_DEBUG)
202             ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExpireTicks set mNextAckTimeTick to %u", rc->mNextAckTimeTick);
203 #endif
204         }
205     });
206
207     for (RetransTableEntry & entry : mRetransTable)
208     {
209         ReliableMessageContext * rc = entry.rc;
210         if (rc)
211         {
212             // Decrement Retransmit timeout by elapsed timeticks
213             TickProceed(entry.nextRetransTimeTick, deltaTicks);
214 #if defined(RMP_TICKLESS_DEBUG)
215             ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExpireTicks set nextRetransTimeTick to %u",
216                             entry.nextRetransTimeTick);
217 #endif
218         } // rc entry is allocated
219     }
220
221     // Re-Adjust the base time stamp to the most recent tick boundary
222     mTimeStampBase += (deltaTicks << mTimerIntervalShift);
223
224 #if defined(RMP_TICKLESS_DEBUG)
225     ChipLogProgress(ExchangeManager, "ReliableMessageMgr::ExpireTicks mTimeStampBase to %" PRIu64, mTimeStampBase);
226 #endif
227 }
228
229 void ReliableMessageMgr::Timeout(System::Layer * aSystemLayer, void * aAppState, System::Error aError)
230 {
231     ReliableMessageMgr * manager = reinterpret_cast<ReliableMessageMgr *>(aAppState);
232
233     VerifyOrDie((aSystemLayer != nullptr) && (manager != nullptr));
234
235 #if defined(RMP_TICKLESS_DEBUG)
236     ChipLogProgress(ExchangeManager, "ReliableMessageMgr::Timeout\n");
237 #endif
238
239     // Make sure all tick counts are sync'd to the current time
240     manager->ExpireTicks();
241
242     // Execute any actions that are due this tick
243     manager->ExecuteActions();
244
245     // Calculate next physical wakeup
246     manager->StartTimer();
247 }
248
249 CHIP_ERROR ReliableMessageMgr::AddToRetransTable(ReliableMessageContext * rc, RetransTableEntry ** rEntry)
250 {
251     bool added     = false;
252     CHIP_ERROR err = CHIP_NO_ERROR;
253
254     VerifyOrDie(rc != nullptr && rc->mExchange != nullptr);
255
256     for (RetransTableEntry & entry : mRetransTable)
257     {
258         // Check the exchContext pointer for finding an empty slot in Table
259         if (!entry.rc)
260         {
261             // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
262             ExpireTicks();
263
264             entry.rc          = rc;
265             entry.sendCount   = 0;
266             entry.retainedBuf = EncryptedPacketBufferHandle();
267
268             *rEntry = &entry;
269
270             // Increment the reference count
271             rc->Retain();
272             added = true;
273
274             break;
275         }
276     }
277
278     if (!added)
279     {
280         ChipLogError(ExchangeManager, "mRetransTable Already Full");
281         err = CHIP_ERROR_RETRANS_TABLE_FULL;
282     }
283
284     return err;
285 }
286
287 void ReliableMessageMgr::StartRetransmision(RetransTableEntry * entry)
288 {
289     VerifyOrDie(entry != nullptr && entry->rc != nullptr);
290
291     entry->nextRetransTimeTick = static_cast<uint16_t>(entry->rc->GetCurrentRetransmitTimeoutTick() +
292                                                        GetTickCounterFromTimeDelta(System::Timer::GetCurrentEpoch()));
293
294     // Check if the timer needs to be started and start it.
295     StartTimer();
296 }
297
298 void ReliableMessageMgr::PauseRetransmision(ReliableMessageContext * rc, uint32_t PauseTimeMillis)
299 {
300     for (RetransTableEntry & entry : mRetransTable)
301     {
302         if (entry.rc == rc)
303         {
304             entry.nextRetransTimeTick = static_cast<uint16_t>(entry.nextRetransTimeTick + (PauseTimeMillis >> mTimerIntervalShift));
305             break;
306         }
307     }
308 }
309
310 void ReliableMessageMgr::ResumeRetransmision(ReliableMessageContext * rc)
311 {
312     for (RetransTableEntry & entry : mRetransTable)
313     {
314         if (entry.rc == rc)
315         {
316             entry.nextRetransTimeTick = 0;
317             break;
318         }
319     }
320 }
321
322 bool ReliableMessageMgr::CheckAndRemRetransTable(ReliableMessageContext * rc, uint32_t ackMsgId)
323 {
324     for (RetransTableEntry & entry : mRetransTable)
325     {
326         if ((entry.rc == rc) && entry.retainedBuf.GetMsgId() == ackMsgId)
327         {
328             // Clear the entry from the retransmision table.
329             ClearRetransTable(entry);
330
331 #if !defined(NDEBUG)
332             ChipLogProgress(ExchangeManager, "Rxd Ack; Removing MsgId:%08" PRIX32 " from Retrans Table", ackMsgId);
333 #endif
334             return true;
335         }
336     }
337
338     return false;
339 }
340
341 CHIP_ERROR ReliableMessageMgr::SendFromRetransTable(RetransTableEntry * entry)
342 {
343     CHIP_ERROR err              = CHIP_NO_ERROR;
344     ReliableMessageContext * rc = entry->rc;
345
346     if (rc)
347     {
348         err = mSessionMgr->SendEncryptedMessage(entry->rc->mExchange->GetSecureSession(), std::move(entry->retainedBuf),
349                                                 &entry->retainedBuf);
350
351         if (err == CHIP_NO_ERROR)
352         {
353             // Update the counters
354             entry->sendCount++;
355         }
356         else
357         {
358             // Remove from table
359             ChipLogError(ExchangeManager, "Crit-err %ld when sending CHIP MsgId:%08" PRIX32 ", send tries: %d", long(err),
360                          entry->retainedBuf.GetMsgId(), entry->sendCount);
361
362             ClearRetransTable(*entry);
363         }
364     }
365     else
366     {
367         ChipLogError(ExchangeManager, "Table entry invalid");
368     }
369
370     return err;
371 }
372
373 void ReliableMessageMgr::ClearRetransTable(ReliableMessageContext * rc)
374 {
375     for (RetransTableEntry & entry : mRetransTable)
376     {
377         if (entry.rc == rc)
378         {
379             // Clear the retransmit table entry.
380             ClearRetransTable(entry);
381         }
382     }
383 }
384
385 void ReliableMessageMgr::ClearRetransTable(RetransTableEntry & rEntry)
386 {
387     if (rEntry.rc)
388     {
389         VerifyOrDie(rEntry.rc->mExchange != nullptr);
390
391         // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
392         ExpireTicks();
393
394         rEntry.rc->Release();
395         rEntry.rc = nullptr;
396
397         // Clear all other fields
398         rEntry = RetransTableEntry();
399
400         // Schedule next physical wakeup, unless shutting down
401         if (mSystemLayer)
402             StartTimer();
403     }
404 }
405
406 void ReliableMessageMgr::FailRetransTableEntries(ReliableMessageContext * rc, CHIP_ERROR err)
407 {
408     for (RetransTableEntry & entry : mRetransTable)
409     {
410         if (entry.rc == rc)
411         {
412             // Remove the entry from the retransmission table.
413             ClearRetransTable(entry);
414
415             // Application callback OnSendError.
416             rc->mDelegate->OnSendError(err);
417         }
418     }
419 }
420
421 void ReliableMessageMgr::StartTimer()
422 {
423     CHIP_ERROR res            = CHIP_NO_ERROR;
424     uint64_t nextWakeTimeTick = UINT64_MAX;
425     bool foundWake            = false;
426
427     // When do we need to next wake up to send an ACK?
428
429     ExecuteForAllContext([&nextWakeTimeTick, &foundWake](ReliableMessageContext * rc) {
430         if (rc->IsAckPending() && rc->mNextAckTimeTick < nextWakeTimeTick)
431         {
432             nextWakeTimeTick = rc->mNextAckTimeTick;
433             foundWake        = true;
434 #if defined(RMP_TICKLESS_DEBUG)
435             ChipLogProgress(ExchangeManager, "ReliableMessageMgr::StartTimer next ACK time %u", nextWakeTimeTick);
436 #endif
437         }
438     });
439
440     for (RetransTableEntry & entry : mRetransTable)
441     {
442         ReliableMessageContext * rc = entry.rc;
443         if (rc)
444         {
445             // When do we need to next wake up for ReliableMessageProtocol retransmit?
446             if (entry.nextRetransTimeTick < nextWakeTimeTick)
447             {
448                 nextWakeTimeTick = entry.nextRetransTimeTick;
449                 foundWake        = true;
450 #if defined(RMP_TICKLESS_DEBUG)
451                 ChipLogProgress(ExchangeManager, "ReliableMessageMgr::StartTimer RetransTime %u", nextWakeTimeTick);
452 #endif
453             }
454         }
455     }
456
457     if (foundWake)
458     {
459         // Set timer for next tick boundary - subtract the elapsed time from the current tick
460         System::Timer::Epoch timerExpiryEpoch = (nextWakeTimeTick << mTimerIntervalShift) + mTimeStampBase;
461
462 #if defined(RMP_TICKLESS_DEBUG)
463         ChipLogProgress(ExchangeManager, "ReliableMessageMgr::StartTimer wake at %" PRIu64 " ms (%" PRIu64 " %" PRIu64 ")",
464                         timerExpiryEpoch, nextWakeTimeTick, mTimeStampBase);
465 #endif
466         if (timerExpiryEpoch != mCurrentTimerExpiry)
467         {
468             // If the tick boundary has expired in the past (delayed processing of event due to other system activity),
469             // expire the timer immediately
470             uint64_t now           = System::Timer::GetCurrentEpoch();
471             uint64_t timerArmValue = (timerExpiryEpoch > now) ? timerExpiryEpoch - now : 0;
472
473 #if defined(RMP_TICKLESS_DEBUG)
474             ChipLogProgress(ExchangeManager, "ReliableMessageMgr::StartTimer set timer for %" PRIu64, timerArmValue);
475 #endif
476             StopTimer();
477             res = mSystemLayer->StartTimer((uint32_t) timerArmValue, Timeout, this);
478
479             VerifyOrDieWithMsg(res == CHIP_NO_ERROR, ExchangeManager, "Cannot start ReliableMessageMgr::Timeout\n");
480             mCurrentTimerExpiry = timerExpiryEpoch;
481 #if defined(RMP_TICKLESS_DEBUG)
482         }
483         else
484         {
485             ChipLogProgress(ExchangeManager, "ReliableMessageMgr::StartTimer timer already set for %" PRIu64, timerExpiryEpoch);
486 #endif
487         }
488     }
489     else
490     {
491 #if defined(RMP_TICKLESS_DEBUG)
492         ChipLogProgress(ExchangeManager, "Not setting ReliableMessageProtocol timeout at %" PRIu64,
493                         System::Timer::GetCurrentEpoch());
494 #endif
495         StopTimer();
496     }
497
498     TicklessDebugDumpRetransTable("ReliableMessageMgr::StartTimer Dumping mRetransTable entries after setting wakeup times");
499 }
500
501 void ReliableMessageMgr::StopTimer()
502 {
503     mSystemLayer->CancelTimer(Timeout, this);
504 }
505
506 int ReliableMessageMgr::TestGetCountRetransTable()
507 {
508     int count = 0;
509
510     for (RetransTableEntry & entry : mRetransTable)
511     {
512         ReliableMessageContext * rc = entry.rc;
513         if (rc)
514             count++;
515     }
516
517     return count;
518 }
519
520 } // namespace Messaging
521 } // namespace chip