Matter SDK Coverage Report
Current view: top level - messaging - ExchangeContext.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 83.3 % 30 25
Test Date: 2025-01-17 19:00:11 Functions: 81.0 % 21 17

            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 defines the classes corresponding to CHIP Exchange Context.
      21              :  *
      22              :  */
      23              : 
      24              : #pragma once
      25              : 
      26              : #include <lib/core/ReferenceCounted.h>
      27              : #include <lib/support/BitFlags.h>
      28              : #include <lib/support/DLLUtil.h>
      29              : #include <lib/support/ReferenceCountedHandle.h>
      30              : #include <lib/support/TypeTraits.h>
      31              : #include <messaging/ExchangeDelegate.h>
      32              : #include <messaging/Flags.h>
      33              : #include <messaging/ReliableMessageContext.h>
      34              : #include <protocols/Protocols.h>
      35              : #include <transport/SessionManager.h>
      36              : 
      37              : namespace chip {
      38              : 
      39              : namespace Messaging {
      40              : 
      41              : class ExchangeManager;
      42              : class ExchangeContext;
      43              : class ExchangeMessageDispatch;
      44              : using ExchangeHandle = ReferenceCountedHandle<ExchangeContext>;
      45              : 
      46              : class ExchangeContextDeletor
      47              : {
      48              : public:
      49              :     static void Release(ExchangeContext * obj);
      50              : };
      51              : 
      52              : /**
      53              :  *  @brief
      54              :  *    This class represents an ongoing conversation (ExchangeContext) between two or more nodes.
      55              :  *    It defines methods for encoding and communicating CHIP messages within an ExchangeContext
      56              :  *    over various transport mechanisms, for example, TCP, UDP, or CHIP Reliable Messaging.
      57              :  *
      58              :  */
      59              : class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
      60              :                                    public ReferenceCounted<ExchangeContext, ExchangeContextDeletor>,
      61              :                                    public SessionDelegate
      62              : {
      63              :     friend class ExchangeManager;
      64              :     friend class ExchangeContextDeletor;
      65              : 
      66              : public:
      67              :     typedef System::Clock::Timeout Timeout; // Type used to express the timeout in this ExchangeContext
      68              : 
      69              :     ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, const SessionHandle & session, bool Initiator,
      70              :                     ExchangeDelegate * delegate, bool isEphemeralExchange = false);
      71              : 
      72              :     ~ExchangeContext() override;
      73              : 
      74              :     /**
      75              :      *  Determine whether the context is the initiator of the exchange.
      76              :      *
      77              :      *  @return Returns 'true' if it is the initiator, else 'false'.
      78              :      */
      79              :     bool IsInitiator() const;
      80              : 
      81         9643 :     bool IsEncryptionRequired() const { return mDispatch.IsEncryptionRequired(); }
      82              : 
      83        34255 :     bool IsGroupExchangeContext() const { return mSession && mSession->IsGroupSession(); }
      84              : 
      85              :     // Implement SessionDelegate
      86            0 :     NewSessionHandlingPolicy GetNewSessionHandlingPolicy() override { return NewSessionHandlingPolicy::kStayAtOldSession; }
      87              :     void OnSessionReleased() override;
      88              : 
      89              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
      90              :     void OnSessionConnectionClosed(CHIP_ERROR conErr) override;
      91              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
      92              :     /**
      93              :      *  Send a CHIP message on this exchange.
      94              :      *
      95              :      *  If SendMessage returns success and the message was not expecting a
      96              :      *  response, the exchange will close itself before returning, unless the
      97              :      *  message being sent is a standalone ack.  If SendMessage returns failure,
      98              :      *  the caller is responsible for deciding what to do (e.g. closing the
      99              :      *  exchange, trying to re-establish a secure session, etc).
     100              :      *
     101              :      *  @param[in]    protocolId    The protocol identifier of the CHIP message to be sent.
     102              :      *
     103              :      *  @param[in]    msgType       The message type of the corresponding protocol.
     104              :      *
     105              :      *  @param[in]    msgPayload    A handle to the packet buffer holding the CHIP message.
     106              :      *
     107              :      *  @param[in]    sendFlags     Flags set by the application for the CHIP message being sent.
     108              :      *
     109              :      *  @retval  #CHIP_ERROR_INVALID_ARGUMENT               if an invalid argument was passed to this SendMessage API.
     110              :      *  @retval  #CHIP_ERROR_NOT_CONNECTED                  if the context was associated with a connection that is now
     111              :      *                                                       closed.
     112              :      *  @retval  #CHIP_ERROR_INCORRECT_STATE                if the state of the exchange context is incorrect.
     113              :      *  @retval  #CHIP_NO_ERROR                             if the CHIP layer successfully sent the message down to the
     114              :      *                                                       network layer.
     115              :      */
     116              :     CHIP_ERROR SendMessage(Protocols::Id protocolId, uint8_t msgType, System::PacketBufferHandle && msgPayload,
     117              :                            const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone));
     118              : 
     119              :     /**
     120              :      * A strongly-message-typed version of SendMessage.
     121              :      */
     122              :     template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
     123         9096 :     CHIP_ERROR SendMessage(MessageType msgType, System::PacketBufferHandle && msgPayload,
     124              :                            const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone))
     125              :     {
     126         9096 :         return SendMessage(Protocols::MessageTypeTraits<MessageType>::ProtocolId(), to_underlying(msgType), std::move(msgPayload),
     127         9096 :                            sendFlags);
     128              :     }
     129              : 
     130              :     /**
     131              :      * A notification that we will have SendMessage called on us in the future
     132              :      * (and should stay open until that happens).
     133              :      */
     134         3530 :     void WillSendMessage() { mFlags.Set(Flags::kFlagWillSendMessage); }
     135              : 
     136              :     /**
     137              :      *  Handle a received CHIP message on this exchange.
     138              :      *
     139              :      *  @param[in]    messageCounter  The message counter of the packet.
     140              :      *  @param[in]    payloadHeader   A reference to the PayloadHeader object.
     141              :      *  @param[in]    msgFlags        The message flags corresponding to the received message
     142              :      *  @param[in]    msgBuf          A handle to the packet buffer holding the CHIP message.
     143              :      *
     144              :      *  @retval  #CHIP_ERROR_INVALID_ARGUMENT               if an invalid argument was passed to this HandleMessage API.
     145              :      *  @retval  #CHIP_ERROR_INCORRECT_STATE                if the state of the exchange context is incorrect.
     146              :      *  @retval  #CHIP_NO_ERROR                             if the CHIP layer successfully delivered the message up to the
     147              :      *                                                       protocol layer.
     148              :      */
     149              :     CHIP_ERROR HandleMessage(uint32_t messageCounter, const PayloadHeader & payloadHeader, MessageFlags msgFlags,
     150              :                              System::PacketBufferHandle && msgBuf);
     151              : 
     152         9704 :     ExchangeDelegate * GetDelegate() const { return mDelegate; }
     153         4120 :     void SetDelegate(ExchangeDelegate * delegate) { mDelegate = delegate; }
     154              : 
     155        43614 :     ExchangeManager * GetExchangeMgr() const { return mExchangeMgr; }
     156              : 
     157       183199 :     ReliableMessageContext * GetReliableMessageContext() { return static_cast<ReliableMessageContext *>(this); };
     158              : 
     159        34286 :     SessionHandle GetSessionHandle() const
     160              :     {
     161        34286 :         VerifyOrDieWithObject(mSession, this);
     162        34286 :         auto sessionHandle = mSession.Get();
     163        34286 :         return std::move(sessionHandle.Value());
     164        34286 :     }
     165              : 
     166           68 :     bool HasSessionHandle() const { return mSession; }
     167              : 
     168            0 :     uint16_t GetExchangeId() const { return mExchangeId; }
     169              : 
     170              :     /*
     171              :      * In order to use reference counting (see refCount below) we use a hold/free paradigm where users of the exchange
     172              :      * can hold onto it while it's out of their direct control to make sure it isn't closed before everyone's ready.
     173              :      * A customized version of reference counting is used since there are some extra stuff to do within Release.
     174              :      */
     175              :     void Close();
     176              :     void Abort();
     177              : 
     178              :     // Applies a suggested response timeout value based on the session type and the given upper layer processing time for
     179              :     // the next message to the exchange. The exchange context must have a valid session when calling this function.
     180              :     //
     181              :     // This function is an equivalent of SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout))
     182              :     void UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout);
     183              : 
     184              :     // Set the response timeout for the exchange context, regardless of the underlying session type. Using
     185              :     // UseSuggestedResponseTimeout to set a timeout based on the type of the session and the application processing time instead of
     186              :     // using this function is recommended.
     187              :     //
     188              :     // If a timeout of 0 is provided, it implies no response is expected. Consequently, ExchangeDelegate::OnResponseTimeout will not
     189              :     // be called.
     190              :     //
     191              :     void SetResponseTimeout(Timeout timeout);
     192              : 
     193              :     // This API is used by commands that need to shut down all existing
     194              :     // sessions/exchanges on a fabric but need to make sure the response to the
     195              :     // command still goes out on the exchange the command came in on.  This API
     196              :     // will ensure that all secure sessions for the fabric this exchanges is on
     197              :     // are released except the one this exchange is using, and will release
     198              :     // that session once this exchange is done sending the response.
     199              :     //
     200              :     // This API is a no-op if called on an exchange that is not using a
     201              :     // SecureSession.
     202              :     void AbortAllOtherCommunicationOnFabric();
     203              : 
     204              :     /**
     205              :      *  Determine whether a response is currently expected for a message that was sent over
     206              :      *  this exchange.  While this is true, attempts to send other messages that expect a response
     207              :      *  will fail.
     208              :      *
     209              :      *  @return Returns 'true' if response expected, else 'false'.
     210              :      */
     211              :     bool IsResponseExpected() const;
     212              : 
     213              :     /**
     214              :      * Determine whether we are expecting our consumer to send a message on
     215              :      * this exchange (i.e. WillSendMessage was called and the message has not
     216              :      * yet been sent).
     217              :      */
     218         5854 :     bool IsSendExpected() const { return mFlags.Has(Flags::kFlagWillSendMessage); }
     219              : 
     220              :     /**
     221              :      * Tracks whether we have received at least one application level message
     222              :      * during the life-time of this exchange
     223              :      *
     224              :      * @return Returns 'true' if we have received at least one message, else 'false'
     225              :      */
     226         8086 :     inline bool HasReceivedAtLeastOneMessage() { return mFlags.Has(Flags::kFlagReceivedAtLeastOneMessage); }
     227              : 
     228              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     229              :     SessionHolder & GetSessionHolder() { return mSession; }
     230              : 
     231              :     enum class InjectedFailureType : uint8_t
     232              :     {
     233              :         kFailOnSend = 0x01
     234              :     };
     235              : 
     236              :     void InjectFailure(InjectedFailureType failureType) { mInjectedFailures.Set(failureType); }
     237              : 
     238              :     void ClearInjectedFailures() { mInjectedFailures.ClearAll(); }
     239              : #endif
     240              : 
     241            0 :     void DumpToLog() const
     242              :     {
     243            0 :         ChipLogError(ExchangeManager, "ExchangeContext: " ChipLogFormatExchangeId " delegate=" ChipLogFormatRtti,
     244              :                      ChipLogValueExchangeId(GetExchangeId(), IsInitiator()), ChipLogValueRtti(mDelegate));
     245            0 :     }
     246              : 
     247              : private:
     248              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     249              :     BitFlags<InjectedFailureType> mInjectedFailures;
     250              : #endif
     251              : 
     252              :     class ExchangeSessionHolder : public SessionHolderWithDelegate
     253              :     {
     254              :     public:
     255         3429 :         ExchangeSessionHolder(ExchangeContext & exchange) : SessionHolderWithDelegate(exchange) {}
     256              :         void GrabExpiredSession(const SessionHandle & session);
     257              :     };
     258              : 
     259         3429 :     Timeout mResponseTimeout{ 0 }; // Maximum time to wait for response (in milliseconds); 0 disables response timeout.
     260              :     ExchangeDelegate * mDelegate   = nullptr;
     261              :     ExchangeManager * mExchangeMgr = nullptr;
     262              : 
     263              :     ExchangeMessageDispatch & mDispatch;
     264              : 
     265              :     ExchangeSessionHolder mSession; // The connection state
     266              :     uint16_t mExchangeId;           // Assigned exchange ID.
     267              : 
     268              :     /**
     269              :      *  Track whether we are now expecting a response to a message sent via this exchange (because that
     270              :      *  message had the kExpectResponse flag set in its sendFlags).
     271              :      *
     272              :      *  @param[in]  inResponseExpected  A Boolean indicating whether (true) or not
     273              :      *                                  (false) a response is currently expected on this
     274              :      *                                  exchange.
     275              :      */
     276              :     void SetResponseExpected(bool inResponseExpected);
     277              : 
     278              :     /**
     279              :      *  Search for an existing exchange that the message applies to.
     280              :      *
     281              :      *  @param[in]    session       The secure session of the received message.
     282              :      *
     283              :      *  @param[in]    packetHeader  A reference to the PacketHeader object.
     284              :      *
     285              :      *  @param[in]    payloadHeader A reference to the PayloadHeader object.
     286              :      *
     287              :      *  @retval  true                                       If a match is found.
     288              :      *  @retval  false                                      If a match is not found.
     289              :      */
     290              :     bool MatchExchange(const SessionHandle & session, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader);
     291              : 
     292              :     /**
     293              :      * Notify our delegate, if any, that we have timed out waiting for a
     294              :      * response.  If aCloseIfNeeded is true, check whether the exchange needs to
     295              :      * be closed.
     296              :      */
     297              :     void NotifyResponseTimeout(bool aCloseIfNeeded);
     298              : 
     299              :     CHIP_ERROR StartResponseTimer();
     300              : 
     301              :     void CancelResponseTimer();
     302              :     static void HandleResponseTimeout(System::Layer * aSystemLayer, void * aAppState);
     303              : 
     304              :     void DoClose(bool clearRetransTable);
     305              : 
     306              :     /**
     307              :      * We have handled an application-level message in some way and should
     308              :      * re-evaluate out state to see whether we should still be open.
     309              :      */
     310              :     void MessageHandled();
     311              : 
     312              :     static ExchangeMessageDispatch & GetMessageDispatch(bool isEphemeralExchange, ExchangeDelegate * delegate);
     313              : 
     314              :     // If SetAutoReleaseSession() is called, this exchange must be using a SecureSession, and should
     315              :     // evict it when the exchange is done with all its work (including any MRP traffic).
     316            4 :     inline void SetIgnoreSessionRelease(bool ignore) { mFlags.Set(Flags::kFlagIgnoreSessionRelease, ignore); }
     317              : 
     318           65 :     inline bool ShouldIgnoreSessionRelease() { return mFlags.Has(Flags::kFlagIgnoreSessionRelease); }
     319              : 
     320         8087 :     inline void SetHasReceivedAtLeastOneMessage(bool hasReceivedMessage)
     321              :     {
     322         8087 :         mFlags.Set(Flags::kFlagReceivedAtLeastOneMessage, hasReceivedMessage);
     323         8087 :     }
     324              : };
     325              : 
     326              : } // namespace Messaging
     327              : } // namespace chip
        

Generated by: LCOV version 2.0-1