LCOV - code coverage report
Current view: top level - app - CommandSender.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 19 45 42.2 %
Date: 2024-02-15 08:20:41 Functions: 5 71 7.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *      This file defines objects for a CHIP IM Invoke Command Sender
      22             :  *
      23             :  */
      24             : 
      25             : #pragma once
      26             : 
      27             : #include <type_traits>
      28             : 
      29             : #include "CommandSenderLegacyCallback.h"
      30             : 
      31             : #include <app/CommandPathParams.h>
      32             : #include <app/MessageDef/InvokeRequestMessage.h>
      33             : #include <app/MessageDef/InvokeResponseMessage.h>
      34             : #include <app/MessageDef/StatusIB.h>
      35             : #include <app/data-model/Encode.h>
      36             : #include <lib/core/CHIPCore.h>
      37             : #include <lib/core/Optional.h>
      38             : #include <lib/core/TLVDebug.h>
      39             : #include <lib/support/BitFlags.h>
      40             : #include <lib/support/CodeUtils.h>
      41             : #include <lib/support/DLLUtil.h>
      42             : #include <lib/support/logging/CHIPLogging.h>
      43             : #include <messaging/ExchangeHolder.h>
      44             : #include <messaging/ExchangeMgr.h>
      45             : #include <messaging/Flags.h>
      46             : #include <protocols/Protocols.h>
      47             : #include <system/SystemPacketBuffer.h>
      48             : #include <system/TLVPacketBufferBackingStore.h>
      49             : 
      50             : #define COMMON_STATUS_SUCCESS 0
      51             : 
      52             : namespace chip {
      53             : namespace app {
      54             : 
      55             : class CommandSender final : public Messaging::ExchangeDelegate
      56             : {
      57             : public:
      58             :     // CommandSender::ExtendableCallback::OnResponse is public SDK API, so we cannot break
      59             :     // source compatibility for it. To allow for additional values to be added at a future
      60             :     // time without constantly changing the function's declaration parameter list, we are
      61             :     // defining the struct ResponseData and adding that to the parameter list to allow for
      62             :     // future extendability.
      63             :     struct ResponseData
      64             :     {
      65             :         // The command path field in invoke command response.
      66             :         const ConcreteCommandPath & path;
      67             :         // The status of the command. It can be any success status, including possibly a cluster-specific one.
      68             :         // If `data` is not null, statusIB will always be a generic SUCCESS status with no-cluster specific
      69             :         // information.
      70             :         const StatusIB & statusIB;
      71             :         // The command data, will be nullptr if the server returns a StatusIB.
      72             :         TLV::TLVReader * data;
      73             :         // Reference for the command. This should be associated with the reference value sent out in the initial
      74             :         // invoke request.
      75             :         Optional<uint16_t> commandRef;
      76             :     };
      77             : 
      78             :     // CommandSender::ExtendableCallback::OnError is public SDK API, so we cannot break source
      79             :     // compatibility for it. To allow for additional values to be added at a future time
      80             :     // without constantly changing the function's declaration parameter list, we are
      81             :     // defining the struct ErrorData and adding that to the parameter list
      82             :     // to allow for future extendability.
      83             :     struct ErrorData
      84             :     {
      85             :         /**
      86             :          * The following errors will be delivered through `error`
      87             :          *
      88             :          * - CHIP_ERROR_TIMEOUT: A response was not received within the expected response timeout.
      89             :          * - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from the server.
      90             :          * - CHIP_ERROR encapsulating a StatusIB: If we got a non-path-specific
      91             :          *   status response from the server.  In that case,
      92             :          *   StatusIB::InitFromChipError can be used to extract the status.
      93             :          * - CHIP_ERROR*: All other cases.
      94             :          */
      95             :         CHIP_ERROR error;
      96             :     };
      97             : 
      98             :     /**
      99             :      * @brief Callback that is extendable for future features, starting with batch commands
     100             :      *
     101             :      * The two major differences between ExtendableCallback and Callback are:
     102             :      * 1. Path-specific errors go to OnResponse instead of OnError
     103             :      *       - Note: Non-path-specific errors still go to OnError.
     104             :      * 2. Instead of having new parameters at the end of the arguments list, with defaults,
     105             :      *    as functionality expands, a parameter whose type is defined in this header is used
     106             :      *    as the argument to the callbacks
     107             :      *
     108             :      * To support batch commands client must use ExtendableCallback.
     109             :      */
     110             :     class ExtendableCallback
     111             :     {
     112             :     public:
     113             :         virtual ~ExtendableCallback() = default;
     114             : 
     115             :         /**
     116             :          * OnResponse will be called for all path specific responses from the server that have been received
     117             :          * and processed. Specifically:
     118             :          *  - When a status code is received and it is IM::Success, aData will be nullptr.
     119             :          *  - When a status code is received and it is IM and/or cluster error, aData will be nullptr.
     120             :          *      - These kinds of errors are referred to as path-specific errors.
     121             :          *  - When a data response is received, aData will point to a valid TLVReader initialized to point at the struct container
     122             :          *    that contains the data payload (callee will still need to open and process the container).
     123             :          *
     124             :          * The CommandSender object MUST continue to exist after this call is completed. The application shall wait until it
     125             :          * receives an OnDone call to destroy the object.
     126             :          *
     127             :          * @param[in] apCommandSender The command sender object that initiated the command transaction.
     128             :          * @param[in] aResponseData   Information pertaining to the response.
     129             :          */
     130             :         ;
     131             :         virtual void OnResponse(CommandSender * commandSender, const ResponseData & aResponseData) {}
     132             : 
     133             :         /**
     134             :          * OnError will be called when a non-path-specific error occurs *after* a successful call to SendCommandRequest().
     135             :          *
     136             :          * The CommandSender object MUST continue to exist after this call is completed. The application shall wait until it
     137             :          * receives an OnDone call to destroy and free the object.
     138             :          *
     139             :          * NOTE: Path specific errors do NOT come to OnError, but instead go to OnResponse.
     140             :          *
     141             :          * @param[in] apCommandSender The command sender object that initiated the command transaction.
     142             :          * @param[in] aErrorData      A error data regarding error that occurred.
     143             :          */
     144             :         virtual void OnError(const CommandSender * apCommandSender, const ErrorData & aErrorData) {}
     145             : 
     146             :         /**
     147             :          * OnDone will be called when CommandSender has finished all work and is safe to destroy and free the
     148             :          * allocated CommandSender object.
     149             :          *
     150             :          * This function will:
     151             :          *      - Always be called exactly *once* for a given CommandSender instance.
     152             :          *      - Be called even in error circumstances.
     153             :          *      - Only be called after a successful call to SendCommandRequest returns, if SendCommandRequest is used.
     154             :          *      - Always be called before a successful return from SendGroupCommandRequest, if SendGroupCommandRequest is used.
     155             :          *
     156             :          * This function must be implemented to destroy the CommandSender object.
     157             :          *
     158             :          * @param[in] apCommandSender   The command sender object of the terminated invoke command transaction.
     159             :          */
     160             :         virtual void OnDone(CommandSender * apCommandSender) = 0;
     161             :     };
     162             : 
     163             :     // `Callback` exists for legacy purposes. If you are developing a new callback implementation,
     164             :     // please use `ExtendableCallback`.
     165             :     using Callback = CommandSenderLegacyCallback;
     166             : 
     167             :     // SetCommandSenderConfig is a public SDK API, so we cannot break source compatibility
     168             :     // for it. By having parameters to that API use this struct instead of individual
     169             :     // function arguments, we centralize required changes to one file when adding new
     170             :     // funtionality.
     171             :     struct ConfigParameters
     172             :     {
     173             :         ConfigParameters & SetRemoteMaxPathsPerInvoke(uint16_t aRemoteMaxPathsPerInvoke)
     174             :         {
     175             :             remoteMaxPathsPerInvoke = aRemoteMaxPathsPerInvoke;
     176             :             return *this;
     177             :         }
     178             : 
     179             :         // If remoteMaxPathsPerInvoke is 1, this will allow the CommandSender client to contain only one command and
     180             :         // doesn't enforce other batch commands requirements.
     181             :         uint16_t remoteMaxPathsPerInvoke = 1;
     182             :     };
     183             : 
     184             :     // AddRequestData is a public SDK API, so we must maintain source compatibility.
     185             :     // Using this struct for API parameters instead of individual parameters allows us
     186             :     // to make necessary changes for new functionality in a single location.
     187             :     struct AddRequestDataParameters
     188             :     {
     189             :         // gcc bug requires us to have the constructor below
     190             :         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
     191             :         AddRequestDataParameters() {}
     192             : 
     193           0 :         AddRequestDataParameters(const Optional<uint16_t> & aTimedInvokeTimeoutMs) : timedInvokeTimeoutMs(aTimedInvokeTimeoutMs) {}
     194             : 
     195             :         // When a value is provided for timedInvokeTimeoutMs, this invoke becomes a timed
     196             :         // invoke. CommandSender will use the minimum of all provided timeouts for execution.
     197             :         const Optional<uint16_t> timedInvokeTimeoutMs;
     198             :         // The command reference is required when sending multiple commands. It allows the caller
     199             :         // to associate this request with its corresponding response.
     200             :         Optional<uint16_t> commandRef;
     201             :     };
     202             : 
     203             :     // PrepareCommand is a public SDK API, so we must maintain source compatibility.
     204             :     // Using this struct for API parameters instead of individual parameters allows us
     205             :     // to make necessary changes for new functionality in a single location.
     206             :     struct PrepareCommandParameters
     207             :     {
     208             :         // gcc bug requires us to have the constructor below
     209             :         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
     210             :         PrepareCommandParameters() {}
     211             : 
     212           0 :         PrepareCommandParameters(const AddRequestDataParameters & aAddRequestDataParam) :
     213           0 :             commandRef(aAddRequestDataParam.commandRef)
     214           0 :         {}
     215             : 
     216             :         PrepareCommandParameters & SetStartDataStruct(bool aStartDataStruct)
     217             :         {
     218             :             startDataStruct = aStartDataStruct;
     219             :             return *this;
     220             :         }
     221             : 
     222             :         PrepareCommandParameters & SetCommandRef(uint16_t aCommandRef)
     223             :         {
     224             :             commandRef.SetValue(aCommandRef);
     225             :             return *this;
     226             :         }
     227             :         // The command reference is required when sending multiple commands. It allows the caller
     228             :         // to associate this request with its corresponding response. We validate the reference
     229             :         // early in PrepareCommand, even though it's not used until FinishCommand. This proactive
     230             :         // validation helps prevent unnecessary writing an InvokeRequest into the packet that later
     231             :         // needs to be undone.
     232             :         //
     233             :         // Currently, provided commandRefs for the first request must start at 0 and increment by one
     234             :         // for each subsequent request. This requirement can be relaxed in the future if a compelling
     235             :         // need arises.
     236             :         // TODO(#30453): After introducing Request/Response tracking, remove statement above about
     237             :         // this currently enforced requirement on commandRefs.
     238             :         Optional<uint16_t> commandRef;
     239             :         // If the InvokeRequest needs to be in a state with a started data TLV struct container
     240             :         bool startDataStruct = false;
     241             :     };
     242             : 
     243             :     // FinishCommand is a public SDK API, so we must maintain source compatibility.
     244             :     // Using this struct for API parameters instead of individual parameters allows us
     245             :     // to make necessary changes for new functionality in a single location.
     246             :     struct FinishCommandParameters
     247             :     {
     248             :         // gcc bug requires us to have the constructor below
     249             :         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
     250             :         FinishCommandParameters() {}
     251             : 
     252             :         FinishCommandParameters(const Optional<uint16_t> & aTimedInvokeTimeoutMs) : timedInvokeTimeoutMs(aTimedInvokeTimeoutMs) {}
     253           0 :         FinishCommandParameters(const AddRequestDataParameters & aAddRequestDataParam) :
     254           0 :             timedInvokeTimeoutMs(aAddRequestDataParam.timedInvokeTimeoutMs), commandRef(aAddRequestDataParam.commandRef)
     255           0 :         {}
     256             : 
     257             :         FinishCommandParameters & SetEndDataStruct(bool aEndDataStruct)
     258             :         {
     259             :             endDataStruct = aEndDataStruct;
     260             :             return *this;
     261             :         }
     262             : 
     263             :         FinishCommandParameters & SetCommandRef(uint16_t aCommandRef)
     264             :         {
     265             :             commandRef.SetValue(aCommandRef);
     266             :             return *this;
     267             :         }
     268             : 
     269             :         // When a value is provided for timedInvokeTimeoutMs, this invoke becomes a timed
     270             :         // invoke. CommandSender will use the minimum of all provided timeouts for execution.
     271             :         const Optional<uint16_t> timedInvokeTimeoutMs;
     272             :         // The command reference is required when sending multiple commands. It allows the caller
     273             :         // to associate this request with its corresponding response. This value must be
     274             :         // the same as the one provided in PrepareCommandParameters when calling PrepareCommand.
     275             :         Optional<uint16_t> commandRef;
     276             :         // If InvokeRequest is in a state where the data TLV struct container is currently open
     277             :         // and FinishCommand should close it.
     278             :         bool endDataStruct = false;
     279             :     };
     280             : 
     281             :     /*
     282             :      * Constructor.
     283             :      *
     284             :      * The callback passed in has to outlive this CommandSender object.
     285             :      * If used in a groups setting, callbacks do not need to be passed.
     286             :      * If callbacks are passed the only one that will be called in a group sesttings is the onDone
     287             :      */
     288             :     CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false,
     289             :                   bool aSuppressResponse = false);
     290             :     CommandSender(ExtendableCallback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false,
     291             :                   bool aSuppressResponse = false);
     292             :     CommandSender(std::nullptr_t, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false,
     293             :                   bool aSuppressResponse = false) :
     294             :         CommandSender(static_cast<Callback *>(nullptr), apExchangeMgr, aIsTimedRequest, aSuppressResponse)
     295             :     {}
     296             :     ~CommandSender();
     297             : 
     298             :     /**
     299             :      * Enables additional features of CommandSender, for example sending batch commands.
     300             :      *
     301             :      * In the case of enabling batch commands, once set it ensures that commands contain all
     302             :      * required data elements while building the InvokeRequestMessage. This must be called
     303             :      * before PrepareCommand.
     304             :      *
     305             :      * @param [in] aConfigParams contains information to configure CommandSender behavior,
     306             :      *                      such as such as allowing a max number of paths per invoke greater than one,
     307             :      *                      based on how many paths the remote peer claims to support.
     308             :      *
     309             :      * @return CHIP_ERROR_INCORRECT_STATE
     310             :      *                      If device has previously called `PrepareCommand`.
     311             :      * @return CHIP_ERROR_INVALID_ARGUMENT
     312             :      *                      Invalid argument value.
     313             :      * @return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE
     314             :      *                      Device has not enabled CHIP_CONFIG_SENDING_BATCH_COMMANDS_ENABLED.
     315             :      */
     316             :     CHIP_ERROR SetCommandSenderConfig(ConfigParameters & aConfigParams);
     317             : 
     318             :     CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, PrepareCommandParameters & aPrepareCommandParams);
     319             : 
     320             :     [[deprecated("PrepareCommand should migrate to calling PrepareCommand with PrepareCommandParameters")]] CHIP_ERROR
     321             :     PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true)
     322             :     {
     323             :         PrepareCommandParameters prepareCommandParams;
     324             :         prepareCommandParams.SetStartDataStruct(aStartDataStruct);
     325             :         return PrepareCommand(aCommandPathParams, prepareCommandParams);
     326             :     }
     327             : 
     328             :     CHIP_ERROR FinishCommand(FinishCommandParameters & aFinishCommandParams);
     329             : 
     330             :     [[deprecated("FinishCommand should migrate to calling FinishCommand with FinishCommandParameters")]] CHIP_ERROR
     331             :     FinishCommand(bool aEndDataStruct = true)
     332             :     {
     333             :         FinishCommandParameters finishCommandParams;
     334             :         finishCommandParams.SetEndDataStruct(aEndDataStruct);
     335             :         return FinishCommand(finishCommandParams);
     336             :     }
     337             :     [[deprecated("FinishCommand should migrate to calling FinishCommand with FinishCommandParameters")]] CHIP_ERROR
     338             :     FinishCommand(const Optional<uint16_t> & aTimedInvokeTimeoutMs)
     339             :     {
     340             :         FinishCommandParameters finishCommandParams(aTimedInvokeTimeoutMs);
     341             :         return FinishCommand(finishCommandParams);
     342             :     }
     343             : 
     344             :     TLV::TLVWriter * GetCommandDataIBTLVWriter();
     345             : 
     346             :     /**
     347             :      * API for adding a data request.  The template parameter T is generally
     348             :      * expected to be a ClusterName::Commands::CommandName::Type struct, but any
     349             :      * object that can be encoded using the DataModel::Encode machinery and
     350             :      * exposes the right command id will work.
     351             :      *
     352             :      * @param [in] aCommandPath  The path of the command being requested.
     353             :      * @param [in] aData         The data for the request.
     354             :      */
     355             :     template <typename CommandDataT, typename std::enable_if_t<!CommandDataT::MustUseTimedInvoke(), int> = 0>
     356             :     CHIP_ERROR AddRequestData(const CommandPathParams & aCommandPath, const CommandDataT & aData)
     357             :     {
     358             :         AddRequestDataParameters addRequestDataParams;
     359             :         return AddRequestData(aCommandPath, aData, addRequestDataParams);
     360             :     }
     361             : 
     362             :     template <typename CommandDataT>
     363           0 :     CHIP_ERROR AddRequestData(const CommandPathParams & aCommandPath, const CommandDataT & aData,
     364             :                               AddRequestDataParameters & aAddRequestDataParams)
     365             :     {
     366           0 :         VerifyOrReturnError(!CommandDataT::MustUseTimedInvoke() || aAddRequestDataParams.timedInvokeTimeoutMs.HasValue(),
     367             :                             CHIP_ERROR_INVALID_ARGUMENT);
     368             : 
     369           0 :         return AddRequestDataInternal(aCommandPath, aData, aAddRequestDataParams);
     370             :     }
     371             :     template <typename CommandDataT>
     372           0 :     CHIP_ERROR AddRequestData(const CommandPathParams & aCommandPath, const CommandDataT & aData,
     373             :                               const Optional<uint16_t> & aTimedInvokeTimeoutMs)
     374             :     {
     375           0 :         AddRequestDataParameters addRequestDataParams(aTimedInvokeTimeoutMs);
     376           0 :         return AddRequestData(aCommandPath, aData, addRequestDataParams);
     377           0 :     }
     378             : 
     379             :     /**
     380             :      * @brief Returns the number of InvokeResponseMessages received.
     381             :      *
     382             :      * Responses to multiple requests might be split across several InvokeResponseMessages.
     383             :      * This function helps track the total count. Primarily for test validation purposes.
     384             :      */
     385             :     size_t GetInvokeResponseMessageCount();
     386             : 
     387             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     388             :     /**
     389             :      * Version of AddRequestData that allows sending a message that is
     390             :      * guaranteed to fail due to requiring a timed invoke but not providing a
     391             :      * timeout parameter.  For use in tests only.
     392             :      */
     393             :     template <typename CommandDataT>
     394             :     CHIP_ERROR TestOnlyAddRequestDataNoTimedCheck(const CommandPathParams & aCommandPath, const CommandDataT & aData,
     395             :                                                   AddRequestDataParameters & aAddRequestDataParams)
     396             :     {
     397             :         return AddRequestDataInternal(aCommandPath, aData, aAddRequestDataParams);
     398             :     }
     399             : 
     400             :     CHIP_ERROR TestOnlyFinishCommand(FinishCommandParameters & aFinishCommandParams)
     401             :     {
     402             :         if (mBatchCommandsEnabled)
     403             :         {
     404             :             VerifyOrReturnError(aFinishCommandParams.commandRef.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
     405             :         }
     406             :         return FinishCommandInternal(aFinishCommandParams);
     407             :     }
     408             : 
     409             :     /**
     410             :      * Version of SendCommandRequest that sets the TimedRequest flag but does not send the TimedInvoke
     411             :      * action. For use in tests only.
     412             :      */
     413             :     CHIP_ERROR TestOnlyCommandSenderTimedRequestFlagWithNoTimedInvoke(const SessionHandle & session,
     414             :                                                                       Optional<System::Clock::Timeout> timeout = NullOptional);
     415             : 
     416             : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
     417             : 
     418             : private:
     419             :     template <typename CommandDataT>
     420           0 :     CHIP_ERROR AddRequestDataInternal(const CommandPathParams & aCommandPath, const CommandDataT & aData,
     421             :                                       AddRequestDataParameters & aAddRequestDataParams)
     422             :     {
     423           0 :         PrepareCommandParameters prepareCommandParams(aAddRequestDataParams);
     424           0 :         ReturnErrorOnFailure(PrepareCommand(aCommandPath, prepareCommandParams));
     425           0 :         TLV::TLVWriter * writer = GetCommandDataIBTLVWriter();
     426           0 :         VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE);
     427           0 :         ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::Tag::kFields), aData));
     428           0 :         FinishCommandParameters finishCommandParams(aAddRequestDataParams);
     429           0 :         return FinishCommand(finishCommandParams);
     430           0 :     }
     431             : 
     432             :     CHIP_ERROR FinishCommandInternal(FinishCommandParameters & aFinishCommandParams);
     433             : 
     434             : public:
     435             :     // Sends a queued up command request to the target encapsulated by the secureSession handle.
     436             :     //
     437             :     // Upon successful return from this call, all subsequent errors that occur during this interaction
     438             :     // will be conveyed through the OnError callback above. In addition, upon completion of work regardless of
     439             :     // whether it was successful or not, the OnDone callback will be invoked to indicate completion of work on this
     440             :     // object and to indicate to the application that it can destroy and free this object.
     441             :     //
     442             :     // Applications can, however, destroy this object at any time after this call, except while handling
     443             :     // an OnResponse or OnError callback, and it will safely clean-up.
     444             :     //
     445             :     // If this call returns failure, the callback's OnDone will never be called; the client is responsible
     446             :     // for destroying this object on failure.
     447             :     //
     448             :     // Client can specify the maximum time to wait for response (in milliseconds) via timeout parameter.
     449             :     // Default timeout value will be used otherwise.
     450             :     //
     451             :     CHIP_ERROR SendCommandRequest(const SessionHandle & session, Optional<System::Clock::Timeout> timeout = NullOptional);
     452             : 
     453             :     // Sends a queued up group command request to the target encapsulated by the secureSession handle.
     454             :     //
     455             :     // If this function is successful, it will invoke the OnDone callback before returning to indicate
     456             :     // to the application that it can destroy and free this object.
     457             :     //
     458             :     CHIP_ERROR SendGroupCommandRequest(const SessionHandle & session);
     459             : 
     460             : private:
     461             :     friend class TestCommandInteraction;
     462             : 
     463             :     enum class State : uint8_t
     464             :     {
     465             :         Idle,                ///< Default state that the object starts out in, where no work has commenced
     466             :         AddingCommand,       ///< In the process of adding a command.
     467             :         AddedCommand,        ///< A command has been completely encoded and is awaiting transmission.
     468             :         AwaitingTimedStatus, ///< Sent a Timed Request and waiting for response.
     469             :         AwaitingResponse,    ///< The command has been sent successfully, and we are awaiting invoke response.
     470             :         ResponseReceived,    ///< Received a response to our invoke and request and processing the response.
     471             :         AwaitingDestruction, ///< The object has completed its work and is awaiting destruction by the application.
     472             :     };
     473             : 
     474             :     union CallbackHandle
     475             :     {
     476          35 :         CallbackHandle(Callback * apCallback) : legacyCallback(apCallback) {}
     477           2 :         CallbackHandle(ExtendableCallback * apExtendableCallback) : extendableCallback(apExtendableCallback) {}
     478             :         Callback * legacyCallback;
     479             :         ExtendableCallback * extendableCallback;
     480             :     };
     481             : 
     482             :     void MoveToState(const State aTargetState);
     483             :     const char * GetStateStr() const;
     484             : 
     485             :     /*
     486             :      * Allocates a packet buffer used for encoding an invoke request payload.
     487             :      *
     488             :      * This can be called multiple times safely, as it will only allocate the buffer once for the lifetime
     489             :      * of this object.
     490             :      */
     491             :     CHIP_ERROR AllocateBuffer();
     492             : 
     493             :     // ExchangeDelegate interface implementation.  Private so people won't
     494             :     // accidentally call it on us when we're not being treated as an actual
     495             :     // ExchangeDelegate.
     496             :     CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     497             :                                  System::PacketBufferHandle && aPayload) override;
     498             :     void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
     499             : 
     500             :     //
     501             :     // Called internally to signal the completion of all work on this object, gracefully close the
     502             :     // exchange (by calling into the base class) and finally, signal to the application that it's
     503             :     // safe to release this object.
     504             :     //
     505             :     void Close();
     506             : 
     507             :     /*
     508             :      * This forcibly closes the exchange context if a valid one is pointed to. Such a situation does
     509             :      * not arise during normal message processing flows that all normally call Close() above. This can only
     510             :      * arise due to application-initiated destruction of the object when this object is handling receiving/sending
     511             :      * message payloads.
     512             :      */
     513             :     void Abort();
     514             : 
     515             :     CHIP_ERROR ProcessInvokeResponse(System::PacketBufferHandle && payload, bool & moreChunkedMessages);
     516             :     CHIP_ERROR ProcessInvokeResponseIB(InvokeResponseIB::Parser & aInvokeResponse);
     517             : 
     518             :     void SetTimedInvokeTimeoutMs(const Optional<uint16_t> & aTimedInvokeTimeoutMs);
     519             : 
     520             :     // Send our queued-up Invoke Request message.  Assumes the exchange is ready
     521             :     // and mPendingInvokeData is populated.
     522             :     CHIP_ERROR SendInvokeRequest();
     523             : 
     524             :     CHIP_ERROR Finalize(System::PacketBufferHandle & commandPacket);
     525             : 
     526             :     CHIP_ERROR SendCommandRequestInternal(const SessionHandle & session, Optional<System::Clock::Timeout> timeout);
     527             : 
     528          18 :     void OnResponseCallback(const ResponseData & aResponseData)
     529             :     {
     530             :         // mpExtendableCallback and mpCallback are mutually exclusive.
     531          18 :         if (mUseExtendableCallback && mCallbackHandle.extendableCallback)
     532             :         {
     533           1 :             mCallbackHandle.extendableCallback->OnResponse(this, aResponseData);
     534             :         }
     535          17 :         else if (mCallbackHandle.legacyCallback)
     536             :         {
     537          17 :             mCallbackHandle.legacyCallback->OnResponse(this, aResponseData.path, aResponseData.statusIB, aResponseData.data);
     538             :         }
     539          18 :     }
     540             : 
     541          23 :     void OnErrorCallback(CHIP_ERROR aError)
     542             :     {
     543             :         // mpExtendableCallback and mpCallback are mutually exclusive.
     544          23 :         if (mUseExtendableCallback && mCallbackHandle.extendableCallback)
     545             :         {
     546           0 :             ErrorData errorData = { aError };
     547           0 :             mCallbackHandle.extendableCallback->OnError(this, errorData);
     548           0 :         }
     549          23 :         else if (mCallbackHandle.legacyCallback)
     550             :         {
     551          23 :             mCallbackHandle.legacyCallback->OnError(this, aError);
     552             :         }
     553          23 :     }
     554             : 
     555          32 :     void OnDoneCallback()
     556             :     {
     557             :         // mpExtendableCallback and mpCallback are mutually exclusive.
     558          32 :         if (mUseExtendableCallback && mCallbackHandle.extendableCallback)
     559             :         {
     560           1 :             mCallbackHandle.extendableCallback->OnDone(this);
     561             :         }
     562          31 :         else if (mCallbackHandle.legacyCallback)
     563             :         {
     564          31 :             mCallbackHandle.legacyCallback->OnDone(this);
     565             :         }
     566          32 :     }
     567             : 
     568             :     Messaging::ExchangeHolder mExchangeCtx;
     569             :     CallbackHandle mCallbackHandle;
     570             :     Messaging::ExchangeManager * mpExchangeMgr = nullptr;
     571             :     InvokeRequestMessage::Builder mInvokeRequestBuilder;
     572             :     // TODO Maybe we should change PacketBufferTLVWriter so we can finalize it
     573             :     // but have it hold on to the buffer, and get the buffer from it later.
     574             :     // Then we could avoid this extra pointer-sized member.
     575             :     System::PacketBufferHandle mPendingInvokeData;
     576             :     // If mTimedInvokeTimeoutMs has a value, we are expected to do a timed
     577             :     // invoke.
     578             :     Optional<uint16_t> mTimedInvokeTimeoutMs;
     579             :     TLV::TLVType mDataElementContainerType = TLV::kTLVType_NotSpecified;
     580             : 
     581             :     chip::System::PacketBufferTLVWriter mCommandMessageWriter;
     582             : 
     583             :     uint16_t mInvokeResponseMessageCount = 0;
     584             :     uint16_t mFinishedCommandCount       = 0;
     585             :     uint16_t mRemoteMaxPathsPerInvoke    = 1;
     586             : 
     587             :     State mState                = State::Idle;
     588             :     bool mSuppressResponse      = false;
     589             :     bool mTimedRequest          = false;
     590             :     bool mBufferAllocated       = false;
     591             :     bool mBatchCommandsEnabled  = false;
     592             :     bool mUseExtendableCallback = false;
     593             : };
     594             : 
     595             : } // namespace app
     596             : } // namespace chip

Generated by: LCOV version 1.14