@@ -1376,8 +1376,7 @@ export class Server {
1376
1376
1377
1377
let connectionAgeTimer : NodeJS . Timeout | null = null ;
1378
1378
let connectionAgeGraceTimer : NodeJS . Timeout | null = null ;
1379
- let keeapliveTimeTimer : NodeJS . Timeout | null = null ;
1380
- let keepaliveTimeoutTimer : NodeJS . Timeout | null = null ;
1379
+ let keepaliveInterval : NodeJS . Timeout | null = null ;
1381
1380
let sessionClosedByServer = false ;
1382
1381
1383
1382
const idleTimeoutObj = this . enableIdleTimeout ( session ) ;
@@ -1421,41 +1420,74 @@ export class Server {
1421
1420
}
1422
1421
1423
1422
if ( this . keepaliveTimeMs < KEEPALIVE_MAX_TIME_MS ) {
1424
- keeapliveTimeTimer = setInterval ( ( ) => {
1425
- keepaliveTimeoutTimer = setTimeout ( ( ) => {
1426
- sessionClosedByServer = true ;
1427
- session . close ( ) ;
1423
+ keepaliveInterval = setInterval ( ( ) => {
1424
+ // NOTE to self: document in PR that prior implementation would overwrite the prior pending timeout
1425
+ // if the timeout had not occurred before the prior interval had elapsed (bad bug)
1426
+ const keepaliveTimeout = setTimeout ( ( ) => {
1427
+ if ( keepaliveInterval ) {
1428
+ clearInterval ( keepaliveInterval ) ;
1429
+ keepaliveInterval = null ;
1430
+ sessionClosedByServer = true ;
1431
+ this . trace ( 'Connection dropped by keepalive timeout' ) ;
1432
+ session . close ( ) ;
1433
+ }
1428
1434
} , this . keepaliveTimeoutMs ) ;
1429
- keepaliveTimeoutTimer . unref ?.( ) ;
1435
+ keepaliveTimeout . unref ?.( ) ;
1430
1436
1431
1437
try {
1432
- session . ping (
1433
- ( err : Error | null , duration : number , payload : Buffer ) => {
1434
- if ( keepaliveTimeoutTimer ) {
1435
- clearTimeout ( keepaliveTimeoutTimer ) ;
1438
+ if (
1439
+ ! session . ping (
1440
+ ( err : Error | null , duration : number , payload : Buffer ) => {
1441
+ clearTimeout ( keepaliveTimeout ) ;
1442
+ if ( err ) {
1443
+ if ( keepaliveInterval ) {
1444
+ clearInterval ( keepaliveInterval ) ;
1445
+ keepaliveInterval = null ;
1446
+ }
1447
+ sessionClosedByServer = true ;
1448
+ this . trace (
1449
+ 'Connection dropped due to error with ping frame ' +
1450
+ err . message +
1451
+ ' return in ' +
1452
+ duration
1453
+ ) ;
1454
+ session . close ( ) ;
1455
+ }
1436
1456
}
1437
-
1438
- if ( err ) {
1439
- sessionClosedByServer = true ;
1440
- this . trace (
1441
- 'Connection dropped due to error of a ping frame ' +
1442
- err . message +
1443
- ' return in ' +
1444
- duration
1445
- ) ;
1446
- session . close ( ) ;
1447
- }
1448
- }
1449
- ) ;
1457
+ )
1458
+ ) {
1459
+ throw new Error ( 'Server keepalive ping send failed' ) ;
1460
+ }
1450
1461
} catch ( e ) {
1451
- clearTimeout ( keepaliveTimeoutTimer ) ;
1452
- // The ping can't be sent because the session is already closed
1462
+ // The ping can't be sent because the session is already closed, max outstanding pings reached, etc
1463
+ clearTimeout ( keepaliveTimeout ) ;
1464
+ if ( keepaliveInterval ) {
1465
+ clearInterval ( keepaliveInterval ) ;
1466
+ keepaliveInterval = null ;
1467
+ }
1468
+ this . trace (
1469
+ 'Connection dropped due to error sending ping frame ' +
1470
+ ( e instanceof Error ? e . message : 'unknown error' )
1471
+ ) ;
1453
1472
session . destroy ( ) ;
1454
1473
}
1455
1474
} , this . keepaliveTimeMs ) ;
1456
- keeapliveTimeTimer . unref ?.( ) ;
1475
+ keepaliveInterval . unref ?.( ) ;
1457
1476
}
1458
1477
1478
+ session . once ( 'goaway' , ( errorCode , lastStreamID , opaqueData ) => {
1479
+ if ( errorCode === http2 . constants . NGHTTP2_ENHANCE_YOUR_CALM ) {
1480
+ this . trace ( 'Connection dropped by client due to ENHANCE_YOUR_CALM' ) ;
1481
+ } else {
1482
+ this . trace (
1483
+ 'Connection dropped by client via GOAWAY with error code ' +
1484
+ errorCode
1485
+ ) ;
1486
+ }
1487
+ sessionClosedByServer = true ;
1488
+ session . destroy ( ) ;
1489
+ } ) ;
1490
+
1459
1491
session . on ( 'close' , ( ) => {
1460
1492
if ( ! sessionClosedByServer ) {
1461
1493
this . trace (
@@ -1471,11 +1503,9 @@ export class Server {
1471
1503
clearTimeout ( connectionAgeGraceTimer ) ;
1472
1504
}
1473
1505
1474
- if ( keeapliveTimeTimer ) {
1475
- clearInterval ( keeapliveTimeTimer ) ;
1476
- if ( keepaliveTimeoutTimer ) {
1477
- clearTimeout ( keepaliveTimeoutTimer ) ;
1478
- }
1506
+ if ( keepaliveInterval ) {
1507
+ clearInterval ( keepaliveInterval ) ;
1508
+ keepaliveInterval = null ;
1479
1509
}
1480
1510
1481
1511
if ( idleTimeoutObj !== null ) {
@@ -1521,8 +1551,7 @@ export class Server {
1521
1551
1522
1552
let connectionAgeTimer : NodeJS . Timeout | null = null ;
1523
1553
let connectionAgeGraceTimer : NodeJS . Timeout | null = null ;
1524
- let keeapliveTimeTimer : NodeJS . Timeout | null = null ;
1525
- let keepaliveTimeoutTimer : NodeJS . Timeout | null = null ;
1554
+ let keepaliveInterval : NodeJS . Timeout | null = null ;
1526
1555
let sessionClosedByServer = false ;
1527
1556
1528
1557
const idleTimeoutObj = this . enableIdleTimeout ( session ) ;
@@ -1565,49 +1594,85 @@ export class Server {
1565
1594
}
1566
1595
1567
1596
if ( this . keepaliveTimeMs < KEEPALIVE_MAX_TIME_MS ) {
1568
- keeapliveTimeTimer = setInterval ( ( ) => {
1569
- keepaliveTimeoutTimer = setTimeout ( ( ) => {
1570
- sessionClosedByServer = true ;
1571
- this . channelzTrace . addTrace (
1572
- 'CT_INFO' ,
1573
- 'Connection dropped by keepalive timeout from ' + clientAddress
1574
- ) ;
1575
-
1576
- session . close ( ) ;
1597
+ keepaliveInterval = setInterval ( ( ) => {
1598
+ const keepaliveTimeout = setTimeout ( ( ) => {
1599
+ if ( keepaliveInterval ) {
1600
+ clearInterval ( keepaliveInterval ) ;
1601
+ keepaliveInterval = null ;
1602
+ sessionClosedByServer = true ;
1603
+ this . channelzTrace . addTrace (
1604
+ 'CT_INFO' ,
1605
+ 'Connection dropped by keepalive timeout from ' + clientAddress
1606
+ ) ;
1607
+ session . close ( ) ;
1608
+ }
1577
1609
} , this . keepaliveTimeoutMs ) ;
1578
- keepaliveTimeoutTimer . unref ?.( ) ;
1610
+ keepaliveTimeout . unref ?.( ) ;
1579
1611
1580
1612
try {
1581
- session . ping (
1582
- ( err : Error | null , duration : number , payload : Buffer ) => {
1583
- if ( keepaliveTimeoutTimer ) {
1584
- clearTimeout ( keepaliveTimeoutTimer ) ;
1585
- }
1586
-
1587
- if ( err ) {
1588
- sessionClosedByServer = true ;
1589
- this . channelzTrace . addTrace (
1590
- 'CT_INFO' ,
1591
- 'Connection dropped due to error of a ping frame ' +
1592
- err . message +
1593
- ' return in ' +
1594
- duration
1595
- ) ;
1596
-
1597
- session . close ( ) ;
1613
+ if (
1614
+ ! session . ping (
1615
+ ( err : Error | null , duration : number , payload : Buffer ) => {
1616
+ clearTimeout ( keepaliveTimeout ) ;
1617
+ if ( err ) {
1618
+ if ( keepaliveInterval ) {
1619
+ clearInterval ( keepaliveInterval ) ;
1620
+ keepaliveInterval = null ;
1621
+ }
1622
+ sessionClosedByServer = true ;
1623
+ this . channelzTrace . addTrace (
1624
+ 'CT_INFO' ,
1625
+ 'Connection dropped due to error with ping frame ' +
1626
+ err . message +
1627
+ ' return in ' +
1628
+ duration
1629
+ ) ;
1630
+ session . close ( ) ;
1631
+ }
1598
1632
}
1599
- }
1600
- ) ;
1633
+ )
1634
+ ) {
1635
+ throw new Error ( 'Server keepalive ping send failed' ) ;
1636
+ }
1601
1637
channelzSessionInfo . keepAlivesSent += 1 ;
1602
1638
} catch ( e ) {
1603
- clearTimeout ( keepaliveTimeoutTimer ) ;
1604
- // The ping can't be sent because the session is already closed
1639
+ // The ping can't be sent because the session is already closed, max outstanding pings reached, etc
1640
+ clearTimeout ( keepaliveTimeout ) ;
1641
+ if ( keepaliveInterval ) {
1642
+ clearInterval ( keepaliveInterval ) ;
1643
+ keepaliveInterval = null ;
1644
+ }
1645
+ this . channelzTrace . addTrace (
1646
+ 'CT_INFO' ,
1647
+ 'Connection dropped due to error sending ping frame ' +
1648
+ ( e instanceof Error ? e . message : 'unknown error' )
1649
+ ) ;
1605
1650
session . destroy ( ) ;
1606
1651
}
1607
1652
} , this . keepaliveTimeMs ) ;
1608
- keeapliveTimeTimer . unref ?.( ) ;
1653
+ keepaliveInterval . unref ?.( ) ;
1609
1654
}
1610
1655
1656
+ session . once ( 'goaway' , ( errorCode , lastStreamID , opaqueData ) => {
1657
+ if ( errorCode === http2 . constants . NGHTTP2_ENHANCE_YOUR_CALM ) {
1658
+ this . channelzTrace . addTrace (
1659
+ 'CT_INFO' ,
1660
+ 'Connection dropped by client due GOAWAY of ENHANCE_YOUR_CALM from ' +
1661
+ clientAddress
1662
+ ) ;
1663
+ } else {
1664
+ this . channelzTrace . addTrace (
1665
+ 'CT_INFO' ,
1666
+ 'Connection dropped by client via GOAWAY with error code ' +
1667
+ errorCode +
1668
+ ' from ' +
1669
+ clientAddress
1670
+ ) ;
1671
+ }
1672
+ sessionClosedByServer = true ;
1673
+ session . destroy ( ) ;
1674
+ } ) ;
1675
+
1611
1676
session . on ( 'close' , ( ) => {
1612
1677
if ( ! sessionClosedByServer ) {
1613
1678
this . channelzTrace . addTrace (
@@ -1627,11 +1692,9 @@ export class Server {
1627
1692
clearTimeout ( connectionAgeGraceTimer ) ;
1628
1693
}
1629
1694
1630
- if ( keeapliveTimeTimer ) {
1631
- clearInterval ( keeapliveTimeTimer ) ;
1632
- if ( keepaliveTimeoutTimer ) {
1633
- clearTimeout ( keepaliveTimeoutTimer ) ;
1634
- }
1695
+ if ( keepaliveInterval ) {
1696
+ clearInterval ( keepaliveInterval ) ;
1697
+ keepaliveInterval = null ;
1635
1698
}
1636
1699
1637
1700
if ( idleTimeoutObj !== null ) {
0 commit comments