Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 29 Jul 2013 17:27:08 -0400
changeset 140387 3d40d270c031f188eb2fdc6ee4b22cefb1f789f1
parent 140386 398c7364058619c1de658f6581d630d861d93131 (current diff)
parent 140372 5065fdc124082ebe40091abdf6648ce67c340656 (diff)
child 140388 8911e64ad234b3519e2aa52b4144db67631b0ea9
child 140389 933bd505fe4a516dcfc1779728d1fa59fe119bd1
child 140459 93ba277cb5c449e57ff63467f4fe344ffe16b051
child 155608 646de1d68ccb42b5512d65c58e36687a31b72bf1
push id25028
push userryanvm@gmail.com
push dateMon, 29 Jul 2013 22:42:06 +0000
treeherdermozilla-central@3d40d270c031 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
3d40d270c031 / 25.0a1 / 20130730030204 / files
nightly linux64
3d40d270c031 / 25.0a1 / 20130730030204 / files
nightly mac
3d40d270c031 / 25.0a1 / 20130730030204 / files
nightly win32
3d40d270c031 / 25.0a1 / 20130730030204 / files
nightly win64
3d40d270c031 / 25.0a1 / 20130730030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team.
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "30af13f2784172ca635db0a5a72494c180c7f885", 
+    "revision": "74877b52dcb397d6de83b682ac5d374cc6d508be", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -522,16 +522,17 @@
 @BINPATH@/components/Activities.manifest
 @BINPATH@/components/ActivityOptions.js
 @BINPATH@/components/ActivityProxy.js
 @BINPATH@/components/ActivityRequestHandler.js
 @BINPATH@/components/ActivityWrapper.js
 @BINPATH@/components/ActivityMessageConfigurator.js
 
 @BINPATH@/components/TCPSocket.js
+@BINPATH@/components/TCPServerSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.js
 @BINPATH@/components/TCPSocket.manifest
 
 @BINPATH@/components/AppProtocolHandler.js
 @BINPATH@/components/AppProtocolHandler.manifest
 
 @BINPATH@/components/Payment.js
 @BINPATH@/components/PaymentFlowInfo.js
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -522,16 +522,17 @@
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 @BINPATH@/components/AlarmsManager.js
 @BINPATH@/components/AlarmsManager.manifest
 @BINPATH@/components/Push.js
 @BINPATH@/components/Push.manifest
 @BINPATH@/components/PushServiceLauncher.js
 @BINPATH@/components/TCPSocket.js
+@BINPATH@/components/TCPServerSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.js
 @BINPATH@/components/TCPSocket.manifest
 
 @BINPATH@/components/AppProtocolHandler.js
 @BINPATH@/components/AppProtocolHandler.manifest
 
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/PeerConnection.js
--- a/dom/mobilemessage/src/gonk/MmsService.js
+++ b/dom/mobilemessage/src/gonk/MmsService.js
@@ -282,16 +282,21 @@ XPCOMUtils.defineLazyGetter(this, "gMmsC
      * Update the MMS proxy info.
      */
     updateProxyInfo: function updateProxyInfo() {
       if (this.proxy === null || this.port === null) {
         if (DEBUG) debug("updateProxyInfo: proxy or port is not yet decided." );
         return;
       }
 
+      if (!this.port) {
+        this.port = 80;
+        if (DEBUG) debug("updateProxyInfo: port is 0. Set to defult port 80.");
+      }
+
       this.proxyInfo =
         gpps.newProxyInfo("http", this.proxy, this.port,
                           Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST,
                           -1, null);
       if (DEBUG) debug("updateProxyInfo: " + JSON.stringify(this.proxyInfo));
     },
 
     /**
--- a/dom/network/interfaces/moz.build
+++ b/dom/network/interfaces/moz.build
@@ -2,19 +2,22 @@
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIDOMConnection.idl',
     'nsIDOMDataErrorEvent.idl',
+    'nsIDOMTCPServerSocket.idl',
     'nsIDOMTCPSocket.idl',
     'nsIDOMUSSDReceivedEvent.idl',
     'nsIMozNavigatorNetwork.idl',
+    'nsITCPServerSocketChild.idl',
+    'nsITCPServerSocketParent.idl',
     'nsITCPSocketChild.idl',
     'nsITCPSocketParent.idl',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIDOMCFStateChangeEvent.idl',
         'nsIDOMMobileConnection.idl',
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsIDOMTCPServerSocket.idl
@@ -0,0 +1,92 @@
+/* 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 "domstubs.idl"
+#include "nsITCPSocketChild.idl"
+
+// Bug 797561 - Expose a server tcp socket API to web applications
+/**
+ * nsIDOMTCPServerSocket
+ *
+ * An interface to a server socket that can accept incoming connections for gaia apps.
+ */
+[scriptable, uuid(821638a1-5327-416d-8031-668764f2ec04)]
+interface nsIDOMTCPServerSocket : nsISupports
+{
+  /**
+   * The port of this server socket object.
+   */
+  readonly attribute unsigned short localPort;
+
+  /**
+   * The onconnect event handler is called when a client connection is accepted.
+   * The data attribute of the event passed to the onconnect handler will be a TCPSocket
+   * instance, which is used for communication between client and server. 
+   */
+  attribute jsval onconnect;
+
+  /**
+   * The onerror handler will be called when the listen of a server socket is aborted.
+   * The data attribute of the event passed to the onerror handler will have a
+   * description of the kind of error.
+   */
+  attribute jsval onerror;
+
+  /**
+   * Close the server socket.
+   */
+  void close();
+};
+
+/**
+ * Internal interfaces for use in cross-process server-socket implementation.
+ * Needed to account for multiple possible types that can be provided to
+ * the socket callbacks as arguments.
+ *
+ * These interfaces are for calling each method from the server socket object
+ * on the parent and child side for an IPC protocol implementation.
+ */
+
+[scriptable, uuid(b64b1e68-4efa-497c-b0d8-69f067ad5ec8)]
+interface nsITCPServerSocketInternal : nsISupports 
+{
+  /**
+   * Initialization after creating a TCP server socket object.
+   *
+   * @param windowVal
+   *        An object to create ArrayBuffer for this window. See Bug 831107.
+   */
+  void init(in jsval windowVal);
+
+  /** 
+   * Listen on a port
+   *
+   * @param localPort 
+   *        The port of the server socket. Pass -1 to indicate no preference,
+   *        and a port will be selected automatically.
+   * @param options 
+   *        An object specifying one or more parameters which
+   *        determine the details of the socket.
+   *
+   *        binaryType: "arraybuffer" to use UInt8 array
+   *        instances in the ondata callback and as the argument
+   *        to send. Defaults to "string", to use JavaScript strings.
+   * @param backlog 
+   *        The maximum length the queue of pending connections may grow to.
+   *        This parameter may be silently limited by the operating system.
+   *        Pass -1 to use the default value.
+   */
+  void listen(in unsigned short localPort, in jsval options, in unsigned short backlog);
+
+  /**
+   * Listener for receiving an accepted socket.
+   */
+  void callListenerAccept(in nsITCPSocketChild socketChild);
+
+  /**
+   * Listener for handling an error caused in chrome process.
+   */
+  void callListenerError(in DOMString message, in DOMString filename,
+                         in uint32_t lineNumber, in uint32_t columnNumber);
+};
--- a/dom/network/interfaces/nsIDOMTCPSocket.idl
+++ b/dom/network/interfaces/nsIDOMTCPSocket.idl
@@ -1,36 +1,43 @@
 /* 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/. */
 
 /**
- * MozTCPSocket exposes a TCP client socket (no server sockets yet)
+ * MozTCPSocket exposes a TCP client and server sockets
  * to highly privileged apps. It provides a buffered, non-blocking
  * interface for sending. For receiving, it uses an asynchronous,
  * event handler based interface.
  */
 
 #include "domstubs.idl"
 #include "nsIDOMEvent.idl"
+#include "nsITCPSocketChild.idl"
+#include "nsIDOMTCPServerSocket.idl"
+
+interface nsISocketTransport;
 
 // Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
 // nsITCPSocket should be an nsIEventTarget but js objects
 // cannot be an nsIEventTarget yet
 // #include "nsIEventTarget.idl"
 
 // Bug 723206 - Constructors implemented in JS from IDL should be
 //              allowed to have arguments
 //
 //  Once bug 723206 will be fixed, this method could be replaced by
 //  arguments when instantiating a TCPSocket object. For example it will
 //  be possible to do (similarly to the WebSocket API):
 //    var s = new MozTCPSocket(host, port); 
 
-[scriptable, uuid(1f99bc6f-73d3-44db-9dbf-5fc441704a7c)]
+// Bug 797561 - Expose a server tcp socket API to web applications
+
+
+[scriptable, uuid(b7803a0b-4492-45ec-ac7a-3e29f6445fa4)]
 interface nsIDOMTCPSocket : nsISupports
 {
   /**
    * Create and return a socket object which will attempt to connect to
    * the given host and port.
    *
    * @param host The hostname of the server to connect to.
    * @param port The port to connect to.
@@ -43,16 +50,36 @@ interface nsIDOMTCPSocket : nsISupports
    *          instances in the ondata callback and as the argument
    *          to send. Defaults to "string", to use JavaScript strings.
    *
    * @return The new TCPSocket instance.
    */
   nsIDOMTCPSocket open(in DOMString host, in unsigned short port, [optional] in jsval options);
 
   /**
+   * Listen on a port
+   *
+   * @param localPort The port of the server socket. Pass -1 to indicate no preference,
+   *                  and a port will be selected automatically.
+   * @param options An object specifying one or more parameters which
+   *                determine the details of the socket.
+   *
+   *        binaryType: "arraybuffer" to use ArrayBuffer
+   *          instances in the ondata callback and as the argument
+   *          to send. Defaults to "string", to use JavaScript strings.
+   * @param backlog The maximum length the queue of pending connections may grow to.
+   *                This parameter may be silently limited by the operating system.
+   *                Pass -1 to use the default value.
+   *
+   * @return The new TCPServerSocket instance.
+   */
+  nsIDOMTCPServerSocket listen(in unsigned short localPort, [optional] in jsval options,
+                               [optional] in unsigned short backlog);
+
+  /**
    * The host of this socket object.
    */
   readonly attribute DOMString host;
 
   /**
    * The port of this socket object.
    */
   readonly attribute unsigned short port;
@@ -178,32 +205,57 @@ interface nsIDOMTCPSocket : nsISupports
   attribute jsval onclose;
 };
 
 /*
  * Internal interfaces for use in cross-process socket implementation.
  * Needed to account for multiple possible types that can be provided to
  * the socket callbacks as arguments.
  */
-[scriptable, uuid(322193a3-da17-4ca5-ad26-3539c519ea4b)]
+[scriptable, uuid(0baa1be1-6a88-4f85-a6c8-29e95f35c122)]
 interface nsITCPSocketInternal : nsISupports {
   // Trigger the callback for |type| and provide a DOMError() object with the given data
   void callListenerError(in DOMString type, in DOMString name);
 
   // Trigger the callback for |type| and provide a string argument
   void callListenerData(in DOMString type, in DOMString data);
 
   // Trigger the callback for |type| and provide an ArrayBuffer argument
   void callListenerArrayBuffer(in DOMString type, in jsval data);
 
   // Trigger the callback for |type| with no argument
   void callListenerVoid(in DOMString type);
 
   // Update the DOM object's readyState and bufferedAmount values with the provided data
   void updateReadyStateAndBuffered(in DOMString readyState, in uint32_t bufferedAmount);
+
+  // Create a socket object on the parent side.
+  // This is called in accepting any open request on the parent side.
+  // 
+  // @param transport
+  //        The accepted socket transport.
+  // @param binaryType
+  //        "arraybuffer" to use ArrayBuffer instances 
+  //        in the ondata callback and as the argument to send.
+  nsIDOMTCPSocket createAcceptedParent(in nsISocketTransport transport,
+                                       in DOMString binaryType);
+
+  // Create a DOM socket on the child side
+  // This is called when the socket is accepted on the parent side.
+  // 
+  // @param socketChild
+  //        The socket child object for the IPC implementation.
+  // @param binaryType
+  //        "arraybuffer" to use ArrayBuffer instances 
+  //        in the ondata callback and as the argument to send.
+  // @param window
+  //        An object to create ArrayBuffer for this window. See Bug 831107.
+  nsIDOMTCPSocket createAcceptedChild(in nsITCPSocketChild socketChild,
+                                      in DOMString binaryType, 
+                                      in nsIDOMWindow window);
 };
 
 /**
  * nsITCPSocketEvent is the event object which is passed as the
  * first argument to all the event handler callbacks. It contains
  * the socket that was associated with the event, the type of event,
  * and the data associated with the event (if any).
  */
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsITCPServerSocketChild.idl
@@ -0,0 +1,39 @@
+/* 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 "domstubs.idl"
+#include "nsIDOMTCPServerSocket.idl"
+
+interface nsITCPServerSocketInternal;
+
+/**
+ * Interface to allow the content process server socket to reach the IPC bridge.
+ * It is used in the server socket implementation on the child side.
+ */
+
+[scriptable, uuid(41a77ec8-fd86-409e-aea9-af2ca407ef8e)]
+interface nsITCPServerSocketChild : nsISupports
+{
+  /**
+   * Tell the chrome process to listen on the port with the given parameters.
+   *
+   * @param serverSocket
+   *        The server socket generated in the listen of nsIDOMTCPSocket
+   *        on the child side.
+   * @param port
+   *        The port of the server socket.
+   * @param backlog 
+   *        The maximum length the queue of pending connections may grow to.
+   * @param binaryType
+   *        "arraybuffer" to use UInt8 array instances or "string" to use String.
+   */
+  [implicit_jscontext]
+  void listen(in nsITCPServerSocketInternal serverSocket, in unsigned short port,
+              in unsigned short backlog, in DOMString binaryType);
+
+  /**
+   * Tell the chrome process to close the server socket.
+   */
+  void close();
+};
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsITCPServerSocketParent.idl
@@ -0,0 +1,42 @@
+/* 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 "domstubs.idl"
+#include "nsITCPSocketParent.idl"
+
+interface nsIDOMTCPServerSocket;
+
+/** 
+ * Interface required to allow the TCP server-socket object in the parent process
+ * to talk to the parent IPC actor.
+ * It is used in the server socket implementation on the parent side.
+ */
+[scriptable, uuid(161ffc9f-54d3-4f21-a536-4166003d0e1d)]
+interface nsITCPServerSocketParent : nsISupports
+{
+  /**
+   * Trigger a callback in the content process when the socket accepts any request.
+   *
+   * @param socket
+   *        The socket generated in accepting any open request on the parent side.
+   */
+  void sendCallbackAccept(in nsITCPSocketParent socket);
+
+  /**
+   * Trigger a callback in the content process when an error occurs.
+   *
+   * @param message
+   *        The error message.
+   * @param filename
+   *        The file name in which the error occured.
+   * @param lineNumber
+   *        The line number in which the error occured.
+   * @param columnNumber
+   *        The column number in which the error occured.
+   */
+  void sendCallbackError(in DOMString message,
+                         in DOMString filename,
+                         in uint32_t lineNumber,
+                         in uint32_t columnNumber);
+};
--- a/dom/network/interfaces/nsITCPSocketChild.idl
+++ b/dom/network/interfaces/nsITCPSocketChild.idl
@@ -3,23 +3,40 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsITCPSocketInternal;
 interface nsIDOMWindow;
 
 // Interface to allow the content process socket to reach the IPC bridge.
-[scriptable, uuid(bdc91763-e9a1-4122-9c2f-8f17505c8c7a)]
+[scriptable, uuid(edf07a93-36a6-4574-8e23-40f64ab5f596)]
 interface nsITCPSocketChild : nsISupports
 {
   // Tell the chrome process to open a corresponding connection with the given parameters
   [implicit_jscontext]
   void open(in nsITCPSocketInternal socket, in DOMString host,
             in unsigned short port, in boolean ssl, in DOMString binaryType,
-            in nsIDOMWindow window, in jsval socketVal);
+            in nsIDOMWindow window, in jsval windowVal);
 
   // Tell the chrome process to perform equivalent operations to all following methods
-  [implicit_jscontext] void send(in jsval data, in unsigned long byteOffset, in unsigned long byteLength);
+  [implicit_jscontext] 
+  void send(in jsval data, in unsigned long byteOffset, in unsigned long byteLength);
   void resume();
   void suspend();
   void close();
+
+  /**
+   * Initialize the TCP socket on the child side for IPC. It is called from the child side,
+   * which is generated in receiving a notification of accepting any open request
+   * on the parent side. We use single implementation that works on a child process 
+   * as well as in the single process model.
+   *
+   * @param socket
+   *        The TCP socket on the child side.
+   *        This instance is connected with the child IPC side of the IPC bridge.
+   * @param windowVal
+   *        The window object on the child side to create data
+   *        as "jsval" for deserialization.
+   */
+  [implicit_jscontext]
+  void setSocketAndWindow(in nsITCPSocketInternal socket, in jsval windowVal);
 };
--- a/dom/network/interfaces/nsITCPSocketParent.idl
+++ b/dom/network/interfaces/nsITCPSocketParent.idl
@@ -1,39 +1,58 @@
 /* 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 "domstubs.idl"
 
 interface nsIDOMTCPSocket;
+interface nsIDOMTCPServerSocket;
+interface nsITCPServerSocketParent;
+interface nsITCPSocketIntermediary;
 
 // Interface required to allow the TCP socket object in the parent process
 // to talk to the parent IPC actor
-[scriptable, uuid(4e7246c6-a8b3-426d-9c17-76dab1e1e14a)]
+[scriptable, uuid(123f654b-4435-43c8-8447-db1b5420a1c2)]
 interface nsITCPSocketParent : nsISupports
 {
   [implicit_jscontext] void initJS(in jsval intermediary);
 
   // Trigger a callback in the content process for |type|, providing a serialized
   // argument of |data|, and update the child's readyState and bufferedAmount values
   // with the given values.
   [implicit_jscontext] void sendCallback(in DOMString type,
                                          in jsval data,
                                          in DOMString readyState,
                                          in uint32_t bufferedAmount);
+
+  // Initialize a parent socket object. It is called from the parent side socket,
+  // which is generated in accepting any open request on the parent side.
+  // The socket after being initialized will be established.
+  //
+  // @param socket
+  //        The socket on the parent side.
+  // @param intermediary
+  //        Intermediate class object. See nsITCPSocketIntermediary.
+  [implicit_jscontext] void setSocketAndIntermediary(in nsIDOMTCPSocket socket,
+                                                     in nsITCPSocketIntermediary intermediary);
 };
 
 // Intermediate class to handle sending multiple possible data types
 // and kicking off the chrome process socket object's connection.
-[scriptable, uuid(afa42841-a6cb-4a91-912f-93099f6a3d18)]
+[scriptable, uuid(38bec1ed-b863-40dd-ba69-7bd92e568ee3)]
 interface nsITCPSocketIntermediary : nsISupports {
   // Open the connection to the server with the given parameters
   nsIDOMTCPSocket open(in nsITCPSocketParent parent,
                        in DOMString host, in unsigned short port,
                        in boolean useSSL, in DOMString binaryType);
 
+  // Listen on a port
+  nsIDOMTCPServerSocket listen(in nsITCPServerSocketParent parent,
+                               in unsigned short port, in unsigned short backlog,
+                               in DOMString binaryType);
+
   // Send a basic string along the connection
   void sendString(in DOMString data);
 
   // Send a typed array
   void sendArrayBuffer(in jsval data);
 };
new file mode 100644
--- /dev/null
+++ b/dom/network/src/PTCPServerSocket.ipdl
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* 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 protocol PNecko;
+include protocol PTCPSocket;
+
+include "mozilla/net/NeckoMessageUtils.h";
+
+namespace mozilla {
+namespace net {
+
+//-------------------------------------------------------------------
+protocol PTCPServerSocket
+{
+  manager PNecko;
+
+parent:
+  Close();
+  RequestDelete();
+
+child:
+  CallbackAccept(PTCPSocket socket);
+  CallbackError(nsString message, nsString filename,
+                uint32_t lineNumber, uint32_t columnNumber);
+  __delete__();
+};
+
+} // namespace net
+} // namespace mozilla
+
--- a/dom/network/src/PTCPSocket.ipdl
+++ b/dom/network/src/PTCPSocket.ipdl
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
 
 /* 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 protocol PNecko;
+include protocol PBrowser;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
 using mozilla::void_t;
 
 struct TCPError {
   nsString name;
 };
@@ -30,24 +31,28 @@ namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PTCPSocket
 {
   manager PNecko;
 
 parent:
+  Open(nsString host, uint16_t port, bool useSSL, nsString binaryType,
+       nullable PBrowser browser);
   Data(SendableData data);
   Suspend();
   Resume();
   Close();
-  RequestDelete();
 
 child:
   Callback(nsString type, CallbackData data,
            nsString readyState, uint32_t bufferedAmount);
+
+both:
+  RequestDelete();
   __delete__();
 };
 
 
 } // namespace net
 } // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/dom/network/src/TCPServerSocket.js
@@ -0,0 +1,182 @@
+/* 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/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+const CC = Components.Constructor;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const ServerSocket = CC(
+        '@mozilla.org/network/server-socket;1', 'nsIServerSocket', 'init'),
+      TCPSocketInternal = Cc[
+        '@mozilla.org/tcp-socket;1'].createInstance(Ci.nsITCPSocketInternal);
+
+/*
+ * Debug logging function
+ */
+
+let debug = true;
+function LOG(msg) {
+  if (debug) {
+    dump("TCPServerSocket: " + msg + "\n");
+  }
+}
+
+/*
+ * nsIDOMTCPServerSocket object
+ */
+
+function TCPServerSocket() {
+  this._localPort = 0;
+  this._binaryType = null;
+
+  this._onconnect = null;
+  this._onerror = null;
+
+  this._inChild = false;
+  this._neckoTCPServerSocket = null;
+  this._serverBridge = null;
+  this.useWin = null;
+}
+
+TCPServerSocket.prototype = {
+  __exposedProps__: {
+    port: 'r',
+    onconnect: 'rw',
+    onerror: 'rw'
+  },
+  get localPort() {
+    return this._localPort;
+  },
+  get onconnect() {
+    return this._onconnect;
+  },
+  set onconnect(f) {
+    this._onconnect = f;
+  },
+  get onerror() {
+    return this._onerror;
+  },
+  set onerror(f) {
+    this._onerror = f;
+  },
+
+  _callListenerAcceptCommon: function tss_callListenerAcceptCommon(socket) {
+    if (this._onconnect) {
+      try {
+        this["onconnect"].call(null, socket);
+      } catch (e) {
+        socket.close();
+      }      
+    }
+    else {
+      socket.close();
+      dump("Received unexpected connection!");
+    }
+  },
+  init: function tss_init(aWindowObj) {
+    this.useWin = aWindowObj;
+  },
+
+  /* nsITCPServerSocketInternal method */
+  listen: function tss_listen(localPort, options, backlog) {
+    this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+                       .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+    this._binaryType = options.binaryType;
+
+    if (this._inChild) {
+      if (this._serverBridge == null) {
+        this._serverBridge = Cc["@mozilla.org/tcp-server-socket-child;1"]
+                                .createInstance(Ci.nsITCPServerSocketChild);
+        this._serverBridge.listen(this, localPort, backlog, options.binaryType);
+      }
+      else {
+        throw new Error("Child TCPServerSocket has already listening. \n");
+      }
+    }
+    else {
+      if (this._neckoTCPServerSocket == null) {
+        this._neckoTCPServerSocket = new ServerSocket(localPort, false, backlog);
+        this._localPort = this._neckoTCPServerSocket.port;
+        this._neckoTCPServerSocket.asyncListen(this);
+      }
+      else {
+        throw new Error("Parent TCPServerSocket has already listening. \n");
+      }
+    }
+  },
+
+  callListenerAccept: function tss_callListenerSocket(socketChild) {
+    // this method is called at child process when the socket is accepted at parent process.
+    let socket = TCPSocketInternal.createAcceptedChild(socketChild, this._binaryType, this.useWin);
+    this._callListenerAcceptCommon(socket);
+  },
+
+  callListenerError: function tss_callListenerError(message, filename, lineNumber, columnNumber) {
+    if (this._onerror) {
+      var type = "error";
+      var error = new Error(message, filename, lineNumber, columnNumber);
+
+      this["onerror"].call(null, new TCPSocketEvent(type, this, error));
+    }    
+  },
+  /* end nsITCPServerSocketInternal method */
+
+  close: function tss_close() {
+    if (this._inChild) {
+      this._serverBridge.close();
+      return;
+    }
+
+    /* Close ServerSocket */
+    if (this._neckoTCPServerSocket) {
+      this._neckoTCPServerSocket.close();
+    }
+  },
+
+  // nsIServerSocketListener (Triggered by _neckoTCPServerSocket.asyncListen)
+  onSocketAccepted: function tss_onSocketAccepted(server, trans) {
+    // precondition: this._inChild == false
+    try {
+      let that = TCPSocketInternal.createAcceptedParent(trans, this._binaryType);
+      this._callListenerAcceptCommon(that);
+    }
+    catch(e) {
+      trans.close(Cr.NS_BINDING_ABORTED);
+    }
+  },
+
+  // nsIServerSocketListener (Triggered by _neckoTCPServerSocket.asyncListen)
+  onStopListening: function tss_onStopListening(server, status) {
+    if (status != Cr.NS_BINDING_ABORTED) {
+      throw new Error("Server socket was closed by unexpected reason.");
+    }
+    this._neckoTCPServerSocket = null;
+  },
+
+  classID: Components.ID("{73065eae-27dc-11e2-895a-000c29987aa2}"),
+
+  classInfo: XPCOMUtils.generateCI({
+    classID: Components.ID("{73065eae-27dc-11e2-895a-000c29987aa2}"),
+    classDescription: "Server TCP Socket",
+    interfaces: [
+      Ci.nsIDOMTCPServerSocket,
+      Ci.nsISupportsWeakReference
+    ],
+    flags: Ci.nsIClassInfo.DOM_OBJECT,
+  }),
+
+  QueryInterface: XPCOMUtils.generateQI([
+    Ci.nsIDOMTCPServerSocket,
+    Ci.nsITCPServerSocketInternal,
+    Ci.nsISupportsWeakReference
+  ])
+}
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TCPServerSocket]);
new file mode 100644
--- /dev/null
+++ b/dom/network/src/TCPServerSocketChild.cpp
@@ -0,0 +1,117 @@
+/* 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 "TCPServerSocketChild.h"
+#include "TCPSocketChild.h"
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/TabChild.h"
+#include "nsIDOMTCPSocket.h"
+#include "nsJSUtils.h"
+#include "nsContentUtils.h"
+#include "jsapi.h"
+#include "jsfriendapi.h"
+
+using mozilla::net::gNeckoChild;
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_1(TCPServerSocketChildBase, mServerSocket)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketChildBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketChildBase)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketChildBase)
+  NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketChild)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+TCPServerSocketChildBase::TCPServerSocketChildBase()
+: mIPCOpen(false)
+{
+}
+
+TCPServerSocketChildBase::~TCPServerSocketChildBase()
+{
+}
+
+NS_IMETHODIMP_(nsrefcnt) TCPServerSocketChild::Release(void)
+{
+  nsrefcnt refcnt = TCPServerSocketChildBase::Release();
+  if (refcnt == 1 && mIPCOpen) {
+    PTCPServerSocketChild::SendRequestDelete();
+    return 1;
+  }
+  return refcnt;
+}
+
+TCPServerSocketChild::TCPServerSocketChild()
+{
+}
+
+NS_IMETHODIMP
+TCPServerSocketChild::Listen(nsITCPServerSocketInternal* aServerSocket, uint16_t aLocalPort,
+                             uint16_t aBacklog, const nsAString & aBinaryType, JSContext* aCx)
+{
+  mServerSocket = aServerSocket;
+  AddIPDLReference();
+  gNeckoChild->SendPTCPServerSocketConstructor(this, aLocalPort, aBacklog, nsString(aBinaryType));
+  return NS_OK;
+}
+
+void
+TCPServerSocketChildBase::ReleaseIPDLReference()
+{
+  MOZ_ASSERT(mIPCOpen);
+  mIPCOpen = false;
+  this->Release();
+}
+
+void
+TCPServerSocketChildBase::AddIPDLReference()
+{
+  MOZ_ASSERT(!mIPCOpen);
+  mIPCOpen = true;
+  this->AddRef();
+}
+
+TCPServerSocketChild::~TCPServerSocketChild()
+{
+}
+
+bool
+TCPServerSocketChild::RecvCallbackAccept(PTCPSocketChild *psocket)
+{
+  TCPSocketChild* socket = static_cast<TCPSocketChild*>(psocket);
+
+  nsresult rv = mServerSocket->CallListenerAccept(static_cast<nsITCPSocketChild*>(socket));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("CallListenerAccept threw exception.");
+  }
+  return true;
+}
+
+bool
+TCPServerSocketChild::RecvCallbackError(const nsString& aMessage,
+                                        const nsString& aFilename,
+                                        const uint32_t& aLineNumber,
+                                        const uint32_t& aColumnNumber)
+{
+  nsresult rv = mServerSocket->CallListenerError(aMessage, aFilename,
+                                                 aLineNumber, aColumnNumber);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("CallListenerError threw exception.");
+  }
+  return true;
+}
+
+NS_IMETHODIMP
+TCPServerSocketChild::Close()
+{
+  SendClose();
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/TCPServerSocketChild.h
@@ -0,0 +1,54 @@
+/* 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 "mozilla/net/PTCPServerSocketChild.h"
+#include "nsITCPServerSocketChild.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+
+#define TCPSERVERSOCKETCHILD_CID \
+  { 0x41a77ec8, 0xfd86, 0x409e, { 0xae, 0xa9, 0xaf, 0x2c, 0xa4, 0x07, 0xef, 0x8e } }
+
+class nsITCPServerSocketInternal;
+struct JSContext;
+struct JSObject;
+
+namespace mozilla {
+namespace dom {
+
+class TCPServerSocketChildBase : public nsITCPServerSocketChild {
+public:
+  NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketChildBase)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+protected:
+  TCPServerSocketChildBase();
+  virtual ~TCPServerSocketChildBase();
+
+  nsCOMPtr<nsITCPServerSocketInternal> mServerSocket;
+  bool mIPCOpen;
+};
+
+class TCPServerSocketChild : public mozilla::net::PTCPServerSocketChild
+                           , public TCPServerSocketChildBase
+{
+public:
+  NS_DECL_NSITCPSERVERSOCKETCHILD
+  NS_IMETHOD_(nsrefcnt) Release() MOZ_OVERRIDE;
+
+  TCPServerSocketChild();
+  ~TCPServerSocketChild();
+
+  virtual bool RecvCallbackAccept(PTCPSocketChild *socket)  MOZ_OVERRIDE;
+  virtual bool RecvCallbackError(const nsString& aMessage,
+                                 const nsString& aFilename,
+                                 const uint32_t& aLineNumber,
+                                 const uint32_t& aColumnNumber) MOZ_OVERRIDE;
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/TCPServerSocketParent.cpp
@@ -0,0 +1,132 @@
+/* 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 "TCPServerSocketParent.h"
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "nsJSUtils.h"
+#include "TCPSocketParent.h"
+#include "mozilla/unused.h"
+#include "mozilla/AppProcessChecker.h"
+
+namespace mozilla {
+namespace dom {
+
+static void
+FireInteralError(mozilla::net::PTCPServerSocketParent* aActor,
+                 uint32_t aLineNo)
+{
+  mozilla::unused <<
+      aActor->SendCallbackError(NS_LITERAL_STRING("Internal error"),
+                          NS_LITERAL_STRING(__FILE__), aLineNo, 0);
+}
+
+NS_IMPL_CYCLE_COLLECTION_2(TCPServerSocketParent, mServerSocket, mIntermediary)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketParent)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketParent)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketParent)
+  NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketParent)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+void
+TCPServerSocketParent::ReleaseIPDLReference()
+{
+  MOZ_ASSERT(mIPCOpen);
+  mIPCOpen = false;
+  this->Release();
+}
+
+void
+TCPServerSocketParent::AddIPDLReference()
+{
+  MOZ_ASSERT(!mIPCOpen);
+  mIPCOpen = true;
+  this->AddRef();
+}
+
+bool
+TCPServerSocketParent::Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort,
+                            const uint16_t& aBacklog, const nsString& aBinaryType)
+{
+  mNeckoParent = neckoParent;
+
+  nsresult rv;
+  mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
+  if (NS_FAILED(rv)) {
+    FireInteralError(this, __LINE__);
+    return true;
+  }
+
+  rv = mIntermediary->Listen(this, aLocalPort, aBacklog, aBinaryType, getter_AddRefs(mServerSocket));
+  if (NS_FAILED(rv) || !mServerSocket) {
+    FireInteralError(this, __LINE__);
+    return true;
+  }
+  return true;
+}
+
+NS_IMETHODIMP
+TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
+{
+  TCPSocketParent* _socket = static_cast<TCPSocketParent*>(socket);
+  PTCPSocketParent* _psocket = static_cast<PTCPSocketParent*>(_socket);
+
+  _socket->AddIPDLReference();
+
+  if (mNeckoParent) {
+    if (mNeckoParent->SendPTCPSocketConstructor(_psocket)) {
+      mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(_psocket);
+    }
+    else {
+      NS_ERROR("Sending data from PTCPSocketParent was failed.");
+    };
+  }
+  else {
+    NS_ERROR("The member value for NeckoParent is wrong.");
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPServerSocketParent::SendCallbackError(const nsAString& message,
+                                         const nsAString& filename,
+                                         uint32_t lineNumber,
+                                         uint32_t columnNumber)
+{
+  mozilla::unused <<
+    PTCPServerSocketParent::SendCallbackError(nsString(message), nsString(filename),
+                                              lineNumber, columnNumber);
+  return NS_OK;
+}
+
+bool
+TCPServerSocketParent::RecvClose()
+{
+  NS_ENSURE_TRUE(mServerSocket, true);
+  mServerSocket->Close();
+  return true;
+}
+
+void
+TCPServerSocketParent::ActorDestroy(ActorDestroyReason why)
+{
+  if (mServerSocket) {
+    mServerSocket->Close();
+    mServerSocket = nullptr;
+  }
+  mNeckoParent = nullptr;
+  mIntermediary = nullptr;
+}
+
+bool
+TCPServerSocketParent::RecvRequestDelete()
+{
+  mozilla::unused << Send__delete__(this);
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/TCPServerSocketParent.h
@@ -0,0 +1,50 @@
+/* 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 "mozilla/net/PNeckoParent.h"
+#include "mozilla/net/PTCPServerSocketParent.h"
+#include "nsITCPSocketParent.h"
+#include "nsITCPServerSocketParent.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMTCPSocket.h"
+
+struct JSContext;
+struct JSObject;
+
+namespace mozilla {
+namespace dom {
+
+class PBrowserParent;
+
+class TCPServerSocketParent : public mozilla::net::PTCPServerSocketParent
+                            , public nsITCPServerSocketParent
+{
+public:
+  NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketParent)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSITCPSERVERSOCKETPARENT
+
+  TCPServerSocketParent() : mNeckoParent(nullptr), mIPCOpen(false) {}
+
+  bool Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort, const uint16_t& aBacklog,
+            const nsString& aBinaryType);
+
+  virtual bool RecvClose() MOZ_OVERRIDE;
+  virtual bool RecvRequestDelete() MOZ_OVERRIDE;
+
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+private:
+  virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
+
+  PNeckoParent* mNeckoParent;
+  nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
+  nsCOMPtr<nsIDOMTCPServerSocket> mServerSocket;
+  bool mIPCOpen;
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/network/src/TCPSocket.js
+++ b/dom/network/src/TCPSocket.js
@@ -22,16 +22,18 @@ const InputStreamPump = CC(
       BinaryInputStream = CC(
         "@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream", "setInputStream"),
       StringInputStream = CC(
         '@mozilla.org/io/string-input-stream;1', 'nsIStringInputStream'),
       ArrayBufferInputStream = CC(
         '@mozilla.org/io/arraybuffer-input-stream;1', 'nsIArrayBufferInputStream'),
       MultiplexInputStream = CC(
         '@mozilla.org/io/multiplex-input-stream;1', 'nsIMultiplexInputStream');
+const TCPServerSocket = CC(
+        "@mozilla.org/tcp-server-socket;1", "nsITCPServerSocketInternal", "init");
 
 const kCONNECTING = 'connecting';
 const kOPEN = 'open';
 const kCLOSING = 'closing';
 const kCLOSED = 'closed';
 
 const BUFFER_SIZE = 65536;
 
@@ -112,16 +114,17 @@ TCPSocket.prototype = {
     ssl: 'r',
     bufferedAmount: 'r',
     suspend: 'r',
     resume: 'r',
     close: 'r',
     send: 'r',
     readyState: 'r',
     binaryType: 'r',
+    listen: 'r',
     onopen: 'rw',
     ondrain: 'rw',
     ondata: 'rw',
     onerror: 'rw',
     onclose: 'rw'
   },
   // The binary type, "string" or "arraybuffer"
   _binaryType: null,
@@ -252,16 +255,46 @@ TCPSocket.prototype = {
             self._socketOutputStream.close();
             self._readyState = kCLOSED;
             self.callListener("close");
           }
         }
       }
     }, null);
   },
+  
+  _initStream: function ts_initStream(binaryType) {
+    this._binaryType = binaryType;
+    this._socketInputStream = this._transport.openInputStream(0, 0, 0);
+    this._socketOutputStream = this._transport.openOutputStream(
+      Ci.nsITransport.OPEN_UNBUFFERED, 0, 0);
+
+    // If the other side is not listening, we will
+    // get an onInputStreamReady callback where available
+    // raises to indicate the connection was refused.
+    this._socketInputStream.asyncWait(
+      this, this._socketInputStream.WAIT_CLOSURE_ONLY, 0, Services.tm.currentThread);
+
+    if (this._binaryType === "arraybuffer") {
+      this._inputStreamBinary = new BinaryInputStream(this._socketInputStream);
+    } else {
+      this._inputStreamScriptable = new ScriptableInputStream(this._socketInputStream);
+    }
+
+    this._multiplexStream = new MultiplexInputStream();
+
+    this._multiplexStreamCopier = new AsyncStreamCopier(
+      this._multiplexStream,
+      this._socketOutputStream,
+      // (nsSocketTransport uses gSocketTransportService)
+      Cc["@mozilla.org/network/socket-transport-service;1"]
+        .getService(Ci.nsIEventTarget),
+      /* source buffered */ true, /* sink buffered */ false,
+      BUFFER_SIZE, /* close source*/ false, /* close sink */ false);
+  },
 
   callListener: function ts_callListener(type, data) {
     if (!this["on" + type])
       return;
 
     this["on" + type].call(null, new TCPSocketEvent(type, this, data || ""));
   },
 
@@ -283,16 +316,42 @@ TCPSocket.prototype = {
   callListenerVoid: function ts_callListenerVoid(type) {
     this.callListener(type);
   },
 
   updateReadyStateAndBuffered: function ts_setReadyState(readyState, bufferedAmount) {
     this._readyState = readyState;
     this._bufferedAmount = bufferedAmount;
   },
+
+  createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) {
+    let that = new TCPSocket();
+    that._transport = transport;
+    that._initStream(binaryType);
+
+    // ReadyState is kOpen since accepted transport stream has already been connected
+    that._readyState = kOPEN;
+    that._inputStreamPump = new InputStreamPump(that._socketInputStream, -1, -1, 0, 0, false);
+    that._inputStreamPump.asyncRead(that, null);
+
+    return that;
+  },
+
+  createAcceptedChild: function ts_createAcceptedChild(socketChild, binaryType, windowObject) {
+    let that = new TCPSocket();
+
+    that._binaryType = binaryType;
+    that._inChild = true;
+    that._readyState = kOPEN;
+    socketChild.setSocketAndWindow(that, windowObject);
+    that._socketBridge = socketChild;
+
+    return that;
+  },
+
   /* end nsITCPSocketInternal methods */
 
   initWindowless: function ts_initWindowless() {
     return Services.prefs.getBoolPref("dom.mozTCPSocket.enabled");
   },
 
   init: function ts_init(aWindow) {
     if (!this.initWindowless())
@@ -385,44 +444,35 @@ TCPSocket.prototype = {
                              .createInstance(Ci.nsITCPSocketChild);
       that._socketBridge.open(that, host, port, !!that._ssl,
                               that._binaryType, this.useWin, this.useWin || this);
       return that;
     }
 
     let transport = that._transport = this._createTransport(host, port, that._ssl);
     transport.setEventSink(that, Services.tm.currentThread);
-
-    that._socketInputStream = transport.openInputStream(0, 0, 0);
-    that._socketOutputStream = transport.openOutputStream(
-      Ci.nsITransport.OPEN_UNBUFFERED, 0, 0);
+    that._initStream(that._binaryType);
+    return that;
+  },
+  
+  listen: function ts_listen(localPort, options, backlog) {
+    if (!this.initWindowless())
+      return null;
 
-    // If the other side is not listening, we will
-    // get an onInputStreamReady callback where available
-    // raises to indicate the connection was refused.
-    that._socketInputStream.asyncWait(
-      that, that._socketInputStream.WAIT_CLOSURE_ONLY, 0, Services.tm.currentThread);
-
-    if (that._binaryType === "arraybuffer") {
-      that._inputStreamBinary = new BinaryInputStream(that._socketInputStream);
-    } else {
-      that._inputStreamScriptable = new ScriptableInputStream(that._socketInputStream);
+    // in the testing case, init won't be called and
+    // hasPrivileges will be null. We want to proceed to test.
+    if (this._hasPrivileges !== true && this._hasPrivileges !== null) {
+      throw new Error("TCPSocket does not have permission in this context.\n");
     }
 
-    that._multiplexStream = new MultiplexInputStream();
+    let that = new TCPServerSocket(this.useWin || this);
 
-    that._multiplexStreamCopier = new AsyncStreamCopier(
-      that._multiplexStream,
-      that._socketOutputStream,
-      // (nsSocketTransport uses gSocketTransportService)
-      Cc["@mozilla.org/network/socket-transport-service;1"]
-        .getService(Ci.nsIEventTarget),
-      /* source buffered */ true, /* sink buffered */ false,
-      BUFFER_SIZE, /* close source*/ false, /* close sink */ false);
-
+    options = options || { binaryType : this.binaryType };
+    backlog = backlog || -1;
+    that.listen(localPort, options, backlog);
     return that;
   },
 
   close: function ts_close() {
     if (this._readyState === kCLOSED || this._readyState === kCLOSING)
       return;
 
     LOG("close called");
--- a/dom/network/src/TCPSocket.manifest
+++ b/dom/network/src/TCPSocket.manifest
@@ -1,8 +1,12 @@
 # TCPSocket.js
 component {cda91b22-6472-11e1-aa11-834fec09cd0a} TCPSocket.js
 contract @mozilla.org/tcp-socket;1 {cda91b22-6472-11e1-aa11-834fec09cd0a}
 category JavaScript-navigator-property mozTCPSocket @mozilla.org/tcp-socket;1
 
 # TCPSocketParentIntermediary.js
 component {afa42841-a6cb-4a91-912f-93099f6a3d18} TCPSocketParentIntermediary.js
 contract @mozilla.org/tcp-socket-intermediary;1 {afa42841-a6cb-4a91-912f-93099f6a3d18}
+
+# TCPServerSocket.js
+component {73065eae-27dc-11e2-895a-000c29987aa2} TCPServerSocket.js
+contract @mozilla.org/tcp-server-socket;1 {73065eae-27dc-11e2-895a-000c29987aa2}
--- a/dom/network/src/TCPSocketChild.cpp
+++ b/dom/network/src/TCPSocketChild.cpp
@@ -1,13 +1,15 @@
 /* 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 <algorithm>
 #include "TCPSocketChild.h"
+#include "mozilla/unused.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "nsIDOMTCPSocket.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
@@ -65,36 +67,37 @@ NS_IMETHODIMP_(nsrefcnt) TCPSocketChild:
   if (refcnt == 1 && mIPCOpen) {
     PTCPSocketChild::SendRequestDelete();
     return 1;
   }
   return refcnt;
 }
 
 TCPSocketChild::TCPSocketChild()
-: mSocketObj(nullptr)
+: mWindowObj(nullptr)
 {
 }
 
 NS_IMETHODIMP
 TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
                      uint16_t aPort, bool aUseSSL, const nsAString& aBinaryType,
-                     nsIDOMWindow* aWindow, const JS::Value& aSocketObj,
+                     nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
                      JSContext* aCx)
 {
   mSocket = aSocket;
-  MOZ_ASSERT(aSocketObj.isObject());
-  mSocketObj = js::CheckedUnwrap(&aSocketObj.toObject());
-  if (!mSocketObj) {
+
+  MOZ_ASSERT(aWindowObj.isObject());
+  mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
+  if (!mWindowObj) {
     return NS_ERROR_FAILURE;
   }
   AddIPDLReference();
-  gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort,
-                                         aUseSSL, nsString(aBinaryType),
-                                         GetTabChildFrom(aWindow));
+  gNeckoChild->SendPTCPSocketConstructor(this);
+  SendOpen(nsString(aHost), aPort, aUseSSL, nsString(aBinaryType),
+           GetTabChildFrom(aWindow));
   return NS_OK;
 }
 
 void
 TCPSocketChildBase::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
@@ -131,18 +134,18 @@ TCPSocketChild::RecvCallback(const nsStr
     rv = mSocket->CallListenerError(aType, err.name());
 
   } else if (aData.type() == CallbackData::TSendableData) {
     const SendableData& data = aData.get_SendableData();
 
     if (data.type() == SendableData::TArrayOfuint8_t) {
       JSContext* cx = nsContentUtils::GetSafeJSContext();
       JS::Rooted<JS::Value> val(cx);
-      JS::Rooted<JSObject*> socket(cx, mSocketObj);
-      bool ok = IPC::DeserializeArrayBuffer(socket, data.get_ArrayOfuint8_t(), &val);
+      JS::Rooted<JSObject*> window(cx, mWindowObj);
+      bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val);
       NS_ENSURE_TRUE(ok, true);
       rv = mSocket->CallListenerArrayBuffer(aType, val);
 
     } else if (data.type() == SendableData::TnsString) {
       rv = mSocket->CallListenerData(aType, data.get_nsString());
 
     } else {
       MOZ_CRASH("Invalid callback data type!");
@@ -206,10 +209,31 @@ TCPSocketChild::Send(const JS::Value& aD
     }
     InfallibleTArray<uint8_t> arr;
     arr.SwapElements(fallibleArr);
     SendData(arr);
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
+                          const JS::Value& aWindowObj,
+                          JSContext* aCx)
+{
+  mSocket = aSocket;
+  MOZ_ASSERT(aWindowObj.isObject());
+  mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
+  if (!mWindowObj) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+bool
+TCPSocketChild::RecvRequestDelete()
+{
+  mozilla::unused << Send__delete__(this);
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/TCPSocketChild.h
+++ b/dom/network/src/TCPSocketChild.h
@@ -42,14 +42,15 @@ public:
 
   TCPSocketChild();
   ~TCPSocketChild();
 
   virtual bool RecvCallback(const nsString& aType,
                             const CallbackData& aData,
                             const nsString& aReadyState,
                             const uint32_t& aBuffered) MOZ_OVERRIDE;
+  virtual bool RecvRequestDelete() MOZ_OVERRIDE;
 private:
-  JSObject* mSocketObj;
+  JSObject* mWindowObj;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/TCPSocketParent.cpp
+++ b/dom/network/src/TCPSocketParent.cpp
@@ -29,29 +29,71 @@ static void
 FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
 {
   mozilla::unused <<
       aActor->SendCallback(NS_LITERAL_STRING("onerror"),
                            TCPError(NS_LITERAL_STRING("InvalidStateError")),
                            NS_LITERAL_STRING("connecting"), 0);
 }
 
-NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParent, mSocket, mIntermediary)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParent)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParent)
+NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParentBase, mSocket, mIntermediary)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParent)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
   NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
+TCPSocketParentBase::TCPSocketParentBase()
+: mIPCOpen(false)
+{
+}
+
+TCPSocketParentBase::~TCPSocketParentBase()
+{
+}
+
+void
+TCPSocketParentBase::ReleaseIPDLReference()
+{
+  MOZ_ASSERT(mIPCOpen);
+  mIPCOpen = false;
+  this->Release();
+}
+
+void
+TCPSocketParentBase::AddIPDLReference()
+{
+  MOZ_ASSERT(!mIPCOpen);
+  mIPCOpen = true;
+  this->AddRef();
+}
+
+NS_IMETHODIMP_(nsrefcnt) TCPSocketParent::Release(void)
+{
+  nsrefcnt refcnt = TCPSocketParentBase::Release();
+  if (refcnt == 1 && mIPCOpen) {
+    mozilla::unused << PTCPSocketParent::SendRequestDelete();
+    return 1;
+  }
+  return refcnt;
+}
+
 bool
-TCPSocketParent::Init(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
-                      const nsString& aBinaryType)
+TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
+                          const nsString& aBinaryType, PBrowserParent* aBrowser)
 {
+  // We don't have browser actors in xpcshell, and hence can't run automated
+  // tests without this loophole.
+  if (aBrowser && !AssertAppProcessPermission(aBrowser, "tcp-socket")) {
+    FireInteralError(this, __LINE__);
+    return true;
+  }
+
   nsresult rv;
   mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
   if (NS_FAILED(rv)) {
     FireInteralError(this, __LINE__);
     return true;
   }
 
   rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, getter_AddRefs(mSocket));
@@ -187,21 +229,29 @@ TCPSocketParent::SendCallback(const nsAS
     return NS_ERROR_FAILURE;
   }
   mozilla::unused <<
       PTCPSocketParent::SendCallback(nsString(aType), data,
                                      nsString(aReadyState), aBuffered);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
+                                          nsITCPSocketIntermediary *intermediary,
+                                          JSContext* cx)
+{
+  mSocket = socket;
+  mIntermediary = intermediary;
+  return NS_OK;
+}
+
 void
 TCPSocketParent::ActorDestroy(ActorDestroyReason why)
 {
-  MOZ_ASSERT(mIPCOpen);
-  mIPCOpen = false;
   if (mSocket) {
     mSocket->Close();
   }
   mSocket = nullptr;
   mIntermediaryObj = nullptr;
   mIntermediary = nullptr;
 }
 
--- a/dom/network/src/TCPSocketParent.h
+++ b/dom/network/src/TCPSocketParent.h
@@ -6,43 +6,61 @@
 #include "nsITCPSocketParent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMTCPSocket.h"
 
 struct JSContext;
 class JSObject;
 
+#define TCPSOCKETPARENT_CID \
+  { 0x4e7246c6, 0xa8b3, 0x426d, { 0x9c, 0x17, 0x76, 0xda, 0xb1, 0xe1, 0xe1, 0x4a } }
+
 namespace mozilla {
 namespace dom {
 
 class PBrowserParent;
 
-class TCPSocketParent : public mozilla::net::PTCPSocketParent
-                      , public nsITCPSocketParent
+class TCPSocketParentBase : public nsITCPSocketParent
 {
 public:
-  NS_DECL_CYCLE_COLLECTION_CLASS(TCPSocketParent)
+  NS_DECL_CYCLE_COLLECTION_CLASS(TCPSocketParentBase)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSITCPSOCKETPARENT
+
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+protected:
+  TCPSocketParentBase();
+  virtual ~TCPSocketParentBase();
 
-  TCPSocketParent() : mIntermediaryObj(nullptr), mIPCOpen(true) {}
+  nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
+  nsCOMPtr<nsIDOMTCPSocket> mSocket;
+  bool mIPCOpen;
+};
 
-  bool Init(const nsString& aHost, const uint16_t& aPort,
-            const bool& useSSL, const nsString& aBinaryType);
+class TCPSocketParent : public mozilla::net::PTCPSocketParent
+                      , public TCPSocketParentBase
+{
+public:
+  NS_DECL_NSITCPSOCKETPARENT
+  NS_IMETHOD_(nsrefcnt) Release() MOZ_OVERRIDE;
+
+  TCPSocketParent() : mIntermediaryObj(nullptr) {}
+
+  virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort,
+                        const bool& useSSL, const nsString& aBinaryType,
+                        PBrowserParent* aBrowser);
 
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvClose() MOZ_OVERRIDE;
   virtual bool RecvData(const SendableData& aData) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
-  nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
-  nsCOMPtr<nsIDOMTCPSocket> mSocket;
   JSObject* mIntermediaryObj;
-  bool mIPCOpen;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/TCPSocketParentIntermediary.js
+++ b/dom/network/src/TCPSocketParentIntermediary.js
@@ -9,40 +9,76 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function TCPSocketParentIntermediary() {
 }
 
 TCPSocketParentIntermediary.prototype = {
-  open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) {
+  _setCallbacks: function(aParentSide, socket) {
     aParentSide.initJS(this);
-
-    let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
-    let socket = this._socket = baseSocket.open(aHost, aPort,
-                                                {useSSL: aUseSSL,
-                                                binaryType: aBinaryType});
-    if (!socket)
-      return null;
+    this._socket = socket;
 
     // Create handlers for every possible callback that attempt to trigger
     // corresponding callbacks on the child object.
     ["open", "drain", "data", "error", "close"].forEach(
       function(p) {
         socket["on" + p] = function(data) {
           aParentSide.sendCallback(p, data.data, socket.readyState,
                                    socket.bufferedAmount);
         };
       }
     );
+ },
 
+  open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) {
+    let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
+    let socket = baseSocket.open(aHost, aPort, {useSSL: aUseSSL, binaryType: aBinaryType});
+    if (!socket)
+      return null;
+
+    // Handlers are set to the JS-implemented socket object on the parent side.
+    this._setCallbacks(aParentSide, socket);
     return socket;
   },
 
+  listen: function(aTCPServerSocketParent, aLocalPort, aBacklog, aBinaryType) {
+    let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
+    let serverSocket = baseSocket.listen(aLocalPort, { binaryType: aBinaryType }, aBacklog);
+    if (!serverSocket)
+      return null;
+
+    let localPort = serverSocket.localPort;
+
+    serverSocket["onconnect"] = function(socket) {
+      var socketParent = Cc["@mozilla.org/tcp-socket-parent;1"]
+                            .createInstance(Ci.nsITCPSocketParent);
+      var intermediary = new TCPSocketParentIntermediary();
+      // Handlers are set to the JS-implemented socket object on the parent side,
+      // so that the socket parent object can communicate data
+      // with the corresponding socket child object through IPC.
+      intermediary._setCallbacks(socketParent, socket);
+      // The members in the socket parent object are set with arguments,
+      // so that the socket parent object can communicate data 
+      // with the JS socket object on the parent side via the intermediary object.
+      socketParent.setSocketAndIntermediary(socket, intermediary);
+      aTCPServerSocketParent.sendCallbackAccept(socketParent);
+    };
+
+    serverSocket["onerror"] = function(data) {
+        var error = data.data;
+
+        aTCPServerSocketParent.sendCallbackError(error.message, error.filename,
+                                                 error.lineNumber, error.columnNumber);
+    };
+
+    return serverSocket;
+  },
+
   sendString: function(aData) {
     return this._socket.send(aData);
   },
 
   sendArrayBuffer: function(aData) {
     return this._socket.send(aData, 0, aData.byteLength);
   },
 
--- a/dom/network/src/moz.build
+++ b/dom/network/src/moz.build
@@ -1,43 +1,49 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom.network += [
     'Constants.h',
+    'TCPServerSocketChild.h',
+    'TCPServerSocketParent.h',
     'TCPSocketChild.h',
     'TCPSocketParent.h',
     'Types.h',
 ]
 
 CPP_SOURCES += [
     'Connection.cpp',
+    'TCPServerSocketChild.cpp',
+    'TCPServerSocketParent.cpp',
     'TCPSocketChild.cpp',
     'TCPSocketParent.cpp',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     CPP_SOURCES += [
         'MobileConnection.cpp',
     ]
     EXTRA_JS_MODULES = [
         'NetworkStatsDB.jsm',
         'NetworkStatsService.jsm',
     ]
 
 EXTRA_COMPONENTS += [
+    'TCPServerSocket.js',
     'TCPSocket.js',
     'TCPSocket.manifest',
     'TCPSocketParentIntermediary.js',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     EXTRA_COMPONENTS += [
         'NetworkStatsManager.js',
         'NetworkStatsManager.manifest',
     ]
 
 IPDL_SOURCES += [
+    'PTCPServerSocket.ipdl',
     'PTCPSocket.ipdl',
 ]
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/unit/test_tcpserversocket.js
@@ -0,0 +1,312 @@
+/**
+ * Test TCPSocket.js by creating an XPCOM-style server socket, then sending
+ * data in both directions and making sure each side receives their data
+ * correctly and with the proper events.
+ *
+ * This test is derived from netwerk/test/unit/test_socks.js, except we don't
+ * involve a subprocess.
+ *
+ * Future work:
+ * - SSL.  see https://bugzilla.mozilla.org/show_bug.cgi?id=466524
+ *             https://bugzilla.mozilla.org/show_bug.cgi?id=662180
+ *   Alternatively, mochitests could be used.
+ * - Testing overflow logic.
+ *
+ **/
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+const CC = Components.Constructor;
+
+/**
+ *
+ * Constants
+ *
+ */
+
+// Test parameter.
+const PORT = 8085;
+const BACKLOG = -1;
+
+// Some binary data to send.
+const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0],
+      DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length),
+      TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER),
+      HELLO_WORLD = "hlo wrld. ",
+      BIG_ARRAY = new Array(65539);
+
+TYPED_DATA_ARRAY.set(DATA_ARRAY, 0);
+
+for (var i_big = 0; i_big < BIG_ARRAY.length; i_big++) {
+  BIG_ARRAY[i_big] = Math.floor(Math.random() * 256);
+}
+
+const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
+const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
+BIG_TYPED_ARRAY.set(BIG_ARRAY);
+
+const TCPSocket = new (CC("@mozilla.org/tcp-socket;1",
+                     "nsIDOMTCPSocket"))();
+
+const gInChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+                  .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+/**
+ *
+ * Helper functions
+ *
+ */
+
+
+function makeSuccessCase(name) {
+  return function() {
+    do_print('got expected: ' + name);
+    run_next_test();
+  };
+}
+
+function makeJointSuccess(names) {
+  let funcs = {}, successCount = 0;
+  names.forEach(function(name) {
+    funcs[name] = function() {
+      do_print('got expected: ' + name);
+      if (++successCount === names.length)
+        run_next_test();
+    };
+  });
+  return funcs;
+}
+
+function makeFailureCase(name) {
+  return function() {
+    let argstr;
+    if (arguments.length) {
+      argstr = '(args: ' +
+        Array.map(arguments, function(x) { return x.data + ""; }).join(" ") + ')';
+    }
+    else {
+      argstr = '(no arguments)';
+    }
+    do_throw('got unexpected: ' + name + ' ' + argstr);
+  };
+}
+
+function makeExpectData(name, expectedData, fromEvent, callback) {
+  let dataBuffer = fromEvent ? null : [], done = false;
+  let dataBufferView = null;
+  return function(receivedData) {
+    if (receivedData.data) {
+      receivedData = receivedData.data;
+    }
+    let recvLength = receivedData.byteLength !== undefined ?
+        receivedData.byteLength : receivedData.length;
+
+    if (fromEvent) {
+      if (dataBuffer) {
+        let newBuffer = new ArrayBuffer(dataBuffer.byteLength + recvLength);
+        let newBufferView = new Uint8Array(newBuffer);
+        newBufferView.set(dataBufferView, 0);
+        newBufferView.set(receivedData, dataBuffer.byteLength);
+        dataBuffer = newBuffer;
+        dataBufferView = newBufferView;
+      }
+      else {
+        dataBuffer = receivedData;
+        dataBufferView = new Uint8Array(dataBuffer);
+      }
+    }
+    else {
+      dataBuffer = dataBuffer.concat(receivedData);
+    }
+    do_print(name + ' received ' + recvLength + ' bytes');
+
+    if (done)
+      do_throw(name + ' Received data event when already done!');
+
+    let dataView = dataBuffer.byteLength !== undefined ? new Uint8Array(dataBuffer) : dataBuffer;
+    if (dataView.length >= expectedData.length) {
+      // check the bytes are equivalent
+      for (let i = 0; i < expectedData.length; i++) {
+        if (dataView[i] !== expectedData[i]) {
+          do_throw(name + ' Received mismatched character at position ' + i);
+        }
+      }
+      if (dataView.length > expectedData.length)
+        do_throw(name + ' Received ' + dataView.length + ' bytes but only expected ' +
+                 expectedData.length + ' bytes.');
+
+      done = true;
+      if (callback) {
+        callback();
+      } else {
+        run_next_test();
+      }
+    }
+  };
+}
+
+var server = null, sock = null, connectedsock = null, failure_drain = null;
+var count = 0;
+/**
+ *
+ * Test functions
+ *
+ */
+
+/**
+ * Connect the socket to the server. This test is added as the first
+ * test, and is also added after every test which results in the socket
+ * being closed.
+ */
+
+function connectSock() {
+  if (server) {
+    server.close();
+  }
+
+  var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
+  var options = { binaryType: 'arraybuffer' };
+
+  server = TCPSocket.listen(PORT, options, BACKLOG);
+  server.onconnect = function(socket) {
+    connectedsock = socket;
+    connectedsock.ondata = makeFailureCase('serverdata');
+    connectedsock.onerror = makeFailureCase('servererror');
+    connectedsock.onclose = makeFailureCase('serverclose');
+    yayFuncs.serveropen();
+  };
+  server.onerror = makeFailureCase('error');
+  sock = TCPSocket.open(
+    '127.0.0.1', PORT, options);
+  sock.onopen = yayFuncs.clientopen;
+  sock.ondrain = null;
+  sock.ondata = makeFailureCase('data');
+  sock.onerror = makeFailureCase('error');
+  sock.onclose = makeFailureCase('close');  
+}
+
+/**
+ * Connect the socket to the server after the server was closed.
+ * This test is added after test to close the server was conducted.
+ */
+function openSockInClosingServer() {
+  var success = makeSuccessCase('clientnotopen');
+  var options = { binaryType: 'arraybuffer' };
+  
+  sock = TCPSocket.open(
+    '127.0.0.1', PORT, options);
+
+  sock.onopen = makeFailureCase('open');
+  sock.onerror = success();
+}
+
+/**
+ * Test that sending a small amount of data works, and that buffering
+ * does not take place for this small amount of data.
+ */
+
+function sendDataToServer() {
+  connectedsock.ondata = makeExpectData('serverdata', DATA_ARRAY, true);
+  if (!sock.send(DATA_ARRAY_BUFFER)) {
+    do_throw("send should not have buffered such a small amount of data");
+  }
+}
+
+/**
+ * Test that data sent from the server correctly fires the ondata
+ * callback on the client side.
+ */
+
+function receiveDataFromServer() {
+  connectedsock.ondata = makeFailureCase('serverdata');
+  sock.ondata = makeExpectData('data', DATA_ARRAY, true);
+
+  connectedsock.send(DATA_ARRAY_BUFFER);
+}
+
+/**
+ * Test that when the server closes the connection, the onclose callback
+ * is fired on the client side.
+ */
+
+function serverCloses() {
+  // we don't really care about the server's close event, but we do want to
+  // make sure it happened for sequencing purposes.
+  sock.ondata = makeFailureCase('data');
+  sock.onclose = makeFailureCase('close1');
+  connectedsock.onclose = makeFailureCase('close2');
+
+  server.close();
+  run_next_test();
+}
+
+/**
+ * Test that when the client closes the connection, the onclose callback
+ * is fired on the server side.
+ */
+
+function cleanup() {
+  do_print("Cleaning up");
+  sock.onclose = null;
+  connectedsock.onclose = null;
+
+  server.close();
+  sock.close();
+  if (count == 1){
+    if (!gInChild)
+      Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
+  }
+  count++;
+  run_next_test();
+}
+// - connect, data and events work both ways
+add_test(connectSock);
+
+add_test(sendDataToServer);
+
+add_test(receiveDataFromServer);
+// - server closes on us
+add_test(serverCloses);
+
+// - send and receive after closing server
+add_test(sendDataToServer);
+add_test(receiveDataFromServer);
+// - check a connection refused from client to server after closing server
+add_test(serverCloses);
+
+add_test(openSockInClosingServer);
+
+// - clean up
+add_test(cleanup);
+
+// - send and receive in reverse order for client and server
+add_test(connectSock);
+
+add_test(receiveDataFromServer);
+
+add_test(sendDataToServer);
+
+// - clean up
+
+add_test(cleanup);
+
+function run_test() {
+  if (!gInChild)
+    Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
+
+  run_next_test();
+
+  do_timeout(10000, function() {
+    if (server) {
+      server.close();
+    }
+
+    do_throw(
+      "The test should never take this long unless the system is hosed.");
+  });
+}
--- a/dom/network/tests/unit/test_tcpsocket.js
+++ b/dom/network/tests/unit/test_tcpsocket.js
@@ -83,17 +83,17 @@ function TestServer() {
   do_print('server: listening on', this.listener.port);
   this.listener.asyncListen(this);
 
   this.binaryInput = null;
   this.input = null;
   this.binaryOutput = null;
   this.output = null;
 
-  this.onaccept = null;
+  this.onconnect = null;
   this.ondata = null;
   this.onclose = null;
 }
 
 TestServer.prototype = {
   onSocketAccepted: function(socket, trans) {
     if (this.input)
       do_throw("More than one live connection!?");
@@ -101,18 +101,18 @@ TestServer.prototype = {
     do_print('server: got client connection');
     this.input = trans.openInputStream(0, 0, 0);
     this.binaryInput = new BinaryInputStream(this.input);
     this.output = trans.openOutputStream(0, 0, 0);
     this.binaryOutput = new BinaryOutputStream(this.output);
 
     new InputStreamPump(this.input, -1, -1, 0, 0, false).asyncRead(this, null);
 
-    if (this.onaccept)
-      this.onaccept();
+    if (this.onconnect)
+      this.onconnect();
     else
       do_throw("Received unexpected connection!");
   },
 
   onStopListening: function(socket) {
   },
 
   onDataAvailable: function(request, context, inputStream, offset, count) {
@@ -269,17 +269,17 @@ function connectSock() {
     { binaryType: 'arraybuffer' });
 
   sock.onopen = yayFuncs.clientopen;
   sock.ondrain = null;
   sock.ondata = makeFailureCase('data');
   sock.onerror = makeFailureCase('error');
   sock.onclose = makeFailureCase('close');
 
-  server.onaccept = yayFuncs.serveropen;
+  server.onconnect = yayFuncs.serveropen;
   server.ondata = makeFailureCase('serverdata');
   server.onclose = makeFailureCase('serverclose');
 }
 
 /**
  * Test that sending a small amount of data works, and that buffering
  * does not take place for this small amount of data.
  */
--- a/dom/network/tests/unit/xpcshell.ini
+++ b/dom/network/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head =
 tail =
 
 [test_tcpsocket.js]
-[test_multisend.js]
\ No newline at end of file
+[test_multisend.js]
+[test_tcpserversocket.js]
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/unit_ipc/test_tcpserversocket_ipc.js
@@ -0,0 +1,9 @@
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function run_test() {
+  Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
+  run_test_in_child("../unit/test_tcpserversocket.js", function() {
+    Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
+    do_test_finished();
+  });
+}
--- a/dom/network/tests/unit_ipc/xpcshell.ini
+++ b/dom/network/tests/unit_ipc/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head =
 tail =
 
 [test_tcpsocket_ipc.js]
+[test_tcpserversocket_ipc.js]
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -25,21 +25,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 this.EXPORTED_SYMBOLS = ["PushService"];
 
 const prefs = new Preferences("services.push.");
 
 const kPUSHDB_DB_NAME = "push";
 const kPUSHDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
 const kPUSHDB_STORE_NAME = "push";
-const kCONFLICT_RETRY_ATTEMPTS = 3; // If channelID registration says 409, how
-                                    // many times to retry with a new channelID
-
-const kERROR_CHID_CONFLICT = 409;   // Error code sent by push server if this
-                                    // channel already exists on the server.
 
 const kUDP_WAKEUP_WS_STATUS_CODE = 4774;  // WebSocket Close status code sent
                                           // by server to signal that it can
                                           // wake client up using UDP.
 
 const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
                                  "Push:Registrations"];
 
@@ -1141,32 +1136,20 @@ this.PushService = {
   },
 
   /**
    * Exceptions thrown in _onRegisterError are caught by the promise obtained
    * from _sendRequest, causing the promise to be rejected instead.
    */
   _onRegisterError: function(aPageRecord, aMessageManager, reply) {
     debug("_onRegisterError()");
-    switch (reply.status) {
-      case kERROR_CHID_CONFLICT:
-        if (typeof aPageRecord._attempts !== "number")
-          aPageRecord._attempts = 0;
 
-        if (aPageRecord._attempts < kCONFLICT_RETRY_ATTEMPTS) {
-          aPageRecord._attempts++;
-          // Since register is async, it's OK to launch it in a callback.
-          debug("CONFLICT: trying again");
-          this.register(aPageRecord, aMessageManager);
-          return;
-        }
-        throw { requestID: aPageRecord.requestID, error: "conflict" };
-      default:
-        debug("General failure " + reply.status);
-        throw { requestID: aPageRecord.requestID, error: reply.error };
+    if (reply.status) {
+      debug("General failure " + reply.status);
+      throw { requestID: aPageRecord.requestID, error: reply.error };    
     }
   },
 
   /**
    * Called on message from the child process.
    *
    * Why is the record being deleted from the local database before the server
    * is told?
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -571,20 +571,23 @@ this.ICC_STATUS_ERROR_WRONG_LENGTH = 0x6
 this.ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED = 0x69;
 this.ICC_STATUS_ERROR_WRONG_PARAMETERS = 0x6a;
 
 // ICC call barring facility.
 // TS 27.007, clause 7.4, +CLCK
 this.ICC_CB_FACILITY_SIM = "SC";
 this.ICC_CB_FACILITY_FDN = "FD";
 this.ICC_CB_FACILITY_BAOC = "AO";
-this.ICC_CB_FACILITY_BOIC = "OI";
-this.ICC_CB_FACILITY_BOIC_EX_HC = "OX";
+this.ICC_CB_FACILITY_BAOIC = "OI";
+this.ICC_CB_FACILITY_BAOICxH = "OX";
 this.ICC_CB_FACILITY_BAIC = "AI";
-this.ICC_CB_FACILITY_BIC_ROAM = "IR";
+this.ICC_CB_FACILITY_BAICr = "IR";
+this.ICC_CB_FACILITY_BA_ALL = "AB";
+this.ICC_CB_FACILITY_BA_MO = "AG";
+this.ICC_CB_FACILITY_BA_MT = "AC";
 
 // ICC service class
 // TS 27.007, clause 7.4, +CLCK
 this.ICC_SERVICE_CLASS_NONE = 0; // no user input
 this.ICC_SERVICE_CLASS_VOICE = (1 << 0);
 this.ICC_SERVICE_CLASS_DATA = (1 << 1);
 this.ICC_SERVICE_CLASS_FAX = (1 << 2);
 this.ICC_SERVICE_CLASS_SMS = (1 << 3);
@@ -2503,20 +2506,20 @@ this.CALL_FORWARD_REASON_ALL_CONDITIONAL
 this.CALL_BARRING_PROGRAM_ALL_OUTGOING = 0;
 this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL = 1;
 this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME = 2;
 this.CALL_BARRING_PROGRAM_ALL_INCOMING = 3;
 this.CALL_BARRING_PROGRAM_INCOMING_ROAMING = 4;
 
 this.CALL_BARRING_PROGRAM_TO_FACILITY = {};
 CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_OUTGOING] = ICC_CB_FACILITY_BAOC;
-CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL] = ICC_CB_FACILITY_BOIC;
-CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME] = ICC_CB_FACILITY_BOIC_EX_HC;
+CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL] = ICC_CB_FACILITY_BAOIC;
+CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME] = ICC_CB_FACILITY_BAOICxH;
 CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_INCOMING] = ICC_CB_FACILITY_BAIC;
-CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_ROAMING] = ICC_CB_FACILITY_BIC_ROAM;
+CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_ROAMING] = ICC_CB_FACILITY_BAICr;
 
 // CLIR constants. Must be in sync with nsIDOMMozMobileConnection interface
 this.CLIR_DEFAULT = 0;
 this.CLIR_INVOCATION  = 1;
 this.CLIR_SUPPRESSION = 2;
 
 // MMI procedure as defined in TS.22.030 6.5.2
 this.MMI_PROCEDURE_ACTIVATION = "*";
@@ -2570,16 +2573,27 @@ this.MMI_SC_BAOC = "33";
 this.MMI_SC_BAOIC = "331";
 this.MMI_SC_BAOICxH = "332";
 this.MMI_SC_BAIC = "35";
 this.MMI_SC_BAICr = "351";
 this.MMI_SC_BA_ALL = "330";
 this.MMI_SC_BA_MO = "333";
 this.MMI_SC_BA_MT = "353";
 
+this.MMI_SC_TO_CB_FACILITY = {};
+
+MMI_SC_TO_CB_FACILITY[MMI_SC_BAOC] = ICC_CB_FACILITY_BAOC;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BAOIC] = ICC_CB_FACILITY_BAOIC;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BAOICxH] = ICC_CB_FACILITY_BAOICxH;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BAIC] = ICC_CB_FACILITY_BAIC;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BAICr] = ICC_CB_FACILITY_BAICr;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BA_ALL] = ICC_CB_FACILITY_BA_ALL;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BA_MO] = ICC_CB_FACILITY_BA_MO;
+MMI_SC_TO_CB_FACILITY[MMI_SC_BA_MT] = ICC_CB_FACILITY_BA_MT;
+
 // MMI service code key strings.
 this.MMI_KS_SC_CALL_BARRING = "scCallBarring";
 this.MMI_KS_SC_CALL_FORWARDING = "scCallForwarding";
 this.MMI_KS_SC_CLIP = "scClip";
 this.MMI_KS_SC_CLIR = "scClir";
 this.MMI_KS_SC_PWD = "scPwd";
 this.MMI_KS_SC_CALL_WAITING = "scCallWaiting";
 this.MMI_KS_SC_PIN = "scPin";
@@ -2601,27 +2615,47 @@ this.MMI_ERROR_KS_NEEDS_PUK = "emMmiErro
 this.MMI_ERROR_KS_SIM_BLOCKED = "emMmiErrorSimBlocked";
 
 // MMI status message.
 this.MMI_SM_KS_PIN_CHANGED = "smPinChanged";
 this.MMI_SM_KS_PIN2_CHANGED = "smPin2Changed";
 this.MMI_SM_KS_PIN_UNBLOCKED = "smPinUnblocked";
 this.MMI_SM_KS_PIN2_UNBLOCKED = "smPin2Unblocked";
 this.MMI_SM_KS_SERVICE_ENABLED = "smServiceEnabled";
+this.MMI_SM_KS_SERVICE_ENABLED_FOR = "smServiceEnabledFor";
 this.MMI_SM_KS_SERVICE_DISABLED = "smServiceDisabled";
 this.MMI_SM_KS_SERVICE_REGISTERED = "smServiceRegistered";
 this.MMI_SM_KS_SERVICE_ERASED = "smServiceErased";
 this.MMI_SM_KS_SERVICE_INTERROGATED = "smServiceInterrogated";
 this.MMI_SM_KS_SERVICE_NOT_PROVISIONED = "smServiceNotProvisioned";
 this.MMI_SM_KS_CLIR_PERMANENT = "smClirPermanent";
 this.MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_ON = "smClirDefaultOnNextCallOn";
 this.MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_OFF = "smClirDefaultOnNextCallOff";
 this.MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_ON = "smClirDefaultOffNextCallOn";
 this.MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_OFF = "smClirDefaultOffNextCallOff";
 
+// MMI Service class
+this.MMI_KS_SERVICE_CLASS_VOICE = "serviceClassVoice";
+this.MMI_KS_SERVICE_CLASS_DATA = "serviceClassData";
+this.MMI_KS_SERVICE_CLASS_FAX = "serviceClassFax";
+this.MMI_KS_SERVICE_CLASS_SMS = "serviceClassSms";
+this.MMI_KS_SERVICE_CLASS_DATA_SYNC = "serviceClassDataSync";
+this.MMI_KS_SERVICE_CLASS_DATA_ASYNC = "serviceClassDataAsync";
+this.MMI_KS_SERVICE_CLASS_PACKET = "serviceClassPacket";
+this.MMI_KS_SERVICE_CLASS_PAD = "serviceClassPad";
+
+this.MMI_KS_SERVICE_CLASS_MAPPING = {};
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_VOICE] = MMI_KS_SERVICE_CLASS_VOICE;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA] = MMI_KS_SERVICE_CLASS_DATA;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_FAX] = MMI_KS_SERVICE_CLASS_FAX;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_SMS] = MMI_KS_SERVICE_CLASS_SMS;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA_SYNC] = MMI_KS_SERVICE_CLASS_DATA_SYNC;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA_ASYNC] = MMI_KS_SERVICE_CLASS_DATA_ASYNC;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_PACKET] = MMI_KS_SERVICE_CLASS_PACKET;
+MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_PAD] = MMI_KS_SERVICE_CLASS_PAD;
 /**
  * CDMA PDU constants
  */
 
 // SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4-1
 this.PDU_CDMA_MSG_TYPE_P2P = 0x00;        // Point-to-Point
 this.PDU_CDMA_MSG_TYPE_BROADCAST = 0x01;  // Broadcast
 this.PDU_CDMA_MSG_TYPE_ACK = 0x02;        // Acknowledge
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1893,16 +1893,22 @@ let RIL = {
     // notification the incoming/waiting call may have changed. The main
     // thread thinks that it is rejecting the call with the given index,
     // so only reject if that is still incoming/waiting.
     let call = this.currentCalls[options.callIndex];
     if (!call) {
       return;
     }
 
+    if (this._isCdma) {
+      // AT+CHLD=0 means "release held or UDUB."
+      Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND);
+      return;
+    }
+
     switch (call.state) {
       case CALL_STATE_INCOMING:
         Buf.simpleRequest(REQUEST_UDUB);
         break;
       case CALL_STATE_WAITING:
         // Reject the waiting (second) call, and remain the first call.
         Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND);
         break;
@@ -2534,31 +2540,49 @@ let RIL = {
             return;
           case MMI_PROCEDURE_ACTIVATION:
             options.clirMode = CLIR_INVOCATION;
             break;
           case MMI_PROCEDURE_DEACTIVATION:
             options.clirMode = CLIR_SUPPRESSION;
             break;
           default:
-            _sendMMIError(MMI_ERROR_KS_ERROR);
+            _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CLIR);
             return;
         }
         this.setCLIR(options);
         return;
 
       // Call barring
       case MMI_SC_BAOC:
       case MMI_SC_BAOIC:
       case MMI_SC_BAOICxH:
       case MMI_SC_BAIC:
       case MMI_SC_BAICr:
       case MMI_SC_BA_ALL:
       case MMI_SC_BA_MO:
       case MMI_SC_BA_MT:
+        options.mmiServiceCode = MMI_KS_SC_CALL_BARRING;
+        options.password = mmi.sia || "";
+        options.serviceClass = this._siToServiceClass(mmi.sib);
+        options.facility = MMI_SC_TO_CB_FACILITY[sc];
+        options.procedure = mmi.procedure;
+        if (mmi.procedure === MMI_PROCEDURE_INTERROGATION) {
+          this.queryICCFacilityLock(options);
+          return;
+        } else if (mmi.procedure === MMI_PROCEDURE_ACTIVATION) {
+          options.enabled = 1;
+        } else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
+          options.enabled = 0;
+        } else {
+          _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CALL_BARRING);
+          return;
+        }
+        this.setICCFacilityLock(options);
+        return;
       // Call waiting
       case MMI_SC_CALL_WAITING:
         _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
         return;
     }
 
     // If the MMI code is not a known code and is a recognized USSD request,
     // it shall still be sent as a USSD request.
@@ -5280,27 +5304,66 @@ RIL[REQUEST_DEACTIVATE_DATA_CALL] = func
   this.sendChromeMessage(datacall);
 };
 RIL[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILITY_LOCK(length, options) {
   options.success = (options.rilRequestError === 0);
   if (!options.success) {
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   }
 
+  let services;
   if (length) {
-    options.enabled = Buf.readUint32List()[0] === 0 ? false : true;
+    // Buf.readUint32List()[0] for Call Barring is a bit vector of services.
+    services = Buf.readUint32List()[0];
+  } else {
+    options.success = false;
+    options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+    this.sendChromeMessage(options);
+    return;
+  }
+
+  options.enabled = services === 0 ? false : true;
+
+  if (options.success && (options.rilMessageType === "sendMMI")) {
+    if (!options.enabled) {
+      options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
+    } else {
+      options.statusMessage = MMI_SM_KS_SERVICE_ENABLED_FOR;
+      let serviceClass = [];
+      for (let serviceClassMask = 1;
+           serviceClassMask <= ICC_SERVICE_CLASS_MAX;
+           serviceClassMask <<= 1) {
+        if ((serviceClassMask & services) != 0) {
+          serviceClass.push(MMI_KS_SERVICE_CLASS_MAPPING[serviceClassMask]);
+        }
+      }
+
+      options.additionalInformation = serviceClass;
+    }
   }
   this.sendChromeMessage(options);
 };
 RIL[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, options) {
   options.success = (options.rilRequestError === 0);
   if (!options.success) {
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   }
+
   options.retryCount = length ? Buf.readUint32List()[0] : -1;
+
+  if (options.success && (options.rilMessageType === "sendMMI")) {
+    switch (options.procedure) {
+      case MMI_PROCEDURE_ACTIVATION:
+        options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
+        break;
+      case MMI_PROCEDURE_DEACTIVATION:
+        options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
+        break;
+    }
+  }
   this.sendChromeMessage(options);
 };
 RIL[REQUEST_CHANGE_BARRING_PASSWORD] = null;
 RIL[REQUEST_SIM_OPEN_CHANNEL] = function REQUEST_SIM_OPEN_CHANNEL(length, options) {
   if (options.rilRequestError) {
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
     this.sendChromeMessage(options);
     return;
--- a/dom/system/gonk/tests/test_ril_worker_mmi.js
+++ b/dom/system/gonk/tests/test_ril_worker_mmi.js
@@ -762,18 +762,102 @@ add_test(function test_sendMMI_get_IMEI_
 
   do_check_true(mmiOptions.mmi);
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
   do_check_false(postedMessage.success);
 
   run_next_test();
 });
 
-add_test(function test_sendMMI_call_barring() {
-  testSendMMI("*33#", MMI_ERROR_KS_NOT_SUPPORTED);
+add_test(function test_sendMMI_call_barring_BAIC_interrogation_voice() {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+
+  worker.Buf.readUint32List = function fakeReadUint32List() {
+    return [1];
+  };
+
+  worker.RIL.queryICCFacilityLock =
+    function fakeQueryICCFacilityLock(options){
+      worker.RIL[REQUEST_QUERY_FACILITY_LOCK](1, {
+        rilMessageType: "sendMMI",
+        rilRequestError: ERROR_SUCCESS
+      });
+  }
+
+  worker.RIL.radioState = GECKO_RADIOSTATE_READY;
+  worker.RIL.sendMMI({mmi: "*#33#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_true(postedMessage.success);
+  do_check_true(postedMessage.enabled);
+  do_check_eq(postedMessage.statusMessage,  MMI_SM_KS_SERVICE_ENABLED_FOR);
+  do_check_true(Array.isArray(postedMessage.additionalInformation));
+  do_check_eq(postedMessage.additionalInformation[0], "serviceClassVoice");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_barring_BAIC_activation() {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+  let mmiOptions;
+
+  worker.RIL.setICCFacilityLock =
+    function fakeSetICCFacilityLock(options){
+      mmiOptions = options;
+      worker.RIL[REQUEST_SET_FACILITY_LOCK](0, {
+        rilMessageType: "sendMMI",
+        procedure: MMI_PROCEDURE_ACTIVATION,
+        rilRequestError: ERROR_SUCCESS
+      });
+  }
+
+  worker.RIL.radioState = GECKO_RADIOSTATE_READY;
+  worker.RIL.sendMMI({mmi: "*33#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(mmiOptions.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_true(postedMessage.success);
+  do_check_eq(postedMessage.statusMessage,  MMI_SM_KS_SERVICE_ENABLED);
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_barring_BAIC_deactivation() {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+  let mmiOptions;
+
+  worker.RIL.setICCFacilityLock =
+    function fakeSetICCFacilityLock(options){
+      mmiOptions = options;
+      worker.RIL[REQUEST_SET_FACILITY_LOCK](0, {
+        rilMessageType: "sendMMI",
+        procedure: MMI_PROCEDURE_DEACTIVATION,
+        rilRequestError: ERROR_SUCCESS
+      });
+  }
+
+  worker.RIL.radioState = GECKO_RADIOSTATE_READY;
+  worker.RIL.sendMMI({mmi: "#33#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(mmiOptions.procedure, MMI_PROCEDURE_DEACTIVATION);
+  do_check_true(postedMessage.success);
+  do_check_eq(postedMessage.statusMessage,  MMI_SM_KS_SERVICE_DISABLED);
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_barring_BAIC_procedure_not_supported() {
+  testSendMMI("**33*0000#", MMI_ERROR_KS_NOT_SUPPORTED);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_waiting() {
   testSendMMI("*43#", MMI_ERROR_KS_NOT_SUPPORTED);
 
   run_next_test();
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -467,16 +467,17 @@ var interfaceNamesInGlobalScope =
     "SVGUnitTypes",
     "SVGURIReference",
     "SVGUseElement",
     "SVGViewElement",
     "SVGViewSpec",
     "SVGZoomAndPan",
     "SVGZoomEvent",
     "TCPSocket",
+    "TCPServerSocket",
     "Text",
     "TextMetrics",
     "TimeEvent",
     "TimeRanges",
     "ToString",
     "Touch",
     "TouchEvent",
     "TouchList",
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -84,16 +84,18 @@
 #include "nsJSON.h"
 #include "mozIApplicationClearPrivateDataParams.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Activity.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/EventSource.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/network/TCPSocketChild.h"
+#include "mozilla/dom/network/TCPSocketParent.h"
+#include "mozilla/dom/network/TCPServerSocketChild.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/OSFileConstants.h"
 #include "mozilla/Services.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/FakeSpeechRecognitionService.h"
 #include "mozilla/dom/nsSynthVoiceRegistry.h"
 #endif
@@ -246,16 +248,18 @@ static void Shutdown();
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 using mozilla::dom::alarm::AlarmHalService;
 using mozilla::dom::indexedDB::IndexedDatabaseManager;
 using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManager;
 using mozilla::dom::TCPSocketChild;
+using mozilla::dom::TCPSocketParent;
+using mozilla::dom::TCPServerSocketChild;
 using mozilla::dom::time::TimeService;
 
 // Transformiix
 /* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
 #define TRANSFORMIIX_NODESET_CID \
 { 0x5d5d92cd, 0x6bf8, 0x11d9, { 0xbf, 0x4a, 0x0, 0x0a, 0x95, 0xdc, 0x23, 0x4c } }
 
 #define TRANSFORMIIX_NODESET_CONTRACTID \
@@ -635,16 +639,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincip
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecurityNameSet)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemPrincipal,
     nsScriptSecurityManager::SystemPrincipalSingletonConstructor)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNullPrincipal, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketChild)
+NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketParent)
+NS_GENERIC_FACTORY_CONSTRUCTOR(TCPServerSocketChild)
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 
   MAKE_CTOR(CreateA11yService, nsIAccessibilityService, NS_GetAccessibilityService)
 #endif
 
 static nsresult
@@ -802,16 +808,18 @@ NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CI
 NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_DATABASE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ALARMHALSERVICE_CID);
 NS_DEFINE_NAMED_CID(TCPSOCKETCHILD_CID);
+NS_DEFINE_NAMED_CID(TCPSOCKETPARENT_CID);
+NS_DEFINE_NAMED_CID(TCPSERVERSOCKETCHILD_CID);
 NS_DEFINE_NAMED_CID(NS_TIMESERVICE_CID);
 #ifdef MOZ_WIDGET_GONK
 NS_DEFINE_NAMED_CID(GONK_GPS_GEOLOCATION_PROVIDER_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_MEDIAMANAGERSERVICE_CID);
 #ifdef MOZ_GAMEPAD
 NS_DEFINE_NAMED_CID(NS_GAMEPAD_TEST_CID);
 #endif
@@ -1093,16 +1101,18 @@ static const mozilla::Module::CIDEntry k
   { &kSMS_SERVICE_CID, false, NULL, nsISmsServiceConstructor },
   { &kMMS_SERVICE_CID, false, NULL, nsIMmsServiceConstructor },
   { &kMOBILE_MESSAGE_SERVICE_CID, false, NULL, nsIMobileMessageServiceConstructor },
   { &kMOBILE_MESSAGE_DATABASE_SERVICE_CID, false, NULL, nsIMobileMessageDatabaseServiceConstructor },
   { &kNS_POWERMANAGERSERVICE_CID, false, NULL, nsIPowerManagerServiceConstructor },
   { &kOSFILECONSTANTSSERVICE_CID, true, NULL, OSFileConstantsServiceConstructor },
   { &kNS_ALARMHALSERVICE_CID, false, NULL, nsIAlarmHalServiceConstructor },
   { &kTCPSOCKETCHILD_CID, false, NULL, TCPSocketChildConstructor },
+  { &kTCPSOCKETPARENT_CID, false, NULL, TCPSocketParentConstructor },
+  { &kTCPSERVERSOCKETCHILD_CID, false, NULL, TCPServerSocketChildConstructor },
   { &kNS_TIMESERVICE_CID, false, NULL, nsITimeServiceConstructor },
 #ifdef MOZ_WIDGET_GONK
   { &kGONK_GPS_GEOLOCATION_PROVIDER_CID, false, NULL, nsIGeolocationProviderConstructor },
 #endif
   { &kNS_MEDIAMANAGERSERVICE_CID, false, NULL, nsIMediaManagerServiceConstructor },
 #ifdef MOZ_GAMEPAD
   { &kNS_GAMEPAD_TEST_CID, false, NULL, GamepadServiceTestConstructor },
 #endif
@@ -1251,16 +1261,18 @@ static const mozilla::Module::ContractID
   { SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
   { MMS_SERVICE_CONTRACTID, &kMMS_SERVICE_CID },
   { MOBILE_MESSAGE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_SERVICE_CID },
   { MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_DATABASE_SERVICE_CID },
   { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
   { OSFILECONSTANTSSERVICE_CONTRACTID, &kOSFILECONSTANTSSERVICE_CID },
   { ALARMHALSERVICE_CONTRACTID, &kNS_ALARMHALSERVICE_CID },
   { "@mozilla.org/tcp-socket-child;1", &kTCPSOCKETCHILD_CID },
+  { "@mozilla.org/tcp-socket-parent;1", &kTCPSOCKETPARENT_CID },
+  { "@mozilla.org/tcp-server-socket-child;1", &kTCPSERVERSOCKETCHILD_CID },
   { TIMESERVICE_CONTRACTID, &kNS_TIMESERVICE_CID },
 #ifdef MOZ_WIDGET_GONK
   { GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID, &kGONK_GPS_GEOLOCATION_PROVIDER_CID },
 #endif
 #ifdef MOZ_GAMEPAD
   { NS_GAMEPAD_TEST_CONTRACTID, &kNS_GAMEPAD_TEST_CID },
 #endif
   { MEDIAMANAGERSERVICE_CONTRACTID, &kNS_MEDIAMANAGERSERVICE_CID },
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -391,16 +391,17 @@
 @BINPATH@/components/Push.manifest
 
 @BINPATH@/components/SystemMessageInternal.js
 @BINPATH@/components/SystemMessageManager.js
 @BINPATH@/components/SystemMessageManager.manifest
 
 @BINPATH@/components/TCPSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.js
+@BINPATH@/components/TCPServerSocket.js
 @BINPATH@/components/TCPSocket.manifest
 
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/PeerConnection.js
 @BINPATH@/components/PeerConnection.manifest
 #endif
 
 #ifdef MOZ_SERVICES_HEALTHREPORT
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -10,18 +10,20 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/net/HttpChannelChild.h"
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/WyciwygChannelChild.h"
 #include "mozilla/net/FTPChannelChild.h"
 #include "mozilla/net/WebSocketChannelChild.h"
 #include "mozilla/net/RemoteOpenFileChild.h"
 #include "mozilla/dom/network/TCPSocketChild.h"
+#include "mozilla/dom/network/TCPServerSocketChild.h"
 
 using mozilla::dom::TCPSocketChild;
+using mozilla::dom::TCPServerSocketChild;
 
 namespace mozilla {
 namespace net {
 
 PNeckoChild *gNeckoChild = nullptr;
 
 // C++ file contents
 NeckoChild::NeckoChild()
@@ -149,34 +151,48 @@ bool
 NeckoChild::DeallocPWebSocketChild(PWebSocketChild* child)
 {
   WebSocketChannelChild* p = static_cast<WebSocketChannelChild*>(child);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PTCPSocketChild*
-NeckoChild::AllocPTCPSocketChild(const nsString& aHost,
-                                 const uint16_t& aPort,
-                                 const bool& useSSL,
-                                 const nsString& aBinaryType,
-                                 PBrowserChild* aBrowser)
+NeckoChild::AllocPTCPSocketChild()
 {
-  NS_NOTREACHED("AllocPTCPSocketChild should not be called");
-  return nullptr;
+  TCPSocketChild* p = new TCPSocketChild();
+  p->AddIPDLReference();
+  return p;
 }
 
 bool
 NeckoChild::DeallocPTCPSocketChild(PTCPSocketChild* child)
 {
   TCPSocketChild* p = static_cast<TCPSocketChild*>(child);
   p->ReleaseIPDLReference();
   return true;
 }
 
+PTCPServerSocketChild*
+NeckoChild::AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
+                                  const uint16_t& aBacklog,
+                                  const nsString& aBinaryType)
+{
+  NS_NOTREACHED("AllocPTCPServerSocket should not be called");
+  return nullptr;
+}
+
+bool
+NeckoChild::DeallocPTCPServerSocketChild(PTCPServerSocketChild* child)
+{
+  TCPServerSocketChild* p = static_cast<TCPServerSocketChild*>(child);
+  p->ReleaseIPDLReference();
+  return true;
+}
+
 PRemoteOpenFileChild*
 NeckoChild::AllocPRemoteOpenFileChild(const URIParams&, PBrowserChild*)
 {
   // We don't allocate here: instead we always use IPDL constructor that takes
   // an existing RemoteOpenFileChild
   NS_NOTREACHED("AllocPRemoteOpenFileChild should not be called on child");
   return nullptr;
 }
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -36,22 +36,22 @@ protected:
   virtual bool DeallocPWyciwygChannelChild(PWyciwygChannelChild*);
   virtual PFTPChannelChild*
     AllocPFTPChannelChild(PBrowserChild* aBrowser,
                           const SerializedLoadContext& aSerialized,
                           const FTPChannelCreationArgs& aOpenArgs);
   virtual bool DeallocPFTPChannelChild(PFTPChannelChild*);
   virtual PWebSocketChild* AllocPWebSocketChild(PBrowserChild*, const SerializedLoadContext&);
   virtual bool DeallocPWebSocketChild(PWebSocketChild*);
-  virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& aHost,
-                                                const uint16_t& aPort,
-                                                const bool& useSSL,
-                                                const nsString& aBinaryType,
-                                                PBrowserChild* aBrowser);
+  virtual PTCPSocketChild* AllocPTCPSocketChild();
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*);
+  virtual PTCPServerSocketChild* AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
+                                                       const uint16_t& aBacklog,
+                                                       const nsString& aBinaryType);
+  virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*);
   virtual PRemoteOpenFileChild* AllocPRemoteOpenFileChild(const URIParams&,
                                                           PBrowserChild*);
   virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*);
 };
 
 /**
  * Reference to the PNecko Child protocol.
  * Null if this is not a content process.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -10,28 +10,31 @@
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/WyciwygChannelParent.h"
 #include "mozilla/net/FTPChannelParent.h"
 #include "mozilla/net/WebSocketChannelParent.h"
 #include "mozilla/net/RemoteOpenFileParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/network/TCPSocketParent.h"
+#include "mozilla/dom/network/TCPServerSocketParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/AppProcessChecker.h"
 #include "nsPrintfCString.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsIAppsService.h"
 #include "nsEscape.h"
 #include "RemoteOpenFileParent.h"
 
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
+using mozilla::net::PTCPServerSocketParent;
+using mozilla::dom::TCPServerSocketParent;
 using IPC::SerializedLoadContext;
 
 namespace mozilla {
 namespace net {
 
 // C++ file contents
 NeckoParent::NeckoParent()
 {
@@ -290,54 +293,56 @@ bool
 NeckoParent::DeallocPWebSocketParent(PWebSocketParent* actor)
 {
   WebSocketChannelParent* p = static_cast<WebSocketChannelParent*>(actor);
   p->Release();
   return true;
 }
 
 PTCPSocketParent*
-NeckoParent::AllocPTCPSocketParent(const nsString& aHost,
-                                   const uint16_t& aPort,
-                                   const bool& useSSL,
-                                   const nsString& aBinaryType,
-                                   PBrowserParent* aBrowser)
+NeckoParent::AllocPTCPSocketParent()
 {
-  if (UsingNeckoIPCSecurity() && !aBrowser) {
-    printf_stderr("NeckoParent::AllocPTCPSocket: FATAL error: no browser present \
-                   KILLING CHILD PROCESS\n");
-    return nullptr;
-  }
-  if (aBrowser && !AssertAppProcessPermission(aBrowser, "tcp-socket")) {
-    printf_stderr("NeckoParent::AllocPTCPSocket: FATAL error: app doesn't permit tcp-socket connections \
-                   KILLING CHILD PROCESS\n");
-    return nullptr;
-  }
   TCPSocketParent* p = new TCPSocketParent();
-  p->AddRef();
+  p->AddIPDLReference();
   return p;
 }
 
 bool
-NeckoParent::RecvPTCPSocketConstructor(PTCPSocketParent* aActor,
-                                       const nsString& aHost,
-                                       const uint16_t& aPort,
-                                       const bool& useSSL,
-                                       const nsString& aBinaryType,
-                                       PBrowserParent* aBrowser)
-{
-  return static_cast<TCPSocketParent*>(aActor)->
-      Init(aHost, aPort, useSSL, aBinaryType);
-}
-
-bool
 NeckoParent::DeallocPTCPSocketParent(PTCPSocketParent* actor)
 {
   TCPSocketParent* p = static_cast<TCPSocketParent*>(actor);
-  p->Release();
+  p->ReleaseIPDLReference();
+  return true;
+}
+
+PTCPServerSocketParent*
+NeckoParent::AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
+                                   const uint16_t& aBacklog,
+                                   const nsString& aBinaryType)
+{
+  TCPServerSocketParent* p = new TCPServerSocketParent();
+  p->AddIPDLReference();
+  return p;
+}
+
+bool
+NeckoParent::RecvPTCPServerSocketConstructor(PTCPServerSocketParent* aActor,
+                                             const uint16_t& aLocalPort,
+                                             const uint16_t& aBacklog,
+                                             const nsString& aBinaryType)
+{
+  return static_cast<TCPServerSocketParent*>(aActor)->
+      Init(this, aLocalPort, aBacklog, aBinaryType);
+}
+
+bool
+NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor)
+{
+  TCPServerSocketParent* p = static_cast<TCPServerSocketParent*>(actor);
+   p->ReleaseIPDLReference();
   return true;
 }
 
 PRemoteOpenFileParent*
 NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI,
                                         PBrowserParent* aBrowser)
 {
   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -74,39 +74,37 @@ protected:
                       PFTPChannelParent* aActor,
                       PBrowserParent* aBrowser,
                       const SerializedLoadContext& aSerialized,
                       const FTPChannelCreationArgs& aOpenArgs);
   virtual bool DeallocPFTPChannelParent(PFTPChannelParent*);
   virtual PWebSocketParent* AllocPWebSocketParent(PBrowserParent* browser,
                                                   const SerializedLoadContext& aSerialized);
   virtual bool DeallocPWebSocketParent(PWebSocketParent*);
-  virtual PTCPSocketParent* AllocPTCPSocketParent(const nsString& aHost,
-                                                  const uint16_t& aPort,
-                                                  const bool& useSSL,
-                                                  const nsString& aBinaryType,
-                                                  PBrowserParent* aBrowser);
+virtual PTCPSocketParent* AllocPTCPSocketParent();
 
   virtual PRemoteOpenFileParent* AllocPRemoteOpenFileParent(const URIParams& aFileURI,
                                                             PBrowserParent* aBrowser)
                                                             MOZ_OVERRIDE;
   virtual bool RecvPRemoteOpenFileConstructor(PRemoteOpenFileParent* aActor,
                                               const URIParams& aFileURI,
                                               PBrowserParent* aBrowser)
                                               MOZ_OVERRIDE;
   virtual bool DeallocPRemoteOpenFileParent(PRemoteOpenFileParent* aActor)
                                             MOZ_OVERRIDE;
 
-  virtual bool RecvPTCPSocketConstructor(PTCPSocketParent*,
-                                         const nsString& aHost,
-                                         const uint16_t& aPort,
-                                         const bool& useSSL,
-                                         const nsString& aBinaryType,
-                                         PBrowserParent* aBrowser);
   virtual bool DeallocPTCPSocketParent(PTCPSocketParent*);
+  virtual PTCPServerSocketParent* AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
+                                                        const uint16_t& aBacklog,
+                                                        const nsString& aBinaryType);
+  virtual bool RecvPTCPServerSocketConstructor(PTCPServerSocketParent*,
+                                               const uint16_t& aLocalPort,
+                                               const uint16_t& aBacklog,
+                                               const nsString& aBinaryType);
+  virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*);
   virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
                                    const uint16_t& flags);
   virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname,
                                          const uint16_t& flags,
                                          const nsresult& reason);
 private:
   nsCString mCoreAppsBasePath;
   nsCString mWebAppsBasePath;
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -8,16 +8,17 @@
 include protocol PContent;
 include protocol PHttpChannel;
 include protocol PCookieService;
 include protocol PBrowser;
 include protocol PWyciwygChannel;
 include protocol PFTPChannel;
 include protocol PWebSocket;
 include protocol PTCPSocket;
+include protocol PTCPServerSocket;
 include protocol PRemoteOpenFile;
 include protocol PBlob; //FIXME: bug #792908
 
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
 
 include "SerializedLoadContext.h";
@@ -32,36 +33,36 @@ sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
   manages PWebSocket;
   manages PTCPSocket;
+  manages PTCPServerSocket;
   manages PRemoteOpenFile;
 
 parent:
   __delete__();
 
   PCookieService();
   PHttpChannel(nullable PBrowser browser,
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowser browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
   PWebSocket(PBrowser browser, SerializedLoadContext loadContext);
-  PTCPSocket(nsString host, uint16_t port, bool useSSL, nsString binaryType,
-             nullable PBrowser browser);
-
-  // Request that the parent open a file.
+  PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
   PRemoteOpenFile(URIParams fileuri, nullable PBrowser browser);
 
   HTMLDNSPrefetch(nsString hostname, uint16_t flags);
   CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
 
+both:
+  PTCPSocket();
 };
 
 
 } // namespace net
 } // namespace mozilla
--- a/tools/profiler/shared-libraries-linux.cc
+++ b/tools/profiler/shared-libraries-linux.cc
@@ -9,18 +9,18 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <limits.h>
 #include <unistd.h>
 #include "platform.h"
 #include "shared-libraries.h"
 
-#ifndef __GLIBC__
-/* a crapy version of getline, because it's not included in bionic */
+#if !defined(__GLIBC__) && ANDROID_VERSION < 18
+/* a crapy version of getline, because it's not included in old bionics */
 static ssize_t getline(char **lineptr, size_t *n, FILE *stream)
 {
  char *ret;
  if (!*lineptr) {
    *lineptr = (char*)malloc(4096);
  }
  ret = fgets(*lineptr, 4096, stream);
  if (!ret)