michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: const CC = Components.Constructor; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: const ServerSocket = CC( michael@0: '@mozilla.org/network/server-socket;1', 'nsIServerSocket', 'init'), michael@0: TCPSocketInternal = Cc[ michael@0: '@mozilla.org/tcp-socket;1'].createInstance(Ci.nsITCPSocketInternal); michael@0: michael@0: /* michael@0: * Debug logging function michael@0: */ michael@0: michael@0: let debug = true; michael@0: function LOG(msg) { michael@0: if (debug) { michael@0: dump("TCPServerSocket: " + msg + "\n"); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * nsIDOMTCPServerSocket object michael@0: */ michael@0: michael@0: function TCPServerSocket() { michael@0: this._localPort = 0; michael@0: this._binaryType = null; michael@0: michael@0: this._onconnect = null; michael@0: this._onerror = null; michael@0: michael@0: this._inChild = false; michael@0: this._neckoTCPServerSocket = null; michael@0: this._serverBridge = null; michael@0: this.useWin = null; michael@0: } michael@0: michael@0: TCPServerSocket.prototype = { michael@0: __exposedProps__: { michael@0: port: 'r', michael@0: onconnect: 'rw', michael@0: onerror: 'rw' michael@0: }, michael@0: get localPort() { michael@0: return this._localPort; michael@0: }, michael@0: get onconnect() { michael@0: return this._onconnect; michael@0: }, michael@0: set onconnect(f) { michael@0: this._onconnect = f; michael@0: }, michael@0: get onerror() { michael@0: return this._onerror; michael@0: }, michael@0: set onerror(f) { michael@0: this._onerror = f; michael@0: }, michael@0: michael@0: _callListenerAcceptCommon: function tss_callListenerAcceptCommon(socket) { michael@0: if (this._onconnect) { michael@0: try { michael@0: this["onconnect"].call(null, socket); michael@0: } catch (e) { michael@0: socket.close(); michael@0: } michael@0: } michael@0: else { michael@0: socket.close(); michael@0: dump("Received unexpected connection!"); michael@0: } michael@0: }, michael@0: init: function tss_init(aWindowObj) { michael@0: this.useWin = aWindowObj; michael@0: }, michael@0: michael@0: /* nsITCPServerSocketInternal method */ michael@0: listen: function tss_listen(localPort, options, backlog) { michael@0: this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime) michael@0: .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; michael@0: this._binaryType = options.binaryType; michael@0: michael@0: if (this._inChild) { michael@0: if (this._serverBridge == null) { michael@0: this._serverBridge = Cc["@mozilla.org/tcp-server-socket-child;1"] michael@0: .createInstance(Ci.nsITCPServerSocketChild); michael@0: this._serverBridge.listen(this, localPort, backlog, options.binaryType); michael@0: } michael@0: else { michael@0: throw new Error("Child TCPServerSocket has already listening. \n"); michael@0: } michael@0: } michael@0: else { michael@0: if (this._neckoTCPServerSocket == null) { michael@0: this._neckoTCPServerSocket = new ServerSocket(localPort, false, backlog); michael@0: this._localPort = this._neckoTCPServerSocket.port; michael@0: this._neckoTCPServerSocket.asyncListen(this); michael@0: } michael@0: else { michael@0: throw new Error("Parent TCPServerSocket has already listening. \n"); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: callListenerAccept: function tss_callListenerSocket(socketChild) { michael@0: // this method is called at child process when the socket is accepted at parent process. michael@0: let socket = TCPSocketInternal.createAcceptedChild(socketChild, this._binaryType, this.useWin); michael@0: this._callListenerAcceptCommon(socket); michael@0: }, michael@0: michael@0: callListenerError: function tss_callListenerError(message, filename, lineNumber, columnNumber) { michael@0: if (this._onerror) { michael@0: var type = "error"; michael@0: var error = new Error(message, filename, lineNumber, columnNumber); michael@0: michael@0: this["onerror"].call(null, new TCPSocketEvent(type, this, error)); michael@0: } michael@0: }, michael@0: /* end nsITCPServerSocketInternal method */ michael@0: michael@0: close: function tss_close() { michael@0: if (this._inChild) { michael@0: this._serverBridge.close(); michael@0: return; michael@0: } michael@0: michael@0: /* Close ServerSocket */ michael@0: if (this._neckoTCPServerSocket) { michael@0: this._neckoTCPServerSocket.close(); michael@0: } michael@0: }, michael@0: michael@0: // nsIServerSocketListener (Triggered by _neckoTCPServerSocket.asyncListen) michael@0: onSocketAccepted: function tss_onSocketAccepted(server, trans) { michael@0: // precondition: this._inChild == false michael@0: try { michael@0: let that = TCPSocketInternal.createAcceptedParent(trans, this._binaryType); michael@0: this._callListenerAcceptCommon(that); michael@0: } michael@0: catch(e) { michael@0: trans.close(Cr.NS_BINDING_ABORTED); michael@0: } michael@0: }, michael@0: michael@0: // nsIServerSocketListener (Triggered by _neckoTCPServerSocket.asyncListen) michael@0: onStopListening: function tss_onStopListening(server, status) { michael@0: if (status != Cr.NS_BINDING_ABORTED) { michael@0: throw new Error("Server socket was closed by unexpected reason."); michael@0: } michael@0: this._neckoTCPServerSocket = null; michael@0: }, michael@0: michael@0: classID: Components.ID("{73065eae-27dc-11e2-895a-000c29987aa2}"), michael@0: michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: Components.ID("{73065eae-27dc-11e2-895a-000c29987aa2}"), michael@0: classDescription: "Server TCP Socket", michael@0: interfaces: [ michael@0: Ci.nsIDOMTCPServerSocket, michael@0: Ci.nsISupportsWeakReference michael@0: ], michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: }), michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([ michael@0: Ci.nsIDOMTCPServerSocket, michael@0: Ci.nsITCPServerSocketInternal, michael@0: Ci.nsISupportsWeakReference michael@0: ]) michael@0: } michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TCPServerSocket]);