From f5135f3a9b3407245e2afcfe2f73e94684fcba3b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 13 Mar 2022 22:21:30 -0400 Subject: [PATCH] fix --- lib/Connection.js | 65 ++++++++++++++----- lib/protocol/Protocol.js | 2 +- .../connection/test-connect-bogus-port.js | 17 +++++ 3 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 test/unit/connection/test-connect-bogus-port.js diff --git a/lib/Connection.js b/lib/Connection.js index 76fcbb049..2d7f46c37 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -15,8 +15,9 @@ function Connection(options) { this.config = options.config; - this._socket = options.socket; + this._socket = null; this._protocol = new Protocol({config: this.config, connection: this}); + this._protocolSetup = false; this._connectCalled = false; this.state = 'disconnected'; this.threadId = null; @@ -67,19 +68,29 @@ Connection.prototype.connect = function connect(options, callback) { options = {}; } + this._setupProtocolHandlers(); + this._protocol.handshake(options, wrapCallbackInDomain(this, callback)); + if (!this._connectCalled) { this._connectCalled = true; + this._socket = null; - // Connect either via a UNIX domain socket or a TCP socket. - this._socket = (this.config.socketPath) - ? Net.createConnection(this.config.socketPath) - : Net.createConnection(this.config.port, this.config.host); + try { + // Connect either via a UNIX domain socket or a TCP socket. + this._socket = (this.config.socketPath) + ? Net.createConnection(this.config.socketPath) + : Net.createConnection(this.config.port, this.config.host); + } catch (err) { + this._handleNetworkError(err); + return; + } // Connect socket to connection domain if (Events.usingDomains) { this._socket.domain = this.domain; } + // socket <-> protocol var connection = this; this._protocol.on('data', function(data) { connection._socket.write(data); @@ -94,15 +105,11 @@ Connection.prototype.connect = function connect(options, callback) { connection._protocol.end(); })); + // Set up socket handlers this._socket.on('error', this._handleNetworkError.bind(this)); this._socket.on('connect', this._handleProtocolConnect.bind(this)); - this._protocol.on('handshake', this._handleProtocolHandshake.bind(this)); - this._protocol.on('initialize', this._handleProtocolInitialize.bind(this)); - this._protocol.on('unhandledError', this._handleProtocolError.bind(this)); - this._protocol.on('drain', this._handleProtocolDrain.bind(this)); - this._protocol.on('end', this._handleProtocolEnd.bind(this)); - this._protocol.on('enqueue', this._handleProtocolEnqueue.bind(this)); + // Set connect timeout if (this.config.connectTimeout) { var handleConnectTimeout = this._handleConnectTimeout.bind(this); @@ -112,8 +119,6 @@ Connection.prototype.connect = function connect(options, callback) { }); } } - - this._protocol.handshake(options, wrapCallbackInDomain(this, callback)); }; Connection.prototype.changeUser = function changeUser(options, callback) { @@ -241,18 +246,28 @@ Connection.prototype.end = function end(options, callback) { Connection.prototype.destroy = function() { this.state = 'disconnected'; - this._implyConnect(); - this._socket.destroy(); + this._setupProtocolHandlers(); + + if (this._socket) { + this._socket.destroy(); + } + this._protocol.destroy(); }; Connection.prototype.pause = function() { - this._socket.pause(); + if (this._socket) { + this._socket.pause(); + } + this._protocol.pause(); }; Connection.prototype.resume = function() { - this._socket.resume(); + if (this._socket) { + this._socket.resume(); + } + this._protocol.resume(); }; @@ -450,11 +465,25 @@ Connection.prototype._handleProtocolEnqueue = function _handleProtocolEnqueue(se }; Connection.prototype._implyConnect = function() { - if (!this._connectCalled) { + this._setupProtocolHandlers(); + + if (!this._connectCalled && !this._protocol._destroyed) { this.connect(); } }; +Connection.prototype._setupProtocolHandlers = function _setupProtocolHandlers() { + if (!this._protocolSetup) { + this._protocolSetup = true; + this._protocol.on('handshake', this._handleProtocolHandshake.bind(this)); + this._protocol.on('initialize', this._handleProtocolInitialize.bind(this)); + this._protocol.on('unhandledError', this._handleProtocolError.bind(this)); + this._protocol.on('drain', this._handleProtocolDrain.bind(this)); + this._protocol.on('end', this._handleProtocolEnd.bind(this)); + this._protocol.on('enqueue', this._handleProtocolEnqueue.bind(this)); + } +}; + function createSecureContext (config, cb) { var context = null; var error = null; diff --git a/lib/protocol/Protocol.js b/lib/protocol/Protocol.js index ab371059b..34bfa23c2 100644 --- a/lib/protocol/Protocol.js +++ b/lib/protocol/Protocol.js @@ -186,7 +186,7 @@ Protocol.prototype._enqueue = function(sequence) { sequence.on('end', function () { self._handshaked = true; - if (!self._fatalError) { + if (!self._fatalError && !self._destroyed) { self.emit('handshake', self._handshakeInitializationPacket); } }); diff --git a/test/unit/connection/test-connect-bogus-port.js b/test/unit/connection/test-connect-bogus-port.js new file mode 100644 index 000000000..1fbf5ba3f --- /dev/null +++ b/test/unit/connection/test-connect-bogus-port.js @@ -0,0 +1,17 @@ +var assert = require('assert'); +var common = require('../../common'); + +var connection = common.createConnection({ + port: 99999 +}); + +connection.connect(function (err) { + assert.ok(err); + assert.strictEqual(err.fatal, true); + assert.ok( + err.code === 'ECONNREFUSED' /* Node.js < 0.12 */ || + err.code === 'ERR_SOCKET_BAD_PORT' /* Node.js > 8 */ || + err.name === 'RangeError' + ); + connection.destroy(); +});