mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 803614 - [b2g-bluetooth] Save received file, r=qdot, r=dougt
This commit is contained in:
parent
fe8d9773dd
commit
b3ac908c1d
@ -19,7 +19,13 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#define TARGET_FOLDER "/sdcard/download/bluetooth/"
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
using namespace mozilla;
|
||||
@ -68,12 +74,20 @@ namespace {
|
||||
static const uint32_t kUpdateProgressBase = 50 * 1024;
|
||||
StaticRefPtr<BluetoothOppManager> sInstance;
|
||||
StaticRefPtr<BluetoothOppManagerObserver> sOppObserver;
|
||||
static nsCOMPtr<nsIInputStream> stream = nullptr;
|
||||
|
||||
/*
|
||||
* FIXME / Bug 806749
|
||||
*
|
||||
* Currently Bluetooth*Manager inherits mozilla::ipc::UnixSocketConsumer,
|
||||
* which means that each Bluetooth*Manager can handle only one socket
|
||||
* connection at a time. We need to support concurrent multiple socket
|
||||
* connections, and then we will be able to have multiple file transferring
|
||||
* sessions at a time.
|
||||
*/
|
||||
static uint32_t sSentFileLength = 0;
|
||||
static nsString sFileName;
|
||||
static uint32_t sFileLength = 0;
|
||||
static nsString sContentType;
|
||||
static int sUpdateProgressCounter = 0;
|
||||
static bool sInShutdown = false;
|
||||
}
|
||||
|
||||
@ -95,27 +109,14 @@ BluetoothOppManagerObserver::Observe(nsISupports* aSubject,
|
||||
class ReadFileTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReadFileTask(nsIDOMBlob* aBlob) : mBlob(aBlob)
|
||||
ReadFileTask(nsIInputStream* aInputStream) : mInputStream(aInputStream)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
NS_WARNING("Can't read file from main thread");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (stream == nullptr) {
|
||||
rv = mBlob->GetInternalStream(getter_AddRefs(stream));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't get internal stream of blob");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
/*
|
||||
* 255 is the Minimum OBEX Packet Length (See section 3.3.1.4,
|
||||
@ -123,10 +124,9 @@ public:
|
||||
*/
|
||||
char buf[255];
|
||||
uint32_t numRead;
|
||||
int offset = 0;
|
||||
|
||||
// function inputstream->Read() only works on non-main thread
|
||||
rv = stream->Read(buf, sizeof(buf), &numRead);
|
||||
nsresult rv = mInputStream->Read(buf, sizeof(buf), &numRead);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Needs error handling here
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -146,18 +146,16 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
BluetoothOppManager::BluetoothOppManager() : mConnected(false)
|
||||
, mConnectionId(1)
|
||||
, mLastCommand(0)
|
||||
, mBlob(nullptr)
|
||||
, mRemoteObexVersion(0)
|
||||
, mRemoteConnectionFlags(0)
|
||||
, mRemoteMaxPacketLength(0)
|
||||
, mAbortFlag(false)
|
||||
, mReadFileThread(nullptr)
|
||||
, mPacketLeftLength(0)
|
||||
, mReceiving(false)
|
||||
, mPutFinal(false)
|
||||
@ -302,6 +300,11 @@ BluetoothOppManager::ConfirmReceivingFile(bool aConfirm,
|
||||
mWaitingForConfirmationFlag = false;
|
||||
ReplyToPut(mPutFinal, aConfirm);
|
||||
|
||||
if (aConfirm) {
|
||||
StartFileTransfer(mConnectedDeviceAddress, true,
|
||||
sFileName, sFileLength, sContentType);
|
||||
}
|
||||
|
||||
if (mPutFinal || !aConfirm) {
|
||||
mReceiving = false;
|
||||
FileTransferComplete(mConnectedDeviceAddress, aConfirm, true, sFileName,
|
||||
@ -309,6 +312,43 @@ BluetoothOppManager::ConfirmReceivingFile(bool aConfirm,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::AfterOppConnected()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConnected = true;
|
||||
mUpdateProgressCounter = 1;
|
||||
sSentFileLength = 0;
|
||||
mAbortFlag = false;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::AfterOppDisconnected()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConnected = false;
|
||||
mReceiving = false;
|
||||
mLastCommand = 0;
|
||||
mBlob = nullptr;
|
||||
|
||||
if (mInputStream) {
|
||||
mInputStream->Close();
|
||||
mInputStream = nullptr;
|
||||
}
|
||||
|
||||
if (mOutputStream) {
|
||||
mOutputStream->Close();
|
||||
mOutputStream = nullptr;
|
||||
}
|
||||
|
||||
if (mReadFileThread) {
|
||||
mReadFileThread->Shutdown();
|
||||
mReadFileThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual function of class SocketConsumer
|
||||
void
|
||||
BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
@ -327,7 +367,7 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
|
||||
if (mLastCommand == ObexRequestCode::Connect) {
|
||||
if (opCode == ObexResponseCode::Success) {
|
||||
mConnected = true;
|
||||
AfterOppConnected();
|
||||
|
||||
// Keep remote information
|
||||
mRemoteObexVersion = aMessage->mData[3];
|
||||
@ -382,9 +422,6 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
return;
|
||||
}
|
||||
|
||||
sUpdateProgressCounter = 1;
|
||||
sSentFileLength = 0;
|
||||
mAbortFlag = false;
|
||||
sInstance->SendPutHeaderRequest(sFileName, sFileLength);
|
||||
StartFileTransfer(mConnectedDeviceAddress, false,
|
||||
sFileName, sFileLength, sContentType);
|
||||
@ -394,43 +431,49 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
if (opCode != ObexResponseCode::Success) {
|
||||
// FIXME: Needs error handling here
|
||||
NS_WARNING("[OPP] Disconnect failed");
|
||||
} else {
|
||||
mConnected = false;
|
||||
mReceiving = false;
|
||||
mLastCommand = 0;
|
||||
mBlob = nullptr;
|
||||
mReadFileThread = nullptr;
|
||||
}
|
||||
|
||||
AfterOppDisconnected();
|
||||
} else if (mLastCommand == ObexRequestCode::Put) {
|
||||
if (opCode != ObexResponseCode::Continue) {
|
||||
// FIXME: Needs error handling here
|
||||
NS_WARNING("[OPP] Put failed");
|
||||
} else {
|
||||
if (mAbortFlag || mReadFileThread == nullptr) {
|
||||
SendAbortRequest();
|
||||
} else {
|
||||
if (kUpdateProgressBase * sUpdateProgressCounter < sSentFileLength) {
|
||||
UpdateProgress(mConnectedDeviceAddress, false,
|
||||
sSentFileLength, sFileLength);
|
||||
++sUpdateProgressCounter;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ReadFileTask> task = new ReadFileTask(mBlob);
|
||||
if (mAbortFlag || mReadFileThread) {
|
||||
SendAbortRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL))) {
|
||||
NS_WARNING("Cannot dispatch ring task!");
|
||||
}
|
||||
if (kUpdateProgressBase * mUpdateProgressCounter < sSentFileLength) {
|
||||
UpdateProgress(mConnectedDeviceAddress, false,
|
||||
sSentFileLength, sFileLength);
|
||||
mUpdateProgressCounter = sSentFileLength / kUpdateProgressBase + 1;
|
||||
}
|
||||
|
||||
if (mInputStream) {
|
||||
nsresult rv = mBlob->GetInternalStream(getter_AddRefs(mInputStream));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't get internal stream of blob");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<ReadFileTask> task = new ReadFileTask(mInputStream);
|
||||
if (NS_FAILED(mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL))) {
|
||||
NS_WARNING("Cannot dispatch ring task!");
|
||||
}
|
||||
} else if (mLastCommand == ObexRequestCode::PutFinal) {
|
||||
if (opCode != ObexResponseCode::Success) {
|
||||
// FIXME: Needs error handling here
|
||||
NS_WARNING("[OPP] PutFinal failed");
|
||||
} else {
|
||||
FileTransferComplete(mConnectedDeviceAddress, true, false, sFileName,
|
||||
sSentFileLength, sContentType);
|
||||
SendDisconnectRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
FileTransferComplete(mConnectedDeviceAddress, true, false, sFileName,
|
||||
sSentFileLength, sContentType);
|
||||
SendDisconnectRequest();
|
||||
} else if (mLastCommand == ObexRequestCode::Abort) {
|
||||
if (opCode != ObexResponseCode::Success) {
|
||||
NS_WARNING("[OPP] Abort failed");
|
||||
@ -444,21 +487,59 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
ObexHeaderSet pktHeaders(opCode);
|
||||
|
||||
if (opCode == ObexRequestCode::Connect) {
|
||||
ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders);
|
||||
// Section 3.3.1 "Connect", IrOBEX 1.2
|
||||
// [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
|
||||
// [Headers:var]
|
||||
ParseHeadersAndFindBody(&aMessage->mData[7],
|
||||
receivedLength - 7,
|
||||
&pktHeaders);
|
||||
ReplyToConnect();
|
||||
AfterOppConnected();
|
||||
} else if (opCode == ObexRequestCode::Disconnect) {
|
||||
ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
|
||||
// Section 3.3.2 "Disconnect", IrOBEX 1.2
|
||||
// [opcode:1][length:2][Headers:var]
|
||||
ParseHeadersAndFindBody(&aMessage->mData[3],
|
||||
receivedLength - 3,
|
||||
&pktHeaders);
|
||||
ReplyToDisconnect();
|
||||
AfterOppDisconnected();
|
||||
} else if (opCode == ObexRequestCode::Put ||
|
||||
opCode == ObexRequestCode::PutFinal) {
|
||||
// Section 3.3.3 "Put", IrOBEX 1.2
|
||||
// [opcode:1][length:2][Headers:var]
|
||||
int headerStartIndex = 3;
|
||||
|
||||
if (!mReceiving) {
|
||||
nsString path;
|
||||
path.AssignLiteral(TARGET_FOLDER);
|
||||
|
||||
MOZ_ASSERT(mPacketLeftLength == 0);
|
||||
ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
|
||||
ParseHeadersAndFindBody(&aMessage->mData[headerStartIndex],
|
||||
receivedLength - headerStartIndex,
|
||||
&pktHeaders);
|
||||
|
||||
pktHeaders.GetName(sFileName);
|
||||
pktHeaders.GetContentType(sContentType);
|
||||
pktHeaders.GetLength(&sFileLength);
|
||||
|
||||
path += sFileName;
|
||||
|
||||
nsCOMPtr<nsIFile> f;
|
||||
nsresult rv = NS_NewLocalFile(path, false, getter_AddRefs(f));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Couldn't new a local file");
|
||||
}
|
||||
|
||||
rv = f->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00644);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Couldn't create the file");
|
||||
}
|
||||
|
||||
NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
|
||||
if (!mOutputStream) {
|
||||
NS_WARNING("Couldn't new an output stream");
|
||||
}
|
||||
|
||||
mReceiving = true;
|
||||
mWaitingForConfirmationFlag = true;
|
||||
}
|
||||
@ -471,14 +552,47 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
||||
*/
|
||||
mPutFinal = (opCode == ObexRequestCode::PutFinal);
|
||||
|
||||
uint32_t wrote = 0;
|
||||
if (mPacketLeftLength == 0) {
|
||||
NS_ASSERTION(mPacketLeftLength >= receivedLength,
|
||||
NS_ASSERTION(packetLength >= receivedLength,
|
||||
"Invalid packet length");
|
||||
mPacketLeftLength = packetLength - receivedLength;
|
||||
|
||||
int headerBodyOffset =
|
||||
ParseHeadersAndFindBody(&aMessage->mData[headerStartIndex],
|
||||
receivedLength - headerStartIndex,
|
||||
&pktHeaders);
|
||||
|
||||
if (headerBodyOffset != -1) {
|
||||
/*
|
||||
* Adding by 3 is because the format of a header is like:
|
||||
* [HeaderId:1 (BODY)][HeaderLength:2][Data:n]
|
||||
* and headerStartIndex + headerBodyOffset points to HeaderId,
|
||||
* so adding 3 is to point to the beginning of data.
|
||||
*
|
||||
*/
|
||||
int fileBodyIndex = headerStartIndex + headerBodyOffset + 3;
|
||||
|
||||
mOutputStream->Write((char*)&aMessage->mData[fileBodyIndex],
|
||||
receivedLength - fileBodyIndex, &wrote);
|
||||
NS_ASSERTION(receivedLength - fileBodyIndex == wrote,
|
||||
"Writing to the file failed");
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(mPacketLeftLength >= receivedLength,
|
||||
"Invalid packet length");
|
||||
mPacketLeftLength -= receivedLength;
|
||||
|
||||
mOutputStream->Write((char*)&aMessage->mData[0], receivedLength, &wrote);
|
||||
NS_ASSERTION(receivedLength == wrote, "Writing to the file failed");
|
||||
}
|
||||
|
||||
sSentFileLength += wrote;
|
||||
if (sSentFileLength > kUpdateProgressBase * mUpdateProgressCounter &&
|
||||
!mWaitingForConfirmationFlag) {
|
||||
UpdateProgress(mConnectedDeviceAddress, true,
|
||||
sSentFileLength, sFileLength);
|
||||
mUpdateProgressCounter = sSentFileLength / kUpdateProgressBase + 1;
|
||||
}
|
||||
|
||||
if (mPacketLeftLength == 0) {
|
||||
@ -562,7 +676,6 @@ BluetoothOppManager::SendPutRequest(uint8_t* aFileBody,
|
||||
int aFileBodyLength,
|
||||
bool aFinal)
|
||||
{
|
||||
int sentFileBodyLength = 0;
|
||||
int index = 3;
|
||||
int packetLeftSpace = mRemoteMaxPacketLength - index - 3;
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "mozilla/ipc/UnixSocket.h"
|
||||
#include "nsIDOMFile.h"
|
||||
|
||||
class nsIOutputStream;
|
||||
class nsIInputStream;
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothReplyRunnable;
|
||||
@ -85,6 +88,8 @@ private:
|
||||
void ReplyToConnect();
|
||||
void ReplyToDisconnect();
|
||||
void ReplyToPut(bool aFinal, bool aContinue);
|
||||
void AfterOppConnected();
|
||||
void AfterOppDisconnected();
|
||||
virtual void OnConnectSuccess() MOZ_OVERRIDE;
|
||||
virtual void OnConnectError() MOZ_OVERRIDE;
|
||||
virtual void OnDisconnect() MOZ_OVERRIDE;
|
||||
@ -101,9 +106,12 @@ private:
|
||||
bool mReceiving;
|
||||
bool mPutFinal;
|
||||
bool mWaitingForConfirmationFlag;
|
||||
int mUpdateProgressCounter;
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
nsCOMPtr<nsIThread> mReadFileThread;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -68,13 +68,23 @@ SetObexPacketInfo(uint8_t* retBuf, uint8_t opcode, int packetLength)
|
||||
retBuf[2] = packetLength & 0x00FF;
|
||||
}
|
||||
|
||||
void
|
||||
ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
|
||||
int
|
||||
ParseHeadersAndFindBody(uint8_t* aHeaderStart,
|
||||
int aTotalLength,
|
||||
ObexHeaderSet* aRetHandlerSet)
|
||||
{
|
||||
uint8_t* ptr = buf;
|
||||
uint8_t* ptr = aHeaderStart;
|
||||
|
||||
while (ptr - aHeaderStart < aTotalLength) {
|
||||
ObexHeaderId headerId = (ObexHeaderId)*ptr;
|
||||
|
||||
if (headerId == ObexHeaderId::Body ||
|
||||
headerId == ObexHeaderId::EndOfBody) {
|
||||
return ptr - aHeaderStart;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
|
||||
while (ptr - buf < totalLength) {
|
||||
ObexHeaderId headerId = (ObexHeaderId)*ptr++;
|
||||
int contentLength = 0;
|
||||
uint8_t highByte, lowByte;
|
||||
|
||||
@ -82,7 +92,8 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
|
||||
switch (headerId >> 6)
|
||||
{
|
||||
case 0x00:
|
||||
// NULL terminated Unicode text, length prefixed with 2 byte unsigned integer.
|
||||
// NULL terminated Unicode text, length prefixed with 2-byte
|
||||
// unsigned integer.
|
||||
case 0x01:
|
||||
// byte sequence, length prefixed with 2 byte unsigned integer.
|
||||
highByte = *ptr++;
|
||||
@ -101,18 +112,14 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: This case should be happened when we are receiving header 'Body'
|
||||
// (file body). I will handle this in another bug.
|
||||
if (contentLength + (ptr - buf) > totalLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t* content = new uint8_t[contentLength];
|
||||
memcpy(content, ptr, contentLength);
|
||||
retHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
|
||||
aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
|
||||
|
||||
ptr += contentLength;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -142,6 +142,8 @@ public:
|
||||
|
||||
void GetName(nsString& aRetName)
|
||||
{
|
||||
aRetName.Truncate();
|
||||
|
||||
int length = mHeaders.Length();
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
@ -161,6 +163,8 @@ public:
|
||||
|
||||
void GetContentType(nsString& aRetContentType)
|
||||
{
|
||||
aRetContentType.Truncate();
|
||||
|
||||
int length = mHeaders.Length();
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
@ -196,7 +200,9 @@ int AppendHeaderBody(uint8_t* retBuf, uint8_t* data, int length);
|
||||
int AppendHeaderLength(uint8_t* retBuf, int objectLength);
|
||||
int AppendHeaderConnectionId(uint8_t* retBuf, int connectionId);
|
||||
void SetObexPacketInfo(uint8_t* retBuf, uint8_t opcode, int packetLength);
|
||||
void ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHanderSet);
|
||||
int ParseHeadersAndFindBody(uint8_t* aHeaderStart,
|
||||
int aTotalLength,
|
||||
ObexHeaderSet* aRetHanderSet);
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user