3 * Copyright (c) 2020-2021 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * This file implements the ExchangeManager class.
24 #ifndef __STDC_FORMAT_MACROS
25 #define __STDC_FORMAT_MACROS
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
36 #include <core/CHIPCore.h>
37 #include <core/CHIPEncoding.h>
38 #include <messaging/ExchangeContext.h>
39 #include <messaging/ExchangeMgr.h>
40 #include <protocols/Protocols.h>
41 #include <support/CHIPFaultInjection.h>
42 #include <support/CodeUtils.h>
43 #include <support/RandUtils.h>
44 #include <support/logging/CHIPLogging.h>
46 using namespace chip::Encoding;
47 using namespace chip::Inet;
48 using namespace chip::System;
54 * Constructor for the ExchangeManager class.
55 * It sets the state to kState_NotInitialized.
58 * The class must be initialized via ExchangeManager::Init()
62 ExchangeManager::ExchangeManager() : mReliableMessageMgr(mContextPool)
64 mState = State::kState_NotInitialized;
67 CHIP_ERROR ExchangeManager::Init(SecureSessionMgr * sessionMgr)
69 CHIP_ERROR err = CHIP_NO_ERROR;
71 VerifyOrReturnError(mState == State::kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);
73 mSessionMgr = sessionMgr;
75 mNextExchangeId = GetRandU16();
80 for (auto & handler : UMHandlerPool)
82 // Mark all handlers as unallocated. This handles both initial
83 // initialization and the case when the consumer shuts us down and
84 // then re-initializes without removing registered handlers.
88 mSessionMgr->GetTransportManager()->SetRendezvousSession(this);
90 sessionMgr->SetDelegate(this);
92 mReliableMessageMgr.Init(sessionMgr->SystemLayer(), sessionMgr);
94 err = mMessageCounterSyncMgr.Init(this);
95 ReturnErrorOnFailure(err);
97 mState = State::kState_Initialized;
102 CHIP_ERROR ExchangeManager::Shutdown()
104 mMessageCounterSyncMgr.Shutdown();
105 mReliableMessageMgr.Shutdown();
107 if (mSessionMgr != nullptr)
109 mSessionMgr->SetDelegate(nullptr);
110 mSessionMgr = nullptr;
113 mState = State::kState_NotInitialized;
115 return CHIP_NO_ERROR;
118 ExchangeContext * ExchangeManager::NewContext(SecureSessionHandle session, ExchangeDelegate * delegate)
120 return AllocContext(mNextExchangeId++, session, true, delegate);
123 CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId, ExchangeDelegate * delegate)
125 return RegisterUMH(protocolId, kAnyMessageType, delegate);
128 CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType,
129 ExchangeDelegate * delegate)
131 return RegisterUMH(protocolId, static_cast<int16_t>(msgType), delegate);
134 CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId)
136 return UnregisterUMH(protocolId, kAnyMessageType);
139 CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType)
141 return UnregisterUMH(protocolId, static_cast<int16_t>(msgType));
144 void ExchangeManager::OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * msgLayer)
146 ChipLogError(ExchangeManager, "Accept FAILED, err = %s", ErrorStr(error));
149 ExchangeContext * ExchangeManager::AllocContext(uint16_t ExchangeId, SecureSessionHandle session, bool Initiator,
150 ExchangeDelegate * delegate)
152 CHIP_FAULT_INJECT(FaultInjection::kFault_AllocExchangeContext, return nullptr);
154 for (auto & ec : mContextPool)
156 if (ec.GetReferenceCount() == 0)
158 return ec.Alloc(this, ExchangeId, session, Initiator, delegate);
162 ChipLogError(ExchangeManager, "Alloc ctxt FAILED");
166 CHIP_ERROR ExchangeManager::RegisterUMH(Protocols::Id protocolId, int16_t msgType, ExchangeDelegate * delegate)
168 UnsolicitedMessageHandler * umh = UMHandlerPool;
169 UnsolicitedMessageHandler * selected = nullptr;
171 for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
175 if (selected == nullptr)
178 else if (umh->Matches(protocolId, msgType))
180 umh->Delegate = delegate;
181 return CHIP_NO_ERROR;
185 if (selected == nullptr)
186 return CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS;
188 selected->Delegate = delegate;
189 selected->ProtocolId = protocolId;
190 selected->MessageType = msgType;
192 SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
194 return CHIP_NO_ERROR;
197 CHIP_ERROR ExchangeManager::UnregisterUMH(Protocols::Id protocolId, int16_t msgType)
199 UnsolicitedMessageHandler * umh = UMHandlerPool;
201 for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
203 if (umh->IsInUse() && umh->Matches(protocolId, msgType))
206 SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
207 return CHIP_NO_ERROR;
211 return CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER;
214 bool ExchangeManager::IsMsgCounterSyncMessage(const PayloadHeader & payloadHeader)
216 if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq) ||
217 payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp))
225 void ExchangeManager::HandleGroupMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
226 const SecureSessionHandle & session, System::PacketBufferHandle msgBuf)
228 OnMessageReceived(packetHeader, payloadHeader, session, std::move(msgBuf), nullptr);
231 void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
232 SecureSessionHandle session, System::PacketBufferHandle msgBuf, SecureSessionMgr * msgLayer)
234 CHIP_ERROR err = CHIP_NO_ERROR;
235 UnsolicitedMessageHandler * umh = nullptr;
236 UnsolicitedMessageHandler * matchingUMH = nullptr;
237 bool sendAckAndCloseExchange = false;
239 if (!IsMsgCounterSyncMessage(payloadHeader) && session.IsPeerGroupMsgIdNotSynchronized())
241 Transport::PeerConnectionState * state = mSessionMgr->GetPeerConnectionState(session);
242 VerifyOrReturn(state != nullptr);
244 // Queue the message as needed for sync with destination node.
245 err = mMessageCounterSyncMgr.AddToReceiveTable(packetHeader, payloadHeader, session, std::move(msgBuf));
246 VerifyOrReturn(err == CHIP_NO_ERROR);
248 // Initiate message counter synchronization if no message counter synchronization is in progress.
249 if (!state->IsMsgCounterSyncInProgress())
251 err = mMessageCounterSyncMgr.SendMsgCounterSyncReq(session);
254 if (err != CHIP_NO_ERROR)
256 ChipLogError(ExchangeManager,
257 "Message counter synchronization for received message, failed to send synchronization request, err = %d",
261 // After the message that triggers message counter synchronization is stored, and a message counter
262 // synchronization exchange is initiated, we need to return immediately and re-process the original message
263 // when the synchronization is completed.
268 // Search for an existing exchange that the message applies to. If a match is found...
269 for (auto & ec : mContextPool)
271 if (ec.GetReferenceCount() > 0 && ec.MatchExchange(session, packetHeader, payloadHeader))
273 // Found a matching exchange. Set flag for correct subsequent CRMP
274 // retransmission timeout selection.
275 if (!ec.mReliableMessageContext.HasRcvdMsgFromPeer())
277 ec.mReliableMessageContext.SetMsgRcvdFromPeer(true);
280 // Matched ExchangeContext; send to message handler.
281 ec.HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
283 ExitNow(err = CHIP_NO_ERROR);
287 // Search for an unsolicited message handler if it marked as being sent by an initiator. Since we didn't
288 // find an existing exchange that matches the message, it must be an unsolicited message. However all
289 // unsolicited messages must be marked as being from an initiator.
290 if (payloadHeader.IsInitiator())
292 // Search for an unsolicited message handler that can handle the message. Prefer handlers that can explicitly
293 // handle the message type over handlers that handle all messages for a profile.
294 umh = (UnsolicitedMessageHandler *) UMHandlerPool;
296 matchingUMH = nullptr;
298 for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
300 if (umh->IsInUse() && payloadHeader.HasProtocol(umh->ProtocolId))
302 if (umh->MessageType == payloadHeader.GetMessageType())
308 if (umh->MessageType == kAnyMessageType)
313 // Discard the message if it isn't marked as being sent by an initiator and the message does not need to send
314 // an ack to the peer.
315 else if (!payloadHeader.NeedsAck())
317 ExitNow(err = CHIP_ERROR_UNSOLICITED_MSG_NO_ORIGINATOR);
320 // If we didn't find an existing exchange that matches the message, and no unsolicited message handler registered
321 // to hand this message, we need to create a temporary exchange to send an ack for this message and then close this exchange.
322 sendAckAndCloseExchange = payloadHeader.NeedsAck() && (matchingUMH == nullptr);
324 // If we found a handler or we need to create a new exchange context (EC).
325 if (matchingUMH != nullptr || sendAckAndCloseExchange)
327 ExchangeContext * ec = nullptr;
329 if (sendAckAndCloseExchange)
331 // If rcvd msg is from initiator then this exchange is created as not Initiator.
332 // If rcvd msg is not from initiator then this exchange is created as Initiator.
333 ec = AllocContext(payloadHeader.GetExchangeID(), session, !payloadHeader.IsInitiator(), nullptr);
337 ec = AllocContext(payloadHeader.GetExchangeID(), session, false, matchingUMH->Delegate);
340 VerifyOrExit(ec != nullptr, err = CHIP_ERROR_NO_MEMORY);
342 ChipLogProgress(ExchangeManager, "ec pos: %d, id: %d, Delegate: 0x%x", ec - mContextPool.begin(), ec->GetExchangeId(),
345 ec->HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
347 // Close exchange if it was created only to send ack for a duplicate message.
348 if (sendAckAndCloseExchange)
353 if (err != CHIP_NO_ERROR)
355 ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %d", err);
359 ChannelHandle ExchangeManager::EstablishChannel(const ChannelBuilder & builder, ChannelDelegate * delegate)
361 ChannelContext * channelContext = nullptr;
363 // Find an existing Channel matching the builder
364 mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
365 if (context->MatchesBuilder(builder))
367 channelContext = context;
373 if (channelContext == nullptr)
375 // create a new channel if not found
376 channelContext = mChannelContexts.CreateObject(this);
377 if (channelContext == nullptr)
378 return ChannelHandle{ nullptr };
379 channelContext->Start(builder);
383 channelContext->Retain();
386 ChannelContextHandleAssociation * association = mChannelHandles.CreateObject(channelContext, delegate);
387 channelContext->Release();
388 return ChannelHandle{ association };
391 void ExchangeManager::OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr)
393 mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
394 if (context->MatchesSession(session, mgr))
396 context->OnNewConnection(session);
403 void ExchangeManager::OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr)
405 for (auto & ec : mContextPool)
407 if (ec.GetReferenceCount() > 0 && ec.mSecureSession == session)
410 // Continue iterate because there can be multiple contexts associated with the connection.
414 mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
415 if (context->MatchesSession(session, mgr))
417 context->OnConnectionExpired(session);
424 void ExchangeManager::OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
425 System::PacketBufferHandle msgBuf)
427 auto peer = header.GetSourceNodeId();
428 if (!peer.HasValue())
430 char addrBuffer[Transport::PeerAddress::kMaxToStringSize];
431 source.ToString(addrBuffer, sizeof(addrBuffer));
432 ChipLogError(ExchangeManager, "Unencrypted message from %s is dropped since no source node id in packet header.",
437 auto node = peer.Value();
438 auto notFound = mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
439 if (context->IsCasePairing() && context->MatchNodeId(node))
441 CHIP_ERROR err = context->HandlePairingMessage(header, source, std::move(msgBuf));
442 if (err != CHIP_NO_ERROR)
443 ChipLogError(ExchangeManager, "HandlePairingMessage error %s from node 0x%08" PRIx32 "%08" PRIx32 ".",
444 chip::ErrorStr(err), static_cast<uint32_t>(node >> 32), static_cast<uint32_t>(node));
452 char addrBuffer[Transport::PeerAddress::kMaxToStringSize];
453 source.ToString(addrBuffer, sizeof(addrBuffer));
454 ChipLogError(ExchangeManager,
455 "Unencrypted message from %s is dropped since no session found for node 0x%08" PRIx32 "%08" PRIx32 ".",
456 addrBuffer, static_cast<uint32_t>(node >> 32), static_cast<uint32_t>(node));
461 void ExchangeManager::IncrementContextsInUse()
466 void ExchangeManager::DecrementContextsInUse()
468 if (mContextsInUse >= 1)
474 ChipLogError(ExchangeManager, "No context in use, decrement failed");
478 } // namespace Messaging