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