mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
net: rework autoSelectFamily implementation
PR-URL: https://github.com/nodejs/node/pull/46587 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
@@ -941,7 +941,7 @@ For TCP connections, available `options` are:
|
||||
* `autoSelectFamilyAttemptTimeout` {number}: The amount of time in milliseconds to wait
|
||||
for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option.
|
||||
If set to a positive integer less than `10`, then the value `10` will be used instead.
|
||||
**Default:** `250`.
|
||||
**Default:** initially `250`, but it can be changed at runtime using [`net.setDefaultAutoSelectFamilyAttemptTimeout(value)`][]
|
||||
|
||||
For [IPC][] connections, available `options` are:
|
||||
|
||||
@@ -1528,26 +1528,6 @@ immediately initiates connection with
|
||||
[`socket.connect(port[, host][, connectListener])`][`socket.connect(port)`],
|
||||
then returns the `net.Socket` that starts the connection.
|
||||
|
||||
## `net.setDefaultAutoSelectFamily(value)`
|
||||
|
||||
<!-- YAML
|
||||
added: v19.4.0
|
||||
-->
|
||||
|
||||
Sets the default value of the `autoSelectFamily` option of [`socket.connect(options)`][].
|
||||
|
||||
* `value` {boolean} The new default value. The initial default value is `false`.
|
||||
|
||||
## `net.getDefaultAutoSelectFamily()`
|
||||
|
||||
<!-- YAML
|
||||
added: v19.4.0
|
||||
-->
|
||||
|
||||
Gets the current default value of the `autoSelectFamily` option of [`socket.connect(options)`][].
|
||||
|
||||
* Returns: {boolean} The current default value of the `autoSelectFamily` option.
|
||||
|
||||
## `net.createServer([options][, connectionListener])`
|
||||
|
||||
<!-- YAML
|
||||
@@ -1642,6 +1622,47 @@ Use `nc` to connect to a Unix domain socket server:
|
||||
$ nc -U /tmp/echo.sock
|
||||
```
|
||||
|
||||
## `net.getDefaultAutoSelectFamily()`
|
||||
|
||||
<!-- YAML
|
||||
added: v19.4.0
|
||||
-->
|
||||
|
||||
Gets the current default value of the `autoSelectFamily` option of [`socket.connect(options)`][].
|
||||
|
||||
* Returns: {boolean} The current default value of the `autoSelectFamily` option.
|
||||
|
||||
## `net.setDefaultAutoSelectFamily(value)`
|
||||
|
||||
<!-- YAML
|
||||
added: v19.4.0
|
||||
-->
|
||||
|
||||
Sets the default value of the `autoSelectFamily` option of [`socket.connect(options)`][].
|
||||
|
||||
* `value` {boolean} The new default value. The initial default value is `false`.
|
||||
|
||||
## `net.getDefaultAutoSelectFamilyAttemptTimeout()`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
Gets the current default value of the `autoSelectFamilyAttemptTimeout` option of [`socket.connect(options)`][].
|
||||
|
||||
* Returns: {number} The current default value of the `autoSelectFamilyAttemptTimeout` option.
|
||||
|
||||
## `net.setDefaultAutoSelectFamilyAttemptTimeout(value)`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
Sets the default value of the `autoSelectFamilyAttemptTimeout` option of [`socket.connect(options)`][].
|
||||
|
||||
* `value` {number} The new default value, which must be a positive number. If the number is less than `10`,
|
||||
the value `10` is used insted The initial default value is `250`.
|
||||
|
||||
## `net.isIP(input)`
|
||||
|
||||
<!-- YAML
|
||||
@@ -1727,6 +1748,7 @@ net.isIPv6('fhqwhgads'); // returns false
|
||||
[`net.createConnection(port, host)`]: #netcreateconnectionport-host-connectlistener
|
||||
[`net.createServer()`]: #netcreateserveroptions-connectionlistener
|
||||
[`net.setDefaultAutoSelectFamily(value)`]: #netsetdefaultautoselectfamilyvalue
|
||||
[`net.setDefaultAutoSelectFamilyAttemptTimeout(value)`]: #netsetdefaultautoselectfamilyattempttimeoutvalue
|
||||
[`new net.Socket(options)`]: #new-netsocketoptions
|
||||
[`readable.setEncoding()`]: stream.md#readablesetencodingencoding
|
||||
[`server.close()`]: #serverclosecallback
|
||||
|
||||
@@ -54,7 +54,7 @@ const EE = require('events');
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
const common = require('_tls_common');
|
||||
const { kWrapConnectedHandle } = require('internal/net');
|
||||
const { kReinitializeHandle } = require('internal/net');
|
||||
const JSStreamSocket = require('internal/js_stream_socket');
|
||||
const { Buffer } = require('buffer');
|
||||
let debug = require('internal/util/debuglog').debuglog('tls', (fn) => {
|
||||
@@ -633,14 +633,27 @@ TLSSocket.prototype._wrapHandle = function(wrap, handle) {
|
||||
return res;
|
||||
};
|
||||
|
||||
TLSSocket.prototype[kWrapConnectedHandle] = function(handle) {
|
||||
this._handle = this._wrapHandle(null, handle);
|
||||
TLSSocket.prototype[kReinitializeHandle] = function reinitializeHandle(handle) {
|
||||
const originalServername = this._handle.getServername();
|
||||
const originalSession = this._handle.getSession();
|
||||
|
||||
this.handle = this._wrapHandle(null, handle);
|
||||
this.ssl = this._handle;
|
||||
|
||||
net.Socket.prototype[kReinitializeHandle].call(this, this.handle);
|
||||
this._init();
|
||||
|
||||
if (this._tlsOptions.enableTrace) {
|
||||
this._handle.enableTrace();
|
||||
}
|
||||
|
||||
if (originalSession) {
|
||||
this.setSession(originalSession);
|
||||
}
|
||||
|
||||
if (originalServername) {
|
||||
this.setServername(originalServername);
|
||||
}
|
||||
};
|
||||
|
||||
// This eliminates a cyclic reference to TLSWrap
|
||||
@@ -679,6 +692,30 @@ TLSSocket.prototype._destroySSL = function _destroySSL() {
|
||||
this[kIsVerified] = false;
|
||||
};
|
||||
|
||||
function keylogNewListener(event) {
|
||||
if (event !== 'keylog')
|
||||
return;
|
||||
|
||||
// Guard against enableKeylogCallback after destroy
|
||||
if (!this._handle) return;
|
||||
this._handle.enableKeylogCallback();
|
||||
|
||||
// Remove this listener since it's no longer needed.
|
||||
this.removeListener('newListener', keylogNewListener);
|
||||
}
|
||||
|
||||
function newListener(event) {
|
||||
if (event !== 'session')
|
||||
return;
|
||||
|
||||
// Guard against enableSessionCallbacks after destroy
|
||||
if (!this._handle) return;
|
||||
this._handle.enableSessionCallbacks();
|
||||
|
||||
// Remove this listener since it's no longer needed.
|
||||
this.removeListener('newListener', newListener);
|
||||
}
|
||||
|
||||
// Constructor guts, arbitrarily factored out.
|
||||
let warnOnTlsKeylog = true;
|
||||
let warnOnTlsKeylogError = true;
|
||||
@@ -704,18 +741,9 @@ TLSSocket.prototype._init = function(socket, wrap) {
|
||||
|
||||
// Only call .onkeylog if there is a keylog listener.
|
||||
ssl.onkeylog = onkeylog;
|
||||
this.on('newListener', keylogNewListener);
|
||||
|
||||
function keylogNewListener(event) {
|
||||
if (event !== 'keylog')
|
||||
return;
|
||||
|
||||
// Guard against enableKeylogCallback after destroy
|
||||
if (!this._handle) return;
|
||||
this._handle.enableKeylogCallback();
|
||||
|
||||
// Remove this listener since it's no longer needed.
|
||||
this.removeListener('newListener', keylogNewListener);
|
||||
if (this.listenerCount('newListener', keylogNewListener) === 0) {
|
||||
this.on('newListener', keylogNewListener);
|
||||
}
|
||||
|
||||
if (options.isServer) {
|
||||
@@ -750,18 +778,8 @@ TLSSocket.prototype._init = function(socket, wrap) {
|
||||
ssl.onnewsession = onnewsessionclient;
|
||||
|
||||
// Only call .onnewsession if there is a session listener.
|
||||
this.on('newListener', newListener);
|
||||
|
||||
function newListener(event) {
|
||||
if (event !== 'session')
|
||||
return;
|
||||
|
||||
// Guard against enableSessionCallbacks after destroy
|
||||
if (!this._handle) return;
|
||||
this._handle.enableSessionCallbacks();
|
||||
|
||||
// Remove this listener since it's no longer needed.
|
||||
this.removeListener('newListener', newListener);
|
||||
if (this.listenerCount('newListener', newListener) === 0) {
|
||||
this.on('newListener', newListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ function makeSyncWrite(fd) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
kWrapConnectedHandle: Symbol('wrapConnectedHandle'),
|
||||
kReinitializeHandle: Symbol('reinitializeHandle'),
|
||||
isIP,
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
|
||||
92
lib/net.js
92
lib/net.js
@@ -42,7 +42,7 @@ let debug = require('internal/util/debuglog').debuglog('net', (fn) => {
|
||||
debug = fn;
|
||||
});
|
||||
const {
|
||||
kWrapConnectedHandle,
|
||||
kReinitializeHandle,
|
||||
isIP,
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
@@ -53,7 +53,8 @@ const assert = require('internal/assert');
|
||||
const {
|
||||
UV_EADDRINUSE,
|
||||
UV_EINVAL,
|
||||
UV_ENOTCONN
|
||||
UV_ENOTCONN,
|
||||
UV_ECANCELED
|
||||
} = internalBinding('uv');
|
||||
|
||||
const { Buffer } = require('buffer');
|
||||
@@ -127,6 +128,7 @@ let dns;
|
||||
let BlockList;
|
||||
let SocketAddress;
|
||||
let autoSelectFamilyDefault = getOptionValue('--enable-network-family-autoselection');
|
||||
let autoSelectFamilyAttemptTimeoutDefault = 250;
|
||||
|
||||
const { clearTimeout, setTimeout } = require('timers');
|
||||
const { kTimeout } = require('internal/timers');
|
||||
@@ -238,6 +240,20 @@ function setDefaultAutoSelectFamily(value) {
|
||||
autoSelectFamilyDefault = value;
|
||||
}
|
||||
|
||||
function getDefaultAutoSelectFamilyAttemptTimeout() {
|
||||
return autoSelectFamilyAttemptTimeoutDefault;
|
||||
}
|
||||
|
||||
function setDefaultAutoSelectFamilyAttemptTimeout(value) {
|
||||
validateInt32(value, 'value', 1);
|
||||
|
||||
if (value < 1) {
|
||||
value = 10;
|
||||
}
|
||||
|
||||
autoSelectFamilyAttemptTimeoutDefault = value;
|
||||
}
|
||||
|
||||
// Returns an array [options, cb], where options is an object,
|
||||
// cb is either a function or null.
|
||||
// Used to normalize arguments of Socket.prototype.connect() and
|
||||
@@ -678,7 +694,11 @@ function tryReadStart(socket) {
|
||||
|
||||
// Just call handle.readStart until we have enough in the buffer
|
||||
Socket.prototype._read = function(n) {
|
||||
debug('_read');
|
||||
debug(
|
||||
'_read - n', n,
|
||||
'isConnecting?', !!this.connecting,
|
||||
'hasHandle?', !!this._handle,
|
||||
);
|
||||
|
||||
if (this.connecting || !this._handle) {
|
||||
debug('_read wait for connection');
|
||||
@@ -1017,7 +1037,7 @@ function internalConnect(
|
||||
localAddress = localAddress || DEFAULT_IPV6_ADDR;
|
||||
err = self._handle.bind6(localAddress, localPort, flags);
|
||||
}
|
||||
debug('binding to localAddress: %s and localPort: %d (addressType: %d)',
|
||||
debug('connect: binding to localAddress: %s and localPort: %d (addressType: %d)',
|
||||
localAddress, localPort, addressType);
|
||||
|
||||
err = checkBindError(err, localPort, self._handle);
|
||||
@@ -1028,6 +1048,8 @@ function internalConnect(
|
||||
}
|
||||
}
|
||||
|
||||
debug('connect: attempting to connect to %s:%d (addressType: %d)', address, port, addressType);
|
||||
|
||||
if (addressType === 6 || addressType === 4) {
|
||||
const req = new TCPConnectWrap();
|
||||
req.oncomplete = afterConnect;
|
||||
@@ -1064,20 +1086,21 @@ function internalConnect(
|
||||
}
|
||||
|
||||
|
||||
function internalConnectMultiple(context) {
|
||||
function internalConnectMultiple(context, canceled) {
|
||||
clearTimeout(context[kTimeout]);
|
||||
const self = context.socket;
|
||||
assert(self.connecting);
|
||||
|
||||
// All connections have been tried without success, destroy with error
|
||||
if (context.current === context.addresses.length) {
|
||||
if (canceled || context.current === context.addresses.length) {
|
||||
self.destroy(aggregateErrors(context.errors));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(self.connecting);
|
||||
|
||||
const handle = context.current === 0 ? self._handle : new TCP(TCPConstants.SOCKET);
|
||||
const { localPort, port, flags } = context;
|
||||
const { address, family: addressType } = context.addresses[context.current++];
|
||||
const handle = new TCP(TCPConstants.SOCKET);
|
||||
let localAddress;
|
||||
let err;
|
||||
|
||||
@@ -1101,6 +1124,8 @@ function internalConnectMultiple(context) {
|
||||
}
|
||||
}
|
||||
|
||||
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.address = address;
|
||||
@@ -1190,6 +1215,15 @@ Socket.prototype.connect = function(...args) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Socket.prototype[kReinitializeHandle] = function reinitializeHandle(handle) {
|
||||
this._handle?.close();
|
||||
|
||||
this._handle = handle;
|
||||
this._handle[owner_symbol] = this;
|
||||
|
||||
initSocketHandle(this);
|
||||
};
|
||||
|
||||
function socketToDnsFamily(family) {
|
||||
switch (family) {
|
||||
case 'IPv4':
|
||||
@@ -1237,7 +1271,7 @@ function lookupAndConnect(self, options) {
|
||||
autoSelectFamilyAttemptTimeout = 10;
|
||||
}
|
||||
} else {
|
||||
autoSelectFamilyAttemptTimeout = 250;
|
||||
autoSelectFamilyAttemptTimeout = autoSelectFamilyAttemptTimeoutDefault;
|
||||
}
|
||||
|
||||
// If host is an IP, skip performing a lookup
|
||||
@@ -1279,17 +1313,19 @@ function lookupAndConnect(self, options) {
|
||||
debug('connect: autodetecting');
|
||||
|
||||
dnsopts.all = true;
|
||||
lookupAndConnectMultiple(
|
||||
self,
|
||||
async_id_symbol,
|
||||
lookup,
|
||||
host,
|
||||
options,
|
||||
dnsopts,
|
||||
port,
|
||||
localPort,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
);
|
||||
defaultTriggerAsyncIdScope(self[async_id_symbol], function() {
|
||||
lookupAndConnectMultiple(
|
||||
self,
|
||||
async_id_symbol,
|
||||
lookup,
|
||||
host,
|
||||
options,
|
||||
dnsopts,
|
||||
port,
|
||||
localPort,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1337,6 +1373,8 @@ function lookupAndConnectMultiple(self, async_id_symbol, lookup, host, options,
|
||||
if (!self.connecting) {
|
||||
return;
|
||||
} else if (err) {
|
||||
self.emit('lookup', err, undefined, undefined, host);
|
||||
|
||||
// net.createConnection() creates a net.Socket object and immediately
|
||||
// calls net.Socket.connect() on it (that's us). There are no event
|
||||
// listeners registered yet so defer the error event to the next tick.
|
||||
@@ -1529,7 +1567,7 @@ function afterConnectMultiple(context, status, handle, req, readable, writable)
|
||||
ArrayPrototypePush(context.errors, ex);
|
||||
|
||||
// Try the next address
|
||||
internalConnectMultiple(context);
|
||||
internalConnectMultiple(context, status === UV_ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1540,13 +1578,9 @@ function afterConnectMultiple(context, status, handle, req, readable, writable)
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform initialization sequence on the handle, then move on with the regular callback
|
||||
self._handle = handle;
|
||||
initSocketHandle(self);
|
||||
|
||||
if (self[kWrapConnectedHandle]) {
|
||||
self[kWrapConnectedHandle](handle);
|
||||
initSocketHandle(self); // This is called again to initialize the TLSWrap
|
||||
if (context.current > 1 && self[kReinitializeHandle]) {
|
||||
self[kReinitializeHandle](handle);
|
||||
handle = self._handle;
|
||||
}
|
||||
|
||||
if (hasObserver('net')) {
|
||||
@@ -2248,4 +2282,6 @@ module.exports = {
|
||||
Stream: Socket, // Legacy naming
|
||||
getDefaultAutoSelectFamily,
|
||||
setDefaultAutoSelectFamily,
|
||||
getDefaultAutoSelectFamilyAttemptTimeout,
|
||||
setDefaultAutoSelectFamilyAttemptTimeout,
|
||||
};
|
||||
|
||||
@@ -7,14 +7,12 @@ const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const { Resolver } = require('dns');
|
||||
const { request, createServer } = require('http');
|
||||
const { setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
|
||||
|
||||
// Test that happy eyeballs algorithm is properly implemented when using HTTP.
|
||||
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
|
||||
}
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
setDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
@@ -77,7 +75,6 @@ function createDnsServer(ipv6Addr, ipv4Addr, cb) {
|
||||
{
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout
|
||||
},
|
||||
(res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
@@ -122,7 +119,6 @@ if (common.hasIPv6) {
|
||||
{
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
},
|
||||
(res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
|
||||
@@ -11,6 +11,14 @@ const v8 = require('v8');
|
||||
// after it is destroyed, either because they are detached from it or have been
|
||||
// destroyed themselves.
|
||||
|
||||
// We use an higher autoSelectFamilyAttemptTimeout in this test as the v8.getHeapSnapshot().resume()
|
||||
// will slow the connection flow and we don't want the second connection attempt to start.
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(1000);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(10000);
|
||||
}
|
||||
|
||||
for (const variant of ['ping', 'settings']) {
|
||||
const server = http2.createServer();
|
||||
server.on('session', common.mustCall((session) => {
|
||||
@@ -30,7 +38,7 @@ for (const variant of ['ping', 'settings']) {
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
const client = http2.connect(`http://localhost:${server.address().port}`,
|
||||
const client = http2.connect(`http://localhost:${server.address().port}`, { autoSelectFamilyAttemptTimeout },
|
||||
common.mustCall());
|
||||
client.on('error', (err) => {
|
||||
// We destroy the session so it's possible to get ECONNRESET here.
|
||||
|
||||
@@ -13,6 +13,7 @@ const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const { Resolver } = require('dns');
|
||||
const { request, createServer } = require('https');
|
||||
const { setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
@@ -24,11 +25,8 @@ const options = {
|
||||
|
||||
// Test that happy eyeballs algorithm is properly implemented when using HTTP.
|
||||
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
|
||||
}
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
setDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
@@ -92,7 +90,6 @@ function createDnsServer(ipv6Addr, ipv4Addr, cb) {
|
||||
lookup,
|
||||
rejectUnauthorized: false,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout
|
||||
},
|
||||
(res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
@@ -138,7 +135,6 @@ if (common.hasIPv6) {
|
||||
lookup,
|
||||
rejectUnauthorized: false,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
},
|
||||
(res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
|
||||
@@ -8,15 +8,12 @@ const { parseDNSPacket, writeDNSPacket } = require('../common/dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const { Resolver } = require('dns');
|
||||
const { createConnection, createServer } = require('net');
|
||||
const { createConnection, createServer, setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
|
||||
|
||||
// Test that happy eyeballs algorithm can be enable from command line.
|
||||
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
|
||||
}
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
setDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
@@ -82,7 +79,6 @@ function createDnsServer(ipv6Addr, ipv4Addr, cb) {
|
||||
host: 'example.org',
|
||||
port: port,
|
||||
lookup,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
|
||||
let response = '';
|
||||
|
||||
@@ -6,15 +6,12 @@ const { parseDNSPacket, writeDNSPacket } = require('../common/dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const { Resolver } = require('dns');
|
||||
const { createConnection, createServer } = require('net');
|
||||
const { createConnection, createServer, setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
|
||||
|
||||
// Test that happy eyeballs algorithm is properly implemented when a A record is returned first.
|
||||
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
|
||||
}
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
setDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
@@ -88,7 +85,6 @@ if (common.hasIPv6) {
|
||||
port,
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout
|
||||
});
|
||||
|
||||
let response = '';
|
||||
|
||||
@@ -10,11 +10,11 @@ const { createConnection, createServer } = require('net');
|
||||
|
||||
// Test that happy eyeballs algorithm is properly implemented.
|
||||
|
||||
let autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
|
||||
if (common.isWindows) {
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
|
||||
}
|
||||
// Purposely not using setDefaultAutoSelectFamilyAttemptTimeout here to test the
|
||||
// parameter is correctly used in options.
|
||||
//
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
const autoSelectFamilyAttemptTimeout = common.platformTimeout(common.isWindows ? 1500 : 250);
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
|
||||
@@ -26,13 +26,22 @@ function check(addressType, cb) {
|
||||
|
||||
function lookup(host, dnsopts, cb) {
|
||||
dnsopts.family = addressType;
|
||||
|
||||
if (addressType === 4) {
|
||||
process.nextTick(function() {
|
||||
cb(null, common.localhostIPv4, 4);
|
||||
if (dnsopts.all) {
|
||||
cb(null, [{ address: common.localhostIPv4, family: 4 }]);
|
||||
} else {
|
||||
cb(null, common.localhostIPv4, 4);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
process.nextTick(function() {
|
||||
cb(null, '::1', 6);
|
||||
if (dnsopts.all) {
|
||||
cb(null, [{ address: '::1', family: 6 }]);
|
||||
} else {
|
||||
cb(null, '::1', 6);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -48,7 +57,11 @@ check(4, function() {
|
||||
host: 'localhost',
|
||||
port: 80,
|
||||
lookup(host, dnsopts, cb) {
|
||||
cb(null, undefined, 4);
|
||||
if (dnsopts.all) {
|
||||
cb(null, [{ address: undefined, family: 4 }]);
|
||||
} else {
|
||||
cb(null, undefined, 4);
|
||||
}
|
||||
}
|
||||
}).on('error', common.expectsError({ code: 'ERR_INVALID_IP_ADDRESS' }));
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ const server = net.createServer(function(client) {
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
net.connect(this.address().port, 'localhost')
|
||||
.on('lookup', common.mustCall(function(err, ip, type, host) {
|
||||
.on('lookup', common.mustCallAtLeast(function(err, ip, type, host) {
|
||||
assert.strictEqual(err, null);
|
||||
assert.match(ip, /^(127\.0\.0\.1|::1)$/);
|
||||
assert.match(type.toString(), /^(4|6)$/);
|
||||
assert.strictEqual(host, 'localhost');
|
||||
}));
|
||||
}, 1));
|
||||
}));
|
||||
|
||||
@@ -36,7 +36,11 @@ function connectDoesNotThrow(input) {
|
||||
{
|
||||
// Verify that an error is emitted when an invalid address family is returned.
|
||||
const s = connectDoesNotThrow((host, options, cb) => {
|
||||
cb(null, '127.0.0.1', 100);
|
||||
if (options.all) {
|
||||
cb(null, [{ address: '127.0.0.1', family: 100 }]);
|
||||
} else {
|
||||
cb(null, '127.0.0.1', 100);
|
||||
}
|
||||
});
|
||||
|
||||
s.on('error', common.expectsError({
|
||||
|
||||
@@ -20,17 +20,11 @@ server.on('close', common.mustCall());
|
||||
|
||||
assert.strictEqual(server, server.listen(0, () => {
|
||||
net.createConnection(server.address().port)
|
||||
.on('error', common.mustCall(
|
||||
common.expectsError({
|
||||
code: 'ECONNRESET',
|
||||
name: 'Error'
|
||||
}))
|
||||
);
|
||||
.on('error', common.mustCall((error) => {
|
||||
assert.strictEqual(error.code, 'ECONNRESET');
|
||||
}));
|
||||
net.createConnection(server.address().port)
|
||||
.on('error', common.mustCall(
|
||||
common.expectsError({
|
||||
code: 'ECONNRESET',
|
||||
name: 'Error'
|
||||
}))
|
||||
);
|
||||
.on('error', common.mustCall((error) => {
|
||||
assert.strictEqual(error.code, 'ECONNRESET');
|
||||
}));
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
@@ -11,4 +13,8 @@ for (const autoSelectFamilyAttemptTimeout of [-10, 0]) {
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
}, { code: 'ERR_OUT_OF_RANGE' });
|
||||
|
||||
assert.throws(() => {
|
||||
net.setDefaultAutoSelectFamilyAttemptTimeout(autoSelectFamilyAttemptTimeout);
|
||||
}, { code: 'ERR_OUT_OF_RANGE' });
|
||||
}
|
||||
|
||||
37
test/parallel/test-tls-autoselectfamily-servername.js
Normal file
37
test/parallel/test-tls-autoselectfamily-servername.js
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto) {
|
||||
common.skip('missing crypto');
|
||||
}
|
||||
|
||||
const { setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
|
||||
const { connect } = require('tls');
|
||||
|
||||
// Some of the windows machines in the CI need more time to establish connection
|
||||
setDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
|
||||
|
||||
// Test that TLS connecting works without autoSelectFamily
|
||||
{
|
||||
const socket = connect({
|
||||
host: 'google.com',
|
||||
port: 443,
|
||||
servername: 'google.com',
|
||||
autoSelectFamily: false,
|
||||
});
|
||||
|
||||
socket.on('secureConnect', common.mustCall(() => socket.end()));
|
||||
}
|
||||
|
||||
// Test that TLS connecting works with autoSelectFamily
|
||||
{
|
||||
const socket = connect({
|
||||
host: 'google.com',
|
||||
port: 443,
|
||||
servername: 'google.com',
|
||||
autoSelectFamily: true,
|
||||
});
|
||||
|
||||
socket.on('secureConnect', common.mustCall(() => socket.end()));
|
||||
}
|
||||
Reference in New Issue
Block a user