Matter SDK Coverage Report
Current view: top level - messaging - ExchangeMgr.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 86.6 % 164 142
Test Date: 2025-01-17 19:00:11 Functions: 88.2 % 17 15

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

Generated by: LCOV version 2.0-1