Matter SDK Coverage Report
Current view: top level - app - WriteClient.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 75.3 % 247 186
Test Date: 2025-01-17 19:00:11 Functions: 83.3 % 18 15

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 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 the initiator side of a CHIP Write Interaction.
      22              :  *
      23              :  */
      24              : 
      25              : #include "lib/core/CHIPError.h"
      26              : #include <app/AppConfig.h>
      27              : #include <app/InteractionModelEngine.h>
      28              : #include <app/TimedRequest.h>
      29              : #include <app/WriteClient.h>
      30              : 
      31              : namespace chip {
      32              : namespace app {
      33              : 
      34          429 : void WriteClient::Close()
      35              : {
      36          429 :     MoveToState(State::AwaitingDestruction);
      37              : 
      38          429 :     if (mpCallback)
      39              :     {
      40          429 :         mpCallback->OnDone(this);
      41              :     }
      42          429 : }
      43              : 
      44         1729 : CHIP_ERROR WriteClient::ProcessWriteResponseMessage(System::PacketBufferHandle && payload)
      45              : {
      46         1729 :     CHIP_ERROR err = CHIP_NO_ERROR;
      47         1729 :     System::PacketBufferTLVReader reader;
      48         1729 :     TLV::TLVReader attributeStatusesReader;
      49         1729 :     WriteResponseMessage::Parser writeResponse;
      50         1729 :     AttributeStatusIBs::Parser attributeStatusesParser;
      51              : 
      52         1729 :     reader.Init(std::move(payload));
      53              : 
      54         1729 :     ReturnErrorOnFailure(writeResponse.Init(reader));
      55              : 
      56              : #if CHIP_CONFIG_IM_PRETTY_PRINT
      57         1728 :     writeResponse.PrettyPrint();
      58              : #endif
      59              : 
      60         1728 :     err = writeResponse.GetWriteResponses(&attributeStatusesParser);
      61         1728 :     if (err == CHIP_END_OF_TLV)
      62              :     {
      63            0 :         return CHIP_NO_ERROR;
      64              :     }
      65         1728 :     ReturnErrorOnFailure(err);
      66              : 
      67         1728 :     attributeStatusesParser.GetReader(&attributeStatusesReader);
      68              : 
      69         4205 :     while (CHIP_NO_ERROR == (err = attributeStatusesReader.Next()))
      70              :     {
      71         2477 :         VerifyOrReturnError(TLV::AnonymousTag() == attributeStatusesReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
      72              : 
      73         2477 :         AttributeStatusIB::Parser element;
      74              : 
      75         2477 :         ReturnErrorOnFailure(element.Init(attributeStatusesReader));
      76         2477 :         ReturnErrorOnFailure(ProcessAttributeStatusIB(element));
      77              :     }
      78              : 
      79              :     // if we have exhausted this container
      80         1728 :     if (CHIP_END_OF_TLV == err)
      81              :     {
      82         1728 :         err = CHIP_NO_ERROR;
      83              :     }
      84         1728 :     ReturnErrorOnFailure(err);
      85         1728 :     return writeResponse.ExitContainer();
      86         1729 : }
      87              : 
      88         3965 : CHIP_ERROR WriteClient::PrepareAttributeIB(const ConcreteDataAttributePath & aPath)
      89              : {
      90         3965 :     AttributeDataIBs::Builder & writeRequests  = mWriteRequestBuilder.GetWriteRequests();
      91         3965 :     AttributeDataIB::Builder & attributeDataIB = writeRequests.CreateAttributeDataIBBuilder();
      92         3965 :     ReturnErrorOnFailure(writeRequests.GetError());
      93         3957 :     if (aPath.mDataVersion.HasValue())
      94              :     {
      95           12 :         attributeDataIB.DataVersion(aPath.mDataVersion.Value());
      96           12 :         mHasDataVersion = true;
      97              :     }
      98         3957 :     ReturnErrorOnFailure(attributeDataIB.GetError());
      99         3957 :     AttributePathIB::Builder & path = attributeDataIB.CreatePath();
     100              : 
     101              :     // We are using kInvalidEndpointId just for group write requests. This is not the correct use of ConcreteDataAttributePath.
     102              :     // TODO: update AttributePathParams or ConcreteDataAttributePath for a class supports both nullable list index and missing
     103              :     // endpoint id.
     104         3957 :     if (aPath.mEndpointId != kInvalidEndpointId)
     105              :     {
     106         3957 :         path.Endpoint(aPath.mEndpointId);
     107              :     }
     108         3957 :     path.Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId);
     109         3957 :     if (aPath.IsListItemOperation())
     110              :     {
     111         3473 :         if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
     112              :         {
     113         3473 :             path.ListIndex(DataModel::NullNullable);
     114              :         }
     115              :         else
     116              :         {
     117              :             // We do not support other list operations (i.e. update, delete etc) for now.
     118            0 :             return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     119              :         }
     120              :     }
     121         3957 :     ReturnErrorOnFailure(path.EndOfAttributePathIB());
     122              : 
     123         3771 :     return CHIP_NO_ERROR;
     124              : }
     125              : 
     126         2556 : CHIP_ERROR WriteClient::FinishAttributeIB()
     127              : {
     128         2556 :     AttributeDataIB::Builder & attributeDataIB = mWriteRequestBuilder.GetWriteRequests().GetAttributeDataIBBuilder();
     129         2556 :     ReturnErrorOnFailure(attributeDataIB.EndOfAttributeDataIB());
     130         2549 :     MoveToState(State::AddAttribute);
     131         2549 :     return CHIP_NO_ERROR;
     132              : }
     133              : 
     134         3771 : TLV::TLVWriter * WriteClient::GetAttributeDataIBTLVWriter()
     135              : {
     136         3771 :     return mWriteRequestBuilder.GetWriteRequests().GetAttributeDataIBBuilder().GetWriter();
     137              : }
     138              : 
     139         1790 : CHIP_ERROR WriteClient::FinalizeMessage(bool aHasMoreChunks)
     140              : {
     141         1790 :     System::PacketBufferHandle packet;
     142         1790 :     VerifyOrReturnError(mState == State::AddAttribute, CHIP_ERROR_INCORRECT_STATE);
     143              : 
     144         1790 :     TLV::TLVWriter * writer = mWriteRequestBuilder.GetWriter();
     145         1790 :     VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE);
     146         1790 :     ReturnErrorOnFailure(writer->UnreserveBuffer(kReservedSizeForTLVEncodingOverhead));
     147              : 
     148         1790 :     ReturnErrorOnFailure(mWriteRequestBuilder.GetWriteRequests().EndOfAttributeDataIBs());
     149              : 
     150         1790 :     ReturnErrorOnFailure(mWriteRequestBuilder.MoreChunkedMessages(aHasMoreChunks).EndOfWriteRequestMessage());
     151         1790 :     ReturnErrorOnFailure(mMessageWriter.Finalize(&packet));
     152         1790 :     mChunks.AddToEnd(std::move(packet));
     153         1790 :     return CHIP_NO_ERROR;
     154         1790 : }
     155              : 
     156          485 : CHIP_ERROR WriteClient::EnsureMessage()
     157              : {
     158          485 :     if (mState != State::AddAttribute)
     159              :     {
     160          479 :         return StartNewMessage();
     161              :     }
     162            6 :     return CHIP_NO_ERROR;
     163              : }
     164              : 
     165         1843 : CHIP_ERROR WriteClient::StartNewMessage()
     166              : {
     167         1843 :     uint16_t reservedSize = 0;
     168              : 
     169         1843 :     if (mState == State::AddAttribute)
     170              :     {
     171         1364 :         ReturnErrorOnFailure(FinalizeMessage(true));
     172              :     }
     173              : 
     174              :     // Do not allow timed request with chunks.
     175         1843 :     VerifyOrReturnError(!(mTimedWriteTimeoutMs.HasValue() && !mChunks.IsNull()), CHIP_ERROR_NO_MEMORY);
     176              : 
     177         1843 :     System::PacketBufferHandle packet = System::PacketBufferHandle::New(kMaxSecureSduLengthBytes);
     178         1843 :     VerifyOrReturnError(!packet.IsNull(), CHIP_ERROR_NO_MEMORY);
     179              : 
     180              :     // Always limit the size of the packet to fit within kMaxSecureSduLengthBytes regardless of the available buffer capacity.
     181         1843 :     if (packet->AvailableDataLength() > kMaxSecureSduLengthBytes)
     182              :     {
     183            0 :         reservedSize = static_cast<uint16_t>(packet->AvailableDataLength() - kMaxSecureSduLengthBytes);
     184              :     }
     185              : 
     186              :     // ... and we need to reserve some extra space for the MIC field.
     187         1843 :     reservedSize = static_cast<uint16_t>(reservedSize + Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
     188              : 
     189              :     // ... and the overhead for end of AttributeDataIBs (end of container), more chunks flag, end of WriteRequestMessage (another
     190              :     // end of container).
     191         1843 :     reservedSize = static_cast<uint16_t>(reservedSize + kReservedSizeForTLVEncodingOverhead);
     192              : 
     193              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     194              :     // ... and for unit tests.
     195         1843 :     reservedSize = static_cast<uint16_t>(reservedSize + mReservedSize);
     196              : #endif
     197              : 
     198         1843 :     mMessageWriter.Init(std::move(packet));
     199              : 
     200         1843 :     ReturnErrorOnFailure(mMessageWriter.ReserveBuffer(reservedSize));
     201              : 
     202         1843 :     ReturnErrorOnFailure(mWriteRequestBuilder.Init(&mMessageWriter));
     203         1843 :     mWriteRequestBuilder.SuppressResponse(mSuppressResponse);
     204         1843 :     mWriteRequestBuilder.TimedRequest(mTimedWriteTimeoutMs.HasValue());
     205         1843 :     ReturnErrorOnFailure(mWriteRequestBuilder.GetError());
     206         1843 :     mWriteRequestBuilder.CreateWriteRequests();
     207         1843 :     ReturnErrorOnFailure(mWriteRequestBuilder.GetError());
     208              : 
     209         1843 :     TLV::TLVWriter * writer = mWriteRequestBuilder.GetWriter();
     210         1843 :     VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE);
     211              : 
     212         1843 :     return CHIP_NO_ERROR;
     213         1843 : }
     214              : 
     215            0 : CHIP_ERROR WriteClient::TryPutSinglePreencodedAttributeWritePayload(const ConcreteDataAttributePath & attributePath,
     216              :                                                                     const TLV::TLVReader & data)
     217              : {
     218            0 :     TLV::TLVReader dataToWrite;
     219            0 :     dataToWrite.Init(data);
     220              : 
     221            0 :     TLV::TLVWriter * writer = nullptr;
     222              : 
     223            0 :     ReturnErrorOnFailure(PrepareAttributeIB(attributePath));
     224            0 :     VerifyOrReturnError((writer = GetAttributeDataIBTLVWriter()) != nullptr, CHIP_ERROR_INCORRECT_STATE);
     225            0 :     ReturnErrorOnFailure(writer->CopyElement(TLV::ContextTag(AttributeDataIB::Tag::kData), dataToWrite));
     226            0 :     ReturnErrorOnFailure(FinishAttributeIB());
     227            0 :     return CHIP_NO_ERROR;
     228              : }
     229              : 
     230            0 : CHIP_ERROR WriteClient::PutSinglePreencodedAttributeWritePayload(const chip::app::ConcreteDataAttributePath & attributePath,
     231              :                                                                  const TLV::TLVReader & data)
     232              : {
     233            0 :     TLV::TLVWriter backupWriter;
     234              : 
     235            0 :     mWriteRequestBuilder.GetWriteRequests().Checkpoint(backupWriter);
     236              : 
     237              :     // First attempt to write this attribute.
     238            0 :     CHIP_ERROR err = TryPutSinglePreencodedAttributeWritePayload(attributePath, data);
     239            0 :     if (err == CHIP_ERROR_NO_MEMORY || err == CHIP_ERROR_BUFFER_TOO_SMALL)
     240              :     {
     241              :         // If it failed with no memory, then we create a new chunk for it.
     242            0 :         mWriteRequestBuilder.GetWriteRequests().Rollback(backupWriter);
     243            0 :         ReturnErrorOnFailure(StartNewMessage());
     244            0 :         err = TryPutSinglePreencodedAttributeWritePayload(attributePath, data);
     245              :         // Since we have created a new chunk for this element, the encode is expected to succeed.
     246              :     }
     247            0 :     return err;
     248              : }
     249              : 
     250            0 : CHIP_ERROR WriteClient::PutPreencodedAttribute(const ConcreteDataAttributePath & attributePath, const TLV::TLVReader & data)
     251              : {
     252            0 :     ReturnErrorOnFailure(EnsureMessage());
     253              : 
     254              :     // ListIndex is missing and the data is an array -- we are writing a whole list.
     255            0 :     if (!attributePath.IsListOperation() && data.GetType() == TLV::TLVType::kTLVType_Array)
     256              :     {
     257            0 :         TLV::TLVReader dataReader;
     258            0 :         TLV::TLVReader valueReader;
     259            0 :         CHIP_ERROR err = CHIP_NO_ERROR;
     260              : 
     261            0 :         ConcreteDataAttributePath path = attributePath;
     262              : 
     263            0 :         dataReader.Init(data);
     264            0 :         dataReader.OpenContainer(valueReader);
     265              : 
     266              :         // Encode an empty list for the chunking protocol.
     267            0 :         ReturnErrorOnFailure(EncodeSingleAttributeDataIB(path, DataModel::List<uint8_t>()));
     268              : 
     269            0 :         if (err == CHIP_NO_ERROR)
     270              :         {
     271            0 :             path.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem;
     272            0 :             while ((err = valueReader.Next()) == CHIP_NO_ERROR)
     273              :             {
     274            0 :                 ReturnErrorOnFailure(PutSinglePreencodedAttributeWritePayload(path, valueReader));
     275              :             }
     276              :         }
     277              : 
     278            0 :         if (err == CHIP_END_OF_TLV)
     279              :         {
     280            0 :             err = CHIP_NO_ERROR;
     281              :         }
     282            0 :         return err;
     283            0 :     }
     284              :     // We are writing a non-list attribute, or we are writing a single element of a list.
     285            0 :     return PutSinglePreencodedAttributeWritePayload(attributePath, data);
     286              : }
     287              : 
     288         5136 : const char * WriteClient::GetStateStr() const
     289              : {
     290              : #if CHIP_DETAIL_LOGGING
     291         5136 :     switch (mState)
     292              :     {
     293            0 :     case State::Initialized:
     294            0 :         return "Initialized";
     295              : 
     296         2549 :     case State::AddAttribute:
     297         2549 :         return "AddAttribute";
     298              : 
     299            0 :     case State::AwaitingTimedStatus:
     300            0 :         return "AwaitingTimedStatus";
     301              : 
     302         1736 :     case State::AwaitingResponse:
     303         1736 :         return "AwaitingResponse";
     304              : 
     305          422 :     case State::ResponseReceived:
     306          422 :         return "ResponseReceived";
     307              : 
     308          429 :     case State::AwaitingDestruction:
     309          429 :         return "AwaitingDestruction";
     310              :     }
     311              : #endif // CHIP_DETAIL_LOGGING
     312            0 :     return "N/A";
     313              : }
     314              : 
     315         5136 : void WriteClient::MoveToState(const State aTargetState)
     316              : {
     317         5136 :     mState = aTargetState;
     318         5136 :     ChipLogDetail(DataManagement, "WriteClient moving to [%10.10s]", GetStateStr());
     319         5136 : }
     320              : 
     321          426 : CHIP_ERROR WriteClient::SendWriteRequest(const SessionHandle & session, System::Clock::Timeout timeout)
     322              : {
     323          426 :     CHIP_ERROR err = CHIP_NO_ERROR;
     324              : 
     325          426 :     VerifyOrExit(mState == State::AddAttribute, err = CHIP_ERROR_INCORRECT_STATE);
     326              : 
     327          426 :     err = FinalizeMessage(false /* hasMoreChunks */);
     328          426 :     SuccessOrExit(err);
     329              : 
     330              :     {
     331              :         // Create a new exchange context.
     332          426 :         auto exchange = mpExchangeMgr->NewContext(session, this);
     333          426 :         VerifyOrExit(exchange != nullptr, err = CHIP_ERROR_NO_MEMORY);
     334              : 
     335          426 :         mExchangeCtx.Grab(exchange);
     336              :     }
     337              : 
     338          426 :     VerifyOrReturnError(!(mExchangeCtx->IsGroupExchangeContext() && mHasDataVersion), CHIP_ERROR_INVALID_MESSAGE_TYPE);
     339              : 
     340          426 :     if (timeout == System::Clock::kZero)
     341              :     {
     342          426 :         mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
     343              :     }
     344              :     else
     345              :     {
     346            0 :         mExchangeCtx->SetResponseTimeout(timeout);
     347              :     }
     348              : 
     349          426 :     if (mTimedWriteTimeoutMs.HasValue())
     350              :     {
     351            0 :         err = TimedRequest::Send(mExchangeCtx.Get(), mTimedWriteTimeoutMs.Value());
     352            0 :         SuccessOrExit(err);
     353            0 :         MoveToState(State::AwaitingTimedStatus);
     354              :     }
     355              :     else
     356              :     {
     357          426 :         err = SendWriteRequest();
     358          426 :         SuccessOrExit(err);
     359              :     }
     360              : 
     361          426 : exit:
     362          426 :     if (err != CHIP_NO_ERROR)
     363              :     {
     364            0 :         ChipLogError(DataManagement, "Write client failed to SendWriteRequest: %" CHIP_ERROR_FORMAT, err.Format());
     365              :     }
     366              :     else
     367              :     {
     368              :         // TODO: Ideally this would happen async, but to make sure that we
     369              :         // handle this object dying (e.g. due to IM enging shutdown) while the
     370              :         // async bits are pending we'd need to malloc some state bit that we can
     371              :         // twiddle if we die.  For now just do the OnDone callback sync.
     372          426 :         if (session->IsGroupSession())
     373              :         {
     374              :             // Always shutdown on Group communication
     375            1 :             ChipLogDetail(DataManagement, "Closing on group Communication ");
     376              : 
     377              :             // Tell the application to release the object.
     378              :             // TODO: Consumers expect to hand off ownership of the WriteClient and wait for OnDone
     379              :             // after SendWriteRequest returns success.  Calling OnDone before returning is weird.
     380              :             // Need to refactor the code to avoid this.
     381            1 :             Close();
     382              :         }
     383              :     }
     384              : 
     385          426 :     return err;
     386              : }
     387              : 
     388         1736 : CHIP_ERROR WriteClient::SendWriteRequest()
     389              : {
     390              :     using namespace Protocols::InteractionModel;
     391              :     using namespace Messaging;
     392              : 
     393         1736 :     System::PacketBufferHandle data = mChunks.PopHead();
     394              : 
     395         1736 :     bool isGroupWrite = mExchangeCtx->IsGroupExchangeContext();
     396         1736 :     if (!mChunks.IsNull() && isGroupWrite)
     397              :     {
     398              :         // Reject this request if we have more than one chunk (mChunks is not null after PopHead()), and this is a group
     399              :         // exchange context.
     400            0 :         return CHIP_ERROR_INCORRECT_STATE;
     401              :     }
     402              : 
     403              :     // kExpectResponse is ignored by ExchangeContext in case of groupcast
     404         1736 :     ReturnErrorOnFailure(mExchangeCtx->SendMessage(MsgType::WriteRequest, std::move(data), SendMessageFlags::kExpectResponse));
     405              : 
     406         1736 :     MoveToState(State::AwaitingResponse);
     407         1736 :     return CHIP_NO_ERROR;
     408         1736 : }
     409              : 
     410         1732 : CHIP_ERROR WriteClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     411              :                                           System::PacketBufferHandle && aPayload)
     412              : {
     413              :     using namespace Protocols::InteractionModel;
     414              : 
     415         3464 :     if (mState == State::AwaitingResponse &&
     416              :         // We had sent the last chunk of data, and received all responses
     417         1732 :         mChunks.IsNull())
     418              :     {
     419          422 :         MoveToState(State::ResponseReceived);
     420              :     }
     421              : 
     422         1732 :     CHIP_ERROR err          = CHIP_NO_ERROR;
     423         1732 :     bool sendStatusResponse = false;
     424              :     // Assert that the exchange context matches the client's current context.
     425              :     // This should never fail because even if SendWriteRequest is called
     426              :     // back-to-back, the second call will call Close() on the first exchange,
     427              :     // which clears the OnMessageReceived callback.
     428         1732 :     VerifyOrExit(apExchangeContext == mExchangeCtx.Get(), err = CHIP_ERROR_INCORRECT_STATE);
     429              : 
     430         1732 :     sendStatusResponse = true;
     431              : 
     432         1732 :     if (mState == State::AwaitingTimedStatus)
     433              :     {
     434            0 :         if (aPayloadHeader.HasMessageType(MsgType::StatusResponse))
     435              :         {
     436            0 :             CHIP_ERROR statusError = CHIP_NO_ERROR;
     437            0 :             SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
     438            0 :             sendStatusResponse = false;
     439            0 :             SuccessOrExit(err = statusError);
     440            0 :             err = SendWriteRequest();
     441              :         }
     442              :         else
     443              :         {
     444            0 :             err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     445              :         }
     446              :         // Skip all other processing here (which is for the response to the
     447              :         // write request), no matter whether err is success or not.
     448            0 :         goto exit;
     449              :     }
     450              : 
     451         1732 :     if (aPayloadHeader.HasMessageType(MsgType::WriteResponse))
     452              :     {
     453         1728 :         err = ProcessWriteResponseMessage(std::move(aPayload));
     454         1728 :         SuccessOrExit(err);
     455         1727 :         sendStatusResponse = false;
     456         1727 :         if (!mChunks.IsNull())
     457              :         {
     458              :             // Send the next chunk.
     459         1310 :             SuccessOrExit(err = SendWriteRequest());
     460              :         }
     461              :     }
     462            4 :     else if (aPayloadHeader.HasMessageType(MsgType::StatusResponse))
     463              :     {
     464            3 :         CHIP_ERROR statusError = CHIP_NO_ERROR;
     465            5 :         SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
     466            2 :         SuccessOrExit(err = statusError);
     467            0 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     468              :     }
     469              :     else
     470              :     {
     471            1 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     472              :     }
     473              : 
     474         1732 : exit:
     475         1732 :     if (mpCallback != nullptr)
     476              :     {
     477         1732 :         if (err != CHIP_NO_ERROR)
     478              :         {
     479            5 :             mpCallback->OnError(this, err);
     480              :         }
     481              :     }
     482              : 
     483         1732 :     if (sendStatusResponse)
     484              :     {
     485            5 :         StatusResponse::Send(Status::InvalidAction, apExchangeContext, false /*aExpectResponse*/);
     486              :     }
     487              : 
     488         1732 :     if (mState != State::AwaitingResponse)
     489              :     {
     490          422 :         Close();
     491              :     }
     492              :     // Else we got a response to a Timed Request and just sent the write.
     493              : 
     494         1732 :     return err;
     495              : }
     496              : 
     497            5 : void WriteClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
     498              : {
     499            5 :     ChipLogError(DataManagement, "Time out! failed to receive write response from Exchange: " ChipLogFormatExchange,
     500              :                  ChipLogValueExchange(apExchangeContext));
     501              : 
     502            5 :     if (mpCallback != nullptr)
     503              :     {
     504            5 :         mpCallback->OnError(this, CHIP_ERROR_TIMEOUT);
     505              :     }
     506            5 :     Close();
     507            5 : }
     508              : 
     509         2477 : CHIP_ERROR WriteClient::ProcessAttributeStatusIB(AttributeStatusIB::Parser & aAttributeStatusIB)
     510              : {
     511         2477 :     CHIP_ERROR err = CHIP_NO_ERROR;
     512         2477 :     AttributePathIB::Parser attributePathParser;
     513         2477 :     StatusIB statusIB;
     514         2477 :     StatusIB::Parser StatusIBParser;
     515         2477 :     ConcreteDataAttributePath attributePath;
     516              : 
     517         2477 :     err = aAttributeStatusIB.GetPath(&attributePathParser);
     518         2477 :     SuccessOrExit(err);
     519              : 
     520         2477 :     err = attributePathParser.GetConcreteAttributePath(attributePath);
     521         2477 :     SuccessOrExit(err);
     522              : 
     523         2477 :     err = aAttributeStatusIB.GetErrorStatus(&(StatusIBParser));
     524         2477 :     if (CHIP_NO_ERROR == err)
     525              :     {
     526         2477 :         err = StatusIBParser.DecodeStatusIB(statusIB);
     527         2477 :         SuccessOrExit(err);
     528         2477 :         if (mpCallback != nullptr)
     529              :         {
     530         2477 :             mpCallback->OnResponse(this, attributePath, statusIB);
     531              :         }
     532              :     }
     533              : 
     534            0 : exit:
     535         2477 :     return err;
     536         2477 : }
     537              : 
     538              : } // namespace app
     539              : } // namespace chip
        

Generated by: LCOV version 2.0-1