From d0df008cb041b8dae95bf5febba6fe920b1f1273 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 | 26 ++++++++++-- .../parallel/test-net-persistent-keepalive.js | 32 ++++++++++++++ test/parallel/test-net-persistent-nodelay.js | 37 ++++++++++++++++ .../parallel/test-net-persistent-ref-unref.js | 42 +++++++++++++++++++ 4 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 test/parallel/test-net-persistent-keepalive.js create mode 100644 test/parallel/test-net-persistent-nodelay.js create mode 100644 test/parallel/test-net-persistent-ref-unref.js diff --git a/lib/net.js b/lib/net.js index af8c3dd8feb68e..ee4ecf455602a5 100644 --- a/lib/net.js +++ b/lib/net.js @@ -322,6 +322,11 @@ Socket.prototype._onTimeout = function() { Socket.prototype.setNoDelay = function(enable) { + if (!this._handle) { + this.once('connect', this.setNoDelay.bind(this, enable)); + return; + } + // backwards compatibility: assume true when `enable` is omitted if (this._handle && this._handle.setNoDelay) this._handle.setNoDelay(enable === undefined ? true : !!enable); @@ -329,6 +334,11 @@ Socket.prototype.setNoDelay = function(enable) { Socket.prototype.setKeepAlive = function(setting, msecs) { + if (!this._handle) { + this.once('connect', this.setKeepAlive.bind(this, setting, msecs)); + return; + } + if (this._handle && this._handle.setKeepAlive) this._handle.setKeepAlive(setting, ~~(msecs / 1000)); }; @@ -933,14 +943,22 @@ Socket.prototype.connect = function(options, cb) { Socket.prototype.ref = function() { - if (this._handle) - this._handle.ref(); + if (!this._handle) { + this.once('connect', this.ref.bind(this)); + return; + } + + this._handle.ref(); }; Socket.prototype.unref = function() { - if (this._handle) - this._handle.unref(); + if (!this._handle) { + this.once('connect', this.unref.bind(this)); + return; + } + + 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..86936fd2a517e8 --- /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, 400); + 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(); + }, 600); +}); diff --git a/test/parallel/test-net-persistent-nodelay.js b/test/parallel/test-net-persistent-nodelay.js new file mode 100644 index 00000000000000..32f0b704407083 --- /dev/null +++ b/test/parallel/test-net-persistent-nodelay.js @@ -0,0 +1,37 @@ +var common = require('../common'); +var assert = require('assert'); +var net = require('net'); +var TCPWrap = process.binding('tcp_wrap').TCP; + +var echoServer = net.createServer(function(connection) { + connection.end(); +}); +echoServer.listen(common.PORT); + +var setTrue = 0; + +var Socket = net.Socket; +var setNoDelay = TCPWrap.prototype.setNoDelay; + +TCPWrap.prototype.setNoDelay = function(enable) { + setNoDelay.call(this, enable); + setTrue++; +} + +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) + sock1.on('connect', function() { + setTimeout(function() { + echoServer.close(); + }, 500); + }); +}); + +process.on('exit', function() { + assert.ok(setTrue); +}) diff --git a/test/parallel/test-net-persistent-ref-unref.js b/test/parallel/test-net-persistent-ref-unref.js new file mode 100644 index 00000000000000..e43e484e62b579 --- /dev/null +++ b/test/parallel/test-net-persistent-ref-unref.js @@ -0,0 +1,42 @@ +var common = require('../common'); +var assert = require('assert'); +var net = require('net'); +var TCPWrap = process.binding('tcp_wrap').TCP; + +var echoServer = net.createServer(function(conn) { + conn.end(); +}); + +var ref = TCPWrap.prototype.ref; +var unref = TCPWrap.prototype.unref; + +var refed = false; +var unrefed = false; + +TCPWrap.prototype.ref = function() { + ref.call(this); + refed = true; +} + +TCPWrap.prototype.unref = function() { + unref.call(this); + unrefed = true; +} + +echoServer.listen(common.PORT); + +echoServer.on('listening', function() { + var sock = new net.Socket(); + sock.unref(); + sock.ref(); + sock.connect(common.PORT, function() { + setTimeout(function() { + echoServer.close(); + }, 500); + }) +}) + +process.on('exit', function() { + assert.ok(refed); + assert.ok(unrefed); +})