@@ -757,6 +757,10 @@ void QuicSession::RandomConnectionIDStrategy(
757
757
# define HAVE_SSL_TRACE 1
758
758
#endif
759
759
760
+ QuicCryptoContext::~QuicCryptoContext () {
761
+ // Free any remaining crypto handshake data (if any)
762
+ Cancel ();
763
+ }
760
764
761
765
void QuicCryptoContext::MemoryInfo (MemoryTracker* tracker) const {
762
766
tracker->TrackField (" initial_crypto" , handshake_[0 ]);
@@ -1470,8 +1474,6 @@ QuicSession::QuicSession(
1470
1474
1471
1475
QuicSession::~QuicSession () {
1472
1476
CHECK (!Ngtcp2CallbackScope::InNgtcp2CallbackScope (this ));
1473
- crypto_context_->Cancel ();
1474
- connection_.reset ();
1475
1477
1476
1478
QuicSessionListener* listener_ = listener ();
1477
1479
listener_->OnSessionDestroyed ();
@@ -1637,7 +1639,9 @@ void QuicSession::AddStream(BaseObjectPtr<QuicStream> stream) {
1637
1639
// not immediately torn down, but is allowed to drain
1638
1640
// properly per the QUIC spec description of "immediate close".
1639
1641
void 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 ())
1641
1645
return ;
1642
1646
set_closing ();
1643
1647
@@ -1649,6 +1653,35 @@ void QuicSession::ImmediateClose() {
1649
1653
listener ()->OnSessionClose (err);
1650
1654
}
1651
1655
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
+
1652
1685
// Creates a new stream object and passes it off to the javascript side.
1653
1686
// This has to be called from within a handlescope/contextscope.
1654
1687
BaseObjectPtr<QuicStream> QuicSession::CreateStream (int64_t stream_id) {
@@ -1958,7 +1991,7 @@ bool QuicSession::ReceivePacket(
1958
1991
// then immediately close the connection.
1959
1992
if (err == NGTCP2_ERR_RETRY && is_server ()) {
1960
1993
socket ()->SendRetry (scid_, dcid_, local_address_, remote_address_);
1961
- ImmediateClose ();
1994
+ SilentClose ();
1962
1995
break ;
1963
1996
}
1964
1997
set_last_error (QUIC_ERROR_SESSION, err);
@@ -2050,7 +2083,7 @@ void QuicSession::RemoveFromSocket() {
2050
2083
void QuicSession::RemoveStream (int64_t stream_id) {
2051
2084
Debug (this , " Removing stream %" PRId64, stream_id);
2052
2085
2053
- // ngtcp2 does no extend the max streams count automatically
2086
+ // ngtcp2 does not extend the max streams count automatically
2054
2087
// except in very specific conditions, none of which apply
2055
2088
// once we've gotten this far. We need to manually extend when
2056
2089
// a remote peer initiated stream is removed.
@@ -2104,6 +2137,8 @@ bool QuicSession::SendConnectionClose() {
2104
2137
// it multiple times; whereas for clients, we will serialize it
2105
2138
// once and send once only.
2106
2139
QuicError error = last_error ();
2140
+ Debug (this , " Connection Close code: %" PRIu64 " (family: %s)" ,
2141
+ error.code , error.family_name ());
2107
2142
2108
2143
// If initial keys have not yet been installed, use the alternative
2109
2144
// ImmediateConnectionClose to send a stateless connection close to
@@ -2322,34 +2357,6 @@ void QuicSession::ResumeStream(int64_t stream_id) {
2322
2357
application ()->ResumeStream (stream_id);
2323
2358
}
2324
2359
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
- }
2353
2360
// Begin connection close by serializing the CONNECTION_CLOSE packet.
2354
2361
// There are two variants: one to serialize an application close, the
2355
2362
// other to serialize a protocol close. The frames are generally
@@ -2508,7 +2515,6 @@ void QuicSession::UpdateIdleTimer() {
2508
2515
// serialize stream data that is being sent initially.
2509
2516
bool QuicSession::WritePackets (const char * diagnostic_label) {
2510
2517
CHECK (!Ngtcp2CallbackScope::InNgtcp2CallbackScope (this ));
2511
- CHECK (!is_destroyed ());
2512
2518
2513
2519
// During the draining period, we must not send any frames at all.
2514
2520
if (is_in_draining_period ())
0 commit comments