diff --git a/src/controller/python/chip/bdx/bdx-transfer-manager.cpp b/src/controller/python/chip/bdx/bdx-transfer-manager.cpp index d631b841db8de9..b2bde229d592ca 100644 --- a/src/controller/python/chip/bdx/bdx-transfer-manager.cpp +++ b/src/controller/python/chip/bdx/bdx-transfer-manager.cpp @@ -44,14 +44,17 @@ BdxTransfer * BdxTransferManager::Allocate() BdxTransfer * result = mTransferPool.CreateObject(); VerifyOrReturn(result != nullptr); + // TODO: This needs to intercept the delegate calls so it can free the transfer after it completes. result->SetDelegate(mBdxTransferDelegate); --mExpectedTransfers; return result; } +// This method is only called by BdxTransferServer when creating an exchange context fails. void BdxTransferManager::Release(BdxTransfer * bdxTransfer) { + mBdxTransferDelegate->TransferCompleted(bdxTransfer, CHIP_ERROR_CONNECTION_ABORTED); mTransferPool.ReleaseObject(bdxTransfer); } diff --git a/src/controller/python/chip/bdx/bdx-transfer.cpp b/src/controller/python/chip/bdx/bdx-transfer.cpp index d1076b5bac0d94..9c622df59962fc 100644 --- a/src/controller/python/chip/bdx/bdx-transfer.cpp +++ b/src/controller/python/chip/bdx/bdx-transfer.cpp @@ -88,7 +88,7 @@ void BdxTransfer::HandleTransferSessionOutput(TransferSession::OutputEvent & eve case TransferSession::OutputEventType::kStatusReceived: ChipLogError(BDX, "Received StatusReport %x", static_cast(event.statusData.statusCode)); // TODO: Not a great error type. The issue isn't internal, it's external. We can check the status code, but I don't know - // if that would produce a better error type. + // if that would produce a better error type. Maybe CHIP_ERROR_IM_STATUS_CODE_RECEIVED? EndSession(CHIP_ERROR_INTERNAL); break; case TransferSession::OutputEventType::kInternalError: diff --git a/src/controller/python/chip/bdx/bdx.cpp b/src/controller/python/chip/bdx/bdx.cpp index 6bb19a996583b3..ed25f7b1c3a507 100644 --- a/src/controller/python/chip/bdx/bdx.cpp +++ b/src/controller/python/chip/bdx/bdx.cpp @@ -15,6 +15,8 @@ * limitations under the License. */ +#include + #include #include @@ -40,64 +42,115 @@ OnTransferCompletedCallback gOnTransferCompletedCallback = nullptr; struct TransferData { + bdx::BdxTransfer * Transfer = nullptr; PyObject OnTransferObtainedContext = nullptr; PyObject OnDataReceivedContext = nullptr; PyObject OnTransferCompletedContext = nullptr; }; -} // namespace python +class TransferMap +{ +public: + // This returns the transfer data associated with the given transfer. + TransferData * TransferDataForTransfer(bdx::BdxTransfer * transfer) + { + std::vector::iterator result = std::find(mTransfers.begin(), mTransfers.end(), + [transfer](const TransferData& data) { + return data.Transfer == transfer; + }); + VerifyOrReturnValue(result != mTransfers.end(), nullptr); + return &*result; + } + + // This returns the next transfer data that has no associated BdxTransfer. + TransferData * NextUnassociatedTransferData() + { + std::vector::iterator result = std::find(mTransfers.begin(), mTransfers.end(), + [](const TransferData& data) { + return data.Transfer == nullptr; + }); + VerifyOrReturnValue(result != mTransfers.end(), nullptr); + return &*result; + } + + TransferData * CreateUnassociatedTransferData() + { + return &mTransfers.emplace_back(); + } -namespace bdx { + void RemoveTransferData(TransferData * transferData) + { + std::vector::iterator result = std::find(mTransfers.begin(), mTransfers.end(), + [transferData](const TransferData& data) { + return &data == transferData; + }); + VerifyOrReturn(result != mTransfers.end()); + mTransfers.erase(result); + } + +private: + std::vector mTransfers; +}; -class BdxTransferDelegate : public BdxTransfer::Delegate +class TransferDelegate : public bdx::BdxTransfer::Delegate { public: - ~BdxTransferDelegate() override = default; + TransferDelegate(TransferMap * transfers) : mTransfers(transfers) {} + ~TransferDelegate() override = default; - virtual void InitMessageReceived(BdxTransfer * transfer, TransferSession::TransferInitData init_data) + virtual void InitMessageReceived(bdx::BdxTransfer * transfer, bdx::TransferSession::TransferInitData init_data) { - if (gOnTransferObtainedCallback) + TransferData * transferData = mTransfers->CreateUnassociatedTransferData(); + if (gOnTransferObtainedCallback && transferData) { - // TODO: Get the transfer data from transfer. - python::TransferData * transferData = nullptr; - PyChipError result; - gOnTransferObtainedCallback(transferData->OnTransferObtainedContext, result, transfer, init_data.TransferCtlFlags, - init_data.MaxBlockSize, init_data.StartOffset, init_data.Length, init_data.FileDesignator, - init_data.FileDesLength, init_data.Metadata, init_data.MetadataLength); + transferData->Transfer = transfer; + gOnTransferObtainedCallback(transferData->OnTransferObtainedContext, ToPyChipError(CHIP_NO_ERROR), transfer, + init_data.TransferCtlFlags, init_data.MaxBlockSize, init_data.StartOffset, + init_data.Length, init_data.FileDesignator, init_data.FileDesLength, init_data.Metadata, + init_data.MetadataLength); } } - virtual void DataReceived(BdxTransfer * transfer, const ByteSpan & block) + virtual void DataReceived(bdx::BdxTransfer * transfer, const ByteSpan & block) { - if (gOnDataReceivedCallback) + TransferData * transferData = mTransfers->TransferDataForTransfer(transfer); + if (gOnDataReceivedCallback && transferData) { - // TODO: Get the transfer data from transfer. - python::TransferData * transferData = nullptr; gOnDataReceivedCallback(transferData->OnDataReceivedContext, block.data(), block.size()); } } - virtual void TransferCompleted(BdxTransfer * transfer, CHIP_ERROR result) + virtual void TransferCompleted(bdx::BdxTransfer * transfer, CHIP_ERROR result) { - if (gOnTransferCompletedCallback) + TransferData * transferData = mTransfers->TransferDataForTransfer(transfer); + if (!transferData && result != CHIP_NO_ERROR) + { + // The transfer failed during initialisation. + transferData = mTransfers->NextUnassociatedTransferData(); + if (gOnTransferObtainedCallback && transferData) + { + gOnTransferObtainedCallback(transferData->OnTransferObtainedContext, ToPyChipError(result), nullptr, + static_cast(0), 0, 0, 0, nullptr, 0, nullptr, 0); + } + } + else if (gOnTransferCompletedCallback && transferData) { - // TODO: Get the transfer data from transfer. - python::TransferData * transferData = nullptr; gOnTransferCompletedCallback(transferData->OnTransferCompletedContext, ToPyChipError(result)); + mTransfers->RemoveTransferData(transferData); } } -}; - -} // namespace bdx -} // namespace chip -namespace { +private: + TransferMap * mTransfers = nullptr; +}; -chip::bdx::BdxTransferDelegate gBdxTransferDelegate; -chip::bdx::BdxTransferManager gBdxTransferManager(&gBdxTransferDelegate); -chip::bdx::BdxTransferServer gBdxTransferServer(gBdxTransferManager); +TransferMap gTransfers; +TransferDelegate gBdxTransferDelegate(&gTransfers); +bdx::BdxTransferManager gBdxTransferManager(&gBdxTransferDelegate); +bdx::BdxTransferServer gBdxTransferServer(gBdxTransferManager); -} // namespace +} // namespace python +} // namespace chip using namespace chip::python; @@ -125,8 +178,7 @@ PyChipError pychip_Bdx_StopExpectingBdxTransfer() PyChipError pychip_Bdx_AcceptSendTransfer(chip::bdx::BdxTransfer * transfer, PyObject dataReceivedContext, PyObject transferCompletedContext) { - // TODO: Get the transfer data from transfer. - TransferData * transferData = nullptr; + TransferData * transferData = gTransfers.TransferDataForTransfer(transfer); transferData->OnDataReceivedContext = dataReceivedContext; transferData->OnTransferCompletedContext = transferCompletedContext; transfer->AcceptSend(); @@ -135,8 +187,7 @@ PyChipError pychip_Bdx_AcceptSendTransfer(chip::bdx::BdxTransfer * transfer, PyO PyChipError pychip_Bdx_AcceptReceiveTransfer(chip::bdx::BdxTransfer * transfer, const uint8_t * dataBuffer, size_t dataLength, PyObject transferCompletedContext) { - // TODO: Get the transfer data from transfer. - TransferData * transferData = nullptr; + TransferData * transferData = gTransfers.TransferDataForTransfer(transfer); transferData->OnTransferCompletedContext = transferCompletedContext; chip::ByteSpan data(dataBuffer, dataLength); transfer->AcceptReceive(data);