Bug 1091575: Implement Socket module for Bluetooth daemon (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Fri, 14 Nov 2014 10:04:34 +0100
changeset 215640 9b8fec58f964597e19f1b884a7b516a3d113c465
parent 215639 e4cfdcae2f80c160c941158e1cb4aac21ba300a3
child 215641 b133c8460ea0e2cb08958bdd61efad7c6635a70a
push id12159
push usertdz@users.sourceforge.net
push dateFri, 14 Nov 2014 09:05:57 +0000
treeherderb2g-inbound@b133c8460ea0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1091575
milestone36.0a1
Bug 1091575: Implement Socket module for Bluetooth daemon (under bluetooth2/), r=btian This patch adds support for the Bluetooth daemon's Socket module, which provides OPP functionality.
dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
dom/bluetooth2/bluedroid/BluetoothDaemonSocketInterface.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonSocketInterface.h
dom/bluetooth2/moz.build
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothDaemonHelpers.h"
+#include <limits>
 
 #define MAX_UUID_SIZE 16
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Conversion
 //
@@ -40,16 +41,28 @@ Convert(bool aIn, BluetoothScanMode& aOu
     aOut = SCAN_MODE_NONE; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sScanMode[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(int aIn, int16_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<int16_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<int16_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<int16_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, bool& aOut)
 {
   static const bool sBool[] = {
     CONVERT(0x00, false),
     CONVERT(0x01, true)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
     return NS_ERROR_ILLEGAL_VALUE;
@@ -132,16 +145,36 @@ Convert(uint8_t aIn, BluetoothPropertyTy
       NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sPropertyType))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sPropertyType[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(BluetoothSocketType aIn, uint8_t& aOut)
+{
+  static const uint8_t sSocketType[] = {
+    CONVERT(0, 0), // silences compiler warning
+    CONVERT(BluetoothSocketType::RFCOMM, 0x01),
+    CONVERT(BluetoothSocketType::SCO, 0x02),
+    CONVERT(BluetoothSocketType::L2CAP, 0x03)
+    // EL2CAP not supported
+  };
+  if (NS_WARN_IF(aIn == BluetoothSocketType::EL2CAP) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sSocketType)) ||
+      NS_WARN_IF(!sSocketType[aIn])) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sSocketType[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(int32_t aIn, BluetoothScanMode& aOut)
 {
   static const BluetoothScanMode sScanMode[] = {
     CONVERT(0x00, SCAN_MODE_NONE),
     CONVERT(0x01, SCAN_MODE_CONNECTABLE),
     CONVERT(0x02, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
   };
   if (NS_WARN_IF(aIn < 0) ||
@@ -263,16 +296,33 @@ Convert(const nsAString& aIn, BluetoothP
     BT_LOGR("Invalid property name: %s", NS_ConvertUTF16toUTF8(aIn).get());
     aOut = static_cast<BluetoothPropertyType>(0); // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   return NS_OK;
 }
 
 nsresult
+Convert(const nsAString& aIn, BluetoothServiceName& aOut)
+{
+  NS_ConvertUTF16toUTF8 serviceNameUTF8(aIn);
+  const char* str = serviceNameUTF8.get();
+  size_t len = strlen(str);
+
+  if (NS_WARN_IF(len > sizeof(aOut.mName))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  memcpy(aOut.mName, str, len);
+  memset(aOut.mName + len, 0, sizeof(aOut.mName) - len);
+
+  return NS_OK;
+}
+
+nsresult
 Convert(const nsAString& aIn, BluetoothSspVariant& aOut)
 {
   if (aIn.EqualsLiteral("PasskeyConfirmation")) {
     aOut = SSP_VARIANT_PASSKEY_CONFIRMATION;
   } else if (aIn.EqualsLiteral("PasskeyEntry")) {
     aOut = SSP_VARIANT_PASSKEY_ENTRY;
   } else if (aIn.EqualsLiteral("Consent")) {
     aOut = SSP_VARIANT_CONSENT;
@@ -514,16 +564,28 @@ PackPDU(BluetoothSspVariant aIn, Bluetoo
 }
 
 nsresult
 PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackConversion<BluetoothScanMode, int32_t>(aIn), aPDU);
 }
 
+nsresult
+PackPDU(const BluetoothServiceName& aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackArray<uint8_t>(aIn.mName, sizeof(aIn.mName)), aPDU);
+}
+
+nsresult
+PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothSocketType, uint8_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
@@ -58,16 +58,20 @@ struct BluetoothPinCode {
   uint8_t mPinCode[16];
   uint8_t mLength;
 };
 
 struct BluetoothRemoteName {
   uint8_t mName[249];
 };
 
+struct BluetoothServiceName {
+  uint8_t mName[256];
+};
+
 //
 // Conversion
 //
 // PDUs can only store primitive data types, such as integers or
 // strings. Gecko often uses more complex data types, such as
 // enumerators or structures. Conversion functions convert between
 // primitive data and internal Gecko's data types during a PDU's
 // packing and unpacking.
@@ -75,16 +79,19 @@ struct BluetoothRemoteName {
 
 nsresult
 Convert(bool aIn, uint8_t& aOut);
 
 nsresult
 Convert(bool aIn, BluetoothScanMode& aOut);
 
 nsresult
+Convert(int aIn, int16_t& aOut);
+
+nsresult
 Convert(uint8_t aIn, bool& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothBondState& aOut);
 
@@ -114,16 +121,19 @@ Convert(const nsAString& aIn, BluetoothA
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPinCode& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPropertyType& aOut);
 
 nsresult
+Convert(const nsAString& aIn, BluetoothServiceName& aOut);
+
+nsresult
 Convert(const nsAString& aIn, BluetoothSspVariant& aOut);
 
 nsresult
 Convert(BluetoothAclState aIn, bool& aOut);
 
 nsresult
 Convert(const BluetoothAddress& aIn, nsAString& aOut);
 
@@ -132,16 +142,19 @@ Convert(BluetoothPropertyType aIn, uint8
 
 nsresult
 Convert(const BluetoothRemoteName& aIn, nsAString& aOut);
 
 nsresult
 Convert(BluetoothScanMode aIn, uint8_t& aOut);
 
 nsresult
+Convert(BluetoothSocketType aIn, uint8_t& aOut);
+
+nsresult
 Convert(BluetoothSspVariant aIn, uint8_t& aOut);
 
 //
 // Packing
 //
 
 nsresult
 PackPDU(bool aIn, BluetoothDaemonPDU& aPDU);
@@ -184,16 +197,22 @@ PackPDU(const BluetoothNamedValue& aIn, 
 
 nsresult
 PackPDU(const BluetoothPinCode& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothPropertyType aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
+PackPDU(const BluetoothServiceName& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
 PackPDU(BluetoothSspVariant aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU);
 
 /* |PackConversion| is a helper for packing converted values. Pass
  * an instance of this structure to |PackPDU| to convert a value from
  * the input type to the output type and and write it to the PDU.
@@ -302,16 +321,42 @@ PackPDU(const T1& aIn1, const T2& aIn2, 
   }
   rv = PackPDU(aIn3, aPDU);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return PackPDU(aIn4, aPDU);
 }
 
+template <typename T1, typename T2, typename T3,
+          typename T4, typename T5>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+        const T4& aIn4, const T5& aIn5,
+        BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv = PackPDU(aIn1, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn2, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn3, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn4, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return PackPDU(aIn5, aPDU);
+}
+
 //
 // Unpacking
 //
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, int8_t& aOut)
 {
   return aPDU.Read(aOut);
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothDaemonInterface.h"
 #include "BluetoothDaemonHelpers.h"
 #include "BluetoothDaemonSetupInterface.h"
+#include "BluetoothDaemonSocketInterface.h"
 #include "BluetoothInterfaceHelpers.h"
 #include "mozilla/unused.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
@@ -1449,16 +1450,17 @@ private:
 //
 // Protocol handling
 //
 
 class BluetoothDaemonProtocol MOZ_FINAL
   : public BluetoothDaemonPDUConsumer
   , public BluetoothDaemonSetupModule
   , public BluetoothDaemonCoreModule
+  , public BluetoothDaemonSocketModule
 {
 public:
   BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
 
   // Outgoing PDUs
   //
 
   nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) MOZ_OVERRIDE;
@@ -1472,16 +1474,18 @@ public:
 
   void* FetchUserData(const BluetoothDaemonPDUHeader& aHeader);
 
 private:
   void HandleSetupSvc(const BluetoothDaemonPDUHeader& aHeader,
                       BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleCoreSvc(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU, void* aUserData);
+  void HandleSocketSvc(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU, void* aUserData);
 
   BluetoothDaemonConnection* mConnection;
   nsTArray<void*> mUserDataQ;
 };
 
 BluetoothDaemonProtocol::BluetoothDaemonProtocol(
   BluetoothDaemonConnection* aConnection)
   : mConnection(aConnection)
@@ -1511,24 +1515,34 @@ void
 BluetoothDaemonProtocol::HandleCoreSvc(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   BluetoothDaemonCoreModule::HandleSvc(aHeader, aPDU, aUserData);
 }
 
 void
+BluetoothDaemonProtocol::HandleSocketSvc(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  BluetoothDaemonSocketModule::HandleSvc(aHeader, aPDU, aUserData);
+}
+
+void
 BluetoothDaemonProtocol::Handle(BluetoothDaemonPDU& aPDU)
 {
   static void (BluetoothDaemonProtocol::* const HandleSvc[])(
     const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
     INIT_ARRAY_AT(BluetoothDaemonSetupModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleSetupSvc),
     INIT_ARRAY_AT(BluetoothDaemonCoreModule::SERVICE_ID,
-      &BluetoothDaemonProtocol::HandleCoreSvc)
+      &BluetoothDaemonProtocol::HandleCoreSvc),
+    INIT_ARRAY_AT(BluetoothDaemonSocketModule::SERVICE_ID,
+      &BluetoothDaemonProtocol::HandleSocketSvc)
   };
 
   BluetoothDaemonPDUHeader header;
 
   if (NS_FAILED(UnpackPDU(aPDU, header)) ||
       NS_WARN_IF(!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc))) ||
       NS_WARN_IF(!(HandleSvc[header.mService]))) {
     return;
@@ -1714,17 +1728,18 @@ public:
   void RegisterModule() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mInterface->mProtocol);
 
     if (!mRegisteredSocketModule) {
       mRegisteredSocketModule = true;
       // Init, step 4: Register Socket module
-      mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00, this);
+      mInterface->mProtocol->RegisterModuleCmd(
+        BluetoothDaemonSocketModule::SERVICE_ID, 0x00, this);
     } else if (mRes) {
       // Init, step 5: Signal success to caller
       mRes->Init();
     }
   }
 
 private:
   BluetoothDaemonInterface* mInterface;
@@ -1882,17 +1897,18 @@ private:
 void
 BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
 {
   sNotificationHandler = nullptr;
 
   mResultHandlerQ.AppendElement(aRes);
 
   // Cleanup, step 1: Unregister Socket module
-  mProtocol->UnregisterModuleCmd(0x02, new CleanupResultHandler(this));
+  mProtocol->UnregisterModuleCmd(
+    BluetoothDaemonSocketModule::SERVICE_ID, new CleanupResultHandler(this));
 }
 
 void
 BluetoothDaemonInterface::Enable(BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>(mProtocol)->EnableCmd(aRes);
 }
 
@@ -2071,20 +2087,29 @@ BluetoothDaemonInterface::DispatchError(
                                         BluetoothStatus aStatus)
 {
   BluetoothResultRunnable1<
     BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>::Dispatch(
     aRes, &BluetoothResultHandler::OnError,
     ConstantInitOp1<BluetoothStatus>(aStatus));
 }
 
+// Profile Interfaces
+//
+
 BluetoothSocketInterface*
 BluetoothDaemonInterface::GetBluetoothSocketInterface()
 {
-  return nullptr;
+  if (mSocketInterface) {
+    return mSocketInterface;
+  }
+
+  mSocketInterface = new BluetoothDaemonSocketInterface(mProtocol);
+
+  return mSocketInterface;
 }
 
 BluetoothHandsfreeInterface*
 BluetoothDaemonInterface::GetBluetoothHandsfreeInterface()
 {
   return nullptr;
 }
 
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 
 #include "BluetoothInterface.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothDaemonChannel;
 class BluetoothDaemonProtocol;
+class BluetoothDaemonSocketInterface;
 
 class BluetoothDaemonInterface MOZ_FINAL : public BluetoothInterface
 {
 public:
   class CleanupResultHandler;
   class InitResultHandler;
 
   friend class BluetoothDaemonChannel;
@@ -118,13 +119,15 @@ protected:
 private:
   void DispatchError(BluetoothResultHandler* aRes, BluetoothStatus aStatus);
 
   nsAutoPtr<BluetoothDaemonChannel> mCmdChannel;
   nsAutoPtr<BluetoothDaemonChannel> mNtfChannel;
   nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
 
   nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
+
+  nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonSocketInterface.cpp
@@ -0,0 +1,352 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothDaemonSocketInterface.h"
+#include "BluetoothSocketMessageWatcher.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/unused.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+//
+// Socket module
+//
+
+// Commands
+//
+
+nsresult
+BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
+                                       const nsAString& aServiceName,
+                                       const uint8_t aServiceUuid[16],
+                                       int aChannel, bool aEncrypt,
+                                       bool aAuth,
+                                       BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(
+    SERVICE_ID, OPCODE_LISTEN, 0));
+
+  nsresult rv = PackPDU(
+    aType,
+    PackConversion<nsAString, BluetoothServiceName>(aServiceName),
+    PackArray<uint8_t>(aServiceUuid, 16),
+    PackConversion<int, uint16_t>(aChannel),
+    SocketFlags(aEncrypt, aAuth), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return rv;
+}
+
+nsresult
+BluetoothDaemonSocketModule::ConnectCmd(const nsAString& aBdAddr,
+                                        BluetoothSocketType aType,
+                                        const uint8_t aUuid[16],
+                                        int aChannel, bool aEncrypt,
+                                        bool aAuth,
+                                        BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(
+      SERVICE_ID, OPCODE_CONNECT, 0));
+
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(aBdAddr),
+    aType,
+    PackArray<uint8_t>(aUuid, 16),
+    PackConversion<int, int16_t>(aChannel),
+    SocketFlags(aEncrypt, aAuth), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return rv;
+}
+
+/* |DeleteTask| deletes a class instance on the I/O thread
+ */
+template <typename T>
+class DeleteTask MOZ_FINAL : public Task
+{
+public:
+  DeleteTask(T* aPtr)
+  : mPtr(aPtr)
+  { }
+
+  void Run() MOZ_OVERRIDE
+  {
+    mPtr = nullptr;
+  }
+
+private:
+  nsAutoPtr<T> mPtr;
+};
+
+/* |AcceptWatcher| specializes SocketMessageWatcher for Accept
+ * operations by reading the socket messages from Bluedroid and
+ * forwarding the received client socket to the resource handler.
+ * The first message is received immediately. When there's a new
+ * connection, Bluedroid sends the 2nd message with the socket
+ * info and socket file descriptor.
+ */
+class BluetoothDaemonSocketModule::AcceptWatcher MOZ_FINAL
+  : public SocketMessageWatcher
+{
+public:
+  AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes)
+  : SocketMessageWatcher(aFd, aRes)
+  { }
+
+  void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    if (aStatus == STATUS_SUCCESS) {
+      IntStringIntResultRunnable::Dispatch(
+        GetResultHandler(), &BluetoothSocketResultHandler::Accept,
+        ConstantInitOp3<int, nsString, int>(GetClientFd(), GetBdAddress(),
+                                            GetConnectionStatus()));
+    } else {
+      ErrorRunnable::Dispatch(GetResultHandler(),
+                              &BluetoothSocketResultHandler::OnError,
+                              ConstantInitOp1<BluetoothStatus>(aStatus));
+    }
+
+    MessageLoopForIO::current()->PostTask(
+      FROM_HERE, new DeleteTask<AcceptWatcher>(this));
+  }
+};
+
+nsresult
+BluetoothDaemonSocketModule::AcceptCmd(int aFd,
+                                       BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  /* receive Bluedroid's socket-setup messages and client fd */
+  Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes));
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
+
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonSocketModule::CloseCmd(BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  /* stop the watcher corresponding to |aRes| */
+  Task* t = new DeleteSocketMessageWatcherTask(aRes);
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
+
+  return NS_OK;
+}
+
+void
+BluetoothDaemonSocketModule::HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                                       BluetoothDaemonPDU& aPDU,
+                                       void* aUserData)
+{
+  static void (BluetoothDaemonSocketModule::* const HandleRsp[])(
+    const BluetoothDaemonPDUHeader&,
+    BluetoothDaemonPDU&,
+    BluetoothSocketResultHandler*) = {
+    INIT_ARRAY_AT(OPCODE_ERROR, &BluetoothDaemonSocketModule::ErrorRsp),
+    INIT_ARRAY_AT(OPCODE_LISTEN, &BluetoothDaemonSocketModule::ListenRsp),
+    INIT_ARRAY_AT(OPCODE_CONNECT, &BluetoothDaemonSocketModule::ConnectRsp),
+  };
+
+  if (NS_WARN_IF(MOZ_ARRAY_LENGTH(HandleRsp) <= aHeader.mOpcode) ||
+      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+    return;
+  }
+
+  nsRefPtr<BluetoothSocketResultHandler> res =
+    already_AddRefed<BluetoothSocketResultHandler>(
+      static_cast<BluetoothSocketResultHandler*>(aUserData));
+
+  if (!res) {
+    return; // Return early if no result handler has been set
+  }
+
+  (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+nsresult
+BluetoothDaemonSocketModule::Send(BluetoothDaemonPDU* aPDU,
+                                  BluetoothSocketResultHandler* aRes)
+{
+  aRes->AddRef(); // Keep reference for response
+  return Send(aPDU, static_cast<void*>(aRes));
+}
+
+uint8_t
+BluetoothDaemonSocketModule::SocketFlags(bool aEncrypt, bool aAuth)
+{
+  return (0x01 * aEncrypt) | (0x02 * aAuth);
+}
+
+// Responses
+//
+
+void
+BluetoothDaemonSocketModule::ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                      BluetoothDaemonPDU& aPDU,
+                                      BluetoothSocketResultHandler* aRes)
+{
+  ErrorRunnable::Dispatch(
+    aRes, &BluetoothSocketResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+class BluetoothDaemonSocketModule::ListenInitOp MOZ_FINAL : private PDUInitOp
+{
+public:
+  ListenInitOp(BluetoothDaemonPDU& aPDU)
+  : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (int& aArg1) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    aArg1 = pdu.AcquireFd();
+
+    if (NS_WARN_IF(aArg1 < 0)) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonSocketModule::ListenRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                       BluetoothDaemonPDU& aPDU,
+                                       BluetoothSocketResultHandler* aRes)
+{
+  IntResultRunnable::Dispatch(
+    aRes, &BluetoothSocketResultHandler::Listen, ListenInitOp(aPDU));
+}
+
+/* |ConnectWatcher| specializes SocketMessageWatcher for
+ * connect operations by reading the socket messages from
+ * Bluedroid and forwarding the connected socket to the
+ * resource handler.
+ */
+class BluetoothDaemonSocketModule::ConnectWatcher MOZ_FINAL
+  : public SocketMessageWatcher
+{
+public:
+  ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes)
+  : SocketMessageWatcher(aFd, aRes)
+  { }
+
+  void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    if (aStatus == STATUS_SUCCESS) {
+      IntStringIntResultRunnable::Dispatch(
+        GetResultHandler(), &BluetoothSocketResultHandler::Connect,
+        ConstantInitOp3<int, nsString, int>(GetFd(), GetBdAddress(),
+                                            GetConnectionStatus()));
+    } else {
+      ErrorRunnable::Dispatch(GetResultHandler(),
+                              &BluetoothSocketResultHandler::OnError,
+                              ConstantInitOp1<BluetoothStatus>(aStatus));
+    }
+
+    MessageLoopForIO::current()->PostTask(
+      FROM_HERE, new DeleteTask<ConnectWatcher>(this));
+  }
+};
+
+void
+BluetoothDaemonSocketModule::ConnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                        BluetoothDaemonPDU& aPDU,
+                                        BluetoothSocketResultHandler* aRes)
+{
+  /* the file descriptor is attached in the PDU's ancillary data */
+  int fd = aPDU.AcquireFd();
+  if (fd < 0) {
+    ErrorRunnable::Dispatch(aRes, &BluetoothSocketResultHandler::OnError,
+                            ConstantInitOp1<BluetoothStatus>(STATUS_FAIL));
+    return;
+  }
+
+  /* receive Bluedroid's socket-setup messages */
+  Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes));
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
+}
+
+//
+// Socket interface
+//
+
+BluetoothDaemonSocketInterface::BluetoothDaemonSocketInterface(
+  BluetoothDaemonSocketModule* aModule)
+: mModule(aModule)
+{
+  MOZ_ASSERT(mModule);
+}
+
+BluetoothDaemonSocketInterface::~BluetoothDaemonSocketInterface()
+{ }
+
+void
+BluetoothDaemonSocketInterface::Listen(BluetoothSocketType aType,
+                                       const nsAString& aServiceName,
+                                       const uint8_t aServiceUuid[16],
+                                       int aChannel, bool aEncrypt,
+                                       bool aAuth,
+                                       BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ListenCmd(aType, aServiceName, aServiceUuid, aChannel,
+                     aEncrypt, aAuth, aRes);
+}
+
+void
+BluetoothDaemonSocketInterface::Connect(const nsAString& aBdAddr,
+                                        BluetoothSocketType aType,
+                                        const uint8_t aUuid[16],
+                                        int aChannel, bool aEncrypt,
+                                        bool aAuth,
+                                        BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ConnectCmd(aBdAddr, aType, aUuid, aChannel, aEncrypt, aAuth, aRes);
+}
+
+void
+BluetoothDaemonSocketInterface::Accept(int aFd,
+                                    BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->AcceptCmd(aFd, aRes);
+}
+
+void
+BluetoothDaemonSocketInterface::Close(BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->CloseCmd(aRes);
+}
+
+END_BLUETOOTH_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonSocketInterface.h
@@ -0,0 +1,129 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemonsocketinterface_h__
+#define mozilla_dom_bluetooth_bluedroid_bluetoothdaemonsocketinterface_h__
+
+#include "BluetoothDaemonHelpers.h"
+#include "BluetoothInterface.h"
+#include "BluetoothInterfaceHelpers.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+using namespace mozilla::ipc;
+
+class BlutoothDaemonInterface;
+
+class BluetoothDaemonSocketModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x02
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_LISTEN = 0x01,
+    OPCODE_CONNECT = 0x02
+  };
+
+  virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
+
+  // Commands
+  //
+
+  nsresult ListenCmd(BluetoothSocketType aType,
+                     const nsAString& aServiceName,
+                     const uint8_t aServiceUuid[16],
+                     int aChannel, bool aEncrypt, bool aAuth,
+                     BluetoothSocketResultHandler* aRes);
+
+  nsresult ConnectCmd(const nsAString& aBdAddr,
+                      BluetoothSocketType aType,
+                      const uint8_t aUuid[16],
+                      int aChannel, bool aEncrypt, bool aAuth,
+                      BluetoothSocketResultHandler* aRes);
+
+  nsresult AcceptCmd(int aFd, BluetoothSocketResultHandler* aRes);
+
+  nsresult CloseCmd(BluetoothSocketResultHandler* aRes);
+
+protected:
+
+  void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData);
+
+  nsresult Send(BluetoothDaemonPDU* aPDU, BluetoothSocketResultHandler* aRes);
+
+private:
+  class AcceptWatcher;
+  class ConnectWatcher;
+  class ListenInitOp;
+
+  uint8_t SocketFlags(bool aEncrypt, bool aAuth);
+
+  // Responses
+  //
+
+  typedef BluetoothResultRunnable0<BluetoothSocketResultHandler, void>
+    ResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothSocketResultHandler, void,
+                                   int, int>
+    IntResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothSocketResultHandler, void,
+                                   BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  typedef BluetoothResultRunnable3<BluetoothSocketResultHandler, void,
+                                   int, nsString, int,
+                                   int, const nsAString_internal&, int>
+    IntStringIntResultRunnable;
+
+  void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                BluetoothDaemonPDU& aPDU,
+                BluetoothSocketResultHandler* aRes);
+
+  void ListenRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 BluetoothSocketResultHandler* aRes);
+
+  void ConnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                  BluetoothDaemonPDU& aPDU,
+                  BluetoothSocketResultHandler* aRes);
+};
+
+class BluetoothDaemonSocketInterface MOZ_FINAL
+  : public BluetoothSocketInterface
+{
+public:
+  BluetoothDaemonSocketInterface(BluetoothDaemonSocketModule* aModule);
+  ~BluetoothDaemonSocketInterface();
+
+  void Listen(BluetoothSocketType aType,
+              const nsAString& aServiceName,
+              const uint8_t aServiceUuid[16],
+              int aChannel, bool aEncrypt, bool aAuth,
+              BluetoothSocketResultHandler* aRes);
+
+  void Connect(const nsAString& aBdAddr,
+               BluetoothSocketType aType,
+               const uint8_t aUuid[16],
+               int aChannel, bool aEncrypt, bool aAuth,
+               BluetoothSocketResultHandler* aRes);
+
+  void Accept(int aFd, BluetoothSocketResultHandler* aRes);
+
+  void Close(BluetoothSocketResultHandler* aRes);
+
+private:
+  BluetoothDaemonSocketModule* mModule;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth2/moz.build
+++ b/dom/bluetooth2/moz.build
@@ -49,16 +49,17 @@ if CONFIG['MOZ_B2G_BT']:
         elif CONFIG['MOZ_B2G_BT_BLUEDROID']:
             SOURCES += [
                 'bluedroid/BluetoothA2dpHALInterface.cpp',
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothAvrcpHALInterface.cpp',
                 'bluedroid/BluetoothDaemonHelpers.cpp',
                 'bluedroid/BluetoothDaemonInterface.cpp',
                 'bluedroid/BluetoothDaemonSetupInterface.cpp',
+                'bluedroid/BluetoothDaemonSocketInterface.cpp',
                 'bluedroid/BluetoothGattHALInterface.cpp',
                 'bluedroid/BluetoothGattManager.cpp',
                 'bluedroid/BluetoothHALHelpers.cpp',
                 'bluedroid/BluetoothHALInterface.cpp',
                 'bluedroid/BluetoothHandsfreeHALInterface.cpp',
                 'bluedroid/BluetoothOppManager.cpp',
                 'bluedroid/BluetoothServiceBluedroid.cpp',
                 'bluedroid/BluetoothSocket.cpp',