Handle the output event of type TransferSession::OutputEventType::kIn… (#37324)

* Handle the output event of type TransferSession::OutputEventType::kInternalError in the ProcessOuputEvents processing loop

- The transfer session state machine generates an output event of type TransferSession::OutputEventType::kInternalError in
certain error scenarios which put the transfer session in a bad state and when that happens, we need to unwind the processing
loop for events and clean up.

* Update src/protocols/bdx/AsyncTransferFacilitator.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Address review comments

* Update src/protocols/bdx/AsyncTransferFacilitator.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

---------

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
diff --git a/src/protocols/bdx/AsyncTransferFacilitator.cpp b/src/protocols/bdx/AsyncTransferFacilitator.cpp
index 2e3a0f0..eb3d996 100644
--- a/src/protocols/bdx/AsyncTransferFacilitator.cpp
+++ b/src/protocols/bdx/AsyncTransferFacilitator.cpp
@@ -63,6 +63,17 @@
     mTransfer.GetNextAction(outEvent);
     while (outEvent.EventType != TransferSession::OutputEventType::kNone)
     {
+
+        // If the transfer session state machine generates an event of type TransferSession::OutputEventType::kInternalError,
+        // indicating that the session is in a bad state, it will keep doing that thereafter.
+        //
+        // So stop trying to process events, and go ahead and destroy ourselves to clean up the transfer.
+        if (outEvent.EventType == TransferSession::OutputEventType::kInternalError)
+        {
+            mDestroySelfAfterProcessingEvents = true;
+            break;
+        }
+
         if (outEvent.EventType == TransferSession::OutputEventType::kMsgToSend)
         {
             CHIP_ERROR err = SendMessage(outEvent.msgTypeData, outEvent.MsgData);
@@ -170,10 +181,14 @@
     ChipLogDetail(BDX, "NotifyEventHandled : Event %s Error %" CHIP_ERROR_FORMAT,
                   TransferSession::OutputEvent::TypeToString(eventType), status.Format());
 
-    // If this is the end of the transfer (whether a clean end, or some sort of error condition), ensure that
-    // we destroy ourselves after processing any output events that might have been generated by
-    // the transfer session to handle end-of-transfer (e.g. in some error conditions it might want to send
-    // out a status report).
+    // If this is the end of the transfer (whether a clean end, or some sort of error condition), ensure
+    // that we destroy ourselves after unwinding the processing loop in the ProcessOutputEvents API.
+    // We can ignore the status for these output events because none of them are supposed to result in
+    // us sending a StatusReport, and that's all we use the status for.
+    //
+    // In particular, for kTransferTimeout, kAckEOFReceived, and kStatusReceived per spec we
+    // are not supposed to reply with a StatusReport.  And for kInternalError the state machine
+    // is in an unrecoverable state of some sort, and we should stop trying to make use of it.
     if (eventType == TransferSession::OutputEventType::kAckEOFReceived ||
         eventType == TransferSession::OutputEventType::kInternalError ||
         eventType == TransferSession::OutputEventType::kTransferTimeout ||
@@ -181,11 +196,10 @@
     {
         mDestroySelfAfterProcessingEvents = true;
     }
-
-    // If there was an error handling the output event, this should notify the transfer object to abort transfer so it can send a
-    // status report across the exchange when we call ProcessOutputEvents below.
-    if (status != CHIP_NO_ERROR)
+    else if (status != CHIP_NO_ERROR)
     {
+        // If there was an error handling the output event, this should notify the transfer object to abort transfer
+        // so it can send a status report across the exchange when we call ProcessOutputEvents below.
         mTransfer.AbortTransfer(GetBdxStatusCodeFromChipError(status));
     }
 
diff --git a/src/protocols/bdx/AsyncTransferFacilitator.h b/src/protocols/bdx/AsyncTransferFacilitator.h
index 1ad95d3..b9d4b79 100644
--- a/src/protocols/bdx/AsyncTransferFacilitator.h
+++ b/src/protocols/bdx/AsyncTransferFacilitator.h
@@ -72,7 +72,9 @@
      */
     virtual void DestroySelf() = 0;
 
-    // Calling ProcessOutputEvents can destroy this object before the call returns.
+    /**
+     * Calling ProcessOutputEvents can destroy this object before the call returns.
+     */
     void ProcessOutputEvents();
 
     // The transfer session corresponding to this AsyncTransferFacilitator object.