2013-07-29 21:36:43 +04:00
|
|
|
|
/* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2015-01-18 00:26:10 +03:00
|
|
|
|
let debug = true;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
function LOG(msg) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
dump("TCPServerSocket: " + msg + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* nsIDOMTCPServerSocket object
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
function TCPServerSocket() {
|
|
|
|
|
this._localPort = 0;
|
|
|
|
|
this._binaryType = null;
|
|
|
|
|
|
2015-01-18 00:26:10 +03:00
|
|
|
|
this._onconnect = null;
|
|
|
|
|
this._onerror = null;
|
|
|
|
|
|
2013-07-29 21:36:43 +04:00
|
|
|
|
this._inChild = false;
|
|
|
|
|
this._neckoTCPServerSocket = null;
|
|
|
|
|
this._serverBridge = null;
|
2015-01-18 00:26:10 +03:00
|
|
|
|
this.useWin = null;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-18 00:26:10 +03:00
|
|
|
|
// When this API moves to WebIDL and these __exposedProps__ go away, remove
|
|
|
|
|
// this call here and remove the API from XPConnect.
|
|
|
|
|
Cu.skipCOWCallableChecks();
|
|
|
|
|
|
2013-07-29 21:36:43 +04:00
|
|
|
|
TCPServerSocket.prototype = {
|
2015-01-18 00:26:10 +03:00
|
|
|
|
__exposedProps__: {
|
|
|
|
|
localPort: 'r',
|
|
|
|
|
onconnect: 'rw',
|
|
|
|
|
onerror: 'rw'
|
|
|
|
|
},
|
2013-07-29 21:36:43 +04:00
|
|
|
|
get localPort() {
|
|
|
|
|
return this._localPort;
|
|
|
|
|
},
|
2015-01-18 00:26:10 +03:00
|
|
|
|
get onconnect() {
|
|
|
|
|
return this._onconnect;
|
|
|
|
|
},
|
|
|
|
|
set onconnect(f) {
|
|
|
|
|
this._onconnect = f;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
},
|
2015-01-18 00:26:10 +03:00
|
|
|
|
get onerror() {
|
|
|
|
|
return this._onerror;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
},
|
2015-01-18 00:26:10 +03:00
|
|
|
|
set onerror(f) {
|
|
|
|
|
this._onerror = f;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_callListenerAcceptCommon: function tss_callListenerAcceptCommon(socket) {
|
2015-01-18 00:26:10 +03:00
|
|
|
|
if (this._onconnect) {
|
|
|
|
|
try {
|
|
|
|
|
this["onconnect"].call(null, socket);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
socket.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-07-29 21:36:43 +04:00
|
|
|
|
socket.close();
|
2015-01-18 00:26:10 +03:00
|
|
|
|
dump("Received unexpected connection!");
|
2013-07-29 21:36:43 +04:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
init: function tss_init(aWindowObj) {
|
2015-01-18 00:26:10 +03:00
|
|
|
|
this.useWin = aWindowObj;
|
2013-07-29 21:36:43 +04:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/* 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.
|
2015-01-18 00:26:10 +03:00
|
|
|
|
let socket = TCPSocketInternal.createAcceptedChild(socketChild, this._binaryType, this.useWin);
|
2013-07-29 21:36:43 +04:00
|
|
|
|
this._callListenerAcceptCommon(socket);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
callListenerError: function tss_callListenerError(message, filename, lineNumber, columnNumber) {
|
2015-01-18 00:26:10 +03:00
|
|
|
|
if (this._onerror) {
|
|
|
|
|
var type = "error";
|
|
|
|
|
var error = new Error(message, filename, lineNumber, columnNumber);
|
|
|
|
|
|
|
|
|
|
this["onerror"].call(null, new TCPSocketEvent(type, this, error));
|
|
|
|
|
}
|
2013-07-29 21:36:43 +04:00
|
|
|
|
},
|
|
|
|
|
/* 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 {
|
2015-01-18 00:26:10 +03:00
|
|
|
|
let that = TCPSocketInternal.createAcceptedParent(trans, this._binaryType,
|
|
|
|
|
this.useWin);
|
2013-07-29 21:36:43 +04:00
|
|
|
|
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;
|
|
|
|
|
},
|
|
|
|
|
|
2015-01-17 19:57:41 +03:00
|
|
|
|
classID: Components.ID("{73065eae-27dc-11e2-895a-000c29987aa2}"),
|
2013-07-29 21:36:43 +04:00
|
|
|
|
|
2015-01-18 00:26:10 +03:00
|
|
|
|
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,
|
|
|
|
|
}),
|
|
|
|
|
|
2013-07-29 21:36:43 +04:00
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([
|
2015-01-18 00:26:10 +03:00
|
|
|
|
Ci.nsIDOMTCPServerSocket,
|
2013-07-29 21:36:43 +04:00
|
|
|
|
Ci.nsITCPServerSocketInternal,
|
2015-01-18 00:26:10 +03:00
|
|
|
|
Ci.nsISupportsWeakReference
|
2013-07-29 21:36:43 +04:00
|
|
|
|
])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TCPServerSocket]);
|