@@ -287,24 +287,10 @@ function onSessionReady(handle) {
287287 process . nextTick ( emit . bind ( socket , 'session' , session ) ) ;
288288}
289289
290- // Called when the session needs to be closed and destroyed.
291- // If silent is true, then the session is going to be closed
292- // immediately without sending any CONNECTION_CLOSE to the
293- // connected peer. If silent is false, a CONNECTION_CLOSE
294- // is going to be sent to the peer.
290+ // Called when the C++ QuicSession::Close() method has been called.
291+ // Synchronously cleanup and destroy the JavaScript QuicSession.
295292function onSessionClose ( code , family , silent , statelessReset ) {
296- if ( this [ owner_symbol ] ) {
297- if ( silent ) {
298- this [ owner_symbol ] [ kDestroy ] ( statelessReset , family , code ) ;
299- } else {
300- this [ owner_symbol ] [ kClose ] ( family , code ) ;
301- }
302- return ;
303- }
304- // When there's no owner_symbol, the session was closed
305- // before it could be fully set up. Just immediately
306- // close everything down on the native side.
307- this . destroy ( code , family ) ;
293+ this [ owner_symbol ] [ kDestroy ] ( code , family , silent , statelessReset ) ;
308294}
309295
310296// Called by the C++ internals when a QuicSession has been destroyed.
@@ -1654,6 +1640,7 @@ class QuicSession extends EventEmitter {
16541640 maxPacketLength : NGTCP2_DEFAULT_MAX_PKTLEN ,
16551641 servername : undefined ,
16561642 socket : undefined ,
1643+ silentClose : false ,
16571644 statelessReset : false ,
16581645 stats : undefined ,
16591646 pendingStreams : new Set ( ) ,
@@ -1736,46 +1723,15 @@ class QuicSession extends EventEmitter {
17361723
17371724 // Causes the QuicSession to be immediately destroyed, but with
17381725 // additional metadata set.
1739- [ kDestroy ] ( statelessReset , family , code ) {
1726+ [ kDestroy ] ( code , family , silent , statelessReset ) {
17401727 const state = this [ kInternalState ] ;
1741- state . statelessReset = statelessReset ;
17421728 state . closeCode = code ;
17431729 state . closeFamily = family ;
1730+ state . silentClose = silent ;
1731+ state . statelessReset = statelessReset ;
17441732 this . destroy ( ) ;
17451733 }
17461734
1747- // Immediate close has been initiated for the session. Any
1748- // still open QuicStreams must be abandoned and shutdown
1749- // with RESET_STREAM and STOP_SENDING frames transmitted
1750- // as appropriate. Once the streams have been shutdown, a
1751- // CONNECTION_CLOSE will be generated and sent, switching
1752- // the session into the closing period.
1753- [ kClose ] ( family , code ) {
1754- const state = this [ kInternalState ] ;
1755- // Do nothing if the QuicSession has already been destroyed.
1756- if ( state . destroyed )
1757- return ;
1758-
1759- // Set the close code and family so we can keep track.
1760- state . closeCode = code ;
1761- state . closeFamily = family ;
1762-
1763- // Shutdown all pending streams. These are Streams that
1764- // have been created but do not yet have a handle assigned.
1765- for ( const stream of state . pendingStreams )
1766- stream [ kClose ] ( family , code ) ;
1767-
1768- // Shutdown all of the remaining streams
1769- for ( const stream of state . streams . values ( ) )
1770- stream [ kClose ] ( family , code ) ;
1771-
1772- // By this point, all necessary RESET_STREAM and
1773- // STOP_SENDING frames ought to have been sent,
1774- // so now we just trigger sending of the
1775- // CONNECTION_CLOSE frame.
1776- this [ kHandle ] . close ( family , code ) ;
1777- }
1778-
17791735 // Closes the specified stream with the given code. The
17801736 // QuicStream object will be destroyed.
17811737 [ kStreamClose ] ( id , code ) {
@@ -1873,14 +1829,6 @@ class QuicSession extends EventEmitter {
18731829 this [ kInternalState ] . streams . set ( id , stream ) ;
18741830 }
18751831
1876- // The QuicSession will be destroyed if closing has been
1877- // called and there are no remaining streams
1878- [ kMaybeDestroy ] ( ) {
1879- const state = this [ kInternalState ] ;
1880- if ( state . closing && state . streams . size === 0 )
1881- this . destroy ( ) ;
1882- }
1883-
18841832 // Called when a client QuicSession has opted to use the
18851833 // server provided preferred address. This is a purely
18861834 // informationational notification. It is not called on
@@ -1890,6 +1838,17 @@ class QuicSession extends EventEmitter {
18901838 emit . bind ( this , 'usePreferredAddress' , address ) ) ;
18911839 }
18921840
1841+ // The QuicSession will be destroyed if close() has been
1842+ // called and there are no remaining streams
1843+ [ kMaybeDestroy ] ( ) {
1844+ const state = this [ kInternalState ] ;
1845+ if ( state . closing && state . streams . size === 0 ) {
1846+ this . destroy ( ) ;
1847+ return true ;
1848+ }
1849+ return false ;
1850+ }
1851+
18931852 // Closing allows any existing QuicStream's to complete
18941853 // normally but disallows any new QuicStreams from being
18951854 // opened. Calls to openStream() will fail, and new streams
@@ -1910,27 +1869,27 @@ class QuicSession extends EventEmitter {
19101869 // has been destroyed
19111870 if ( state . closing )
19121871 return ;
1913-
19141872 state . closing = true ;
1915- this [ kHandle ] . gracefulClose ( ) ;
19161873
1917- // See if we can close immediately.
1918- this [ kMaybeDestroy ] ( ) ;
1874+ // If there are no active streams, we can close immediately,
1875+ // otherwise set the graceful close flag.
1876+ if ( ! this [ kMaybeDestroy ] ( ) )
1877+ this [ kHandle ] . gracefulClose ( ) ;
19191878 }
19201879
19211880 // Destroying synchronously shuts down and frees the
19221881 // QuicSession immediately, even if there are still open
19231882 // streams.
19241883 //
1925- // A CONNECTION_CLOSE packet is sent to the
1926- // connected peer and the session is immediately
1927- // destroyed.
1884+ // Unless we're in the middle of a silent close, a
1885+ // CONNECTION_CLOSE packet will be sent to the connected
1886+ // peer and the session will be immediately destroyed.
19281887 //
19291888 // If destroy is called with an error argument, the
19301889 // 'error' event is emitted on next tick.
19311890 //
19321891 // Once destroyed, and after the 'error' event (if any),
1933- // the close event is emitted on next tick.
1892+ // the ' close' event is emitted on next tick.
19341893 destroy ( error ) {
19351894 const state = this [ kInternalState ] ;
19361895 // Destroy can only be called once. Multiple calls will be ignored
@@ -1939,19 +1898,6 @@ class QuicSession extends EventEmitter {
19391898 state . destroyed = true ;
19401899 state . closing = false ;
19411900
1942- if ( typeof error === 'number' ||
1943- ( error != null &&
1944- typeof error === 'object' &&
1945- ! ( error instanceof Error ) ) ) {
1946- const {
1947- closeCode,
1948- closeFamily
1949- } = validateCloseCode ( error ) ;
1950- state . closeCode = closeCode ;
1951- state . closeFamily = closeFamily ;
1952- error = new ERR_QUIC_ERROR ( closeCode , closeFamily ) ;
1953- }
1954-
19551901 // Destroy any pending streams immediately. These
19561902 // are streams that have been created but have not
19571903 // yet been assigned an internal handle.
@@ -1965,16 +1911,20 @@ class QuicSession extends EventEmitter {
19651911 this . removeListener ( 'newListener' , onNewListener ) ;
19661912 this . removeListener ( 'removeListener' , onRemoveListener ) ;
19671913
1914+ // If we are destroying with an error, schedule the
1915+ // error to be emitted on process.nextTick.
19681916 if ( error ) process . nextTick ( emit . bind ( this , 'error' , error ) ) ;
19691917
19701918 const handle = this [ kHandle ] ;
1919+ this [ kHandle ] = undefined ;
1920+
19711921 if ( handle !== undefined ) {
19721922 // Copy the stats for use after destruction
19731923 state . stats = new BigInt64Array ( handle . stats ) ;
1974- state . idleTimeout = ! ! handle . state [ IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT ] ;
1975- // Calling destroy will cause a CONNECTION_CLOSE to be
1976- // sent to the peer and will destroy the QuicSession
1977- // handler immediately.
1924+ state . idleTimeout =
1925+ Boolean ( handle . state [ IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT ] ) ;
1926+
1927+ // Destroy the underlying QuicSession handle
19781928 handle . destroy ( state . closeCode , state . closeFamily ) ;
19791929 } else {
19801930 process . nextTick ( emit . bind ( this , 'close' ) ) ;
@@ -2108,7 +2058,8 @@ class QuicSession extends EventEmitter {
21082058 const state = this [ kInternalState ] ;
21092059 return {
21102060 code : state . closeCode ,
2111- family : state . closeFamily
2061+ family : state . closeFamily ,
2062+ silent : state . silentClose ,
21122063 } ;
21132064 }
21142065
0 commit comments