Matter SDK Coverage Report
Current view: top level - protocols/bdx - AsyncTransferFacilitator.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 0.0 % 73 0
Test Date: 2025-02-22 08:08:07 Functions: 0.0 % 9 0

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2024 Project CHIP Authors
       3              :  *
       4              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       5              :  *    you may not use this file except in compliance with the License.
       6              :  *    You may obtain a copy of the License at
       7              :  *
       8              :  *        http://www.apache.org/licenses/LICENSE-2.0
       9              :  *
      10              :  *    Unless required by applicable law or agreed to in writing, software
      11              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      12              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13              :  *    See the License for the specific language governing permissions and
      14              :  *    limitations under the License.
      15              :  */
      16              : 
      17              : #include "AsyncTransferFacilitator.h"
      18              : 
      19              : #include <protocols/bdx/StatusCode.h>
      20              : #include <system/SystemClock.h>
      21              : 
      22              : namespace chip {
      23              : namespace bdx {
      24              : 
      25            0 : AsyncTransferFacilitator::~AsyncTransferFacilitator() {}
      26              : 
      27            0 : CHIP_ERROR AsyncTransferFacilitator::Init(System::Layer * layer, Messaging::ExchangeContext * exchangeCtx,
      28              :                                           System::Clock::Timeout timeout)
      29              : {
      30            0 :     VerifyOrReturnError(layer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      31            0 :     VerifyOrReturnError(exchangeCtx != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      32            0 :     VerifyOrReturnError(!mExchange, CHIP_ERROR_INCORRECT_STATE);
      33              : 
      34            0 :     mSystemLayer = layer;
      35            0 :     mExchange.Grab(exchangeCtx);
      36            0 :     mTimeout                          = timeout;
      37            0 :     mProcessingOutputEvents           = false;
      38            0 :     mDestroySelfAfterProcessingEvents = false;
      39            0 :     return CHIP_NO_ERROR;
      40              : }
      41              : 
      42              : /**
      43              :  * Get events one by one from the TransferSession and process them,
      44              :  * until there are no more events to process.
      45              :  */
      46            0 : void AsyncTransferFacilitator::ProcessOutputEvents()
      47              : {
      48            0 :     if (mProcessingOutputEvents)
      49              :     {
      50            0 :         ChipLogDetail(BDX,
      51              :                       "ProcessOutputEvents: we are already in the middle of processing events, so nothing to do here; when we "
      52              :                       "unwind to the processing loop the events will get processed.");
      53            0 :         return;
      54              :     }
      55              : 
      56            0 :     mProcessingOutputEvents = true;
      57              : 
      58              :     // Get the next output event and handle it based on the type of event.
      59              :     // If its of type kMsgToSend send it over the exchange, otherwise call the HandleTransferSessionOutput
      60              :     // virtual method that must be implemeted by the subclass of this class to handle the BDX message.
      61            0 :     TransferSession::OutputEvent outEvent;
      62              : 
      63            0 :     mTransfer.GetNextAction(outEvent);
      64            0 :     while (outEvent.EventType != TransferSession::OutputEventType::kNone)
      65              :     {
      66              : 
      67              :         // If the transfer session state machine generates an event of type TransferSession::OutputEventType::kInternalError,
      68              :         // indicating that the session is in a bad state, it will keep doing that thereafter.
      69              :         //
      70              :         // So stop trying to process events, and go ahead and destroy ourselves to clean up the transfer.
      71            0 :         if (outEvent.EventType == TransferSession::OutputEventType::kInternalError)
      72              :         {
      73            0 :             mDestroySelfAfterProcessingEvents = true;
      74            0 :             break;
      75              :         }
      76              : 
      77            0 :         if (outEvent.EventType == TransferSession::OutputEventType::kMsgToSend)
      78              :         {
      79            0 :             CHIP_ERROR err = SendMessage(outEvent.msgTypeData, outEvent.MsgData);
      80              : 
      81              :             // If we failed to send the message across the exchange, just abort the transfer.
      82              :             // We have no way to notify our peer we are doing that (we can't send them a
      83              :             // message!) but eventually they will time out.
      84            0 :             if (err != CHIP_NO_ERROR)
      85              :             {
      86            0 :                 DestroySelf();
      87            0 :                 return;
      88              :             }
      89              : 
      90              :             // If we send out a status report across the exchange, that means there was an error.
      91              :             // We've sent our report about that error and can now abort the transfer.  Our peer
      92              :             // will respond to the status report by tearing down their side.
      93            0 :             if (outEvent.msgTypeData.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
      94              :             {
      95            0 :                 mDestroySelfAfterProcessingEvents = true;
      96            0 :                 break;
      97              :             }
      98              :         }
      99              :         else
     100              :         {
     101            0 :             HandleTransferSessionOutput(outEvent);
     102              :         }
     103            0 :         mTransfer.GetNextAction(outEvent);
     104              :     }
     105              : 
     106            0 :     mProcessingOutputEvents = false;
     107              : 
     108              :     // If mDestroySelfAfterProcessingEvents is set (by our code above or by NotifyEventHandled), we need
     109              :     // to call DestroySelf() after processing all pending output events.
     110            0 :     if (mDestroySelfAfterProcessingEvents)
     111              :     {
     112            0 :         DestroySelf();
     113              :     }
     114            0 : }
     115              : 
     116            0 : CHIP_ERROR AsyncTransferFacilitator::SendMessage(const TransferSession::MessageTypeData msgTypeData,
     117              :                                                  System::PacketBufferHandle & msgBuf)
     118              : {
     119            0 :     VerifyOrReturnError(mExchange, CHIP_ERROR_INCORRECT_STATE);
     120              : 
     121            0 :     Messaging::SendFlags sendFlags;
     122              : 
     123              :     // All messages that are sent expect a response, except for a StatusReport which would indicate an error and
     124              :     // the end of the transfer.
     125            0 :     if (!msgTypeData.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
     126              :     {
     127            0 :         sendFlags.Set(Messaging::SendMessageFlags::kExpectResponse);
     128              :     }
     129              : 
     130            0 :     Messaging::ExchangeContext * ec = mExchange.Get();
     131              : 
     132              :     // Set the response timeout on the exchange before sending the message.
     133            0 :     ec->SetResponseTimeout(mTimeout);
     134            0 :     return ec->SendMessage(msgTypeData.ProtocolId, msgTypeData.MessageType, std::move(msgBuf), sendFlags);
     135              : }
     136              : 
     137            0 : CHIP_ERROR AsyncTransferFacilitator::OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
     138              :                                                        System::PacketBufferHandle && payload)
     139              : {
     140            0 :     VerifyOrReturnError(mExchange, CHIP_ERROR_INCORRECT_STATE);
     141              : 
     142            0 :     VerifyOrReturnError(ec == mExchange.Get(), CHIP_ERROR_INCORRECT_STATE);
     143              : 
     144              :     CHIP_ERROR err =
     145            0 :         mTransfer.HandleMessageReceived(payloadHeader, std::move(payload), System::SystemClock().GetMonotonicTimestamp());
     146            0 :     if (err != CHIP_NO_ERROR)
     147              :     {
     148            0 :         ChipLogError(BDX, "OnMessageReceived: Failed to handle message: %" CHIP_ERROR_FORMAT, err.Format());
     149              : 
     150              :         // This should notify the transfer object to abort transfer so it can send a status report across the exchange
     151              :         // when we call ProcessOutputEvents below.
     152            0 :         mTransfer.AbortTransfer(GetBdxStatusCodeFromChipError(err));
     153              :     }
     154            0 :     else if (!payloadHeader.HasMessageType(MessageType::BlockAckEOF))
     155              :     {
     156              :         // Almost every BDX message expect BlockAckEOF will follow up with a response on the exchange.
     157            0 :         ec->WillSendMessage();
     158              :     }
     159              : 
     160            0 :     ProcessOutputEvents();
     161            0 :     return err;
     162              : }
     163              : 
     164            0 : void AsyncTransferFacilitator::OnResponseTimeout(Messaging::ExchangeContext * ec)
     165              : {
     166            0 :     ChipLogDetail(BDX, "OnResponseTimeout, ec: " ChipLogFormatExchange, ChipLogValueExchange(ec));
     167            0 :     DestroySelf();
     168            0 : }
     169              : 
     170            0 : CHIP_ERROR AsyncResponder::Init(System::Layer * layer, Messaging::ExchangeContext * exchangeCtx, TransferRole role,
     171              :                                 BitFlags<TransferControlFlags> xferControlOpts, uint16_t maxBlockSize,
     172              :                                 System::Clock::Timeout timeout)
     173              : {
     174            0 :     ReturnErrorOnFailure(AsyncTransferFacilitator::Init(layer, exchangeCtx, timeout));
     175            0 :     ReturnErrorOnFailure(mTransfer.WaitForTransfer(role, xferControlOpts, maxBlockSize, timeout));
     176            0 :     return CHIP_NO_ERROR;
     177              : }
     178              : 
     179            0 : void AsyncResponder::NotifyEventHandled(const TransferSession::OutputEventType eventType, CHIP_ERROR status)
     180              : {
     181              :     // If this is the end of the transfer (whether a clean end, or some sort of error condition), ensure
     182              :     // that we destroy ourselves after unwinding the processing loop in the ProcessOutputEvents API.
     183              :     // We can ignore the status for these output events because none of them are supposed to result in
     184              :     // us sending a StatusReport, and that's all we use the status for.
     185              :     //
     186              :     // In particular, for kTransferTimeout, kAckEOFReceived, and kStatusReceived per spec we
     187              :     // are not supposed to reply with a StatusReport.  And for kInternalError the state machine
     188              :     // is in an unrecoverable state of some sort, and we should stop trying to make use of it.
     189            0 :     if (eventType == TransferSession::OutputEventType::kAckEOFReceived ||
     190            0 :         eventType == TransferSession::OutputEventType::kInternalError ||
     191            0 :         eventType == TransferSession::OutputEventType::kTransferTimeout ||
     192              :         eventType == TransferSession::OutputEventType::kStatusReceived)
     193              :     {
     194            0 :         ChipLogProgress(BDX, "NotifyEventHandled : Event %s Error %" CHIP_ERROR_FORMAT,
     195              :                         TransferSession::OutputEvent::TypeToString(eventType), status.Format());
     196            0 :         mDestroySelfAfterProcessingEvents = true;
     197              :     }
     198            0 :     else if (status != CHIP_NO_ERROR)
     199              :     {
     200              :         // If there was an error handling the output event, this should notify the transfer object to abort transfer
     201              :         // so it can send a status report across the exchange when we call ProcessOutputEvents below.
     202            0 :         mTransfer.AbortTransfer(GetBdxStatusCodeFromChipError(status));
     203              :     }
     204              : 
     205            0 :     ProcessOutputEvents();
     206            0 : }
     207              : 
     208              : } // namespace bdx
     209              : } // namespace chip
        

Generated by: LCOV version 2.0-1