Bug 799138 - [b2g-bluetooth] Handle Connect/Disconnect/Put requests sent from remote devices. r=qdot, a=blocking-basecamp
authorEric Chou <echou@mozilla.com>
Tue, 09 Oct 2012 13:56:17 +0800
changeset 113346 475c67cb2458cffd7314218e8841a6d9edf61c0b
parent 113345 0136c82b58cd7a6da2207ba5bb75273e422ffb85
child 113347 d00caf574dd57c5598851d03d62ae7e01bf417ae
push id2293
push userryanvm@gmail.com
push dateSat, 13 Oct 2012 19:46:06 +0000
treeherdermozilla-aurora@a24b525c7f93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot, blocking-basecamp
bugs799138
milestone18.0a2
Bug 799138 - [b2g-bluetooth] Handle Connect/Disconnect/Put requests sent from remote devices. r=qdot, a=blocking-basecamp
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