Net improvements

This commit is contained in:
Kagami Hiiragi 2015-02-17 15:35:40 +03:00
parent 49e4aa4158
commit e52e226662
2 changed files with 29 additions and 53 deletions

View File

@ -91,7 +91,7 @@ TcpTransport.prototype._sendVersion = function() {
})); }));
}; };
TcpTransport.prototype._setupClient = function(client, accepted) { TcpTransport.prototype._setupClient = function(client, incoming) {
var self = this; var self = this;
self._client = client; self._client = client;
var cache = Buffer(0); var cache = Buffer(0);
@ -107,8 +107,8 @@ TcpTransport.prototype._setupClient = function(client, accepted) {
client.on("connect", function() { client.on("connect", function() {
// NOTE(Kagami): This handler shouldn't be called at all for // NOTE(Kagami): This handler shouldn't be called at all for
// accepted sockets but let's be sure. // incoming connections but let's be sure.
if (!accepted) { if (!incoming) {
self.emit("open"); self.emit("open");
self._sendVersion(); self._sendVersion();
} }
@ -155,7 +155,7 @@ TcpTransport.prototype._setupClient = function(client, accepted) {
} }
self.send("verack"); self.send("verack");
verackSent = true; verackSent = true;
if (accepted) { if (incoming) {
self._sendVersion(); self._sendVersion();
} else if (verackReceived) { } else if (verackReceived) {
self.emit("established"); self.emit("established");
@ -256,27 +256,21 @@ TcpTransport.prototype.listen = function() {
var server = self._server = net.createServer(); var server = self._server = net.createServer();
server.listen.apply(server, arguments); server.listen.apply(server, arguments);
// TODO(Kagami): We may want to specify some limits for number of var clientIdCounter = 0;
// connected users.
// TODO(Kagami): Limit number of connected clients (220/192 per
// PyBitmessage).
server.on("connection", function(client) { server.on("connection", function(client) {
var addr = client.remoteAddress; var id = client.id = clientIdCounter++;
var port = client.remotePort; self._clients[id] = client;
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;
client.on("close", function() { client.on("close", function() {
delete self._clients[addr]; delete self._clients[id];
}); });
var transport = new self.constructor(self); var transport = new self.constructor(self);
var accepted = true; var incoming = true;
transport._setupClient(client, accepted); transport._setupClient(client, incoming);
var addr = client.remoteAddress;
var port = client.remotePort;
self.emit("connection", transport, unmap(addr), port); self.emit("connection", transport, unmap(addr), port);
// Emit "open" manually because "connect" for this socket won't be // Emit "open" manually because "connect" for this socket won't be
// fired. // fired.
@ -304,8 +298,8 @@ TcpTransport.prototype.send = function() {
TcpTransport.prototype.broadcast = function() { TcpTransport.prototype.broadcast = function() {
var data = getmsg(arguments); var data = getmsg(arguments);
if (this._server) { if (this._server) {
Object.keys(this._clients).forEach(function(ip) { Object.keys(this._clients).forEach(function(id) {
this._clients[ip].write(data); this._clients[id].write(data);
}, this); }, this);
} else { } else {
throw new Error("Not listening"); throw new Error("Not listening");
@ -316,8 +310,8 @@ TcpTransport.prototype.close = function() {
if (this._client) { if (this._client) {
this._client.end(); this._client.end();
} else if (this._server) { } else if (this._server) {
Object.keys(this._clients).forEach(function(ip) { Object.keys(this._clients).forEach(function(id) {
this._clients[ip].end(); this._clients[id].end();
}, this); }, this);
this._server.close(); this._server.close();
} }

View File

@ -80,7 +80,7 @@ WsTransport.prototype._handleTimeout = function() {
}); });
}; };
WsTransport.prototype._setupClient = function(client, accepted) { WsTransport.prototype._setupClient = function(client, incoming) {
var self = this; var self = this;
self._client = client; self._client = client;
var verackSent = false; var verackSent = false;
@ -89,8 +89,8 @@ WsTransport.prototype._setupClient = function(client, accepted) {
client.on("open", function() { client.on("open", function() {
// NOTE(Kagami): This handler shouldn't be called at all for // NOTE(Kagami): This handler shouldn't be called at all for
// accepted sockets but let's be sure. // incoming connections but let's be sure.
if (!accepted) { if (!incoming) {
// NOTE(Kagami): We may set timeout only after connection was // NOTE(Kagami): We may set timeout only after connection was
// opened because socket may not yet be available when // opened because socket may not yet be available when
// `_setupClient` is called. // `_setupClient` is called.
@ -130,7 +130,7 @@ WsTransport.prototype._setupClient = function(client, accepted) {
} }
self.send("verack"); self.send("verack");
verackSent = true; verackSent = true;
if (accepted) { if (incoming) {
self._sendVersion(); self._sendVersion();
} else if (verackReceived) { } else if (verackReceived) {
established = true; established = true;
@ -185,33 +185,15 @@ WsTransport.prototype.listen = function(options, callback) {
var self = this; var self = this;
var server = self._server = new WebSocketServer(options, callback); var server = self._server = new WebSocketServer(options, callback);
// TODO(Kagami): We may want to specify some limits for number of // TODO(Kagami): Limit number of connected clients (220/192 per
// connected users. // PyBitmessage).
server.on("connection", function(client) { 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 transport = new self.constructor(self);
var accepted = true; var incoming = true;
transport._setupClient(client, accepted); transport._setupClient(client, incoming);
transport._handleTimeout(); transport._handleTimeout();
var addr = client._socket.remoteAddress;
var port = client._socket.remotePort;
self.emit("connection", transport, unmap(addr), port); self.emit("connection", transport, unmap(addr), port);
// Emit "open" manually because it won't be fired for already opened // Emit "open" manually because it won't be fired for already opened
// socket. // socket.