Skip to content

Commit

Permalink
Merge branch 'socket-providers'
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul-E committed Apr 18, 2014
2 parents 9327492 + 45f0a48 commit 9eb9482
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = function(grunt) {
src: FIREFOX_FILES
.concat(FILES.preamble)
.concat(FILES.src)
//.concat('providers/*.js')
.concat('providers/*.js')
.concat('src/firefox-postamble.js'),
dest: 'freedom-for-firefox.jsm'
}
Expand Down
125 changes: 125 additions & 0 deletions providers/client_socket.js
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));
};
49 changes: 49 additions & 0 deletions providers/server_socket.js
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;
};
69 changes: 69 additions & 0 deletions providers/tcp_socket.js
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);
}

0 comments on commit 9eb9482

Please sign in to comment.