Bug 799138 - [b2g-bluetooth] Handle Connect/Disconnect/Put requests sent from remote devices, r=qdot
authorEric Chou <echou@mozilla.com>
Tue, 09 Oct 2012 13:56:17 +0800
changeset 109724 dd61540f237caed9b66e05419ecc200ef6f1f51d
parent 109723 66f9632e35390f9037ebdba9e6c386ad1ca468c9
child 109725 22d192c5d1fd86f86bfe680bf78dc938df79bd31
child 109728 b992224cdd55d70e0bec80c68da428eeb7d3688e
push id23648
push useremorley@mozilla.com
push dateTue, 09 Oct 2012 14:23:49 +0000
treeherdermozilla-central@dd61540f237c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs799138
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 799138 - [b2g-bluetooth] Handle Connect/Disconnect/Put requests sent from remote devices, r=qdot
dom/bluetooth/BluetoothOppManager.cpp
dom/bluetooth/BluetoothOppManager.h
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ b/dom/bluetooth/BluetoothOppManager.cpp
@@ -90,16 +90,17 @@ BluetoothOppManager::BluetoothOppManager
                                            , mConnectionId(1)
                                            , mLastCommand(0)
                                            , mBlob(nullptr)
                                            , mRemoteObexVersion(0)
                                            , mRemoteConnectionFlags(0)
                                            , mRemoteMaxPacketLength(0)
                                            , mAbortFlag(false)
                                            , mReadFileThread(nullptr)
+                                           , mPacketLeftLength(0)
 {
 }
 
 BluetoothOppManager::~BluetoothOppManager()
 {
 }
 
 //static
@@ -183,22 +184,30 @@ BluetoothOppManager::StopSendingFile(Blu
 
   return true;
 }
 
 // Virtual function of class SocketConsumer
 void
 BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
 {
-  uint8_t responseCode = aMessage->mData[0];
-  int packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
+  uint8_t opCode;
+  int packetLength;
   int receivedLength = aMessage->mSize;
 
+  if (mPacketLeftLength > 0) {
+    opCode = ObexRequestCode::Put;
+    packetLength = mPacketLeftLength;
+  } else {
+    opCode = aMessage->mData[0];
+    packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
+  }
+
   if (mLastCommand == ObexRequestCode::Connect) {
-    if (responseCode == ObexResponseCode::Success) {
+    if (opCode == ObexResponseCode::Success) {
       mConnected = true;
 
       // Keep remote information
       mRemoteObexVersion = aMessage->mData[3];
       mRemoteConnectionFlags = aMessage->mData[4];
       mRemoteMaxPacketLength =
         (((int)(aMessage->mData[5]) << 8) | aMessage->mData[6]);
 
@@ -231,26 +240,27 @@ BluetoothOppManager::ReceiveSocketData(U
 
         sUpdateProgressCounter = 1;
         sSentFileLength = 0;
         mAbortFlag = false;
         sInstance->SendPutHeaderRequest(sFileName, sFileLength);
       }
     }
   } else if (mLastCommand == ObexRequestCode::Disconnect) {
-    if (responseCode != ObexResponseCode::Success) {
+    if (opCode != ObexResponseCode::Success) {
       // FIXME: Needs error handling here
       NS_WARNING("[OPP] Disconnect failed");
     } else {
       mConnected = false;
+      mLastCommand = 0;
       mBlob = nullptr;
       mReadFileThread = nullptr;
     }
   } else if (mLastCommand == ObexRequestCode::Put) {
-    if (responseCode != ObexResponseCode::Continue) {
+    if (opCode != ObexResponseCode::Continue) {
       // FIXME: Needs error handling here
       NS_WARNING("[OPP] Put failed");
     } else {
       if (mAbortFlag || mReadFileThread == nullptr) {
         SendAbortRequest();
       } else {
         // Sending system message "bluetooth-opp-update-progress" every 50kb,
         if (kUpdateProgressBase * sUpdateProgressCounter < sSentFileLength) {
@@ -261,40 +271,75 @@ BluetoothOppManager::ReceiveSocketData(U
         nsRefPtr<ReadFileTask> task = new ReadFileTask(mBlob);
 
         if (NS_FAILED(mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL))) {
           NS_WARNING("Cannot dispatch ring task!");
         }
       }
     }
   } else if (mLastCommand == ObexRequestCode::PutFinal) {
-    if (responseCode != ObexResponseCode::Success) {
+    if (opCode != ObexResponseCode::Success) {
       // FIXME: Needs error handling here
       NS_WARNING("[OPP] PutFinal failed");
     } else {
       FileTransferComplete(true, false, sFileName, sSentFileLength);
       SendDisconnectRequest();
     }
   } else if (mLastCommand == ObexRequestCode::Abort) {
-    if (responseCode != ObexResponseCode::Success) {
+    if (opCode != ObexResponseCode::Success) {
       NS_WARNING("[OPP] Abort failed");
     }
 
     FileTransferComplete(false, false, sFileName, sSentFileLength);
     SendDisconnectRequest();
+  } else {
+    // Remote request or unknown mLastCommand
+    if (opCode == ObexRequestCode::Connect) {
+      ReplyToConnect();
+    } else if (opCode == ObexRequestCode::Disconnect) {
+      ReplyToDisconnect();
+    } else if (opCode == ObexRequestCode::Put ||
+               opCode == ObexRequestCode::PutFinal) {
+      /*
+       * A PUT request from remote devices may be divided into multiple parts.
+       * In other words, one request may need to be received multiple times,
+       * so here we keep a variable mPacketLeftLength to indicate if current
+       * PUT request is done.
+       */
+      bool final = (opCode == ObexRequestCode::PutFinal);
+
+      if (mPacketLeftLength == 0) {
+        if (receivedLength < packetLength) {
+          mPacketLeftLength = packetLength - receivedLength;
+        } else {
+          ReplyToPut(final);
+        }
+      } else {
+        NS_ASSERTION(mPacketLeftLength < receivedLength,
+                     "Invalid packet length");
+
+        if (mPacketLeftLength <= receivedLength) {
+          ReplyToPut(final);
+          mPacketLeftLength = 0;
+        } else {
+          mPacketLeftLength -= receivedLength;
+        }
+      }
+    }
   }
 }
 
 void
 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]
+  // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
+  // [Headers:var]
   uint8_t req[255];
   int index = 7;
 
   req[3] = 0x10; // version=1.0
   req[4] = 0x00; // flag=0x00
   req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
   req[6] = BluetoothOppManager::MAX_PACKET_LENGTH;
 
@@ -303,17 +348,18 @@ BluetoothOppManager::SendConnectRequest(
   mLastCommand = ObexRequestCode::Connect;
 
   UnixSocketRawData* s = new UnixSocketRawData(index);
   memcpy(s->mData, req, s->mSize);
   SendSocketData(s);
 }
 
 void
-BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName, int aFileSize)
+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);
@@ -349,17 +395,17 @@ BluetoothOppManager::SendPutRequest(uint
   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
+  // Section 3.3.3 "Put", IrOBEX 1.2
   // [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;
@@ -373,17 +419,17 @@ BluetoothOppManager::SendPutRequest(uint
   SendSocketData(s);
 
   delete [] req;
 }
 
 void
 BluetoothOppManager::SendDisconnectRequest()
 {
-  // IrOBEX 1.2 3.3.2
+  // Section 3.3.2 "Disconnect", IrOBEX 1.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);
@@ -403,16 +449,79 @@ BluetoothOppManager::SendAbortRequest()
   mLastCommand = ObexRequestCode::Abort;
 
   UnixSocketRawData* s = new UnixSocketRawData(index);
   memcpy(s->mData, req, s->mSize);
   SendSocketData(s);
 }
 
 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]
+  // [Headers:var]
+  uint8_t req[255];
+  int index = 7;
+
+  req[3] = 0x10; // version=1.0
+  req[4] = 0x00; // flag=0x00
+  req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
+  req[6] = BluetoothOppManager::MAX_PACKET_LENGTH;
+
+  SetObexPacketInfo(req, ObexResponseCode::Success, index);
+
+  UnixSocketRawData* s = new UnixSocketRawData(index);
+  memcpy(s->mData, req, s->mSize);
+  SendSocketData(s);
+}
+
+void
+BluetoothOppManager::ReplyToDisconnect()
+{
+  if (!mConnected) return;
+  mConnected = false;
+
+  // Section 3.3.2 "Disconnect", IrOBEX 1.2
+  // [opcode:1][length:2][Headers:var]
+  uint8_t req[255];
+  int index = 3;
+
+  SetObexPacketInfo(req, ObexResponseCode::Success, index);
+
+  UnixSocketRawData* s = new UnixSocketRawData(index);
+  memcpy(s->mData, req, s->mSize);
+  SendSocketData(s);
+}
+
+void
+BluetoothOppManager::ReplyToPut(bool aFinal)
+{
+  if (!mConnected) return;
+
+  // Section 3.3.2 "Disconnect", IrOBEX 1.2
+  // [opcode:1][length:2][Headers:var]
+  uint8_t req[255];
+  int index = 3;
+
+  if (aFinal) {
+    SetObexPacketInfo(req, ObexResponseCode::Success, index);
+  } else {
+    SetObexPacketInfo(req, ObexResponseCode::Continue, index);
+  }
+
+  UnixSocketRawData* s = new UnixSocketRawData(index);
+  memcpy(s->mData, req, s->mSize);
+  SendSocketData(s);
+}
+
+void
 BluetoothOppManager::FileTransferComplete(bool aSuccess,
                                           bool aReceived,
                                           const nsString& aFileName,
                                           uint32_t aFileLength)
 {
   nsString type, name;
   BluetoothValue v;
   InfallibleTArray<BluetoothNamedValue> parameters;
--- a/dom/bluetooth/BluetoothOppManager.h
+++ b/dom/bluetooth/BluetoothOppManager.h
@@ -57,24 +57,28 @@ public:
   void SendDisconnectRequest();
   void SendAbortRequest();
 
 private:
   BluetoothOppManager();
   void FileTransferComplete(bool aSuccess, bool aReceived,
                             const nsString& aFileName, uint32_t aFileLength);
   void UpdateProgress(uint32_t aProcessed, uint32_t aFileLength);
+  void ReplyToConnect();
+  void ReplyToDisconnect();
+  void ReplyToPut(bool aFinal);
 
   bool mConnected;
   int mConnectionId;
   int mLastCommand;
   uint8_t mRemoteObexVersion;
   uint8_t mRemoteConnectionFlags;
   int mRemoteMaxPacketLength;
   bool mAbortFlag;
+  int mPacketLeftLength;
 
   nsCOMPtr<nsIDOMBlob> mBlob;
   nsCOMPtr<nsIThread> mReadFileThread;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif