net: fix family autoselection timeout handling

PR-URL: https://github.com/nodejs/node/pull/47860
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Paolo Insogna 2023-05-11 09:14:03 -07:00 committed by GitHub
parent 4eec3626f2
commit 2d24b29cf4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 16 deletions

View file

@ -134,7 +134,6 @@ let autoSelectFamilyAttemptTimeoutDefault = 250;
const { clearTimeout, setTimeout } = require('timers');
const { kTimeout } = require('internal/timers');
const kTimeoutTriggered = Symbol('kTimeoutTriggered');
const DEFAULT_IPV4_ADDR = '0.0.0.0';
const DEFAULT_IPV6_ADDR = '::';
@ -1106,9 +1105,10 @@ function internalConnectMultiple(context, canceled) {
assert(self.connecting);
const handle = context.current === 0 ? self._handle : new TCP(TCPConstants.SOCKET);
const current = context.current++;
const handle = current === 0 ? self._handle : new TCP(TCPConstants.SOCKET);
const { localPort, port, flags } = context;
const { address, family: addressType } = context.addresses[context.current++];
const { address, family: addressType } = context.addresses[current];
let localAddress;
let err;
@ -1135,7 +1135,7 @@ function internalConnectMultiple(context, canceled) {
debug('connect/multiple: attempting to connect to %s:%d (addressType: %d)', address, port, addressType);
const req = new TCPConnectWrap();
req.oncomplete = FunctionPrototypeBind(afterConnectMultiple, undefined, context);
req.oncomplete = FunctionPrototypeBind(afterConnectMultiple, undefined, context, current);
req.address = address;
req.port = port;
req.localAddress = localAddress;
@ -1162,8 +1162,12 @@ function internalConnectMultiple(context, canceled) {
return;
}
// If the attempt has not returned an error, start the connection timer
context[kTimeout] = setTimeout(internalConnectMultipleTimeout, context.timeout, context, req);
if (current < context.addresses.length - 1) {
debug('connect/multiple: setting the attempt timeout to %d ms', context.timeout);
// If the attempt has not returned an error, start the connection timer
context[kTimeout] = setTimeout(internalConnectMultipleTimeout, context.timeout, context, req, handle);
}
}
Socket.prototype.connect = function(...args) {
@ -1478,7 +1482,6 @@ function lookupAndConnectMultiple(
localPort,
timeout,
[kTimeout]: null,
[kTimeoutTriggered]: false,
errors: [],
};
@ -1581,9 +1584,12 @@ function afterConnect(status, handle, req, readable, writable) {
}
}
function afterConnectMultiple(context, status, handle, req, readable, writable) {
function afterConnectMultiple(context, current, status, handle, req, readable, writable) {
// Make sure another connection is not spawned
clearTimeout(context[kTimeout]);
// One of the connection has completed and correctly dispatched but after timeout, ignore this one
if (context[kTimeoutTriggered]) {
if (status === 0 && current !== context.current - 1) {
debug('connect/multiple: ignoring successful but timedout connection to %s:%s', req.address, req.port);
handle.close();
return;
@ -1591,8 +1597,6 @@ function afterConnectMultiple(context, status, handle, req, readable, writable)
const self = context.socket;
// Make sure another connection is not spawned
clearTimeout(context[kTimeout]);
// Some error occurred, add to the list of exceptions
if (status !== 0) {
@ -1633,8 +1637,10 @@ function afterConnectMultiple(context, status, handle, req, readable, writable)
afterConnect(status, handle, req, readable, writable);
}
function internalConnectMultipleTimeout(context, req) {
context[kTimeoutTriggered] = true;
function internalConnectMultipleTimeout(context, req, handle) {
debug('connect/multiple: connection to %s:%s timed out', req.address, req.port);
req.oncomplete = undefined;
handle.close();
internalConnectMultiple(context);
}