Matter SDK Coverage Report
Current view: top level - app - CommandSender.h (source / functions) Coverage Total Hit
Test: SHA:0a260ffe149e0486eee9e451428453f0b12a3d3c Lines: 75.7 % 37 28
Test Date: 2025-06-06 07:10:05 Functions: 12.5 % 56 7

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

Generated by: LCOV version 2.0-1