diff --git a/dom/bluetooth/BluetoothOppManager.cpp b/dom/bluetooth/BluetoothOppManager.cpp index aec315cdadfc..6139a20dabf7 100644 --- a/dom/bluetooth/BluetoothOppManager.cpp +++ b/dom/bluetooth/BluetoothOppManager.cpp @@ -230,6 +230,7 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false) , mSendTransferCompleteFlag(false) , mSuccessFlag(false) , mWaitingForConfirmationFlag(false) + , mCurrentBlobIndex(-1) { mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); Listen(); @@ -275,10 +276,7 @@ BluetoothOppManager::Connect(const nsAString& aDeviceObjectPath, } BluetoothService* bs = BluetoothService::Get(); - if (!bs) { - NS_WARNING("BluetoothService not available!"); - return false; - } + NS_ENSURE_TRUE(bs, false); nsString uuid; BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid); @@ -354,69 +352,50 @@ BluetoothOppManager::Listen() return true; } -bool -BluetoothOppManager::SendFile(BlobParent* aActor) +void +BluetoothOppManager::StartSendingNextFile() { - if (mBlob) { - // Means there's a sending process. Reply error. - return false; - } + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!IsTransferring()); + MOZ_ASSERT(mBlobs.Length() > mCurrentBlobIndex + 1); - /* - * Process of sending a file: - * - Keep blob because OPP connection has not been established yet. - * - Try to retrieve file name from the blob or assign one if failed to get. - * - Create an OPP connection by SendConnectRequest() - * - After receiving the response, start to read file and send. - */ - mBlob = aActor->GetBlob(); + mBlob = mBlobs[++mCurrentBlobIndex]; - sFileName.Truncate(); - - nsCOMPtr file = do_QueryInterface(mBlob); - if (file) { - file->GetName(sFileName); - } - - /** - * We try our best to get the file extention to avoid interoperability issues. - * However, once we found that we are unable to get suitable extension or - * information about the content type, sending a pre-defined file name without - * extension would be fine. - */ - if (sFileName.IsEmpty()) { - sFileName.AssignLiteral("Unknown"); - } - - int32_t offset = sFileName.RFindChar('/'); - if (offset != kNotFound) { - sFileName = Substring(sFileName, offset + 1); - } - - offset = sFileName.RFindChar('.'); - if (offset == kNotFound) { - nsCOMPtr mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID); - - if (mimeSvc) { - nsString mimeType; - mBlob->GetType(mimeType); - - nsCString extension; - nsresult rv = - mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType), - EmptyCString(), - extension); - if (NS_SUCCEEDED(rv)) { - sFileName.AppendLiteral("."); - AppendUTF8toUTF16(extension, sFileName); - } - } - } - - SendConnectRequest(); - mTransferMode = false; + // Before sending content, we have to send a header including + // information such as file name, file length and content type. + ExtractBlobHeaders(); StartFileTransfer(); + if (mCurrentBlobIndex == 0) { + // We may have more than one file waiting for transferring, but only one + // CONNECT request would be sent. Therefore check if this is the very first + // file at the head of queue. + SendConnectRequest(); + } else { + SendPutHeaderRequest(sFileName, sFileLength); + AfterFirstPut(); + } + + mTransferMode = false; +} + +bool +BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, + BlobParent* aActor) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (mCurrentBlobIndex >= 0) { + if (mConnectedDeviceAddress != aDeviceAddress) { + return false; + } + + mBlobs.AppendElement(aActor->GetBlob().get()); + return true; + } + + mBlobs.AppendElement(aActor->GetBlob().get()); + StartSendingNextFile(); return true; } @@ -431,17 +410,13 @@ BluetoothOppManager::StopSendingFile() bool BluetoothOppManager::ConfirmReceivingFile(bool aConfirm) { - if (!mConnected) return false; + NS_ENSURE_TRUE(mConnected, false); + NS_ENSURE_TRUE(mWaitingForConfirmationFlag, false); + + MOZ_ASSERT(mPacketLeftLength == 0); - if (!mWaitingForConfirmationFlag) { - NS_WARNING("We are not waiting for a confirmation now."); - return false; - } mWaitingForConfirmationFlag = false; - NS_ASSERTION(mPacketLeftLength == 0, - "Should not be in the middle of receiving a PUT packet."); - // For the first packet of first file bool success = false; if (aConfirm) { @@ -490,9 +465,10 @@ BluetoothOppManager::AfterOppDisconnected() mConnected = false; mLastCommand = 0; - mBlob = nullptr; mPacketLeftLength = 0; + ClearQueue(); + // We can't reset mSuccessFlag here since this function may be called // before we send system message of transfer complete // mSuccessFlag = false; @@ -537,11 +513,11 @@ BluetoothOppManager::DeleteReceivedFile() bool BluetoothOppManager::CreateFile() { + MOZ_ASSERT(mPacketLeftLength == 0); + nsString path; path.AssignLiteral(TARGET_FOLDER); - MOZ_ASSERT(mPacketLeftLength == 0); - nsCOMPtr f; nsresult rv; rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f)); @@ -600,17 +576,11 @@ BluetoothOppManager::CreateFile() bool BluetoothOppManager::WriteToFile(const uint8_t* aData, int aDataLength) { - if (!mOutputStream) { - NS_WARNING("No available output stream"); - return false; - } + NS_ENSURE_TRUE(mOutputStream, false); uint32_t wrote = 0; mOutputStream->Write((const char*)aData, aDataLength, &wrote); - if (aDataLength != wrote) { - NS_WARNING("Writing to the file failed"); - return false; - } + NS_ENSURE_TRUE(aDataLength == wrote, false); return true; } @@ -644,6 +614,8 @@ BluetoothOppManager::ExtractPacketHeaders(const ObexHeaderSet& aHeader) bool BluetoothOppManager::ExtractBlobHeaders() { + RetrieveSentFileName(); + nsresult rv = mBlob->GetType(sContentType); if (NS_FAILED(rv)) { NS_WARNING("Can't get content type"); @@ -681,6 +653,52 @@ BluetoothOppManager::ExtractBlobHeaders() return true; } +void +BluetoothOppManager::RetrieveSentFileName() +{ + sFileName.Truncate(); + + nsCOMPtr file = do_QueryInterface(mBlob); + if (file) { + file->GetName(sFileName); + } + + /** + * We try our best to get the file extention to avoid interoperability issues. + * However, once we found that we are unable to get suitable extension or + * information about the content type, sending a pre-defined file name without + * extension would be fine. + */ + if (sFileName.IsEmpty()) { + sFileName.AssignLiteral("Unknown"); + } + + int32_t offset = sFileName.RFindChar('/'); + if (offset != kNotFound) { + sFileName = Substring(sFileName, offset + 1); + } + + offset = sFileName.RFindChar('.'); + if (offset == kNotFound) { + nsCOMPtr mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID); + + if (mimeSvc) { + nsString mimeType; + mBlob->GetType(mimeType); + + nsCString extension; + nsresult rv = + mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType), + EmptyCString(), + extension); + if (NS_SUCCEEDED(rv)) { + sFileName.AppendLiteral("."); + AppendUTF8toUTF16(extension, sFileName); + } + } + } +} + bool BluetoothOppManager::IsReservedChar(PRUnichar c) { @@ -845,6 +863,17 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage) } } +void +BluetoothOppManager::ClearQueue() +{ + mCurrentBlobIndex = -1; + mBlob = nullptr; + + while (!mBlobs.IsEmpty()) { + mBlobs.RemoveElement(mBlobs[0]); + } +} + void BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage) { @@ -884,7 +913,17 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage) if (mLastCommand == ObexRequestCode::PutFinal) { mSuccessFlag = true; FileTransferComplete(); - SendDisconnectRequest(); + + if (mInputStream) { + mInputStream->Close(); + mInputStream = nullptr; + } + + if (mCurrentBlobIndex + 1 == mBlobs.Length()) { + SendDisconnectRequest(); + } else { + StartSendingNextFile(); + } } else if (mLastCommand == ObexRequestCode::Abort) { SendDisconnectRequest(); FileTransferComplete(); @@ -909,16 +948,8 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage) mRemoteMaxPacketLength = (((int)(aMessage->mData[5]) << 8) | aMessage->mData[6]); - /* - * Before sending content, we have to send a header including - * information such as file name, file length and content type. - */ - if (ExtractBlobHeaders()) { - sInstance->SendPutHeaderRequest(sFileName, sFileLength); - } + sInstance->SendPutHeaderRequest(sFileName, sFileLength); } else if (mLastCommand == ObexRequestCode::Put) { - - // Send PutFinal packet when we get response if (sWaitingToSendPutFinal) { SendPutFinalRequest(); return; @@ -997,6 +1028,8 @@ void BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName, int aFileSize) { + if (!mConnected) return; + uint8_t* req = new uint8_t[mRemoteMaxPacketLength]; int len = aFileName.Length(); @@ -1086,6 +1119,8 @@ BluetoothOppManager::SendPutFinalRequest() void BluetoothOppManager::SendDisconnectRequest() { + if (!mConnected) return; + // Section 3.3.2 "Disconnect", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] uint8_t req[255]; @@ -1102,6 +1137,8 @@ BluetoothOppManager::SendDisconnectRequest() void BluetoothOppManager::SendAbortRequest() { + if (!mConnected) return; + // Section 3.3.5 "Abort", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] uint8_t req[255]; @@ -1125,7 +1162,6 @@ void BluetoothOppManager::ReplyToConnect() { if (mConnected) return; - mConnected = true; // Section 3.3.1 "Connect", IrOBEX 1.2 // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2] @@ -1149,7 +1185,6 @@ void BluetoothOppManager::ReplyToDisconnect() { if (!mConnected) return; - mConnected = false; // Section 3.3.2 "Disconnect", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] diff --git a/dom/bluetooth/BluetoothOppManager.h b/dom/bluetooth/BluetoothOppManager.h index fb06c680d4fd..762f09a9a3a3 100644 --- a/dom/bluetooth/BluetoothOppManager.h +++ b/dom/bluetooth/BluetoothOppManager.h @@ -9,9 +9,10 @@ #include "BluetoothCommon.h" #include "BluetoothSocketObserver.h" +#include "DeviceStorage.h" #include "mozilla/dom/ipc/Blob.h" #include "mozilla/ipc/UnixSocket.h" -#include "DeviceStorage.h" +#include "nsCOMArray.h" class nsIOutputStream; class nsIInputStream; @@ -54,7 +55,7 @@ public: void Disconnect(); bool Listen(); - bool SendFile(BlobParent* aBlob); + bool SendFile(const nsAString& aDeviceAddress, BlobParent* aBlob); bool StopSendingFile(); bool ConfirmReceivingFile(bool aConfirm); @@ -88,6 +89,7 @@ public: private: BluetoothOppManager(); void StartFileTransfer(); + void StartSendingNextFile(); void FileTransferComplete(); void UpdateProgress(); void ReceivingFileConfirmation(); @@ -102,6 +104,8 @@ private: void AfterOppDisconnected(); void ValidateFileName(); bool IsReservedChar(PRUnichar c); + void ClearQueue(); + void RetrieveSentFileName(); /** * OBEX session status. @@ -170,7 +174,9 @@ private: nsAutoArrayPtr mBodySegment; nsAutoArrayPtr mReceivedDataBuffer; + int mCurrentBlobIndex; nsCOMPtr mBlob; + nsCOMArray mBlobs; /** * A seperate member thread is required because our read calls can block diff --git a/dom/bluetooth/linux/BluetoothDBusService.cpp b/dom/bluetooth/linux/BluetoothDBusService.cpp index 3ab16deacca1..80f0b6c313d6 100644 --- a/dom/bluetooth/linux/BluetoothDBusService.cpp +++ b/dom/bluetooth/linux/BluetoothDBusService.cpp @@ -2719,7 +2719,7 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress, BluetoothValue v = true; nsAutoString errorStr; - if (!opp->SendFile(aBlobParent)) { + if (!opp->SendFile(aDeviceAddress, aBlobParent)) { errorStr.AssignLiteral("Calling SendFile() failed"); }