Bug 1154281: Merge |UnixSocketConsumer| into |BluetoothSocket|, r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Tue, 21 Apr 2015 10:33:06 +0200
changeset 259179 d2c32fcc1b38f0aa47dad336a83083276c9f75de
parent 259178 5b93fef2c8483832ab4092073807897c0c8bd293
child 259180 995b1851e85aea819c5123847951dc1ea48c7a14
push id8007
push userraliiev@mozilla.com
push dateMon, 11 May 2015 19:23:16 +0000
treeherdermozilla-aurora@e2ce1aac996e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1154281
milestone40.0a1
Bug 1154281: Merge |UnixSocketConsumer| into |BluetoothSocket|, r=btian |BluetoothSocket| is the last remaining user of |UnixSocketConsumer|. Since the latter class is deprecated, it's the best option to merge it into the socket class. The functionality of |UnixSocketConsumer| is provided by |ListenSocket| and |StreamSocket|.
dom/bluetooth/bluez/BluetoothSocket.cpp
dom/bluetooth/bluez/BluetoothSocket.h
--- a/dom/bluetooth/bluez/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluez/BluetoothSocket.cpp
@@ -1,35 +1,572 @@
 /* -*- 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 "BluetoothSocket.h"
-
+#include <fcntl.h>
 #include "BluetoothSocketObserver.h"
 #include "BluetoothUnixSocketConnector.h"
+#include "mozilla/unused.h"
+#include "nsTArray.h"
 #include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
 
 using namespace mozilla::ipc;
-USING_BLUETOOTH_NAMESPACE
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+static const size_t MAX_READ_SIZE = 1 << 16;
+
+//
+// BluetoothSocketIO
+//
+
+class BluetoothSocket::BluetoothSocketIO final
+  : public UnixSocketWatcher
+  , protected SocketIOBase
+{
+public:
+  BluetoothSocketIO(MessageLoop* mIOLoop,
+                    BluetoothSocket* aConsumer,
+                    UnixSocketConnector* aConnector,
+                    const nsACString& aAddress);
+  ~BluetoothSocketIO();
+
+  void                GetSocketAddr(nsAString& aAddrStr) const;
+  SocketConsumerBase* GetConsumer();
+  SocketBase*         GetSocketBase();
+
+  // Shutdown state
+  //
+
+  bool IsShutdownOnMainThread() const;
+  void ShutdownOnMainThread();
+
+  bool IsShutdownOnIOThread() const;
+  void ShutdownOnIOThread();
+
+  // Delayed-task handling
+  //
+
+  void SetDelayedConnectTask(CancelableTask* aTask);
+  void ClearDelayedConnectTask();
+  void CancelDelayedConnectTask();
+
+  // Task callback methods
+  //
+
+  /**
+   * Run bind/listen to prepare for further runs of accept()
+   */
+  void Listen();
+
+  /**
+   * Connect to a socket
+   */
+  void Connect();
+
+  void Send(UnixSocketRawData* aData);
+
+  // I/O callback methods
+  //
+
+  void OnAccepted(int aFd, const sockaddr_any* aAddr,
+                  socklen_t aAddrLen) override;
+  void OnConnected() override;
+  void OnError(const char* aFunction, int aErrno) override;
+  void OnListening() override;
+  void OnSocketCanReceiveWithoutBlocking() override;
+  void OnSocketCanSendWithoutBlocking() override;
+
+private:
+  void FireSocketError();
+
+  // Set up flags on file descriptor.
+  static bool SetSocketFlags(int aFd);
+
+  /**
+   * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
+   * directly from main thread. All non-main-thread accesses should happen with
+   * mIO as container.
+   */
+  RefPtr<BluetoothSocket> mConsumer;
+
+  /**
+   * Connector object used to create the connection we are currently using.
+   */
+  nsAutoPtr<UnixSocketConnector> mConnector;
+
+  /**
+   * If true, do not requeue whatever task we're running
+   */
+  bool mShuttingDownOnIOThread;
+
+  /**
+   * Address we are connecting to, assuming we are creating a client connection.
+   */
+  nsCString mAddress;
+
+  /**
+   * Size of the socket address struct
+   */
+  socklen_t mAddrSize;
+
+  /**
+   * Address struct of the socket currently in use
+   */
+  sockaddr_any mAddr;
+
+  /**
+   * Task member for delayed connect task. Should only be access on main thread.
+   */
+  CancelableTask* mDelayedConnectTask;
+};
+
+BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO(
+  MessageLoop* mIOLoop,
+  BluetoothSocket* aConsumer,
+  UnixSocketConnector* aConnector,
+  const nsACString& aAddress)
+  : UnixSocketWatcher(mIOLoop)
+  , SocketIOBase(MAX_READ_SIZE)
+  , mConsumer(aConsumer)
+  , mConnector(aConnector)
+  , mShuttingDownOnIOThread(false)
+  , mAddress(aAddress)
+  , mDelayedConnectTask(nullptr)
+{
+  MOZ_ASSERT(mConsumer);
+  MOZ_ASSERT(mConnector);
+}
+
+BluetoothSocket::BluetoothSocketIO::~BluetoothSocketIO()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsShutdownOnMainThread());
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::GetSocketAddr(nsAString& aAddrStr) const
+{
+  if (!mConnector) {
+    NS_WARNING("No connector to get socket address from!");
+    aAddrStr.Truncate();
+    return;
+  }
+  mConnector->GetSocketAddr(mAddr, aAddrStr);
+}
+
+SocketConsumerBase*
+BluetoothSocket::BluetoothSocketIO::GetConsumer()
+{
+  return mConsumer.get();
+}
+
+SocketBase*
+BluetoothSocket::BluetoothSocketIO::GetSocketBase()
+{
+  return GetConsumer();
+}
+
+bool
+BluetoothSocket::BluetoothSocketIO::IsShutdownOnMainThread() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return mConsumer == nullptr;
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::ShutdownOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!IsShutdownOnMainThread());
+
+  mConsumer = nullptr;
+}
+
+bool
+BluetoothSocket::BluetoothSocketIO::IsShutdownOnIOThread() const
+{
+  return mShuttingDownOnIOThread;
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::ShutdownOnIOThread()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(!mShuttingDownOnIOThread);
+
+  Close(); // will also remove fd from I/O loop
+  mShuttingDownOnIOThread = true;
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::SetDelayedConnectTask(CancelableTask* aTask)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mDelayedConnectTask = aTask;
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::ClearDelayedConnectTask()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mDelayedConnectTask = nullptr;
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::CancelDelayedConnectTask()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mDelayedConnectTask) {
+    return;
+  }
+
+  mDelayedConnectTask->Cancel();
+  ClearDelayedConnectTask();
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::Listen()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(mConnector);
+
+  // This will set things we don't particularly care about, but it will hand
+  // back the correct structure size which is what we do care about.
+  if (!mConnector->CreateAddr(true, mAddrSize, mAddr, nullptr)) {
+    NS_WARNING("Cannot create socket address!");
+    FireSocketError();
+    return;
+  }
+
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
+      NS_WARNING("Cannot create socket fd!");
+      FireSocketError();
+      return;
+    }
+    if (!SetSocketFlags(fd)) {
+      NS_WARNING("Cannot set socket flags!");
+      FireSocketError();
+      return;
+    }
+    SetFd(fd);
+
+    // calls OnListening on success, or OnError otherwise
+    nsresult rv = UnixSocketWatcher::Listen(
+      reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+    NS_WARN_IF(NS_FAILED(rv));
+  }
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::Connect()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(mConnector);
+
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
+      NS_WARNING("Cannot create socket fd!");
+      FireSocketError();
+      return;
+    }
+    if (!SetSocketFlags(fd)) {
+      NS_WARNING("Cannot set socket flags!");
+      FireSocketError();
+      return;
+    }
+    SetFd(fd);
+  }
+
+  if (!mConnector->CreateAddr(false, mAddrSize, mAddr, mAddress.get())) {
+    NS_WARNING("Cannot create socket address!");
+    FireSocketError();
+    return;
+  }
+
+  // calls OnConnected() on success, or OnError() otherwise
+  nsresult rv = UnixSocketWatcher::Connect(
+    reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+  NS_WARN_IF(NS_FAILED(rv));
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::Send(UnixSocketRawData* aData)
+{
+  EnqueueData(aData);
+  AddWatchers(WRITE_WATCHER, false);
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnAccepted(
+  int aFd, const sockaddr_any* aAddr, socklen_t aAddrLen)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
+  MOZ_ASSERT(aAddr);
+  MOZ_ASSERT(aAddrLen > 0 && (size_t)aAddrLen <= sizeof(mAddr));
+
+  memcpy (&mAddr, aAddr, aAddrLen);
+  mAddrSize = aAddrLen;
+
+  if (!mConnector->SetUp(aFd)) {
+    NS_WARNING("Could not set up socket!");
+    return;
+  }
+
+  RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  Close();
+  if (!SetSocketFlags(aFd)) {
+    return;
+  }
+  SetSocket(aFd, SOCKET_IS_CONNECTED);
+
+  nsRefPtr<nsRunnable> r =
+    new SocketIOEventRunnable<BluetoothSocketIO>(
+      this, SocketIOEventRunnable<BluetoothSocketIO>::CONNECT_SUCCESS);
+  NS_DispatchToMainThread(r);
+
+  AddWatchers(READ_WATCHER, true);
+  if (HasPendingData()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnConnected()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
+
+  if (!SetSocketFlags(GetFd())) {
+    NS_WARNING("Cannot set socket flags!");
+    FireSocketError();
+    return;
+  }
+
+  if (!mConnector->SetUp(GetFd())) {
+    NS_WARNING("Could not set up socket!");
+    FireSocketError();
+    return;
+  }
+
+  nsRefPtr<nsRunnable> r =
+    new SocketIOEventRunnable<BluetoothSocketIO>(
+      this, SocketIOEventRunnable<BluetoothSocketIO>::CONNECT_SUCCESS);
+  NS_DispatchToMainThread(r);
+
+  AddWatchers(READ_WATCHER, true);
+  if (HasPendingData()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnListening()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
+
+  if (!mConnector->SetUpListenSocket(GetFd())) {
+    NS_WARNING("Could not set up listen socket!");
+    FireSocketError();
+    return;
+  }
+
+  AddWatchers(READ_WATCHER, true);
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnError(const char* aFunction, int aErrno)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  UnixFdWatcher::OnError(aFunction, aErrno);
+  FireSocketError();
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnSocketCanReceiveWithoutBlocking()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
+
+  ssize_t res = ReceiveData(GetFd(), this);
+  if (res < 0) {
+    /* I/O error */
+    RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  } else if (!res) {
+    /* EOF or peer shutdown */
+    RemoveWatchers(READ_WATCHER);
+  }
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::OnSocketCanSendWithoutBlocking()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
+
+  nsresult rv = SendPendingData(GetFd(), this);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  if (HasPendingData()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+BluetoothSocket::BluetoothSocketIO::FireSocketError()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  // Clean up watchers, statuses, fds
+  Close();
+
+  // Tell the main thread we've errored
+  nsRefPtr<nsRunnable> r =
+    new SocketIOEventRunnable<BluetoothSocketIO>(
+      this, SocketIOEventRunnable<BluetoothSocketIO>::CONNECT_ERROR);
+
+  NS_DispatchToMainThread(r);
+}
+
+bool
+BluetoothSocket::BluetoothSocketIO::SetSocketFlags(int aFd)
+{
+  // Set socket addr to be reused even if kernel is still waiting to close
+  int n = 1;
+  if (setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0) {
+    return false;
+  }
+
+  // Set close-on-exec bit.
+  int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFD));
+  if (-1 == flags) {
+    return false;
+  }
+  flags |= FD_CLOEXEC;
+  if (-1 == TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFD, flags))) {
+    return false;
+  }
+
+  // Set non-blocking status flag.
+  flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
+  if (-1 == flags) {
+    return false;
+  }
+  flags |= O_NONBLOCK;
+  if (-1 == TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags))) {
+    return false;
+  }
+
+  return true;
+}
+
+//
+// Socket tasks
+//
+
+class BluetoothSocket::ListenTask final
+  : public SocketIOTask<BluetoothSocketIO>
+{
+public:
+  ListenTask(BluetoothSocketIO* aIO)
+    : SocketIOTask<BluetoothSocketIO>(aIO)
+  { }
+
+  void Run() override
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    if (!IsCanceled()) {
+      GetIO()->Listen();
+    }
+  }
+};
+
+class BluetoothSocket::ConnectTask final
+  : public SocketIOTask<BluetoothSocketIO>
+{
+public:
+  ConnectTask(BluetoothSocketIO* aIO)
+    : SocketIOTask<BluetoothSocketIO>(aIO)
+  { }
+
+  void Run() override
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+    MOZ_ASSERT(!IsCanceled());
+
+    GetIO()->Connect();
+  }
+};
+
+class BluetoothSocket::DelayedConnectTask final
+  : public SocketIOTask<BluetoothSocketIO>
+{
+public:
+  DelayedConnectTask(BluetoothSocketIO* aIO)
+    : SocketIOTask<BluetoothSocketIO>(aIO)
+  { }
+
+  void Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (IsCanceled()) {
+      return;
+    }
+
+    BluetoothSocketIO* io = GetIO();
+    if (io->IsShutdownOnMainThread()) {
+      return;
+    }
+
+    io->ClearDelayedConnectTask();
+    XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new ConnectTask(io));
+  }
+};
+
+//
+// BluetoothSocket
+//
 
 BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
                                  BluetoothSocketType aType,
                                  bool aAuth,
                                  bool aEncrypt)
   : mObserver(aObserver)
   , mType(aType)
   , mAuth(aAuth)
   , mEncrypt(aEncrypt)
+  , mIO(nullptr)
 {
   MOZ_ASSERT(aObserver);
 }
 
+BluetoothSocket::~BluetoothSocket()
+{
+  MOZ_ASSERT(!mIO);
+}
+
 bool
 BluetoothSocket::Connect(const nsAString& aDeviceAddress,
                          const BluetoothUuid& aServiceUuid,
                          int aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
 
@@ -96,8 +633,127 @@ BluetoothSocket::OnConnectError()
 void
 BluetoothSocket::OnDisconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
   mObserver->OnSocketDisconnect(this);
 }
 
+bool
+BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mIO) {
+    return false;
+  }
+
+  MOZ_ASSERT(!mIO->IsShutdownOnMainThread());
+  XRE_GetIOMessageLoop()->PostTask(
+    FROM_HERE,
+    new SocketIOSendTask<BluetoothSocketIO, UnixSocketRawData>(mIO, aData));
+
+  return true;
+}
+
+bool
+BluetoothSocket::SendSocketData(const nsACString& aStr)
+{
+  if (aStr.Length() > MAX_READ_SIZE) {
+    return false;
+  }
+
+  nsAutoPtr<UnixSocketRawData> data(
+    new UnixSocketRawData(aStr.BeginReading(), aStr.Length()));
+
+  if (!SendSocketData(data)) {
+    return false;
+  }
+
+  unused << data.forget();
+
+  return true;
+}
+
+void
+BluetoothSocket::CloseSocket()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mIO) {
+    return;
+  }
+
+  mIO->CancelDelayedConnectTask();
+
+  // From this point on, we consider mIO as being deleted.
+  // We sever the relationship here so any future calls to listen or connect
+  // will create a new implementation.
+  mIO->ShutdownOnMainThread();
+
+  XRE_GetIOMessageLoop()->PostTask(
+    FROM_HERE, new SocketIOShutdownTask<BluetoothSocketIO>(mIO));
+
+  mIO = nullptr;
+
+  NotifyDisconnect();
+}
+
+void
+BluetoothSocket::GetSocketAddr(nsAString& aAddrStr)
+{
+  aAddrStr.Truncate();
+  if (!mIO || GetConnectionStatus() != SOCKET_CONNECTED) {
+    NS_WARNING("No socket currently open!");
+    return;
+  }
+  mIO->GetSocketAddr(aAddrStr);
+}
+
+bool
+BluetoothSocket::ConnectSocket(BluetoothUnixSocketConnector* aConnector,
+                               const char* aAddress,
+                               int aDelayMs)
+{
+  MOZ_ASSERT(aConnector);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<UnixSocketConnector> connector(aConnector);
+
+  if (mIO) {
+    NS_WARNING("Socket already connecting/connected!");
+    return false;
+  }
+
+  nsCString addr(aAddress);
+  MessageLoop* ioLoop = XRE_GetIOMessageLoop();
+  mIO = new BluetoothSocketIO(ioLoop, this, connector.forget(), addr);
+  SetConnectionStatus(SOCKET_CONNECTING);
+  if (aDelayMs > 0) {
+    DelayedConnectTask* connectTask = new DelayedConnectTask(mIO);
+    mIO->SetDelayedConnectTask(connectTask);
+    MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
+  } else {
+    ioLoop->PostTask(FROM_HERE, new ConnectTask(mIO));
+  }
+  return true;
+}
+
+bool
+BluetoothSocket::ListenSocket(BluetoothUnixSocketConnector* aConnector)
+{
+  MOZ_ASSERT(aConnector);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<UnixSocketConnector> connector(aConnector);
+
+  if (mIO) {
+    NS_WARNING("Socket already connecting/connected!");
+    return false;
+  }
+
+  mIO = new BluetoothSocketIO(
+    XRE_GetIOMessageLoop(), this, connector.forget(), EmptyCString());
+  SetConnectionStatus(SOCKET_LISTENING);
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new ListenTask(mIO));
+  return true;
+}
+
+END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluez/BluetoothSocket.h
+++ b/dom/bluetooth/bluez/BluetoothSocket.h
@@ -3,29 +3,37 @@
 /* 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_BluetoothSocket_h
 #define mozilla_dom_bluetooth_BluetoothSocket_h
 
 #include "BluetoothCommon.h"
-#include "mozilla/ipc/UnixSocket.h"
+#include <stdlib.h>
+#include "mozilla/ipc/SocketBase.h"
+#include "mozilla/ipc/UnixSocketWatcher.h"
+#include "mozilla/RefPtr.h"
+#include "nsAutoPtr.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSocketObserver;
+class BluetoothUnixSocketConnector;
 
-class BluetoothSocket : public mozilla::ipc::UnixSocketConsumer
+class BluetoothSocket final : public mozilla::ipc::SocketConsumerBase
 {
 public:
   BluetoothSocket(BluetoothSocketObserver* aObserver,
                   BluetoothSocketType aType,
                   bool aAuth,
                   bool aEncrypt);
+  ~BluetoothSocket();
 
   bool Connect(const nsAString& aDeviceAddress,
                const BluetoothUuid& aServiceUuid,
                int aChannel);
   bool Listen(const nsAString& aServiceName,
               const BluetoothUuid& aServiceUuid,
               int aChannel);
   inline void Disconnect()
@@ -39,18 +47,80 @@ public:
   virtual void ReceiveSocketData(
     nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) override;
 
   inline void GetAddress(nsAString& aDeviceAddress)
   {
     GetSocketAddr(aDeviceAddress);
   }
 
+  /**
+   * Queue data to be sent to the socket on the IO thread. Can only be called on
+   * originating thread.
+   *
+   * @param aMessage Data to be sent to socket
+   *
+   * @return true if data is queued, false otherwise (i.e. not connected)
+   */
+  bool SendSocketData(mozilla::ipc::UnixSocketRawData* aMessage);
+
+  /**
+   * Convenience function for sending strings to the socket (common in bluetooth
+   * profile usage). Converts to a UnixSocketRawData struct. Can only be called
+   * on originating thread.
+   *
+   * @param aMessage String to be sent to socket
+   *
+   * @return true if data is queued, false otherwise (i.e. not connected)
+   */
+  bool SendSocketData(const nsACString& aMessage);
+
+  /**
+   * Starts a task on the socket that will try to connect to a socket in a
+   * non-blocking manner.
+   *
+   * @param aConnector Connector object for socket type specific functions
+   * @param aAddress Address to connect to.
+   * @param aDelayMs Time delay in milli-seconds.
+   *
+   * @return true on connect task started, false otherwise.
+   */
+  bool ConnectSocket(BluetoothUnixSocketConnector* aConnector,
+                     const char* aAddress,
+                     int aDelayMs = 0);
+
+  /**
+   * Starts a task on the socket that will try to accept a new connection in a
+   * non-blocking manner.
+   *
+   * @param aConnector Connector object for socket type specific functions
+   *
+   * @return true on listen started, false otherwise
+   */
+  bool ListenSocket(BluetoothUnixSocketConnector* aConnector);
+
+  /**
+   * Queues the internal representation of socket for deletion. Can be called
+   * from main thread.
+   */
+  void CloseSocket();
+
+  /**
+   * Get the current sockaddr for the socket
+   */
+  void GetSocketAddr(nsAString& aAddrStr);
+
 private:
+  class BluetoothSocketIO;
+  class ConnectTask;
+  class DelayedConnectTask;
+  class ListenTask;
+
   BluetoothSocketObserver* mObserver;
   BluetoothSocketType mType;
   bool mAuth;
   bool mEncrypt;
+  BluetoothSocketIO* mIO;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif