-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
244 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
try { | ||
const socketTransportService = Components.classes["@mozilla.org/network/socket-transport-service;1"] | ||
.getService(Components.interfaces.nsISocketTransportService); | ||
const mainThread = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread; | ||
} catch (e) { | ||
// Components is not defined in web workers, | ||
// but we don't need this ClientSocket in a worker. | ||
} | ||
|
||
/* | ||
* Waits for data/disconnect on a nsIAsyncInputStream | ||
* stream. ClientSocket isn't used as the callback to exporting | ||
* onInputStreamReady into the public API of ClientSocket. | ||
*/ | ||
function nsIInputStreamCallback(clientSocket) { | ||
if (!(this instanceof nsIInputStreamCallback)) { | ||
return new nsIInputStreamCallback(clientSocket); | ||
} | ||
this.socket = clientSocket; | ||
clientSocket.rawInputStream.asyncWait(this, 0, 0, mainThread); | ||
} | ||
|
||
nsIInputStreamCallback.prototype.onInputStreamReady = function(stream) { | ||
var bytesAvailable; | ||
var binaryReader = this.socket.binaryReader; | ||
try { | ||
bytesAvailable = binaryReader.available(); | ||
} catch (e) { | ||
// The error name is NS_BASE_STREAM_CLOSED if the connection | ||
// closed normally. | ||
if (e.name !== 'NS_BASE_STREAM_CLOSED') { | ||
console.warn(e); | ||
} | ||
this.socket.disconnect(); | ||
return; | ||
} | ||
|
||
var lineData = binaryReader.readByteArray(bytesAvailable); | ||
var buffer = ArrayBuffer(lineData.length); | ||
var typedBuffer = new Uint8Array(buffer); | ||
typedBuffer.set(lineData); | ||
var socketTransportService = Components.classes["@mozilla.org/network/socket-transport-service;1"] | ||
.getService(Components.interfaces.nsISocketTransportService); | ||
if (typeof this.socket.onData === 'function') { | ||
this.socket.onData(typedBuffer); | ||
} | ||
this.socket.rawInputStream.asyncWait(this, 0, 0, mainThread); | ||
}; | ||
|
||
function ClientSocket(incomingTransport) { | ||
if (!(this instanceof ClientSocket)) { | ||
return new ClientSocket(incomingTransport); | ||
} | ||
if (typeof incomingTransport !== 'undefined') { | ||
this._setupTransport(incomingTransport); | ||
} | ||
} | ||
|
||
ClientSocket.prototype._setupTransport = function(transport) { | ||
this.transport = transport; | ||
|
||
// Set up readers | ||
this.binaryReader = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream); | ||
this.rawInputStream = this.transport.openInputStream(0,0,0); | ||
this.binaryReader.setInputStream(this.rawInputStream); | ||
|
||
new nsIInputStreamCallback(this); | ||
|
||
// set up writers | ||
this.outputStream = transport.openOutputStream(0, 0, 0); | ||
|
||
}; | ||
|
||
ClientSocket.prototype.connect = function(hostname, port) { | ||
if (typeof this.transport !== 'undefined') { | ||
throw new Error('Socket already connected'); | ||
} | ||
|
||
var transport = socketTransportService.createTransport([null], | ||
0, | ||
hostname, | ||
port, | ||
null); | ||
this._setupTransport(transport); | ||
this.socketType = 'tcp'; | ||
}; | ||
|
||
// TODO: This writ is happening async, so result should be returned async | ||
ClientSocket.prototype.write = function(data) { | ||
var stringData = this.arrayBufferToString(data); | ||
this.outputStream.write(stringData, stringData.length); | ||
}; | ||
|
||
ClientSocket.prototype.disconnect = function() { | ||
this.binaryReader.close(0); | ||
this.rawInputStream.close(0); | ||
this.transport.close(0); | ||
// Delete transport so getInfo doesn't think we are connected | ||
delete this.transport; | ||
if (typeof this.onDisconnect === 'function') { | ||
this.onDisconnect(); | ||
} | ||
}; | ||
|
||
ClientSocket.prototype.getInfo = function() { | ||
var transport = this.transport; | ||
|
||
if (typeof transport === 'undefined') { | ||
return {socketType: this.socketType, | ||
connected: false}; | ||
} | ||
var nsINetAddrPeer = transport.getScriptablePeerAddr(); | ||
var nsINetAddrLocal = transport.getScriptableSelfAddr(); | ||
var info = {connected: true, | ||
peerAddress: nsINetAddrPeer.address, | ||
peerPort: nsINetAddrPeer.port, | ||
localAddress: nsINetAddrLocal.address, | ||
localPort: nsINetAddrLocal.port}; | ||
return info; | ||
|
||
}; | ||
|
||
ClientSocket.prototype.arrayBufferToString = function(buf) { | ||
return String.fromCharCode.apply(null, new Uint8Array(buf)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
function nsIServerSocketListener(serverSocket) { | ||
if (!(this instanceof nsIServerSocketListener)) { | ||
return new nsIServerSocketListener(serverSocket); | ||
} | ||
this.serverSocket = serverSocket; | ||
} | ||
|
||
nsIServerSocketListener.prototype.onSocketAccepted = function(nsiServerSocket, transport) { | ||
var clientSocket = new ClientSocket(transport); | ||
if(typeof this.serverSocket.onConnect === 'function') { | ||
this.serverSocket.onConnect(clientSocket); | ||
} | ||
}; | ||
|
||
nsIServerSocketListener.prototype.onStopListening = function(nsiServerSocket, status) { | ||
}; | ||
|
||
// Address is currently ignored, as it is not possible to specify a | ||
// listening address in Firefox. | ||
function ServerSocket(address, port, backlog) { | ||
if (!(this instanceof ServerSocket)) { | ||
return new ServerSocket(address, port, backlog); | ||
} | ||
if (typeof backlog !== 'number') { | ||
backlog = -1; | ||
} | ||
this.nsIServerSocket = Components.classes["@mozilla.org/network/server-socket;1"] | ||
.createInstance(Components.interfaces.nsIServerSocket); | ||
this.nsIServerSocket.init(port, 0, backlog); | ||
} | ||
|
||
ServerSocket.prototype.listen = function() { | ||
this.nsIServerSocket.asyncListen(new nsIServerSocketListener(this)); | ||
}; | ||
|
||
ServerSocket.prototype.disconnect = function() { | ||
this.nsIServerSocket.close(); | ||
}; | ||
|
||
ServerSocket.prototype.getInfo = function() { | ||
var nsIServerSocket = this.nsIServerSocket; | ||
var port = nsIServerSocket.port; | ||
var localAddress = '127.0.0.1'; | ||
var socketType = 'tcp'; | ||
var info = {socketType: socketType, | ||
localAddress: localAddress, | ||
localPort: port}; | ||
return info; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
Socket_firefox.incommingConnections = {}; | ||
Socket_firefox.socketNumber = 1; | ||
|
||
function Socket_firefox(channel, dispatchEvent, socketId) { | ||
var incommingConnections = Socket_firefox.incommingConnections; | ||
this.dispatchEvent = dispatchEvent; | ||
this.socketId = socketId; | ||
if (socketId in incommingConnections) { | ||
this.clientSocket = incommingConnections[socketId]; | ||
delete incommingConnections[socketId]; | ||
this.clientSocket.onData = this._onData.bind(this); | ||
} | ||
} | ||
|
||
Socket_firefox.prototype.getInfo = function(continuation) { | ||
if(this.clientSocket) { | ||
continuation(this.clientSocket.getInfo()); | ||
} | ||
}; | ||
|
||
Socket_firefox.prototype.close = function(continuation) { | ||
if(this.clientSocket) { | ||
this.clientSocket.close(); | ||
} | ||
continuation(); | ||
}; | ||
|
||
Socket_firefox.prototype.connect = function(hostname, port, continuation) { | ||
this.clientSocket = new ClientSocket(); | ||
this.clientSocket.onData = this.onData.bind(this); | ||
this.clientSocket.connect(hostname, port); | ||
continuation(); | ||
}; | ||
|
||
Socket_firefox.prototype.write = function(buffer, continuation) { | ||
if (this.clientSocket) { | ||
this.clientSocket.write(buffer); | ||
continuation(); | ||
} | ||
}; | ||
|
||
Socket_firefox.prototype.listen = function(host, port, continuation) { | ||
this.serverSocket = new ServerSocket(host, port); | ||
this.host = host; | ||
this.port = port; | ||
this.serverSocket.onConnect = this._onConnect.bind(this); | ||
this.serverSocket.listen(); | ||
continuation(); | ||
}; | ||
|
||
Socket_firefox.prototype._onData = function(buffer) { | ||
this.dispatchEvent("onData", | ||
{data: buffer.buffer}); | ||
}; | ||
|
||
Socket_firefox.prototype._onConnect = function(clientSocket) { | ||
var socketNumber = Socket_firefox.socketNumber++; | ||
Socket_firefox.incommingConnections[socketNumber] = clientSocket; | ||
this.dispatchEvent("onConnection", { socket: socketNumber, | ||
host: this.host, | ||
port: this.port | ||
}); | ||
|
||
}; | ||
|
||
/** REGISTER PROVIDER **/ | ||
if (typeof fdom !== 'undefined') { | ||
fdom.apis.register("core.tcpsocket", Socket_firefox); | ||
} |