Line data Source code
1 : /*
2 : * Copyright (c) 2020 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 defines the classes corresponding to CHIP reliable message
21 : * protocol.
22 : */
23 :
24 : #pragma once
25 :
26 : #include <array>
27 : #include <stdint.h>
28 :
29 : #include <lib/core/CHIPError.h>
30 : #include <lib/core/Optional.h>
31 : #include <lib/support/BitFlags.h>
32 : #include <lib/support/Pool.h>
33 : #include <messaging/ExchangeContext.h>
34 : #include <messaging/ReliableMessageAnalyticsDelegate.h>
35 : #include <messaging/ReliableMessageProtocolConfig.h>
36 : #include <system/SystemLayer.h>
37 : #include <system/SystemPacketBuffer.h>
38 : #include <transport/SessionUpdateDelegate.h>
39 : #include <transport/raw/MessageHeader.h>
40 :
41 : namespace chip {
42 : namespace Messaging {
43 :
44 : enum class SendMessageFlags : uint16_t;
45 : class ReliableMessageContext;
46 :
47 : class ReliableMessageMgr
48 : {
49 : public:
50 : /**
51 : * @class RetransTableEntry
52 : *
53 : * @brief
54 : * This class is part of the CHIP Reliable Messaging Protocol and is used
55 : * to keep track of CHIP messages that have been sent and are expecting an
56 : * acknowledgment back. If the acknowledgment is not received within a
57 : * specific timeout, the message would be retransmitted from this table.
58 : *
59 : */
60 : struct RetransTableEntry
61 : {
62 : RetransTableEntry(ReliableMessageContext * rc);
63 : ~RetransTableEntry();
64 :
65 : ExchangeHandle ec; /**< The context for the stored CHIP message. */
66 : EncryptedPacketBufferHandle retainedBuf; /**< The packet buffer holding the CHIP message. */
67 : System::Clock::Timestamp nextRetransTime; /**< A counter representing the next retransmission time for the message. */
68 : uint8_t sendCount; /**< The number of times we have tried to send this entry,
69 : including both successfully and failure send. */
70 : };
71 :
72 : ReliableMessageMgr(ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & contextPool);
73 : ~ReliableMessageMgr();
74 :
75 : void Init(chip::System::Layer * systemLayer);
76 : void Shutdown();
77 :
78 : /**
79 : * Iterate through active exchange contexts and retrans table entries. If an
80 : * action needs to be triggered by ReliableMessageProtocol time facilities,
81 : * execute that action.
82 : */
83 : void ExecuteActions();
84 :
85 : /**
86 : * Handle physical wakeup of system due to ReliableMessageProtocol wakeup.
87 : *
88 : */
89 : static void Timeout(System::Layer * aSystemLayer, void * aAppState);
90 :
91 : /**
92 : * Add a CHIP message into the retransmission table to be subsequently resent if a corresponding acknowledgment
93 : * is not received within the retransmission timeout.
94 : *
95 : * @param[in] rc A pointer to the ExchangeContext object.
96 : *
97 : * @param[out] rEntry A pointer to a pointer of a retransmission table entry added into the table.
98 : *
99 : * @retval #CHIP_ERROR_RETRANS_TABLE_FULL If there is no empty slot left in the table for addition.
100 : * @retval #CHIP_NO_ERROR On success.
101 : */
102 : CHIP_ERROR AddToRetransTable(ReliableMessageContext * rc, RetransTableEntry ** rEntry);
103 :
104 : /**
105 : * Calculate the backoff timer for the retransmission.
106 : *
107 : * @param[in] baseInterval The base interval to use for the backoff calculation, either the active or idle interval.
108 : * @param[in] sendCount Count of how many times this message
109 : * has been retransmitted so far (0 if it has
110 : * been sent only once with no retransmits,
111 : * 1 if it has been sent twice, etc).
112 : * @param[in] computeMaxPossible Disable randomness such that the maximum value is used instead.
113 : *
114 : * @retval The backoff time value, including jitter.
115 : */
116 : static System::Clock::Timeout GetBackoff(System::Clock::Timeout baseInterval, uint8_t sendCount,
117 : bool computeMaxPossible = false);
118 :
119 : /**
120 : * Start retranmisttion of cached encryped packet for current entry.
121 : *
122 : * @param[in] entry A pointer to a retransmission table entry added into the table.
123 : *
124 : * @retval #CHIP_NO_ERROR On success.
125 : */
126 : void StartRetransmision(RetransTableEntry * entry);
127 :
128 : /**
129 : * Iterate through active exchange contexts and retrans table entries. Clear the entry matching
130 : * the specified ExchangeContext and the message ID from the retransmision table.
131 : *
132 : * @param[in] rc A pointer to the ExchangeContext object.
133 : * @param[in] ackMessageCounter The acknowledged message counter of the received packet.
134 : *
135 : * @retval #CHIP_NO_ERROR On success.
136 : */
137 : bool CheckAndRemRetransTable(ReliableMessageContext * rc, uint32_t ackMessageCounter);
138 :
139 : /**
140 : * Send the specified entry from the retransmission table.
141 : *
142 : * @param[in] entry A pointer to a retransmission table entry object that needs to be sent.
143 : *
144 : * @return #CHIP_NO_ERROR On success, else corresponding CHIP_ERROR returned from SendMessage.
145 : */
146 : CHIP_ERROR SendFromRetransTable(RetransTableEntry * entry);
147 :
148 : /**
149 : * Clear entries matching a specified ExchangeContext.
150 : *
151 : * @param[in] rc A pointer to the ExchangeContext object.
152 : *
153 : */
154 : void ClearRetransTable(ReliableMessageContext * rc);
155 :
156 : /**
157 : * Clear an entry in the retransmission table.
158 : *
159 : * @param[in] rEntry A reference to the RetransTableEntry object.
160 : *
161 : */
162 : void ClearRetransTable(RetransTableEntry & rEntry);
163 :
164 : /**
165 : * Iterate through active exchange contexts and retrans table entries.
166 : * Determine how many ReliableMessageProtocol ticks we need to sleep before we
167 : * need to physically wake the CPU to perform an action. Set a timer to go off
168 : * when we next need to wake the system.
169 : *
170 : */
171 : void StartTimer();
172 :
173 : /**
174 : * Stop the timer for retransmistion on current node.
175 : *
176 : */
177 : void StopTimer();
178 :
179 : /**
180 : * Registers a delegate to perform an address lookup and update all active sessions.
181 : *
182 : * @param[in] sessionUpdateDelegate - Pointer to delegate to perform address lookup
183 : * that will update all active session. A null pointer is allowed if you
184 : * no longer have a valid delegate.
185 : *
186 : */
187 : void RegisterSessionUpdateDelegate(SessionUpdateDelegate * sessionUpdateDelegate);
188 :
189 : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
190 : /**
191 : * Registers a delegate interested in analytic information
192 : *
193 : * @param[in] analyticsDelegate - Pointer to delegate for reporting analytic
194 : */
195 : void RegisterAnalyticsDelegate(ReliableMessageAnalyticsDelegate * analyticsDelegate);
196 : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
197 :
198 : /**
199 : * Map a send error code to the error code we should actually use for
200 : * success checks. This maps some error codes to CHIP_NO_ERROR as
201 : * appropriate.
202 : */
203 : static CHIP_ERROR MapSendError(CHIP_ERROR error, uint16_t exchangeId, bool isInitiator);
204 :
205 : #if CHIP_CONFIG_TEST
206 : // Functions for testing
207 : int TestGetCountRetransTable();
208 :
209 : // Enumerate the retransmission table. Clearing an entry while enumerating
210 : // that entry is allowed. F must take a RetransTableEntry as an argument
211 : // and return Loop::Continue or Loop::Break.
212 : template <typename F>
213 : void EnumerateRetransTable(F && functor)
214 : {
215 : mRetransTable.ForEachActiveObject(std::forward<F>(functor));
216 : }
217 : #endif // CHIP_CONFIG_TEST
218 :
219 : /**
220 : * Set the value to add to the MRP backoff time we compute. This is meant to
221 : * account for high network latency on the sending side (us) that can't be
222 : * known to the message recipient and hence is not captured in the MRP
223 : * parameters the message recipient communicates to us.
224 : *
225 : * If set to NullOptional falls back to the compile-time
226 : * CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST.
227 : *
228 : * This is a static, not a regular member, because API consumers may need to
229 : * set this before actually bringing up the stack and having access to a
230 : * ReliableMessageMgr.
231 : */
232 : static void SetAdditionalMRPBackoffTime(const Optional<System::Clock::Timeout> & additionalTime);
233 :
234 : private:
235 : /**
236 : * Calculates the next retransmission time for the entry
237 : * Function sets the nextRetransTime of the entry
238 : *
239 : * @param[in,out] entry RetransTableEntry for which we need to calculate the nextRetransTime
240 : */
241 : void CalculateNextRetransTime(RetransTableEntry & entry);
242 :
243 : ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & mContextPool;
244 : chip::System::Layer * mSystemLayer;
245 :
246 : /* Placeholder function to run a function for all exchanges */
247 : template <typename Function>
248 25130 : void ExecuteForAllContext(Function function)
249 : {
250 231724 : mContextPool.ForEachActiveObject([&](auto * ec) {
251 206594 : function(ec->GetReliableMessageContext());
252 206594 : return Loop::Continue;
253 : });
254 25130 : }
255 :
256 : void TicklessDebugDumpRetransTable(const char * log);
257 :
258 : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
259 : void NotifyMessageSendAnalytics(const RetransTableEntry & entry, const SessionHandle & sessionHandle,
260 : const ReliableMessageAnalyticsDelegate::EventType & eventType);
261 : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
262 :
263 : // ReliableMessageProtocol Global tables for timer context
264 : ObjectPool<RetransTableEntry, CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE> mRetransTable;
265 :
266 : SessionUpdateDelegate * mSessionUpdateDelegate = nullptr;
267 : #if CHIP_CONFIG_MRP_ANALYTICS_ENABLED
268 : ReliableMessageAnalyticsDelegate * mAnalyticsDelegate = nullptr;
269 : #endif // CHIP_CONFIG_MRP_ANALYTICS_ENABLED
270 :
271 : static System::Clock::Timeout sAdditionalMRPBackoffTime;
272 : };
273 :
274 : } // namespace Messaging
275 : } // namespace chip
|