author | Ryan 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 id | 25028 |
push user | ryanvm@gmail.com |
push date | Mon, 29 Jul 2013 22:42:06 +0000 |
treeherder | mozilla-central@3d40d270c031 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 25.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
25.0a1
/
20130730030204
/
pushlog to previous
nightly linux64
25.0a1
/
20130730030204
/
pushlog to previous
nightly mac
25.0a1
/
20130730030204
/
pushlog to previous
nightly win32
25.0a1
/
20130730030204
/
pushlog to previous
nightly win64
25.0a1
/
20130730030204
/
pushlog to previous
|
--- 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)