Skip to content

Commit b1ada0a

Browse files
authored
tls: handle cases where the raw socket is destroyed
Ensure that the `'close'` event is emitted on a `TLSSocket` when it is created from an existing raw `net.Socket` and the raw socket is not closed cleanly (destroyed). Refs: 048e0bec5147 Refs: #49902 (comment) Fixes: #49902 PR-URL: #49980 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent e01c1d7 commit b1ada0a

File tree

2 files changed

+38
-14
lines changed

2 files changed

+38
-14
lines changed

lib/_tls_wrap.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -657,10 +657,20 @@ tls_wrap.TLSWrap.prototype.close = function close(cb) {
657657
cb();
658658
};
659659

660-
if (this._parentWrap && this._parentWrap._handle === this._parent) {
661-
this._parentWrap.once('close', done);
662-
return this._parentWrap.destroy();
660+
if (this._parentWrap) {
661+
if (this._parentWrap._handle === null) {
662+
// The socket handle was already closed.
663+
done();
664+
return;
665+
}
666+
667+
if (this._parentWrap._handle === this._parent) {
668+
this._parentWrap.once('close', done);
669+
this._parentWrap.destroy();
670+
return;
671+
}
663672
}
673+
664674
return this._parent.close(done);
665675
};
666676

test/parallel/test-tls-socket-close.js

+25-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ if (!common.hasCrypto)
66
const assert = require('assert');
77
const tls = require('tls');
88
const net = require('net');
9+
const Countdown = require('../common/countdown');
910
const fixtures = require('../common/fixtures');
1011

1112
const key = fixtures.readKey('agent2-key.pem');
@@ -14,19 +15,28 @@ const cert = fixtures.readKey('agent2-cert.pem');
1415
let serverTlsSocket;
1516
const tlsServer = tls.createServer({ cert, key }, (socket) => {
1617
serverTlsSocket = socket;
18+
socket.on('close', dec);
1719
});
1820

1921
// A plain net server, that manually passes connections to the TLS
20-
// server to be upgraded
22+
// server to be upgraded.
2123
let netSocket;
24+
let netSocketCloseEmitted = false;
2225
const netServer = net.createServer((socket) => {
23-
tlsServer.emit('connection', socket);
24-
2526
netSocket = socket;
26-
}).listen(0, common.mustCall(function() {
27+
tlsServer.emit('connection', socket);
28+
socket.on('close', () => {
29+
netSocketCloseEmitted = true;
30+
assert.strictEqual(serverTlsSocket.destroyed, true);
31+
});
32+
}).listen(0, common.mustCall(() => {
2733
connectClient(netServer);
2834
}));
2935

36+
const countdown = new Countdown(2, () => {
37+
netServer.close();
38+
});
39+
3040
// A client that connects, sends one message, and closes the raw connection:
3141
function connectClient(server) {
3242
const clientTlsSocket = tls.connect({
@@ -41,18 +51,22 @@ function connectClient(server) {
4151
assert(serverTlsSocket);
4252

4353
netSocket.destroy();
54+
assert.strictEqual(netSocket.destroyed, true);
4455

4556
setImmediate(() => {
46-
assert.strictEqual(netSocket.destroyed, true);
47-
57+
// Close callbacks are executed after `setImmediate()` callbacks.
58+
assert.strictEqual(netSocketCloseEmitted, false);
59+
assert.strictEqual(serverTlsSocket.destroyed, false);
4860
setImmediate(() => {
49-
assert.strictEqual(clientTlsSocket.destroyed, true);
50-
assert.strictEqual(serverTlsSocket.destroyed, true);
51-
52-
tlsServer.close();
53-
netServer.close();
61+
assert.strictEqual(netSocketCloseEmitted, true);
5462
});
5563
});
5664
}));
5765
}));
66+
67+
clientTlsSocket.on('close', dec);
68+
}
69+
70+
function dec() {
71+
countdown.dec();
5872
}

0 commit comments

Comments
 (0)