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 108184 4489b74f83994c5d8d8bea9e2b71594cc7193b8a
parent 108183 b4abff203299239af4134efc6f298d7ec03c4403
child 108185 f4e6abb6160f644546f14533640e81d3c54fc24d
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewerscjones, echou
bugs776182
milestone18.0a1
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