Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
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 ExchangeManager class.
21 : *
22 : */
23 :
24 : #ifndef __STDC_FORMAT_MACROS
25 : #define __STDC_FORMAT_MACROS
26 : #endif
27 :
28 : #ifndef __STDC_LIMIT_MACROS
29 : #define __STDC_LIMIT_MACROS
30 : #endif
31 :
32 : #include <cstring>
33 : #include <inttypes.h>
34 : #include <stddef.h>
35 :
36 : #include <crypto/RandUtils.h>
37 : #include <lib/core/CHIPCore.h>
38 : #include <lib/core/CHIPEncoding.h>
39 : #include <lib/support/CHIPFaultInjection.h>
40 : #include <lib/support/CodeUtils.h>
41 : #include <lib/support/logging/CHIPLogging.h>
42 : #include <messaging/ExchangeContext.h>
43 : #include <messaging/ExchangeMgr.h>
44 : #include <protocols/Protocols.h>
45 :
46 : using namespace chip::Encoding;
47 : using namespace chip::Inet;
48 : using namespace chip::System;
49 :
50 : namespace chip {
51 : namespace Messaging {
52 :
53 : /**
54 : * Constructor for the ExchangeManager class.
55 : * It sets the state to kState_NotInitialized.
56 : *
57 : * @note
58 : * The class must be initialized via ExchangeManager::Init()
59 : * prior to use.
60 : *
61 : */
62 684 : ExchangeManager::ExchangeManager() : mReliableMessageMgr(mContextPool)
63 : {
64 76 : mState = State::kState_NotInitialized;
65 76 : }
66 :
67 309 : CHIP_ERROR ExchangeManager::Init(SessionManager * sessionManager)
68 : {
69 309 : CHIP_ERROR err = CHIP_NO_ERROR;
70 :
71 309 : VerifyOrReturnError(mState == State::kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);
72 :
73 309 : mSessionManager = sessionManager;
74 :
75 309 : mNextExchangeId = chip::Crypto::GetRandU16();
76 309 : mNextKeyId = 0;
77 :
78 2781 : for (auto & handler : UMHandlerPool)
79 : {
80 : // Mark all handlers as unallocated. This handles both initial
81 : // initialization and the case when the consumer shuts us down and
82 : // then re-initializes without removing registered handlers.
83 2472 : handler.Reset();
84 : }
85 :
86 309 : sessionManager->SetMessageDelegate(this);
87 :
88 309 : mReliableMessageMgr.Init(sessionManager->SystemLayer());
89 :
90 309 : mState = State::kState_Initialized;
91 :
92 309 : return err;
93 : }
94 :
95 309 : void ExchangeManager::Shutdown()
96 : {
97 309 : VerifyOrReturn(mState != State::kState_NotInitialized);
98 :
99 309 : mReliableMessageMgr.Shutdown();
100 :
101 309 : if (mSessionManager != nullptr)
102 : {
103 309 : mSessionManager->SetMessageDelegate(nullptr);
104 309 : mSessionManager = nullptr;
105 : }
106 :
107 309 : mState = State::kState_NotInitialized;
108 : }
109 :
110 1669 : ExchangeContext * ExchangeManager::NewContext(const SessionHandle & session, ExchangeDelegate * delegate, bool isInitiator)
111 : {
112 1669 : if (!session->IsActiveSession())
113 : {
114 : // Disallow creating exchange on an inactive session
115 6 : ChipLogError(ExchangeManager, "NewContext failed: session inactive");
116 6 : return nullptr;
117 : }
118 1663 : return mContextPool.CreateObject(this, mNextExchangeId++, session, isInitiator, delegate);
119 : }
120 :
121 384 : CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId,
122 : UnsolicitedMessageHandler * handler)
123 : {
124 384 : return RegisterUMH(protocolId, kAnyMessageType, handler);
125 : }
126 :
127 352 : CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType,
128 : UnsolicitedMessageHandler * handler)
129 : {
130 352 : return RegisterUMH(protocolId, static_cast<int16_t>(msgType), handler);
131 : }
132 :
133 381 : CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId)
134 : {
135 381 : return UnregisterUMH(protocolId, kAnyMessageType);
136 : }
137 :
138 335 : CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType)
139 : {
140 335 : return UnregisterUMH(protocolId, static_cast<int16_t>(msgType));
141 : }
142 :
143 736 : CHIP_ERROR ExchangeManager::RegisterUMH(Protocols::Id protocolId, int16_t msgType, UnsolicitedMessageHandler * handler)
144 : {
145 736 : UnsolicitedMessageHandlerSlot * selected = nullptr;
146 :
147 5827 : for (auto & umh : UMHandlerPool)
148 : {
149 5205 : if (!umh.IsInUse())
150 : {
151 4641 : if (selected == nullptr)
152 622 : selected = &umh;
153 : }
154 564 : else if (umh.Matches(protocolId, msgType))
155 : {
156 114 : umh.Handler = handler;
157 114 : return CHIP_NO_ERROR;
158 : }
159 : }
160 :
161 622 : if (selected == nullptr)
162 0 : return CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS;
163 :
164 622 : selected->Handler = handler;
165 622 : selected->ProtocolId = protocolId;
166 622 : selected->MessageType = msgType;
167 :
168 622 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
169 :
170 622 : return CHIP_NO_ERROR;
171 : }
172 :
173 716 : CHIP_ERROR ExchangeManager::UnregisterUMH(Protocols::Id protocolId, int16_t msgType)
174 : {
175 1905 : for (auto & umh : UMHandlerPool)
176 : {
177 1795 : if (umh.IsInUse() && umh.Matches(protocolId, msgType))
178 : {
179 606 : umh.Reset();
180 606 : SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
181 606 : return CHIP_NO_ERROR;
182 : }
183 : }
184 :
185 110 : return CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER;
186 : }
187 :
188 9473 : void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
189 : const SessionHandle & session, DuplicateMessage isDuplicate,
190 : System::PacketBufferHandle && msgBuf)
191 : {
192 9473 : UnsolicitedMessageHandlerSlot * matchingUMH = nullptr;
193 :
194 : #if CHIP_PROGRESS_LOGGING
195 9473 : auto * protocolName = Protocols::GetProtocolName(payloadHeader.GetProtocolID());
196 9473 : auto * msgTypeName = Protocols::GetMessageTypeName(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType());
197 :
198 : //
199 : // 32-bit value maximum = 10 chars + text preamble (6) + trailer (1) + null (1) + 2 buffer = 20
200 : //
201 : char ackBuf[20];
202 9473 : ackBuf[0] = '\0';
203 9473 : if (payloadHeader.GetAckMessageCounter().HasValue())
204 : {
205 7836 : snprintf(ackBuf, sizeof(ackBuf), " (Ack:" ChipLogFormatMessageCounter ")", payloadHeader.GetAckMessageCounter().Value());
206 : }
207 :
208 9473 : CompressedFabricId compressedFabricId = 0;
209 9473 : if (session->IsSecureSession() && mSessionManager->GetFabricTable() != nullptr)
210 : {
211 9377 : auto fabricInfo = mSessionManager->GetFabricTable()->FindFabricWithIndex(session->AsSecureSession()->GetFabricIndex());
212 9377 : if (fabricInfo)
213 : {
214 9330 : compressedFabricId = fabricInfo->GetCompressedFabricId();
215 : }
216 : }
217 :
218 : //
219 : // Legend that can be used to decode this log line can be found in README.md
220 : //
221 9473 : ChipLogProgress(ExchangeManager,
222 : ">>> [E:" ChipLogFormatExchangeId " S:%u M:" ChipLogFormatMessageCounter
223 : "%s] (%s) Msg RX from %u:" ChipLogFormatX64 " [%04X] --- Type %04x:%02x (%s:%s)",
224 : ChipLogValueExchangeIdFromReceivedHeader(payloadHeader), session->SessionIdForLogging(),
225 : packetHeader.GetMessageCounter(), ackBuf, Transport::GetSessionTypeString(session), session->GetFabricIndex(),
226 : ChipLogValueX64(session->GetPeer().GetNodeId()), static_cast<uint16_t>(compressedFabricId),
227 : payloadHeader.GetProtocolID().GetProtocolId(), payloadHeader.GetMessageType(), protocolName, msgTypeName);
228 : #endif
229 :
230 9473 : MessageFlags msgFlags;
231 9473 : if (isDuplicate == DuplicateMessage::Yes)
232 : {
233 5 : msgFlags.Set(MessageFlagValues::kDuplicateMessage);
234 : }
235 :
236 : // Skip retrieval of exchange for group message since no exchange is stored
237 : // for group msg (optimization)
238 9473 : if (!packetHeader.IsGroupSession())
239 : {
240 : // Search for an existing exchange that the message applies to. If a match is found...
241 9473 : bool found = false;
242 9473 : mContextPool.ForEachActiveObject([&](auto * ec) {
243 34611 : if (ec->MatchExchange(session, packetHeader, payloadHeader))
244 : {
245 7813 : ChipLogDetail(ExchangeManager, "Found matching exchange: " ChipLogFormatExchange ", Delegate: %p",
246 : ChipLogValueExchange(ec), ec->GetDelegate());
247 :
248 : // Matched ExchangeContext; send to message handler.
249 7813 : ec->HandleMessage(packetHeader.GetMessageCounter(), payloadHeader, msgFlags, std::move(msgBuf));
250 7813 : found = true;
251 7813 : return Loop::Break;
252 : }
253 26798 : return Loop::Continue;
254 : });
255 :
256 9473 : if (found)
257 : {
258 7813 : return;
259 : }
260 : }
261 : else
262 : {
263 0 : ChipLogProgress(ExchangeManager, "Received Groupcast Message with GroupId 0x%04X (%d)",
264 : packetHeader.GetDestinationGroupId().Value(), packetHeader.GetDestinationGroupId().Value());
265 : }
266 :
267 : // Do not handle messages that don't match an existing exchange on an
268 : // inactive session, since we should not be creating new exchanges there.
269 1660 : if (!session->IsActiveSession())
270 : {
271 0 : ChipLogProgress(ExchangeManager, "Dropping message on inactive session that does not match an existing exchange");
272 0 : return;
273 : }
274 :
275 : // If it's not a duplicate message, search for an unsolicited message handler if it is marked as being sent by an initiator.
276 : // Since we didn't find an existing exchange that matches the message, it must be an unsolicited message. However all
277 : // unsolicited messages must be marked as being from an initiator.
278 1660 : if (!msgFlags.Has(MessageFlagValues::kDuplicateMessage) && payloadHeader.IsInitiator())
279 : {
280 : // Search for an unsolicited message handler that can handle the message. Prefer handlers that can explicitly
281 : // handle the message type over handlers that handle all messages for a profile.
282 1605 : matchingUMH = nullptr;
283 :
284 13969 : for (auto & umh : UMHandlerPool)
285 : {
286 12432 : if (umh.IsInUse() && payloadHeader.HasProtocol(umh.ProtocolId))
287 : {
288 1617 : if (umh.MessageType == payloadHeader.GetMessageType())
289 : {
290 68 : matchingUMH = &umh;
291 68 : break;
292 : }
293 :
294 1549 : if (umh.MessageType == kAnyMessageType)
295 1524 : matchingUMH = &umh;
296 : }
297 : }
298 : }
299 : // Discard the message if it isn't marked as being sent by an initiator and the message does not need to send
300 : // an ack to the peer.
301 55 : else if (!payloadHeader.NeedsAck())
302 : {
303 : // We can easily get standalone acks here: any time we fail to get a
304 : // timely ack for the last message in an exchange and retransmit it,
305 : // then get acks for both the message and the retransmit, the second ack
306 : // will end up in this block. That's not really an error condition, so
307 : // there is no need to log an error in that case.
308 48 : if (!payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StandaloneAck))
309 : {
310 : // Using same error message for all errors to reduce code size.
311 2 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT,
312 : CHIP_ERROR_UNSOLICITED_MSG_NO_ORIGINATOR.Format());
313 : }
314 48 : return;
315 : }
316 :
317 : // If we found a handler, create an exchange to handle the message.
318 1612 : if (matchingUMH != nullptr)
319 : {
320 1592 : ExchangeDelegate * delegate = nullptr;
321 :
322 : // Fetch delegate from the handler
323 1592 : CHIP_ERROR err = matchingUMH->Handler->OnUnsolicitedMessageReceived(payloadHeader, delegate);
324 1592 : if (err != CHIP_NO_ERROR)
325 : {
326 : // Using same error message for all errors to reduce code size.
327 0 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT, err.Format());
328 0 : SendStandaloneAckIfNeeded(packetHeader, payloadHeader, session, msgFlags, std::move(msgBuf));
329 0 : return;
330 : }
331 :
332 1592 : ExchangeContext * ec = mContextPool.CreateObject(this, payloadHeader.GetExchangeID(), session, false, delegate);
333 :
334 1592 : if (ec == nullptr)
335 : {
336 0 : if (delegate != nullptr)
337 : {
338 0 : matchingUMH->Handler->OnExchangeCreationFailed(delegate);
339 : }
340 :
341 : // Using same error message for all errors to reduce code size.
342 0 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT, CHIP_ERROR_NO_MEMORY.Format());
343 : // No resource for creating new exchange, SendStandaloneAckIfNeeded probably also fails, so do not try it here
344 0 : return;
345 : }
346 :
347 1592 : ChipLogDetail(ExchangeManager, "Handling via exchange: " ChipLogFormatExchange ", Delegate: %p", ChipLogValueExchange(ec),
348 : ec->GetDelegate());
349 :
350 1592 : if (ec->IsEncryptionRequired() != packetHeader.IsEncrypted())
351 : {
352 1 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT,
353 : CHIP_ERROR_INVALID_MESSAGE_TYPE.Format());
354 1 : ec->Close();
355 1 : SendStandaloneAckIfNeeded(packetHeader, payloadHeader, session, msgFlags, std::move(msgBuf));
356 1 : return;
357 : }
358 :
359 1591 : err = ec->HandleMessage(packetHeader.GetMessageCounter(), payloadHeader, msgFlags, std::move(msgBuf));
360 1591 : if (err != CHIP_NO_ERROR)
361 : {
362 : // Using same error message for all errors to reduce code size.
363 3 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT, err.Format());
364 : }
365 1591 : return;
366 : }
367 :
368 20 : SendStandaloneAckIfNeeded(packetHeader, payloadHeader, session, msgFlags, std::move(msgBuf));
369 : }
370 :
371 21 : void ExchangeManager::SendStandaloneAckIfNeeded(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
372 : const SessionHandle & session, MessageFlags msgFlags,
373 : System::PacketBufferHandle && msgBuf)
374 : {
375 :
376 : // If using the MRP protocol and we need to send a StandaloneAck, create an EphemeralExchange to send
377 : // the StandaloneAck.
378 21 : if (!session->AllowsMRP() || !payloadHeader.NeedsAck())
379 8 : return;
380 :
381 : // If rcvd msg is from initiator then this exchange is created as not Initiator.
382 : // If rcvd msg is not from initiator then this exchange is created as Initiator.
383 : // Create a EphemeralExchange to generate a StandaloneAck
384 13 : ExchangeContext * ec = mContextPool.CreateObject(this, payloadHeader.GetExchangeID(), session, !payloadHeader.IsInitiator(),
385 13 : nullptr, true /* IsEphemeralExchange */);
386 :
387 13 : if (ec == nullptr)
388 : {
389 : // Using same error message for all errors to reduce code size.
390 0 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT, CHIP_ERROR_NO_MEMORY.Format());
391 0 : return;
392 : }
393 :
394 13 : ChipLogDetail(ExchangeManager, "Generating StandaloneAck via exchange: " ChipLogFormatExchange, ChipLogValueExchange(ec));
395 :
396 : // No need to verify packet encryption type, the EphemeralExchange can handle both secure and insecure messages.
397 :
398 13 : CHIP_ERROR err = ec->HandleMessage(packetHeader.GetMessageCounter(), payloadHeader, msgFlags, std::move(msgBuf));
399 13 : if (err != CHIP_NO_ERROR)
400 : {
401 : // Using same error message for all errors to reduce code size.
402 0 : ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %" CHIP_ERROR_FORMAT, err.Format());
403 : }
404 :
405 : // The exchange should be closed inside HandleMessage function. So don't bother close it here.
406 : }
407 :
408 310 : void ExchangeManager::CloseAllContextsForDelegate(const ExchangeDelegate * delegate)
409 : {
410 310 : mContextPool.ForEachActiveObject([&](auto * ec) {
411 10 : if (ec->GetDelegate() == delegate)
412 : {
413 : // Make sure to null out the delegate before closing the context, so
414 : // we don't notify the delegate that the context is closing. We
415 : // have to do this, because the delegate might be partially
416 : // destroyed by this point.
417 1 : ec->SetDelegate(nullptr);
418 1 : ec->Close();
419 : }
420 10 : return Loop::Continue;
421 : });
422 310 : }
423 :
424 : } // namespace Messaging
425 : } // namespace chip
|