Bug 776182: Patch 3 - Socket I/O for ipc unix sockets; r=cjones r=echou
authorKyle Machulis <kyle@nonpolynomial.com>
Tue, 25 Sep 2012 13:13:15 -0700
changeset 108075 4489b74f83994c5d8d8bea9e2b71594cc7193b8a
parent 108074 b4abff203299239af4134efc6f298d7ec03c4403
child 108076 f4e6abb6160f644546f14533640e81d3c54fc24d
push id23533
push usermlamouri@mozilla.com
push dateWed, 26 Sep 2012 10:57:37 +0000
treeherdermozilla-central@df69d95f636c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, echou
bugs776182
milestone18.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 776182: Patch 3 - Socket I/O for ipc unix sockets; r=cjones r=echou
dom/bluetooth/BluetoothReplyRunnable.cpp
dom/bluetooth/BluetoothService.cpp
dom/bluetooth/BluetoothService.h
dom/bluetooth/BluetoothUnixSocketConnector.cpp
dom/bluetooth/BluetoothUnixSocketConnector.h
dom/bluetooth/Makefile.in
dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.h
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
ipc/Makefile.in
ipc/unixsocket/Makefile.in
ipc/unixsocket/UnixSocket.cpp
ipc/unixsocket/UnixSocket.h
toolkit/library/Makefile.in
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -60,21 +60,21 @@ BluetoothReplyRunnable::FireErrorString(
   
   return rs->FireError(mDOMRequest, mErrorString);
 }
 
 NS_IMETHODIMP
 BluetoothReplyRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mDOMRequest);
+  MOZ_ASSERT(mReply);
 
   nsresult rv;
 
-  MOZ_ASSERT(mDOMRequest);
-
   if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
     rv = FireReply(JSVAL_VOID);
   } else {
     jsval v; 
     if (!ParseSuccessfulReply(&v)) {
       rv = FireErrorString();
     } else {
       rv = FireReply(v);
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -15,16 +15,17 @@
 
 #include "jsapi.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/ipc/UnixSocket.h"
 #include "nsContentUtils.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
@@ -237,20 +238,19 @@ BluetoothService::Create()
     return BluetoothServiceChildProcess::Create();
   }
 #endif
 
 #if defined(MOZ_BLUETOOTH_GONK)
   return new BluetoothGonkService();
 #elif defined(MOZ_BLUETOOTH_DBUS)
   return new BluetoothDBusService();
-#else
+#endif
   NS_WARNING("No platform support for bluetooth!");
   return nullptr;
-#endif
 }
 
 bool
 BluetoothService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
@@ -355,26 +355,16 @@ BluetoothService::DistributeSignal(const
   ol->Broadcast(aSignal);
 }
 
 nsresult
 BluetoothService::StartStopBluetooth(bool aStart)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-#ifdef DEBUG
-  if (aStart && mLastRequestedEnable) {
-    MOZ_ASSERT(false, "Calling Start twice in a row!");
-  }
-  else if (!aStart && !mLastRequestedEnable) {
-    MOZ_ASSERT(false, "Calling Stop twice in a row!");
-  }
-  mLastRequestedEnable = aStart;
-#endif
-
   if (gInShutdown) {
     if (aStart) {
       // Don't try to start if we're already shutting down.
       MOZ_ASSERT(false, "Start called while in shutdown!");
       return NS_ERROR_FAILURE;
     }
 
     if (!mBluetoothCommandThread) {
@@ -692,17 +682,17 @@ BluetoothService::Observe(nsISupports* a
   return NS_ERROR_UNEXPECTED;
 }
 
 bool
 SetJsObject(JSContext* aContext,
             JSObject* aObj,
             const InfallibleTArray<BluetoothNamedValue>& aData)
 {
-  for (int i = 0; i < aData.Length(); i++) {
+  for (uint32_t i = 0; i < aData.Length(); i++) {
     jsval v;
     if (aData[i].value().type() == BluetoothValue::TnsString) {
       nsString data = aData[i].value().get_nsString();
       JSString* JsData = JS_NewStringCopyN(aContext,
                                            NS_ConvertUTF16toUTF8(data).get(),
                                            data.Length());
       NS_ENSURE_TRUE(JsData, NS_ERROR_OUT_OF_MEMORY);
       v = STRING_TO_JSVAL(JsData);
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -9,16 +9,22 @@
 
 #include "BluetoothCommon.h"
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsIObserver.h"
 #include "nsIThread.h"
 #include "nsTObserverArray.h"
 
+namespace mozilla {
+namespace ipc {
+class UnixSocketConsumer;
+}
+}
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothManager;
 class BluetoothNamedValue;
 class BluetoothReplyRunnable;
 class BluetoothSignal;
 
 typedef mozilla::ObserverList<BluetoothSignal> BluetoothSignalObserverList;
@@ -221,25 +227,23 @@ public:
   virtual nsresult
   RemoveDeviceInternal(const nsAString& aAdapterPath,
                        const nsAString& aObjectPath,
                        BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
-                      int aType,
+                      BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
+                      mozilla::ipc::UnixSocketConsumer* aSocketConsumer,
                       BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
-  CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) = 0;
-
-  virtual bool
   SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode,
                      BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
   SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey,
                      BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothUnixSocketConnector.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * NOTE: Due to being based on the dbus compatibility layer for
+ * android's bluetooth implementation, this file is licensed under the
+ * apache license instead of MPL.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/l2cap.h>
+
+#include "BluetoothUnixSocketConnector.h"
+#include "nsThreadUtils.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
+
+static
+int get_bdaddr(const char *str, bdaddr_t *ba)
+{
+  char *d = ((char*)ba) + 5, *endp;
+  for (int i = 0; i < 6; i++) {
+    *d-- = strtol(str, &endp, 16);
+    MOZ_ASSERT(!(*endp != ':' && i != 5));
+    str = endp + 1;
+  }
+  return 0;
+}
+
+BluetoothUnixSocketConnector::BluetoothUnixSocketConnector(
+  BluetoothSocketType aType,
+  int aChannel,
+  bool aAuth,
+  bool aEncrypt) : mType(aType)
+                 , mChannel(aChannel)
+                 , mAuth(aAuth)
+                 , mEncrypt(aEncrypt)
+{
+}
+
+int
+BluetoothUnixSocketConnector::Create()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  int lm = 0;
+  int fd = -1;
+  int sndbuf;
+
+  switch (mType) {
+  case BluetoothSocketType::RFCOMM:
+    fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+    break;
+  case BluetoothSocketType::SCO:
+    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+    break;
+  case BluetoothSocketType::L2CAP:
+    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+    break;
+  default:
+    return -1;
+  }
+
+  if (fd < 0) {
+    NS_WARNING("Could not open bluetooth socket!");
+    return -1;
+  }
+
+  /* kernel does not yet support LM for SCO */
+  switch (mType) {
+  case BluetoothSocketType::RFCOMM:
+    lm |= mAuth ? RFCOMM_LM_AUTH : 0;
+    lm |= mEncrypt ? RFCOMM_LM_ENCRYPT : 0;
+    lm |= (mAuth && mEncrypt) ? RFCOMM_LM_SECURE : 0;
+    break;
+  case BluetoothSocketType::L2CAP:
+    lm |= mAuth ? L2CAP_LM_AUTH : 0;
+    lm |= mEncrypt ? L2CAP_LM_ENCRYPT : 0;
+    lm |= (mAuth && mEncrypt) ? L2CAP_LM_SECURE : 0;
+    break;
+  }
+
+  if (lm) {
+    if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
+      NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
+      return -1;
+    }
+  }
+
+  if (mType == BluetoothSocketType::RFCOMM) {
+    sndbuf = RFCOMM_SO_SNDBUF;
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
+      NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
+      return -1;
+    }
+  }
+
+  return fd;
+}
+
+bool
+BluetoothUnixSocketConnector::ConnectInternal(int aFd, const char* aAddress)
+{
+  int n = 1;
+  setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+  
+  socklen_t addr_sz;
+  struct sockaddr *addr;
+  bdaddr_t bd_address_obj;
+
+  if (get_bdaddr(aAddress, &bd_address_obj)) {
+    NS_WARNING("Can't get bluetooth address!");
+    return false;
+  }
+
+  switch (mType) {
+  case BluetoothSocketType::RFCOMM:
+    struct sockaddr_rc addr_rc;
+    addr = (struct sockaddr *)&addr_rc;
+    addr_sz = sizeof(addr_rc);
+
+    memset(addr, 0, addr_sz);
+    addr_rc.rc_family = AF_BLUETOOTH;
+    addr_rc.rc_channel = mChannel;
+    memcpy(&addr_rc.rc_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
+    break;
+  case BluetoothSocketType::SCO:
+    struct sockaddr_sco addr_sco;
+    addr = (struct sockaddr *)&addr_sco;
+    addr_sz = sizeof(addr_sco);
+
+    memset(addr, 0, addr_sz);
+    addr_sco.sco_family = AF_BLUETOOTH;
+    memcpy(&addr_sco.sco_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
+    break;
+  default:
+    NS_WARNING("Socket type unknown!");
+    return false;
+  }
+
+  int ret = connect(aFd, addr, addr_sz);
+
+  if (ret) {
+#if DEBUG
+    //LOG("Socket connect errno=%d\n", errno);
+#endif
+    NS_WARNING("Socket connect error!");
+    return false;
+  }
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothUnixSocketConnector.h
@@ -0,0 +1,34 @@
+/* -*- 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_BluetoothUnixSocketConnector_h
+#define mozilla_dom_bluetooth_BluetoothUnixSocketConnector_h
+
+#include "BluetoothCommon.h"
+#include <mozilla/ipc/UnixSocket.h>
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothUnixSocketConnector : public mozilla::ipc::UnixSocketConnector
+{
+public:
+  BluetoothUnixSocketConnector(BluetoothSocketType aType, int aChannel,
+                               bool aAuth, bool aEncrypt);
+  virtual ~BluetoothUnixSocketConnector()
+  {}
+  virtual int Create() MOZ_OVERRIDE;
+  virtual bool ConnectInternal(int aFd, const char* aAddress) MOZ_OVERRIDE;
+
+private:
+  BluetoothSocketType mType;
+  int mChannel;
+  bool mAuth;
+  bool mEncrypt;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -46,16 +46,17 @@ CPPSRCS += \
   BluetoothDevice.cpp \
   BluetoothPropertyEvent.cpp \
   BluetoothReplyRunnable.cpp \
   BluetoothPropertyContainer.cpp \
   BluetoothUtils.cpp \
   BluetoothChild.cpp \
   BluetoothParent.cpp \
   BluetoothServiceChildProcess.cpp \
+  BluetoothUnixSocketConnector.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothManager.idl \
   nsIDOMBluetoothAdapter.idl \
   nsIDOMBluetoothDevice.idl \
   nsIDOMBluetoothDeviceEvent.idl \
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -198,33 +198,26 @@ BluetoothServiceChildProcess::RemoveDevi
 {
   SendRequest(aRunnable,
               UnpairRequest(nsString(aAdapterPath), nsString(aObjectPath)));
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceChildProcess::GetSocketViaService(
-                                              const nsAString& aObjectPath,
-                                              const nsAString& aService,
-                                              int aType,
-                                              bool aAuth,
-                                              bool aEncrypt,
-                                              BluetoothReplyRunnable* aRunnable)
+                                       const nsAString& aObjectPath,
+                                       const nsAString& aService,
+                                       BluetoothSocketType aType,
+                                       bool aAuth,
+                                       bool aEncrypt,
+                                       mozilla::ipc::UnixSocketConsumer* aConsumer,
+                                       BluetoothReplyRunnable* aRunnable)
 {
-  MOZ_NOT_REACHED("Implement me!");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-bool
-BluetoothServiceChildProcess::CloseSocket(int aFd,
-                                          BluetoothReplyRunnable* aRunnable)
-{
-  MOZ_NOT_REACHED("Implement me!");
-  return false;
+  MOZ_NOT_REACHED("This should never be called!");
+  return NS_ERROR_FAILURE;
 }
 
 bool
 BluetoothServiceChildProcess::SetPinCodeInternal(
                                                 const nsAString& aDeviceAddress,
                                                 const nsAString& aPinCode,
                                                 BluetoothReplyRunnable* aRunnable)
 {
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -5,16 +5,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_ipc_bluetoothservicechildprocess_h__
 #define mozilla_dom_bluetooth_ipc_bluetoothservicechildprocess_h__
 
 #include "BluetoothService.h"
 
 namespace mozilla {
+namespace ipc {
+class UnixSocketConsumer;
+}
 namespace dom {
 namespace bluetooth {
 
 class BluetoothChild;
 
 } // namespace bluetooth
 } // namespace dom
 } // namespace mozilla
@@ -81,39 +84,37 @@ public:
   virtual nsresult
   RemoveDeviceInternal(const nsAString& aAdapterPath,
                        const nsAString& aObjectPath,
                        BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
-                      int aType,
+                      BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
+                      mozilla::ipc::UnixSocketConsumer* aConsumer,
                       BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
-  CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
-
-  virtual bool
   SetPinCodeInternal(const nsAString& aDeviceAddress,
                      const nsAString& aPinCode,
                      BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
   SetPasskeyInternal(const nsAString& aDeviceAddress,
                      uint32_t aPasskey,
                      BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
   SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
                                  bool aConfirm,
                                  BluetoothReplyRunnable* aRunnable)
-    MOZ_OVERRIDE;
+                                 MOZ_OVERRIDE;
 
   virtual bool
   SetAuthorizationInternal(const nsAString& aDeviceAddress,
                            bool aAllow,
                            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
 protected:
   BluetoothServiceChildProcess();
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -15,26 +15,27 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #include "base/basictypes.h"
 #include "BluetoothDBusService.h"
 #include "BluetoothServiceUuid.h"
 #include "BluetoothReplyRunnable.h"
+#include "BluetoothUnixSocketConnector.h"
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
 #include "nsIDOMDOMRequest.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "nsDebug.h"
 #include "nsDataHashtable.h"
-#include "mozilla/ipc/Socket.h"
+#include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/ipc/DBusThread.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 /**
  * Some rules for dealing with memory in DBus:
@@ -1845,28 +1846,36 @@ BluetoothDBusService::GetDevicePath(cons
 int
 GetDeviceServiceChannel(const nsAString& aObjectPath,
                         const nsAString& aPattern,
                         int aAttributeId)
 {
   // This is a blocking call, should not be run on main thread.
   MOZ_ASSERT(!NS_IsMainThread());
 
+#ifdef MOZ_WIDGET_GONK
+  // GetServiceAttributeValue only exists in android's bluez dbus binding
+  // implementation
   nsCString tempPattern = NS_ConvertUTF16toUTF8(aPattern);
   const char* pattern = tempPattern.get();
 
   DBusMessage *reply =
     dbus_func_args(gThreadConnection->GetConnection(),
                    NS_ConvertUTF16toUTF8(aObjectPath).get(),
                    DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
                    DBUS_TYPE_STRING, &pattern,
                    DBUS_TYPE_UINT16, &aAttributeId,
                    DBUS_TYPE_INVALID);
 
   return reply ? dbus_returns_int32(reply) : -1;
+#else
+  // FIXME/Bug 793977 qdot: Just return something for desktop, until we have a
+  // parser for the GetServiceAttributes xml block
+  return 1;
+#endif
 }
 
 // static
 bool
 BluetoothDBusService::RemoveReservedServicesInternal(const nsAString& aAdapterPath,
                                                      const nsTArray<uint32_t>& aServiceHandles)
 {
   MOZ_ASSERT(!NS_IsMainThread());
@@ -2158,133 +2167,87 @@ BluetoothDBusService::PrepareAdapterInte
 
   return NS_OK;
 }
 
 class CreateBluetoothSocketRunnable : public nsRunnable
 {
 public:
   CreateBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
+                                UnixSocketConsumer* aConsumer,
                                 const nsAString& aObjectPath,
                                 const nsAString& aServiceUUID,
-                                int aType,
+                                BluetoothSocketType aType,
                                 bool aAuth,
                                 bool aEncrypt)
     : mRunnable(dont_AddRef(aRunnable)),
+      mConsumer(aConsumer),
       mObjectPath(aObjectPath),
       mServiceUUID(aServiceUUID),
       mType(aType),
       mAuth(aAuth),
       mEncrypt(aEncrypt)
   {
   }
 
   nsresult
   Run()
   {
     NS_WARNING("Running create socket!\n");
     MOZ_ASSERT(!NS_IsMainThread());
 
     nsString address = GetAddressFromObjectPath(mObjectPath);
     int channel = GetDeviceServiceChannel(mObjectPath, mServiceUUID, 0x0004);
-    int fd = mozilla::ipc::GetNewSocket(mType, NS_ConvertUTF16toUTF8(address).get(),
-                                        channel, mAuth, mEncrypt);
     BluetoothValue v;
     nsString replyError;
-    if (fd < 0) {
+    BluetoothUnixSocketConnector c(mType, channel, mAuth, mEncrypt);
+    if (!mConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(address).get())) {
       replyError.AssignLiteral("SocketConnectionError");
       DispatchBluetoothReply(mRunnable, v, replyError);
       return NS_ERROR_FAILURE;
     }
-
-    v = (uint32_t)fd;
-
+    // Bluetooth value needs to be set to something to succeed.
+    v = true;
     DispatchBluetoothReply(mRunnable, v, replyError);
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
+  nsRefPtr<UnixSocketConsumer> mConsumer;
   nsString mObjectPath;
   nsString mServiceUUID;
-  int mType;
+  BluetoothSocketType mType;
   bool mAuth;
   bool mEncrypt;
 };
 
 nsresult
 BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
                                           const nsAString& aService,
-                                          int aType,
+                                          BluetoothSocketType aType,
                                           bool aAuth,
                                           bool aEncrypt,
+                                          mozilla::ipc::UnixSocketConsumer* aConsumer,
                                           BluetoothReplyRunnable* aRunnable)
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
   if (!mConnection || !gThreadConnection) {
     NS_ERROR("Bluetooth service not started yet!");
     return NS_ERROR_FAILURE;
   }
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
-  nsRefPtr<nsRunnable> func(new CreateBluetoothSocketRunnable(runnable, aObjectPath,
+  nsRefPtr<nsRunnable> func(new CreateBluetoothSocketRunnable(runnable,
+                                                              aConsumer,
+                                                              aObjectPath,
                                                               aService, aType,
                                                               aAuth, aEncrypt));
   if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
 
   runnable.forget();
   return NS_OK;
 }
 
-class CloseBluetoothSocketRunnable : public nsRunnable
-{
-public:
-  CloseBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
-                               int aFd)
-    : mRunnable(dont_AddRef(aRunnable)),
-      mFd(aFd)
-  {
-  }
-
-  nsresult
-  Run()
-  {
-    BluetoothValue v;
-    nsString replyError;
-    if (mozilla::ipc::CloseSocket(mFd) != 0) {
-      replyError.AssignLiteral("SocketConnectionError");
-      DispatchBluetoothReply(mRunnable, v, replyError);
-      return NS_ERROR_FAILURE;
-    }
-
-    DispatchBluetoothReply(mRunnable, v, replyError);
-
-    return NS_OK;
-  }
-
-private:
-  nsRefPtr<BluetoothReplyRunnable> mRunnable;
-  int mFd;
-};
-
-bool
-BluetoothDBusService::CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
-  if (!mConnection || !gThreadConnection) {
-    NS_ERROR("Bluetooth service not started yet!");
-    return false;
-  }
-  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
-
-  nsRefPtr<nsRunnable> func(new CloseBluetoothSocketRunnable(runnable, aFd));
-  if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
-    NS_WARNING("Cannot dispatch firmware loading task!");
-    return false;
-  }
-
-  runnable.forget();
-  return true;
-}
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -65,23 +65,22 @@ public:
 
   static bool
   RemoveReservedServicesInternal(const nsAString& aAdapterPath,
                                  const nsTArray<uint32_t>& aServiceHandles);
 
   virtual nsresult
   GetSocketViaService(const nsAString& aObjectPath,
                       const nsAString& aService,
-                      int aType,
+                      BluetoothSocketType aType,
                       bool aAuth,
                       bool aEncrypt,
+                      mozilla::ipc::UnixSocketConsumer* aConsumer,
                       BluetoothReplyRunnable* aRunnable);
 
-  virtual bool CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable);
-
   virtual nsresult
   CreatePairedDeviceInternal(const nsAString& aAdapterPath,
                              const nsAString& aDeviceAddress,
                              int aTimeout,
                              BluetoothReplyRunnable* aRunnable);
 
   virtual nsresult
   RemoveDeviceInternal(const nsAString& aAdapterPath,
--- a/ipc/Makefile.in
+++ b/ipc/Makefile.in
@@ -11,18 +11,22 @@ include $(DEPTH)/config/autoconf.mk
 
 DIRS += chromium glue ipdl testshell
 
 ifdef MOZ_B2G_RIL #{
 DIRS += ril
 endif #}
 
 ifdef MOZ_B2G_BT #{
-DIRS += dbus socket
+DIRS += dbus
 endif #}
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
-DIRS += netd
+DIRS += netd unixsocket
+endif
+
+ifeq ($(OS_ARCH),Linux)
+DIRS += unixsocket
 endif
 
 TOOL_DIRS = app
 
 include $(topsrcdir)/config/rules.mk
--- a/ipc/unixsocket/Makefile.in
+++ b/ipc/unixsocket/Makefile.in
@@ -5,27 +5,23 @@
 DEPTH = ../..
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = ipc
-LIBRARY_NAME = mozipcsocket_s
+LIBRARY_NAME = mozipcunixsocket_s
 FORCE_STATIC_LIB = 1
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
 
 EXPORTS_NAMESPACES = mozilla/ipc
 
-EXPORTS_mozilla/ipc = \
-  Socket.h \
-  $(NULL)
+EXPORTS_mozilla/ipc = UnixSocket.h
 
-CPPSRCS += \
-  Socket.cpp \
-  $(NULL)
+CPPSRCS += UnixSocket.cpp
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 include $(topsrcdir)/config/rules.mk
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -1,180 +1,395 @@
 /* -*- 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 "Socket.h"
+#include "UnixSocket.h"
 
+#include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sco.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/l2cap.h>
-
-#include "nsThreadUtils.h"
+#include "base/eintr_wrapper.h"
+#include "base/message_loop.h"
 
-#undef LOG
-#if defined(MOZ_WIDGET_GONK)
-#include <android/log.h>
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
-#else
-#define LOG(args...)  printf(args);
-#endif
-#define TYPE_AS_STR(t)                                                  \
-  ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP"))
+#include "mozilla/Monitor.h"
+#include "mozilla/Util.h"
+#include "mozilla/FileUtils.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
 
 namespace mozilla {
 namespace ipc {
-static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
 
-static const int TYPE_RFCOMM = 1;
-static const int TYPE_SCO = 2;
-static const int TYPE_L2CAP = 3;
-
-static int get_bdaddr(const char *str, bdaddr_t *ba)
+class UnixSocketImpl : public MessageLoopForIO::Watcher
 {
-  char *d = ((char*)ba) + 5, *endp;
-  for (int i = 0; i < 6; i++) {
-    *d-- = strtol(str, &endp, 16);
-    MOZ_ASSERT(*endp != ':' && i != 5);
-    str = endp + 1;
+public:
+  UnixSocketImpl(UnixSocketConsumer* aConsumer, int aFd)
+    : mConsumer(aConsumer)
+    , mIOLoop(nullptr)
+    , mFd(aFd)
+  {
+  }
+
+  ~UnixSocketImpl()
+  {
+    mReadWatcher.StopWatchingFileDescriptor();
+    mWriteWatcher.StopWatchingFileDescriptor();
+  }
+
+  void QueueWriteData(UnixSocketRawData* aData)
+  {
+    mOutgoingQ.AppendElement(aData);
+    OnFileCanWriteWithoutBlocking(mFd);
+  }
+
+  bool isFdValid()
+  {
+    return mFd > 0;
+  }
+
+  void SetUpIO()
+  {
+    MOZ_ASSERT(!mIOLoop);
+    mIOLoop = MessageLoopForIO::current();
+    mIOLoop->WatchFileDescriptor(mFd,
+                                 true,
+                                 MessageLoopForIO::WATCH_READ,
+                                 &mReadWatcher,
+                                 this);
+  }
+
+  void PrepareRemoval()
+  {
+    mConsumer.forget();
   }
-  return 0;
+
+  /**
+   * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
+   * directly from main thread. All non-main-thread accesses should happen with
+   * mImpl as container.
+   */
+  RefPtr<UnixSocketConsumer> mConsumer;
+
+private:
+  /**
+   * libevent triggered functions that reads data from socket when available and
+   * guarenteed non-blocking. Only to be called on IO thread.
+   *
+   * @param aFd File descriptor to read from
+   */
+  virtual void OnFileCanReadWithoutBlocking(int aFd);
+
+  /**
+   * libevent or developer triggered functions that writes data to socket when
+   * available and guarenteed non-blocking. Only to be called on IO thread.
+   *
+   * @param aFd File descriptor to read from
+   */
+  virtual void OnFileCanWriteWithoutBlocking(int aFd);
+
+  /**
+   * IO Loop pointer. Must be initalized and called from IO thread only.
+   */
+  MessageLoopForIO* mIOLoop;
+
+  /**
+   * Raw data queue. Must be pushed/popped from IO thread only.
+   */
+  typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue;
+  UnixSocketRawDataQueue mOutgoingQ;
+
+  /**
+   * File descriptor to read from/write to. Connection happens on user provided
+   * thread. Read/write/close happens on IO thread.
+   */
+  ScopedClose mFd;
+
+  /**
+   * Incoming packet. Only to be accessed on IO Thread.
+   */
+  nsAutoPtr<UnixSocketRawData> mIncoming;
+
+  /**
+   * Read watcher for libevent. Only to be accessed on IO Thread.
+   */
+  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
+
+  /**
+   * Write watcher for libevent. Only to be accessed on IO Thread.
+   */
+  MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
+};
+
+static void
+DestroyImpl(UnixSocketImpl* impl)
+{
+  delete impl;
 }
 
-int
-OpenSocket(int type, const char* aAddress, int channel, bool auth, bool encrypt)
+class SocketReceiveTask : public nsRunnable
 {
-  MOZ_ASSERT(!NS_IsMainThread());
-  int lm = 0;
-  int fd = -1;
-  int sndbuf;
+public:
+  SocketReceiveTask(UnixSocketImpl* aImpl, UnixSocketRawData* aData) :
+    mImpl(aImpl),
+    mRawData(aData)
+  {
+    MOZ_ASSERT(aImpl);
+    MOZ_ASSERT(aData);
+  }
 
-  switch (type) {
-  case TYPE_RFCOMM:
-    fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-    break;
-  case TYPE_SCO:
-    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
-    break;
-  case TYPE_L2CAP:
-    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-    break;
-  default:
-    return -1;
+  NS_IMETHOD Run()
+  {
+    if(!mImpl->mConsumer) {
+      NS_WARNING("mConsumer is null, aborting receive!");
+      // Since we've already explicitly closed and the close happened before
+      // this, this isn't really an error. Since we've warned, return OK.
+      return NS_OK;
+    }
+    mImpl->mConsumer->ReceiveSocketData(mRawData);
+    return NS_OK;
+  }
+private:
+  UnixSocketImpl* mImpl;
+  nsAutoPtr<UnixSocketRawData> mRawData;
+};
+
+class SocketSendTask : public Task
+{
+public:
+  SocketSendTask(UnixSocketConsumer* aConsumer, UnixSocketImpl* aImpl,
+                 UnixSocketRawData* aData)
+    : mConsumer(aConsumer),
+      mImpl(aImpl),
+      mData(aData)
+  {
+    MOZ_ASSERT(aConsumer);
+    MOZ_ASSERT(aImpl);
+    MOZ_ASSERT(aData);
   }
 
-  if (fd < 0) {
-    NS_WARNING("Could not open bluetooth socket!");
-    return -1;
+  void Run()
+  {
+    mImpl->QueueWriteData(mData);
+  }
+
+private:
+  nsRefPtr<UnixSocketConsumer> mConsumer;
+  UnixSocketImpl* mImpl;
+  UnixSocketRawData* mData;
+};
+
+class StartImplReadingTask : public Task
+{
+public:
+  StartImplReadingTask(UnixSocketImpl* aImpl)
+    : mImpl(aImpl)
+  {
+  }
+
+  void Run()
+  {
+    mImpl->SetUpIO();
+  }
+private:
+  UnixSocketImpl* mImpl;
+};
+
+bool
+UnixSocketConnector::Connect(int aFd, const char* aAddress)
+{
+  if (!ConnectInternal(aFd, aAddress))
+  {
+    return false;
+  }
+
+  // Set close-on-exec bit.
+  int flags = fcntl(aFd, F_GETFD);
+  if (-1 == flags) {
+    return false;
+  }
+
+  flags |= FD_CLOEXEC;
+  if (-1 == fcntl(aFd, F_SETFD, flags)) {
+    return false;
+  }
+
+  // Select non-blocking IO.
+  if (-1 == fcntl(aFd, F_SETFL, O_NONBLOCK)) {
+    return false;
   }
 
-  /* kernel does not yet support LM for SCO */
-  switch (type) {
-  case TYPE_RFCOMM:
-    lm |= auth ? RFCOMM_LM_AUTH : 0;
-    lm |= encrypt ? RFCOMM_LM_ENCRYPT : 0;
-    lm |= (auth && encrypt) ? RFCOMM_LM_SECURE : 0;
-    break;
-  case TYPE_L2CAP:
-    lm |= auth ? L2CAP_LM_AUTH : 0;
-    lm |= encrypt ? L2CAP_LM_ENCRYPT : 0;
-    lm |= (auth && encrypt) ? L2CAP_LM_SECURE : 0;
-    break;
+  return true;
+}
+
+UnixSocketConsumer::~UnixSocketConsumer()
+{
+}
+
+bool
+UnixSocketConsumer::SendSocketData(UnixSocketRawData* aData)
+{
+  if (!mImpl) {
+    return false;
+  }
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                   new SocketSendTask(this, mImpl, aData));
+  return true;
+}
+
+bool
+UnixSocketConsumer::SendSocketData(const nsACString& aStr)
+{
+  if (!mImpl) {
+    return false;
+  }
+  if (aStr.Length() > UnixSocketRawData::MAX_DATA_SIZE) {
+    return false;
+  }
+  nsCString str(aStr);
+  UnixSocketRawData* d = new UnixSocketRawData(aStr.Length());
+  memcpy(d->mData, str.get(), aStr.Length());
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                   new SocketSendTask(this, mImpl, d));
+  return true;
+}
+
+void
+UnixSocketConsumer::CloseSocket()
+{
+  if (!mImpl) {
+    return;
   }
+  // To make sure the owner doesn't die on the IOThread, remove pointer here
+  mImpl->PrepareRemoval();
+  // Line it up to be destructed on the IO Thread
+  // Kill our pointer to it
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                   NewRunnableFunction(DestroyImpl,
+                                                       mImpl.forget()));
+}
 
-  if (lm) {
-    if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
-      LOG("setsockopt(RFCOMM_LM) failed, throwing");
-      return -1;
-    }
-  }
-
-  if (type == TYPE_RFCOMM) {
-    sndbuf = RFCOMM_SO_SNDBUF;
-    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
-      LOG("setsockopt(SO_SNDBUF) failed, throwing");
-      return -1;
+void
+UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
+{
+  // Keep reading data until either
+  //
+  //   - mIncoming is completely read
+  //     If so, sConsumer->MessageReceived(mIncoming.forget())
+  //
+  //   - mIncoming isn't completely read, but there's no more
+  //     data available on the socket
+  //     If so, break;
+  while (true) {
+    if (!mIncoming) {
+      mIncoming = new UnixSocketRawData();
+      ssize_t ret = read(aFd, mIncoming->mData, UnixSocketRawData::MAX_DATA_SIZE);
+      if (ret <= 0) {
+        if (ret == -1) {
+          if (errno == EINTR) {
+            continue; // retry system call when interrupted
+          }
+          else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            mIncoming.forget();
+            return; // no data available: return and re-poll
+          }
+          // else fall through to error handling on other errno's
+        }
+#ifdef DEBUG
+        nsAutoString str;
+        str.AssignLiteral("Cannot read from network, error ");
+        str += (int)ret;
+        NS_WARNING(NS_ConvertUTF16toUTF8(str).get());
+#endif
+        // At this point, assume that we can't actually access
+        // the socket anymore
+        mIncoming.forget();
+        mReadWatcher.StopWatchingFileDescriptor();
+        mWriteWatcher.StopWatchingFileDescriptor();
+        mConsumer->CloseSocket();
+        return;
+      }
+      mIncoming->mData[ret] = 0;
+      mIncoming->mSize = ret;
+      nsRefPtr<SocketReceiveTask> t =
+        new SocketReceiveTask(this, mIncoming.forget());
+      NS_DispatchToMainThread(t);
+      if (ret < ssize_t(UnixSocketRawData::MAX_DATA_SIZE)) {
+        return;
+      }
     }
   }
-
-  int n = 1;
-  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
-  
-  socklen_t addr_sz;
-  struct sockaddr *addr;
-  bdaddr_t bd_address_obj;
-
-  int mPort = channel;
-
-  char mAddress[18];
-  mAddress[17] = '\0';
-  strncpy(&mAddress[0], aAddress, 17);
-
-  if (get_bdaddr(aAddress, &bd_address_obj)) {
-    NS_WARNING("Can't get bluetooth address!");
-    return -1;
-  }
-
-  switch (type) {
-  case TYPE_RFCOMM:
-    struct sockaddr_rc addr_rc;
-    addr = (struct sockaddr *)&addr_rc;
-    addr_sz = sizeof(addr_rc);
-
-    memset(addr, 0, addr_sz);
-    addr_rc.rc_family = AF_BLUETOOTH;
-    addr_rc.rc_channel = mPort;
-    memcpy(&addr_rc.rc_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
-    break;
-  case TYPE_SCO:
-    struct sockaddr_sco addr_sco;
-    addr = (struct sockaddr *)&addr_sco;
-    addr_sz = sizeof(addr_sco);
-
-    memset(addr, 0, addr_sz);
-    addr_sco.sco_family = AF_BLUETOOTH;
-    memcpy(&addr_sco.sco_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
-    break;
-  default:
-    NS_WARNING("Socket type unknown!");
-    return -1;
-  }
-
-  int ret = connect(fd, addr, addr_sz);
-
-  if (ret) {
-#if DEBUG
-    LOG("Socket connect errno=%d\n", errno);
-#endif
-    NS_WARNING("Socket connect error!");
-    return -1;
-  }
-
-  // Match android_bluetooth_HeadsetBase.cpp line 384
-  // Skip many lines
-  return fd;
 }
 
-int
-GetNewSocket(int type, const char* aAddress, int channel, bool auth, bool encrypt)
+void
+UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
 {
-  return OpenSocket(type, aAddress, channel, auth, encrypt);
+  // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
+  //
+  // Otherwise, save the byte position of the next byte to write
+  // within mCurrentRilRawData, and request another write when the
+  // system won't block.
+  //
+  while (true) {
+    UnixSocketRawData* data;
+    if (mOutgoingQ.IsEmpty()) {
+      return;
+    }
+    data = mOutgoingQ.ElementAt(0);
+    const uint8_t *toWrite;
+    toWrite = data->mData;
+
+    while (data->mCurrentWriteOffset < data->mSize) {
+      ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
+      ssize_t written;
+      written = write (aFd, toWrite + data->mCurrentWriteOffset,
+                       write_amount);
+      if (written > 0) {
+        data->mCurrentWriteOffset += written;
+      }
+      if (written != write_amount) {
+        break;
+      }
+    }
+
+    if (data->mCurrentWriteOffset != data->mSize) {
+      MessageLoopForIO::current()->WatchFileDescriptor(
+        aFd,
+        false,
+        MessageLoopForIO::WATCH_WRITE,
+        &mWriteWatcher,
+        this);
+      return;
+    }
+    mOutgoingQ.RemoveElementAt(0);
+    delete data;
+  }
 }
 
-int
-CloseSocket(int aFd)
+bool
+UnixSocketConsumer::ConnectSocket(UnixSocketConnector& aConnector,
+                                  const char* aAddress)
 {
-  // This can block since we aren't opening sockets O_NONBLOCK
   MOZ_ASSERT(!NS_IsMainThread());
-  return close(aFd);
+  MOZ_ASSERT(!mImpl);
+  ScopedClose fd(aConnector.Create());
+  if (fd < 0) {
+    return false;
+  }
+  if (!aConnector.Connect(fd, aAddress)) {
+    return false;
+  }
+  mImpl = new UnixSocketImpl(this, fd.forget());
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                   new StartImplReadingTask(mImpl));
+  return true;
 }
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/unixsocket/UnixSocket.h
+++ b/ipc/unixsocket/UnixSocket.h
@@ -1,22 +1,170 @@
 /* -*- 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_ipc_Socket_h
-#define mozilla_ipc_Socket_h
+#ifndef mozilla_ipc_UnixSocket_h
+#define mozilla_ipc_UnixSocket_h
+
+#include <stdlib.h>
+#include "nsString.h"
+#include "nsAutoPtr.h"
+#include "mozilla/RefPtr.h"
 
 namespace mozilla {
 namespace ipc {
 
-int
-GetNewSocket(int type, const char* aAddress, int channel, bool auth, bool encrypt);
+struct UnixSocketRawData
+{
+  static const size_t MAX_DATA_SIZE = 1024;
+  uint8_t mData[MAX_DATA_SIZE];
+
+  // Number of octets in mData.
+  size_t mSize;
+  size_t mCurrentWriteOffset;
+
+  /** 
+   * Constructor for situations where size is not known beforehand. (for
+   * example, when reading a packet)
+   *
+   */
+  UnixSocketRawData() :
+    mSize(0),
+    mCurrentWriteOffset(0)
+  {
+  }
+
+  /** 
+   * Constructor for situations where size is known beforehand (for example,
+   * when being assigned strings)
+   *
+   */
+  UnixSocketRawData(int aSize) :
+    mSize(aSize),
+    mCurrentWriteOffset(0)
+  {
+  }
+
+};
+
+class UnixSocketImpl;
+
+/** 
+ * UnixSocketConnector defines the socket creation and connection/listening
+ * functions for a UnixSocketConsumer. Due to the fact that socket setup can
+ * vary between protocols (unix sockets, tcp sockets, bluetooth sockets, etc),
+ * this allows the user to create whatever connection mechanism they need while
+ * still depending on libevent for non-blocking communication handling.
+ *
+ * FIXME/Bug 793980: Currently only virtual, since we only support bluetooth.
+ * Should make connection functions for other unix sockets so we can support
+ * things like RIL.
+ */
+class UnixSocketConnector
+{
+public:
+  UnixSocketConnector()
+  {}
+
+  virtual ~UnixSocketConnector()
+  {}
+
+  /** 
+   * Establishs a file descriptor for a socket.
+   *
+   * @return File descriptor for socket
+   */
+  virtual int Create() = 0;
 
-int
-CloseSocket(int aFd);
+  /** 
+   * Runs connect function on a file descriptor for the address specified. Makes
+   * sure socket is marked with flags expected by the UnixSocket handler
+   * (non-block, etc...)
+   *
+   * @param aFd File descriptor created by Create() function
+   * @param aAddress Address to connect to
+   *
+   * @return true if connected, false otherwise
+   */
+  bool Connect(int aFd, const char* aAddress);
+  
+protected:
+  /** 
+   * Internal type-specific connection function to be overridden by child
+   * classes.
+   *
+   * @param aFd File descriptor created by Create() function
+   * @param aAddress Address to connect to
+   *
+   * @return true if connected, false otherwise
+   */
+  virtual bool ConnectInternal(int aFd, const char* aAddress) = 0;
+};
+
+class UnixSocketConsumer : public RefCounted<UnixSocketConsumer>
+{
+public:
+  UnixSocketConsumer()
+    : mImpl(nullptr)
+  {}
+
+  virtual ~UnixSocketConsumer();
+  
+  /** 
+   * Function to be called whenever data is received. This is only called on the
+   * main thread.
+   *
+   * @param aMessage Data received from the socket.
+   */
+  virtual void ReceiveSocketData(UnixSocketRawData* aMessage) = 0;
+
+  /** 
+   * 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(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);
+
+  /** 
+   * Connects to a socket. Due to the fact that this is a blocking connect (and
+   * for things such as bluetooth, it /will/ block), it is expected to be run on
+   * a thread provided by the user. It cannot run on the main thread. Runs the
+   * Create() and Connect() functions in the UnixSocketConnector.
+   *
+   * @param aConnector Connector object for socket type specific functions
+   * @param aAddress Address to connect to.
+   *
+   * @return true on connection, false otherwise.
+   */
+  bool ConnectSocket(UnixSocketConnector& aConnector, const char* aAddress);
+
+  /** 
+   * Queues the internal representation of socket for deletion. Can be called
+   * from main thread.
+   *
+   */
+  void CloseSocket();
+
+private:
+  nsAutoPtr<UnixSocketImpl> mImpl;
+};
 
 } // namespace ipc
 } // namepsace mozilla
 
 #endif // mozilla_ipc_Socket_h
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -106,17 +106,17 @@ STATIC_LIBS += \
   dombindings_s \
   $(NULL)
 
 ifdef MOZ_B2G_RIL #{
 STATIC_LIBS += mozril_s
 endif #}
 
 ifdef MOZ_B2G_BT #{
-STATIC_LIBS += mozdbus_s mozipcsocket_s
+STATIC_LIBS += mozdbus_s mozipcunixsocket_s
 endif #}
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 STATIC_LIBS += moznetd_s
 endif
 
 ifdef MOZ_IPDL_TESTS
 STATIC_LIBS += ipdlunittest_s