From 9fa5e6a6a8b08f0b413ac7c8aba414136151e036 Mon Sep 17 00:00:00 2001 From: Evan Lucas Date: Wed, 18 Feb 2015 12:02:01 -0600 Subject: [PATCH] net: persist net.Socket options before connect Remembers net.Socket options called before connect and retroactively applies them after the handle has been created. This change makes the following function calls more user-friendly: - setKeepAlive() - setNoDelay() - ref() - unref() Related: https://github.com/joyent/node/issues/7077 and https://github.com/joyent/node/issues/8572 --- lib/net.js | 20 +++++++++ .../parallel/test-net-persistent-keepalive.js | 32 ++++++++++++++ test/parallel/test-net-persistent-nodelay.js | 42 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 test/parallel/test-net-persistent-keepalive.js create mode 100644 test/parallel/test-net-persistent-nodelay.js diff --git a/lib/net.js b/lib/net.js index af8c3dd8feb68e..c0c46c6f92659c 100644 --- a/lib/net.js +++ b/lib/net.js @@ -121,6 +121,9 @@ function Socket(options) { this._hadError = false; this._handle = null; this._host = null; + this._unref = false; + this._setNoDelay = null; + this._setKeepAlive = null; if (typeof options === 'number') options = { fd: options }; // Legacy interface. @@ -325,12 +328,16 @@ Socket.prototype.setNoDelay = function(enable) { // backwards compatibility: assume true when `enable` is omitted if (this._handle && this._handle.setNoDelay) this._handle.setNoDelay(enable === undefined ? true : !!enable); + else + this._setNoDelay = enable === undefined ? true : !!enable; }; Socket.prototype.setKeepAlive = function(setting, msecs) { if (this._handle && this._handle.setKeepAlive) this._handle.setKeepAlive(setting, ~~(msecs / 1000)); + else + this._setKeepAlive = [setting, ~~(msecs / 1000)]; }; @@ -766,6 +773,15 @@ function connect(self, address, port, addressType, localAddress, localPort) { var err; + if (self._setNoDelay) + self.setNoDelay(self._setNoDelay); + + if (self._setKeepAlive) + self.setKeepAlive(self._setKeepAlive[0], self._setKeepAlive[1]); + + if (self._unref) + self.unref(); + if (localAddress || localPort) { var bind; @@ -933,12 +949,16 @@ Socket.prototype.connect = function(options, cb) { Socket.prototype.ref = function() { + this._unref = false; + if (this._handle) this._handle.ref(); }; Socket.prototype.unref = function() { + this._unref = new Date(); + if (this._handle) this._handle.unref(); }; diff --git a/test/parallel/test-net-persistent-keepalive.js b/test/parallel/test-net-persistent-keepalive.js new file mode 100644 index 00000000000000..65401bca818c1f --- /dev/null +++ b/test/parallel/test-net-persistent-keepalive.js @@ -0,0 +1,32 @@ +var common = require('../common'); +var assert = require('assert'); +var net = require('net'); + +var serverConnection; +var echoServer = net.createServer(function(connection) { + serverConnection = connection; + connection.setTimeout(0); + assert.notEqual(connection.setKeepAlive, undefined); + connection.on('end', function() { + connection.end(); + }); +}); +echoServer.listen(common.PORT); + +echoServer.on('listening', function() { + var clientConnection = new net.Socket({}); + // send a keepalive packet after 1000 ms + // and make sure it persists + clientConnection.setKeepAlive(true, 1000); + clientConnection.connect(common.PORT); + clientConnection.setTimeout(0); + + setTimeout(function() { + // make sure both connections are still open + assert.equal(serverConnection.readyState, 'open'); + assert.equal(clientConnection.readyState, 'open'); + serverConnection.end(); + clientConnection.end(); + echoServer.close(); + }, 1200); +}); diff --git a/test/parallel/test-net-persistent-nodelay.js b/test/parallel/test-net-persistent-nodelay.js new file mode 100644 index 00000000000000..5384dd94a7717f --- /dev/null +++ b/test/parallel/test-net-persistent-nodelay.js @@ -0,0 +1,42 @@ +var common = require('../common'); +var assert = require('assert'); +var net = require('net'); + +var serverConnection; +var echoServer = net.createServer(function(connection) { + serverConnection = connection; + connection.end() +}); +echoServer.listen(common.PORT); + +var setTrue = false; + +var Socket = net.Socket; + +Socket.prototype.setNoDelay = function(enable) { + if (this._handle && this._handle.setNoDelay) { + if (enable === undefined || !!enable) { + setTrue = true; + } + this._handle.setNoDelay(enable === undefined ? true : !!enable); + } else { + this._setNoDelay = enable === undefined ? true : !!enable; + } +} + +echoServer.on('listening', function() { + var sock1 = new Socket({}); + // setNoDelay before the handle is created + // there is probably a better way to test this + + sock1.setNoDelay(); + sock1.connect(common.PORT, function() { + var sock2 = new Socket({}); + sock2.connect(common.PORT, function() { + assert.ok(setTrue); + setTimeout(function() { + echoServer.close(); + }, 500); + }); + }); +});