23
23
24
24
const {
25
25
ArrayIsArray,
26
+ ArrayPrototypeIncludes,
26
27
ArrayPrototypeIndexOf,
27
28
ArrayPrototypePush,
28
29
Boolean,
@@ -97,6 +98,7 @@ const {
97
98
ERR_INVALID_HANDLE_TYPE ,
98
99
ERR_SERVER_ALREADY_LISTEN ,
99
100
ERR_SERVER_NOT_RUNNING ,
101
+ ERR_SOCKET_CONNECTION_TIMEOUT ,
100
102
ERR_SOCKET_CLOSED ,
101
103
ERR_SOCKET_CLOSED_BEFORE_CONNECTION ,
102
104
ERR_MISSING_ARGS ,
@@ -127,7 +129,7 @@ let cluster;
127
129
let dns ;
128
130
let BlockList ;
129
131
let SocketAddress ;
130
- let autoSelectFamilyDefault = getOptionValue ( '--enable- network-family-autoselection' ) ;
132
+ let autoSelectFamilyDefault = getOptionValue ( '--network-family-autoselection' ) ;
131
133
let autoSelectFamilyAttemptTimeoutDefault = 250 ;
132
134
133
135
const { clearTimeout, setTimeout } = require ( 'timers' ) ;
@@ -1092,6 +1094,11 @@ function internalConnectMultiple(context, canceled) {
1092
1094
1093
1095
// All connections have been tried without success, destroy with error
1094
1096
if ( canceled || context . current === context . addresses . length ) {
1097
+ if ( context . errors . length === 0 ) {
1098
+ self . destroy ( new ERR_SOCKET_CONNECTION_TIMEOUT ( ) ) ;
1099
+ return ;
1100
+ }
1101
+
1095
1102
self . destroy ( aggregateErrors ( context . errors ) ) ;
1096
1103
return ;
1097
1104
}
@@ -1322,6 +1329,7 @@ function lookupAndConnect(self, options) {
1322
1329
options ,
1323
1330
dnsopts ,
1324
1331
port ,
1332
+ localAddress ,
1325
1333
localPort ,
1326
1334
autoSelectFamilyAttemptTimeout ,
1327
1335
) ;
@@ -1364,7 +1372,9 @@ function lookupAndConnect(self, options) {
1364
1372
} ) ;
1365
1373
}
1366
1374
1367
- function lookupAndConnectMultiple ( self , async_id_symbol , lookup , host , options , dnsopts , port , localPort , timeout ) {
1375
+ function lookupAndConnectMultiple (
1376
+ self , async_id_symbol , lookup , host , options , dnsopts , port , localAddress , localPort , timeout ,
1377
+ ) {
1368
1378
defaultTriggerAsyncIdScope ( self [ async_id_symbol ] , function emitLookup ( ) {
1369
1379
lookup ( host , dnsopts , function emitLookup ( err , addresses ) {
1370
1380
// It's possible we were destroyed while looking this up.
@@ -1385,6 +1395,7 @@ function lookupAndConnectMultiple(self, async_id_symbol, lookup, host, options,
1385
1395
// Filter addresses by only keeping the one which are either IPv4 or IPV6.
1386
1396
// The first valid address determines which group has preference on the
1387
1397
// alternate family sorting which happens later.
1398
+ const validAddresses = [ [ ] , [ ] ] ;
1388
1399
const validIps = [ [ ] , [ ] ] ;
1389
1400
let destinations ;
1390
1401
for ( let i = 0 , l = addresses . length ; i < l ; i ++ ) {
@@ -1397,12 +1408,19 @@ function lookupAndConnectMultiple(self, async_id_symbol, lookup, host, options,
1397
1408
destinations = addressType === 6 ? { 6 : 0 , 4 : 1 } : { 4 : 0 , 6 : 1 } ;
1398
1409
}
1399
1410
1400
- ArrayPrototypePush ( validIps [ destinations [ addressType ] ] , address ) ;
1411
+ const destination = destinations [ addressType ] ;
1412
+
1413
+ // Only try an address once
1414
+ if ( ! ArrayPrototypeIncludes ( validIps [ destination ] , ip ) ) {
1415
+ ArrayPrototypePush ( validAddresses [ destination ] , address ) ;
1416
+ ArrayPrototypePush ( validIps [ destination ] , ip ) ;
1417
+ }
1401
1418
}
1402
1419
}
1403
1420
1421
+
1404
1422
// When no AAAA or A records are available, fail on the first one
1405
- if ( ! validIps [ 0 ] . length && ! validIps [ 1 ] . length ) {
1423
+ if ( ! validAddresses [ 0 ] . length && ! validAddresses [ 1 ] . length ) {
1406
1424
const { address : firstIp , family : firstAddressType } = addresses [ 0 ] ;
1407
1425
1408
1426
if ( ! isIP ( firstIp ) ) {
@@ -1420,16 +1438,36 @@ function lookupAndConnectMultiple(self, async_id_symbol, lookup, host, options,
1420
1438
1421
1439
// Sort addresses alternating families
1422
1440
const toAttempt = [ ] ;
1423
- for ( let i = 0 , l = MathMax ( validIps [ 0 ] . length , validIps [ 1 ] . length ) ; i < l ; i ++ ) {
1424
- if ( i in validIps [ 0 ] ) {
1425
- ArrayPrototypePush ( toAttempt , validIps [ 0 ] [ i ] ) ;
1441
+ for ( let i = 0 , l = MathMax ( validAddresses [ 0 ] . length , validAddresses [ 1 ] . length ) ; i < l ; i ++ ) {
1442
+ if ( i in validAddresses [ 0 ] ) {
1443
+ ArrayPrototypePush ( toAttempt , validAddresses [ 0 ] [ i ] ) ;
1426
1444
}
1427
- if ( i in validIps [ 1 ] ) {
1428
- ArrayPrototypePush ( toAttempt , validIps [ 1 ] [ i ] ) ;
1445
+ if ( i in validAddresses [ 1 ] ) {
1446
+ ArrayPrototypePush ( toAttempt , validAddresses [ 1 ] [ i ] ) ;
1429
1447
}
1430
1448
}
1431
1449
1450
+ if ( toAttempt . length === 1 ) {
1451
+ debug ( 'connect/multiple: only one address found, switching back to single connection' ) ;
1452
+ const { address : ip , family : addressType } = toAttempt [ 0 ] ;
1453
+
1454
+ self . _unrefTimer ( ) ;
1455
+ defaultTriggerAsyncIdScope (
1456
+ self [ async_id_symbol ] ,
1457
+ internalConnect ,
1458
+ self ,
1459
+ ip ,
1460
+ port ,
1461
+ addressType ,
1462
+ localAddress ,
1463
+ localPort ,
1464
+ ) ;
1465
+
1466
+ return ;
1467
+ }
1468
+
1432
1469
self . autoSelectFamilyAttemptedAddresses = [ ] ;
1470
+ debug ( 'connect/multiple: will try the following addresses' , toAttempt ) ;
1433
1471
1434
1472
const context = {
1435
1473
socket : self ,
@@ -1543,6 +1581,13 @@ function afterConnect(status, handle, req, readable, writable) {
1543
1581
}
1544
1582
1545
1583
function afterConnectMultiple ( context , status , handle , req , readable , writable ) {
1584
+ // One of the connection has completed and correctly dispatched but after timeout, ignore this one
1585
+ if ( context [ kTimeoutTriggered ] ) {
1586
+ debug ( 'connect/multiple: ignoring successful but timedout connection to %s:%s' , req . address , req . port ) ;
1587
+ handle . close ( ) ;
1588
+ return ;
1589
+ }
1590
+
1546
1591
const self = context . socket ;
1547
1592
1548
1593
// Make sure another connection is not spawned
@@ -1571,13 +1616,6 @@ function afterConnectMultiple(context, status, handle, req, readable, writable)
1571
1616
return ;
1572
1617
}
1573
1618
1574
- // One of the connection has completed and correctly dispatched but after timeout, ignore this one
1575
- if ( context [ kTimeoutTriggered ] ) {
1576
- debug ( 'connect/multiple: ignoring successful but timedout connection to %s:%s' , req . address , req . port ) ;
1577
- handle . close ( ) ;
1578
- return ;
1579
- }
1580
-
1581
1619
if ( context . current > 1 && self [ kReinitializeHandle ] ) {
1582
1620
self [ kReinitializeHandle ] ( handle ) ;
1583
1621
handle = self . _handle ;
0 commit comments