@@ -757,6 +757,10 @@ void QuicSession::RandomConnectionIDStrategy(
757757# define HAVE_SSL_TRACE 1
758758#endif
759759
760+ QuicCryptoContext::~QuicCryptoContext () {
761+ // Free any remaining crypto handshake data (if any)
762+ Cancel ();
763+ }
760764
761765void QuicCryptoContext::MemoryInfo (MemoryTracker* tracker) const {
762766 tracker->TrackField (" initial_crypto" , handshake_[0 ]);
@@ -1470,8 +1474,6 @@ QuicSession::QuicSession(
14701474
14711475QuicSession::~QuicSession () {
14721476 CHECK (!Ngtcp2CallbackScope::InNgtcp2CallbackScope (this ));
1473- crypto_context_->Cancel ();
1474- connection_.reset ();
14751477
14761478 QuicSessionListener* listener_ = listener ();
14771479 listener_->OnSessionDestroyed ();
@@ -1637,7 +1639,9 @@ void QuicSession::AddStream(BaseObjectPtr<QuicStream> stream) {
16371639// not immediately torn down, but is allowed to drain
16381640// properly per the QUIC spec description of "immediate close".
16391641void QuicSession::ImmediateClose () {
1640- if (is_closing () || is_silent_closing ())
1642+ // If ImmediateClose or SilentClose has already been called,
1643+ // do not re-enter.
1644+ if (is_closing ())
16411645 return ;
16421646 set_closing ();
16431647
@@ -1649,6 +1653,35 @@ void QuicSession::ImmediateClose() {
16491653 listener ()->OnSessionClose (err);
16501654}
16511655
1656+ // Silent Close must start with the JavaScript side, which must
1657+ // clean up state, abort any still existing QuicSessions, then
1658+ // destroy the handle when done. The most important characteristic
1659+ // of the SilentClose is that no frames are sent to the peer.
1660+ //
1661+ // When a valid stateless reset is received, the connection is
1662+ // immediately and unrecoverably closed at the ngtcp2 level.
1663+ // Specifically, it will be put into the draining_period so
1664+ // absolutely no frames can be sent. What we need to do is
1665+ // notify the JavaScript side and destroy the connection with
1666+ // a flag set that indicates stateless reset.
1667+ void QuicSession::SilentClose () {
1668+ CHECK (!is_silent_closing ());
1669+ set_silent_closing ();
1670+ set_closing ();
1671+
1672+ QuicError err = last_error ();
1673+ Debug (this ,
1674+ " Silent close with %s code %" PRIu64 " (stateless reset? %s)" ,
1675+ err.family_name (),
1676+ err.code ,
1677+ is_stateless_reset () ? " yes" : " no" );
1678+
1679+ int flags = QuicSessionListener::SESSION_CLOSE_FLAG_SILENT;
1680+ if (is_stateless_reset ())
1681+ flags |= QuicSessionListener::SESSION_CLOSE_FLAG_STATELESS_RESET;
1682+ listener ()->OnSessionClose (err, flags);
1683+ }
1684+
16521685// Creates a new stream object and passes it off to the javascript side.
16531686// This has to be called from within a handlescope/contextscope.
16541687BaseObjectPtr<QuicStream> QuicSession::CreateStream (int64_t stream_id) {
@@ -1958,7 +1991,7 @@ bool QuicSession::ReceivePacket(
19581991 // then immediately close the connection.
19591992 if (err == NGTCP2_ERR_RETRY && is_server ()) {
19601993 socket ()->SendRetry (scid_, dcid_, local_address_, remote_address_);
1961- ImmediateClose ();
1994+ SilentClose ();
19621995 break ;
19631996 }
19641997 set_last_error (QUIC_ERROR_SESSION, err);
@@ -2050,7 +2083,7 @@ void QuicSession::RemoveFromSocket() {
20502083void QuicSession::RemoveStream (int64_t stream_id) {
20512084 Debug (this , " Removing stream %" PRId64, stream_id);
20522085
2053- // ngtcp2 does no extend the max streams count automatically
2086+ // ngtcp2 does not extend the max streams count automatically
20542087 // except in very specific conditions, none of which apply
20552088 // once we've gotten this far. We need to manually extend when
20562089 // a remote peer initiated stream is removed.
@@ -2104,6 +2137,8 @@ bool QuicSession::SendConnectionClose() {
21042137 // it multiple times; whereas for clients, we will serialize it
21052138 // once and send once only.
21062139 QuicError error = last_error ();
2140+ Debug (this , " Connection Close code: %" PRIu64 " (family: %s)" ,
2141+ error.code , error.family_name ());
21072142
21082143 // If initial keys have not yet been installed, use the alternative
21092144 // ImmediateConnectionClose to send a stateless connection close to
@@ -2322,34 +2357,6 @@ void QuicSession::ResumeStream(int64_t stream_id) {
23222357 application ()->ResumeStream (stream_id);
23232358}
23242359
2325- // Silent Close must start with the JavaScript side, which must
2326- // clean up state, abort any still existing QuicSessions, then
2327- // destroy the handle when done. The most important characteristic
2328- // of the SilentClose is that no frames are sent to the peer.
2329- //
2330- // When a valid stateless reset is received, the connection is
2331- // immediately and unrecoverably closed at the ngtcp2 level.
2332- // Specifically, it will be put into the draining_period so
2333- // absolutely no frames can be sent. What we need to do is
2334- // notify the JavaScript side and destroy the connection with
2335- // a flag set that indicates stateless reset.
2336- void QuicSession::SilentClose () {
2337- CHECK (!is_silent_closing ());
2338- set_silent_closing ();
2339- set_closing ();
2340-
2341- QuicError err = last_error ();
2342- Debug (this ,
2343- " Silent close with %s code %" PRIu64 " (stateless reset? %s)" ,
2344- err.family_name (),
2345- err.code ,
2346- is_stateless_reset () ? " yes" : " no" );
2347-
2348- int flags = QuicSessionListener::SESSION_CLOSE_FLAG_SILENT;
2349- if (is_stateless_reset ())
2350- flags |= QuicSessionListener::SESSION_CLOSE_FLAG_STATELESS_RESET;
2351- listener ()->OnSessionClose (err, flags);
2352- }
23532360// Begin connection close by serializing the CONNECTION_CLOSE packet.
23542361// There are two variants: one to serialize an application close, the
23552362// other to serialize a protocol close. The frames are generally
@@ -2508,7 +2515,6 @@ void QuicSession::UpdateIdleTimer() {
25082515// serialize stream data that is being sent initially.
25092516bool QuicSession::WritePackets (const char * diagnostic_label) {
25102517 CHECK (!Ngtcp2CallbackScope::InNgtcp2CallbackScope (this ));
2511- CHECK (!is_destroyed ());
25122518
25132519 // During the draining period, we must not send any frames at all.
25142520 if (is_in_draining_period ())
0 commit comments