LCOV - code coverage report
Current view: top level - messaging - ExchangeMgr.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 131 145 90.3 %
Date: 2024-02-15 08:20:41 Functions: 15 15 100.0 %

          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

Generated by: LCOV version 1.14