LCOV - code coverage report
Current view: top level - messaging - ExchangeContext.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 26 27 96.3 %
Date: 2024-02-15 08:20:41 Functions: 18 20 90.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 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        9405 :     bool IsEncryptionRequired() const { return mDispatch.IsEncryptionRequired(); }
      82             : 
      83       33719 :     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             :     /**
      90             :      *  Send a CHIP message on this exchange.
      91             :      *
      92             :      *  If SendMessage returns success and the message was not expecting a
      93             :      *  response, the exchange will close itself before returning, unless the
      94             :      *  message being sent is a standalone ack.  If SendMessage returns failure,
      95             :      *  the caller is responsible for deciding what to do (e.g. closing the
      96             :      *  exchange, trying to re-establish a secure session, etc).
      97             :      *
      98             :      *  @param[in]    protocolId    The protocol identifier of the CHIP message to be sent.
      99             :      *
     100             :      *  @param[in]    msgType       The message type of the corresponding protocol.
     101             :      *
     102             :      *  @param[in]    msgPayload    A handle to the packet buffer holding the CHIP message.
     103             :      *
     104             :      *  @param[in]    sendFlags     Flags set by the application for the CHIP message being sent.
     105             :      *
     106             :      *  @retval  #CHIP_ERROR_INVALID_ARGUMENT               if an invalid argument was passed to this SendMessage API.
     107             :      *  @retval  #CHIP_ERROR_NOT_CONNECTED                  if the context was associated with a connection that is now
     108             :      *                                                       closed.
     109             :      *  @retval  #CHIP_ERROR_INCORRECT_STATE                if the state of the exchange context is incorrect.
     110             :      *  @retval  #CHIP_NO_ERROR                             if the CHIP layer successfully sent the message down to the
     111             :      *                                                       network layer.
     112             :      */
     113             :     CHIP_ERROR SendMessage(Protocols::Id protocolId, uint8_t msgType, System::PacketBufferHandle && msgPayload,
     114             :                            const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone));
     115             : 
     116             :     /**
     117             :      * A strongly-message-typed version of SendMessage.
     118             :      */
     119             :     template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
     120        8872 :     CHIP_ERROR SendMessage(MessageType msgType, System::PacketBufferHandle && msgPayload,
     121             :                            const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone))
     122             :     {
     123        8872 :         return SendMessage(Protocols::MessageTypeTraits<MessageType>::ProtocolId(), to_underlying(msgType), std::move(msgPayload),
     124        8872 :                            sendFlags);
     125             :     }
     126             : 
     127             :     /**
     128             :      * A notification that we will have SendMessage called on us in the future
     129             :      * (and should stay open until that happens).
     130             :      */
     131        3383 :     void WillSendMessage() { mFlags.Set(Flags::kFlagWillSendMessage); }
     132             : 
     133             :     /**
     134             :      *  Handle a received CHIP message on this exchange.
     135             :      *
     136             :      *  @param[in]    messageCounter  The message counter of the packet.
     137             :      *  @param[in]    payloadHeader   A reference to the PayloadHeader object.
     138             :      *  @param[in]    msgFlags        The message flags corresponding to the received message
     139             :      *  @param[in]    msgBuf          A handle to the packet buffer holding the CHIP message.
     140             :      *
     141             :      *  @retval  #CHIP_ERROR_INVALID_ARGUMENT               if an invalid argument was passed to this HandleMessage API.
     142             :      *  @retval  #CHIP_ERROR_INCORRECT_STATE                if the state of the exchange context is incorrect.
     143             :      *  @retval  #CHIP_NO_ERROR                             if the CHIP layer successfully delivered the message up to the
     144             :      *                                                       protocol layer.
     145             :      */
     146             :     CHIP_ERROR HandleMessage(uint32_t messageCounter, const PayloadHeader & payloadHeader, MessageFlags msgFlags,
     147             :                              System::PacketBufferHandle && msgBuf);
     148             : 
     149        9450 :     ExchangeDelegate * GetDelegate() const { return mDelegate; }
     150        3744 :     void SetDelegate(ExchangeDelegate * delegate) { mDelegate = delegate; }
     151             : 
     152       42665 :     ExchangeManager * GetExchangeMgr() const { return mExchangeMgr; }
     153             : 
     154      182024 :     ReliableMessageContext * GetReliableMessageContext() { return static_cast<ReliableMessageContext *>(this); };
     155             : 
     156       33238 :     SessionHandle GetSessionHandle() const
     157             :     {
     158       33238 :         VerifyOrDie(mSession);
     159       33238 :         auto sessionHandle = mSession.Get();
     160       33238 :         return std::move(sessionHandle.Value());
     161       33238 :     }
     162             : 
     163          93 :     bool HasSessionHandle() const { return mSession; }
     164             : 
     165       19013 :     uint16_t GetExchangeId() const { return mExchangeId; }
     166             : 
     167             :     /*
     168             :      * In order to use reference counting (see refCount below) we use a hold/free paradigm where users of the exchange
     169             :      * can hold onto it while it's out of their direct control to make sure it isn't closed before everyone's ready.
     170             :      * A customized version of reference counting is used since there are some extra stuff to do within Release.
     171             :      */
     172             :     void Close();
     173             :     void Abort();
     174             : 
     175             :     // Applies a suggested response timeout value based on the session type and the given upper layer processing time for
     176             :     // the next message to the exchange. The exchange context must have a valid session when calling this function.
     177             :     //
     178             :     // This function is an equivalent of SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout))
     179             :     void UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout);
     180             : 
     181             :     // Set the response timeout for the exchange context, regardless of the underlying session type. Using
     182             :     // UseSuggestedResponseTimeout to set a timeout based on the type of the session and the application processing time instead of
     183             :     // using this function is recommended.
     184             :     //
     185             :     // If a timeout of 0 is provided, it implies no response is expected. Consequently, ExchangeDelegate::OnResponseTimeout will not
     186             :     // be called.
     187             :     //
     188             :     void SetResponseTimeout(Timeout timeout);
     189             : 
     190             :     // This API is used by commands that need to shut down all existing
     191             :     // sessions/exchanges on a fabric but need to make sure the response to the
     192             :     // command still goes out on the exchange the command came in on.  This API
     193             :     // will ensure that all secure sessions for the fabric this exchanges is on
     194             :     // are released except the one this exchange is using, and will release
     195             :     // that session once this exchange is done sending the response.
     196             :     //
     197             :     // This API is a no-op if called on an exchange that is not using a
     198             :     // SecureSession.
     199             :     void AbortAllOtherCommunicationOnFabric();
     200             : 
     201             :     /**
     202             :      *  Determine whether a response is currently expected for a message that was sent over
     203             :      *  this exchange.  While this is true, attempts to send other messages that expect a response
     204             :      *  will fail.
     205             :      *
     206             :      *  @return Returns 'true' if response expected, else 'false'.
     207             :      */
     208             :     bool IsResponseExpected() const;
     209             : 
     210             :     /**
     211             :      * Determine whether we are expecting our consumer to send a message on
     212             :      * this exchange (i.e. WillSendMessage was called and the message has not
     213             :      * yet been sent).
     214             :      */
     215        5396 :     bool IsSendExpected() const { return mFlags.Has(Flags::kFlagWillSendMessage); }
     216             : 
     217             :     /**
     218             :      * Tracks whether we have received at least one application level message
     219             :      * during the life-time of this exchange
     220             :      *
     221             :      * @return Returns 'true' if we have received at least one message, else 'false'
     222             :      */
     223        7929 :     inline bool HasReceivedAtLeastOneMessage() { return mFlags.Has(Flags::kFlagReceivedAtLeastOneMessage); }
     224             : 
     225             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     226             :     SessionHolder & GetSessionHolder() { return mSession; }
     227             : 
     228             :     enum class InjectedFailureType : uint8_t
     229             :     {
     230             :         kFailOnSend = 0x01
     231             :     };
     232             : 
     233             :     void InjectFailure(InjectedFailureType failureType) { mInjectedFailures.Set(failureType); }
     234             : 
     235             :     void ClearInjectedFailures() { mInjectedFailures.ClearAll(); }
     236             : #endif
     237             : 
     238             : private:
     239             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     240             :     BitFlags<InjectedFailureType> mInjectedFailures;
     241             : #endif
     242             : 
     243             :     class ExchangeSessionHolder : public SessionHolderWithDelegate
     244             :     {
     245             :     public:
     246        3268 :         ExchangeSessionHolder(ExchangeContext & exchange) : SessionHolderWithDelegate(exchange) {}
     247             :         void GrabExpiredSession(const SessionHandle & session);
     248             :     };
     249             : 
     250        3268 :     Timeout mResponseTimeout{ 0 }; // Maximum time to wait for response (in milliseconds); 0 disables response timeout.
     251             :     ExchangeDelegate * mDelegate   = nullptr;
     252             :     ExchangeManager * mExchangeMgr = nullptr;
     253             : 
     254             :     ExchangeMessageDispatch & mDispatch;
     255             : 
     256             :     ExchangeSessionHolder mSession; // The connection state
     257             :     uint16_t mExchangeId;           // Assigned exchange ID.
     258             : 
     259             :     /**
     260             :      *  Track whether we are now expecting a response to a message sent via this exchange (because that
     261             :      *  message had the kExpectResponse flag set in its sendFlags).
     262             :      *
     263             :      *  @param[in]  inResponseExpected  A Boolean indicating whether (true) or not
     264             :      *                                  (false) a response is currently expected on this
     265             :      *                                  exchange.
     266             :      */
     267             :     void SetResponseExpected(bool inResponseExpected);
     268             : 
     269             :     /**
     270             :      *  Search for an existing exchange that the message applies to.
     271             :      *
     272             :      *  @param[in]    session       The secure session of the received message.
     273             :      *
     274             :      *  @param[in]    packetHeader  A reference to the PacketHeader object.
     275             :      *
     276             :      *  @param[in]    payloadHeader A reference to the PayloadHeader object.
     277             :      *
     278             :      *  @retval  true                                       If a match is found.
     279             :      *  @retval  false                                      If a match is not found.
     280             :      */
     281             :     bool MatchExchange(const SessionHandle & session, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader);
     282             : 
     283             :     /**
     284             :      * Notify our delegate, if any, that we have timed out waiting for a
     285             :      * response.  If aCloseIfNeeded is true, check whether the exchange needs to
     286             :      * be closed.
     287             :      */
     288             :     void NotifyResponseTimeout(bool aCloseIfNeeded);
     289             : 
     290             :     CHIP_ERROR StartResponseTimer();
     291             : 
     292             :     void CancelResponseTimer();
     293             :     static void HandleResponseTimeout(System::Layer * aSystemLayer, void * aAppState);
     294             : 
     295             :     void DoClose(bool clearRetransTable);
     296             : 
     297             :     /**
     298             :      * We have handled an application-level message in some way and should
     299             :      * re-evaluate out state to see whether we should still be open.
     300             :      */
     301             :     void MessageHandled();
     302             : 
     303             :     static ExchangeMessageDispatch & GetMessageDispatch(bool isEphemeralExchange, ExchangeDelegate * delegate);
     304             : 
     305             :     // If SetAutoReleaseSession() is called, this exchange must be using a SecureSession, and should
     306             :     // evict it when the exchange is done with all its work (including any MRP traffic).
     307           4 :     inline void SetIgnoreSessionRelease(bool ignore) { mFlags.Set(Flags::kFlagIgnoreSessionRelease, ignore); }
     308             : 
     309          51 :     inline bool ShouldIgnoreSessionRelease() { return mFlags.Has(Flags::kFlagIgnoreSessionRelease); }
     310             : 
     311        7924 :     inline void SetHasReceivedAtLeastOneMessage(bool hasReceivedMessage)
     312             :     {
     313        7924 :         mFlags.Set(Flags::kFlagReceivedAtLeastOneMessage, hasReceivedMessage);
     314        7924 :     }
     315             : };
     316             : 
     317             : } // namespace Messaging
     318             : } // namespace chip

Generated by: LCOV version 1.14