LCOV - code coverage report
Current view: top level - app - CommandResponseSender.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 28 76 36.8 %
Date: 2024-02-15 08:20:41 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /*
       2             :  *    Copyright (c) 2024 Project CHIP Authors
       3             :  *    All rights reserved.
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : #include "CommandResponseSender.h"
      19             : #include "InteractionModelEngine.h"
      20             : #include "messaging/ExchangeContext.h"
      21             : 
      22             : namespace chip {
      23             : namespace app {
      24             : using Status = Protocols::InteractionModel::Status;
      25             : 
      26           0 : CHIP_ERROR CommandResponseSender::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext,
      27             :                                                     const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
      28             : {
      29           0 :     CHIP_ERROR err = CHIP_NO_ERROR;
      30           0 :     Optional<Status> failureStatusToSend;
      31             : 
      32           0 :     if (mState == State::AwaitingStatusResponse &&
      33           0 :         aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
      34             :     {
      35           0 :         CHIP_ERROR statusError = CHIP_NO_ERROR;
      36           0 :         err                    = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError);
      37           0 :         VerifyOrExit(err == CHIP_NO_ERROR, failureStatusToSend.SetValue(Status::InvalidAction));
      38           0 :         err = statusError;
      39           0 :         VerifyOrExit(err == CHIP_NO_ERROR, failureStatusToSend.SetValue(Status::InvalidAction));
      40             : 
      41             :         // If SendCommandResponse() fails, we are responsible for closing the exchange,
      42             :         // as stipulated by the API contract. We fulfill this obligation by not sending
      43             :         // a message expecting a response on the exchange. Since we are in the middle
      44             :         // of processing an incoming message, the exchange will close itself once we are
      45             :         // done processing it, if there is no response to wait for at that point.
      46           0 :         err = SendCommandResponse();
      47           0 :         VerifyOrExit(err == CHIP_NO_ERROR, failureStatusToSend.SetValue(Status::Failure));
      48             : 
      49           0 :         bool moreToSend = !mChunks.IsNull();
      50           0 :         if (!moreToSend)
      51             :         {
      52             :             // We are sending the final message and do not anticipate any further responses. We are
      53             :             // calling ExitNow() to immediately execute Close() and subsequently return from this function.
      54           0 :             ExitNow();
      55             :         }
      56           0 :         return CHIP_NO_ERROR;
      57             :     }
      58             : 
      59           0 :     ChipLogDetail(DataManagement, "CommandResponseSender: Unexpected message type %d", aPayloadHeader.GetMessageType());
      60           0 :     err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
      61           0 :     if (mState != State::AllInvokeResponsesSent)
      62             :     {
      63           0 :         failureStatusToSend.SetValue(Status::Failure);
      64           0 :         ExitNow();
      65             :     }
      66           0 :     StatusResponse::Send(Status::InvalidAction, mExchangeCtx.Get(), false /*aExpectResponse*/);
      67           0 :     return err;
      68           0 : exit:
      69           0 :     if (failureStatusToSend.HasValue())
      70             :     {
      71           0 :         StatusResponse::Send(failureStatusToSend.Value(), mExchangeCtx.Get(), false /*aExpectResponse*/);
      72             :     }
      73           0 :     Close();
      74           0 :     return err;
      75           0 : }
      76             : 
      77           0 : void CommandResponseSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
      78             : {
      79           0 :     ChipLogDetail(DataManagement, "CommandResponseSender: Timed out waiting for response from requester mState=[%10.10s]",
      80             :                   GetStateStr());
      81           0 :     Close();
      82           0 : }
      83             : 
      84          28 : CHIP_ERROR CommandResponseSender::StartSendingCommandResponses()
      85             : {
      86          28 :     VerifyOrReturnError(mState == State::ReadyForInvokeResponses, CHIP_ERROR_INCORRECT_STATE);
      87             :     // If SendCommandResponse() fails, we are obligated to close the exchange as per the API
      88             :     // contract. However, this method's contract also stipulates that in the event of our
      89             :     // failure, the caller bears the responsibility of closing the exchange.
      90          28 :     ReturnErrorOnFailure(SendCommandResponse());
      91             : 
      92          27 :     if (HasMoreToSend())
      93             :     {
      94           0 :         MoveToState(State::AwaitingStatusResponse);
      95           0 :         mExchangeCtx->SetDelegate(this);
      96             :     }
      97             :     else
      98             :     {
      99          27 :         Close();
     100             :     }
     101          27 :     return CHIP_NO_ERROR;
     102             : }
     103             : 
     104          28 : CHIP_ERROR CommandResponseSender::SendCommandResponse()
     105             : {
     106          28 :     VerifyOrReturnError(HasMoreToSend(), CHIP_ERROR_INCORRECT_STATE);
     107          28 :     if (mChunks.IsNull())
     108             :     {
     109           0 :         VerifyOrReturnError(mReportResponseDropped, CHIP_ERROR_INCORRECT_STATE);
     110           0 :         SendStatusResponse(Status::ResourceExhausted);
     111           0 :         mReportResponseDropped = false;
     112           0 :         return CHIP_NO_ERROR;
     113             :     }
     114          28 :     System::PacketBufferHandle commandResponsePayload = mChunks.PopHead();
     115             : 
     116          28 :     Messaging::SendFlags sendFlag = Messaging::SendMessageFlags::kNone;
     117          28 :     if (HasMoreToSend())
     118             :     {
     119           0 :         sendFlag = Messaging::SendMessageFlags::kExpectResponse;
     120           0 :         mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
     121             :     }
     122             : 
     123          28 :     ReturnErrorOnFailure(mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::InvokeCommandResponse,
     124             :                                                    std::move(commandResponsePayload), sendFlag));
     125             : 
     126          27 :     return CHIP_NO_ERROR;
     127          28 : }
     128             : 
     129          27 : const char * CommandResponseSender::GetStateStr() const
     130             : {
     131             : #if CHIP_DETAIL_LOGGING
     132          27 :     switch (mState)
     133             :     {
     134           0 :     case State::ReadyForInvokeResponses:
     135           0 :         return "ReadyForInvokeResponses";
     136             : 
     137           0 :     case State::AwaitingStatusResponse:
     138           0 :         return "AwaitingStatusResponse";
     139             : 
     140          27 :     case State::AllInvokeResponsesSent:
     141          27 :         return "AllInvokeResponsesSent";
     142             :     }
     143             : #endif // CHIP_DETAIL_LOGGING
     144           0 :     return "N/A";
     145             : }
     146             : 
     147          27 : void CommandResponseSender::MoveToState(const State aTargetState)
     148             : {
     149          27 :     if (mState == aTargetState)
     150             :     {
     151           0 :         return;
     152             :     }
     153          27 :     mState = aTargetState;
     154          27 :     ChipLogDetail(DataManagement, "Command response sender moving to [%10.10s]", GetStateStr());
     155             : }
     156             : 
     157          27 : void CommandResponseSender::Close()
     158             : {
     159          27 :     MoveToState(State::AllInvokeResponsesSent);
     160          27 :     mCloseCalled = true;
     161          27 :     if (mResponseSenderDoneCallback)
     162             :     {
     163           0 :         mResponseSenderDoneCallback->mCall(mResponseSenderDoneCallback->mContext);
     164             :     }
     165          27 : }
     166             : 
     167             : } // namespace app
     168             : } // namespace chip

Generated by: LCOV version 1.14