Bug 795410 - patch 3: Get file content and send, r=qdot

From 01ff8209cc5242bdf6c89432899ab4658e71e58a Mon Sep 17 00:00:00 2001
This commit is contained in:
Eric Chou 2012-09-28 20:03:36 +08:00
parent c10fa5f9db
commit 53ea233ce5
2 changed files with 245 additions and 6 deletions

View File

@ -13,16 +13,84 @@
#include "ObexBase.h"
#include "mozilla/RefPtr.h"
#include "nsIDOMFile.h"
#include "nsIInputStream.h"
USING_BLUETOOTH_NAMESPACE
using namespace mozilla::ipc;
static mozilla::RefPtr<BluetoothOppManager> sInstance;
static nsCOMPtr<nsIInputStream> stream = nullptr;
static uint64_t sSentFileSize = 0;
class ReadFileTask : public nsRunnable
{
public:
ReadFileTask(nsIDOMBlob* aBlob) : mBlob(aBlob)
{
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMETHOD Run()
{
if (NS_IsMainThread()) {
NS_WARNING("Can't read file from main thread");
return NS_ERROR_FAILURE;
}
uint64_t fileSize;
nsresult rv = mBlob->GetSize(&fileSize);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
return NS_ERROR_FAILURE;;
}
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;
}
}
/*
* 255 is the Minimum OBEX Packet Length (See section 3.3.1.4,
* IrOBEX ver 1.2)
*/
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);
if (NS_FAILED(rv)) {
// Needs error handling here
return NS_ERROR_FAILURE;
}
if (numRead > 0) {
if (sSentFileSize + numRead >= fileSize) {
sInstance->SendPutRequest((uint8_t*)buf, numRead, true);
} else {
sInstance->SendPutRequest((uint8_t*)buf, numRead, false);
}
sSentFileSize += numRead;
}
return NS_OK;
};
private:
nsCOMPtr<nsIDOMBlob> mBlob;
};
BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mConnectionId(1)
, mLastCommand(0)
, mBlob(nullptr)
, mRemoteObexVersion(0)
, mRemoteConnectionFlags(0)
, mRemoteMaxPacketLength(0)
{
}
@ -82,7 +150,21 @@ bool
BluetoothOppManager::SendFile(BlobParent* aActor,
BluetoothReplyRunnable* aRunnable)
{
// will implement in another patch.
if (mBlob) {
// Means there's a sending process. Reply error.
return false;
}
/*
* Process of sending a file:
* - Keep blob because OPP connection has not been established yet.
* - Create an OPP connection by SendConnectRequest()
* - After receiving the response, start to read file and send.
*/
mBlob = aActor->GetBlob();
SendConnectRequest();
return true;
}
@ -98,21 +180,83 @@ void
BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
{
uint8_t responseCode = aMessage->mData[0];
int packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
int receivedLength = aMessage->mSize;
if (mLastCommand == ObexRequestCode::Connect) {
if (responseCode == ObexResponseCode::Success) {
mConnected = true;
// Keep remote information
mRemoteObexVersion = aMessage->mData[3];
mRemoteConnectionFlags = aMessage->mData[4];
mRemoteMaxPacketLength =
(((int)(aMessage->mData[5]) << 8) | aMessage->mData[6]);
if (mBlob) {
/*
* Before sending content, we have to send a header including
* information such as file name, file length and content type.
*/
nsresult rv;
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
nsString fileName;
if (file) {
rv = file->GetName(fileName);
}
if (!file || fileName.IsEmpty()) {
fileName.AssignLiteral("Unknown");
}
uint64_t fileSize;
rv = mBlob->GetSize(&fileSize);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
return;
}
sSentFileSize = 0;
sInstance->SendPutHeaderRequest(fileName, fileSize);
}
}
} else if (mLastCommand == ObexRequestCode::Disconnect) {
if (responseCode == ObexResponseCode::Success) {
if (responseCode != ObexResponseCode::Success) {
// FIXME: Needs error handling here
NS_WARNING("[OPP] Disconnect failed");
} else {
mConnected = false;
mBlob = nullptr;
}
} else if (mLastCommand == ObexRequestCode::Put) {
if (responseCode != ObexResponseCode::Continue) {
// FIXME: Needs error handling here
NS_WARNING("[OPP] Put failed");
} else {
nsCOMPtr<nsIThread> t;
NS_NewThread(getter_AddRefs(t));
nsRefPtr<ReadFileTask> task = new ReadFileTask(mBlob);
if (NS_FAILED(t->Dispatch(task, NS_DISPATCH_NORMAL))) {
NS_WARNING("Cannot dispatch ring task!");
}
}
} else if (mLastCommand == ObexRequestCode::PutFinal) {
if (responseCode != ObexResponseCode::Success) {
// FIXME: Needs error handling here
NS_WARNING("[OPP] PutFinal failed");
} else {
SendDisconnectRequest();
}
}
}
void
BluetoothOppManager::SendConnectReqeust()
BluetoothOppManager::SendConnectRequest()
{
if (mConnected) return;
// Section 3.3.1 "Connect", IrOBEX 1.2
// [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2][Headers:var]
uint8_t req[255];
@ -123,7 +267,7 @@ BluetoothOppManager::SendConnectReqeust()
req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
req[6] = BluetoothOppManager::MAX_PACKET_LENGTH;
index += AppendHeaderConnectionId(&req[index], mConnectionId++);
index += AppendHeaderConnectionId(&req[index], mConnectionId);
SetObexPacketInfo(req, ObexRequestCode::Connect, index);
mLastCommand = ObexRequestCode::Connect;
@ -132,3 +276,86 @@ BluetoothOppManager::SendConnectReqeust()
SendSocketData(s);
}
void
BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName, int aFileSize)
{
uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
const PRUnichar* fileNamePtr = aFileName.BeginReading();
uint32_t len = aFileName.Length();
uint8_t* fileName = new uint8_t[(len + 1) * 2];
for (int i = 0; i < len; i++) {
fileName[i * 2] = (uint8_t)(fileNamePtr[i] >> 8);
fileName[i * 2 + 1] = (uint8_t)fileNamePtr[i];
}
fileName[len * 2] = 0x00;
fileName[len * 2 + 1] = 0x00;
int index = 3;
index += AppendHeaderConnectionId(&req[index], mConnectionId);
index += AppendHeaderName(&req[index], (char*)fileName, (len + 1) * 2);
index += AppendHeaderLength(&req[index], aFileSize);
SetObexPacketInfo(req, ObexRequestCode::Put, index);
mLastCommand = ObexRequestCode::Put;
UnixSocketRawData* s = new UnixSocketRawData(index);
memcpy(s->mData, req, s->mSize);
SendSocketData(s);
delete [] fileName;
delete [] req;
}
void
BluetoothOppManager::SendPutRequest(uint8_t* aFileBody,
int aFileBodyLength,
bool aFinal)
{
int sentFileBodyLength = 0;
int index = 3;
int packetLeftSpace = mRemoteMaxPacketLength - index - 3;
if (!mConnected) return;
if (aFileBodyLength > packetLeftSpace) {
NS_WARNING("Not allowed such a small MaxPacketLength value");
return;
}
// IrOBEX 1.2 3.3.3
// [opcode:1][length:2][Headers:var]
uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
index += AppendHeaderBody(&req[index], aFileBody, aFileBodyLength);
if (aFinal) {
SetObexPacketInfo(req, ObexRequestCode::PutFinal, index);
mLastCommand = ObexRequestCode::PutFinal;
} else {
SetObexPacketInfo(req, ObexRequestCode::Put, index);
mLastCommand = ObexRequestCode::Put;
}
UnixSocketRawData* s = new UnixSocketRawData(index);
memcpy(s->mData, req, s->mSize);
SendSocketData(s);
delete [] req;
}
void
BluetoothOppManager::SendDisconnectRequest()
{
// IrOBEX 1.2 3.3.2
// [opcode:1][length:2][Headers:var]
uint8_t req[255];
int index = 3;
SetObexPacketInfo(req, ObexRequestCode::Disconnect, index);
mLastCommand = ObexRequestCode::Disconnect;
UnixSocketRawData* s = new UnixSocketRawData(index);
memcpy(s->mData, req, s->mSize);
SendSocketData(s);
}

View File

@ -10,6 +10,7 @@
#include "BluetoothCommon.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/ipc/UnixSocket.h"
#include "nsIDOMFile.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -50,13 +51,24 @@ public:
bool StopSendingFile(BluetoothReplyRunnable* aRunnable);
// xxx For runnable use
void SendConnectRequest();
void SendPutHeaderRequest(const nsAString& aFileName, int aFileSize);
void SendPutRequest(uint8_t* aFileBody, int aFileBodyLength,
bool aFinal);
void SendDisconnectRequest();
private:
BluetoothOppManager();
void SendConnectReqeust();
bool mConnected;
int mConnectionId;
int mLastCommand;
uint8_t mRemoteObexVersion;
uint8_t mRemoteConnectionFlags;
int mRemoteMaxPacketLength;
nsCOMPtr<nsIDOMBlob> mBlob;
};
END_BLUETOOTH_NAMESPACE