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

Generated by: LCOV version 2.0-1