From 0363cf4a80a9599f6e0a4f9023a7acc7363e40e7 Mon Sep 17 00:00:00 2001 From: Devin Nakamura Date: Tue, 25 Aug 2015 15:46:42 -0400 Subject: [PATCH] tls: Closing parent socket also closes the tls sock PR-URL: https://github.com/joyent/node/pull/25642 Reviewed-By: jasnell - James M Snell --- lib/_tls_wrap.js | 4 ++ lib/net.js | 18 +++++---- test/simple/test-tls-destroy-socket.js | 55 ++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 test/simple/test-tls-destroy-socket.js diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 441776ad879..cf2991a8d09 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -231,6 +231,7 @@ function onocspresponse(resp) { function TLSSocket(socket, options) { // Disallow wrapping TLSSocket in TLSSocket assert(!(socket instanceof TLSSocket)); + var self = this; net.Socket.call(this, { handle: socket && socket._handle, @@ -241,6 +242,9 @@ function TLSSocket(socket, options) { if (socket) { this._parent = socket; + socket._destroy = function(exception) { + self._destroy(exception); + }; // To prevent assertion in afterConnect() this._connecting = socket._connecting; } diff --git a/lib/net.js b/lib/net.js index e6e48f4d9fd..3ecd3380078 100644 --- a/lib/net.js +++ b/lib/net.js @@ -468,12 +468,10 @@ Socket.prototype._destroy = function(exception, cb) { return; } - self._connecting = false; - - this.readable = this.writable = false; - - for (var s = this; s !== null; s = s._parent) + for (var s = this; s !== null; s = s._parent) { timers.unenroll(s); + s._connecting = s.readable = s.writable = false; + } debug('close'); if (this._handle) { @@ -482,16 +480,20 @@ Socket.prototype._destroy = function(exception, cb) { var isException = exception ? true : false; this._handle.close(function() { debug('emit close'); - self.emit('close', isException); + for (var s = self; s !== null; s = s._parent) + s.emit('close', isException); }); this._handle.onread = noop; - this._handle = null; + for (var s = this; s !== null; s = s._parent) + s._handle = null; } // we set destroyed to true before firing error callbacks in order // to make it re-entrance safe in case Socket.prototype.destroy() // is called within callbacks - this.destroyed = true; + for (var s = this; s !== null; s = s._parent) + s.destroyed = true; + fireErrorCallbacks(); if (this.server) { diff --git a/test/simple/test-tls-destroy-socket.js b/test/simple/test-tls-destroy-socket.js new file mode 100644 index 00000000000..fd656e97c7b --- /dev/null +++ b/test/simple/test-tls-destroy-socket.js @@ -0,0 +1,55 @@ +if (!process.versions.openssl) { + console.error('Skipping because node compiled without OpenSSL.'); + process.exit(0); +} + +var common = require('../common'); +var assert = require('assert'); +var tls = require('tls'); +var fs = require('fs'); + +var options = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem') +}; + +var normalSock = null; +var hasError = false; +var tlsCloseCount = 0; +var sockCloseCount = 0; + +var server = tls.createServer(options, function(secureSock) { + secureSock.on('error', function() { + hasError = true; + }); + secureSock.on('close', function() { + tlsCloseCount++; + }); + normalSock.on('close', function() { + sockCloseCount++; + }); + + normalSock.destroy(); + secureSock.write('Test!', function(err) { + assert(err); + }); +}); + +server.on('connection', function(sock) { + normalSock = sock; +}); + +server.listen(common.PORT, function() { + var c = tls.connect(common.PORT, {rejectUnauthorized: false}); + c.on('error', function() {}); // ignore socket hangup error + + c.on('end', function() { + server.close(); + }); + + process.on('exit', function() { + assert(hasError); + assert.equal(tlsCloseCount, 1); + assert.equal(sockCloseCount, 1); + }); +});