From e52e22666203bf3db4de627fd9e8c2513a2195df Mon Sep 17 00:00:00 2001 From: Kagami Hiiragi Date: Tue, 17 Feb 2015 15:35:40 +0300 Subject: [PATCH] Net improvements --- lib/net/tcp.js | 44 +++++++++++++++++++------------------------- lib/net/ws.js | 38 ++++++++++---------------------------- 2 files changed, 29 insertions(+), 53 deletions(-) diff --git a/lib/net/tcp.js b/lib/net/tcp.js index 46007ff..5be58b7 100644 --- a/lib/net/tcp.js +++ b/lib/net/tcp.js @@ -91,7 +91,7 @@ TcpTransport.prototype._sendVersion = function() { })); }; -TcpTransport.prototype._setupClient = function(client, accepted) { +TcpTransport.prototype._setupClient = function(client, incoming) { var self = this; self._client = client; var cache = Buffer(0); @@ -107,8 +107,8 @@ TcpTransport.prototype._setupClient = function(client, accepted) { client.on("connect", function() { // NOTE(Kagami): This handler shouldn't be called at all for - // accepted sockets but let's be sure. - if (!accepted) { + // incoming connections but let's be sure. + if (!incoming) { self.emit("open"); self._sendVersion(); } @@ -155,7 +155,7 @@ TcpTransport.prototype._setupClient = function(client, accepted) { } self.send("verack"); verackSent = true; - if (accepted) { + if (incoming) { self._sendVersion(); } else if (verackReceived) { self.emit("established"); @@ -256,27 +256,21 @@ TcpTransport.prototype.listen = function() { var server = self._server = net.createServer(); server.listen.apply(server, arguments); - // TODO(Kagami): We may want to specify some limits for number of - // connected users. + var clientIdCounter = 0; + + // TODO(Kagami): Limit number of connected clients (220/192 per + // PyBitmessage). server.on("connection", function(client) { - var addr = client.remoteAddress; - var port = client.remotePort; - if (self._clients[addr]) { - // NOTE(Kagami): Doesn't allow more than one connection per IP. - // This may obstruct people behind NAT but we copy PyBitmessage's - // behavior here. - client.end(); - return self.emit("warning", new Error( - unmap(addr) + " was tried to create second connection" - )); - } - self._clients[addr] = client; + var id = client.id = clientIdCounter++; + self._clients[id] = client; client.on("close", function() { - delete self._clients[addr]; + delete self._clients[id]; }); var transport = new self.constructor(self); - var accepted = true; - transport._setupClient(client, accepted); + var incoming = true; + transport._setupClient(client, incoming); + var addr = client.remoteAddress; + var port = client.remotePort; self.emit("connection", transport, unmap(addr), port); // Emit "open" manually because "connect" for this socket won't be // fired. @@ -304,8 +298,8 @@ TcpTransport.prototype.send = function() { TcpTransport.prototype.broadcast = function() { var data = getmsg(arguments); if (this._server) { - Object.keys(this._clients).forEach(function(ip) { - this._clients[ip].write(data); + Object.keys(this._clients).forEach(function(id) { + this._clients[id].write(data); }, this); } else { throw new Error("Not listening"); @@ -316,8 +310,8 @@ TcpTransport.prototype.close = function() { if (this._client) { this._client.end(); } else if (this._server) { - Object.keys(this._clients).forEach(function(ip) { - this._clients[ip].end(); + Object.keys(this._clients).forEach(function(id) { + this._clients[id].end(); }, this); this._server.close(); } diff --git a/lib/net/ws.js b/lib/net/ws.js index 64dd451..54ac003 100644 --- a/lib/net/ws.js +++ b/lib/net/ws.js @@ -80,7 +80,7 @@ WsTransport.prototype._handleTimeout = function() { }); }; -WsTransport.prototype._setupClient = function(client, accepted) { +WsTransport.prototype._setupClient = function(client, incoming) { var self = this; self._client = client; var verackSent = false; @@ -89,8 +89,8 @@ WsTransport.prototype._setupClient = function(client, accepted) { client.on("open", function() { // NOTE(Kagami): This handler shouldn't be called at all for - // accepted sockets but let's be sure. - if (!accepted) { + // incoming connections but let's be sure. + if (!incoming) { // NOTE(Kagami): We may set timeout only after connection was // opened because socket may not yet be available when // `_setupClient` is called. @@ -130,7 +130,7 @@ WsTransport.prototype._setupClient = function(client, accepted) { } self.send("verack"); verackSent = true; - if (accepted) { + if (incoming) { self._sendVersion(); } else if (verackReceived) { established = true; @@ -185,33 +185,15 @@ WsTransport.prototype.listen = function(options, callback) { var self = this; var server = self._server = new WebSocketServer(options, callback); - // TODO(Kagami): We may want to specify some limits for number of - // connected users. + // TODO(Kagami): Limit number of connected clients (220/192 per + // PyBitmessage). server.on("connection", function(client) { - var addr = client._socket.remoteAddress; - var port = client._remotePort; - var i; - - // NOTE(Kagami): O(n) search because `clients` array is already - // provided by `ws` library. We may want to optmize it though and - // also disable `clientTracking` option. - for (i = 0; i < server.clients.length; i++) { - if (server.clients[i] !== client && - server.clients[i]._socket.remoteAddress === addr) { - // NOTE(Kagami): Doesn't allow more than one connection per IP. - // This may obstruct people behind NAT but we copy - // PyBitmessage's behavior here. - client.close(); - return self.emit("warning", new Error( - unmap(addr) + " was tried to create second connection" - )); - } - } - var transport = new self.constructor(self); - var accepted = true; - transport._setupClient(client, accepted); + var incoming = true; + transport._setupClient(client, incoming); transport._handleTimeout(); + var addr = client._socket.remoteAddress; + var port = client._socket.remotePort; self.emit("connection", transport, unmap(addr), port); // Emit "open" manually because it won't be fired for already opened // socket.