Skip to content

Commit f7510ca

Browse files
committed
quic: additional cleanups on the c++ side
PR-URL: #34160 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent b5bf5bb commit f7510ca

File tree

3 files changed

+58
-71
lines changed

3 files changed

+58
-71
lines changed

src/quic/node_quic_http3_application.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,8 @@ void Http3Application::StreamClosed(
594594
int64_t stream_id,
595595
uint64_t app_error_code) {
596596
BaseObjectPtr<QuicStream> stream = session()->FindStream(stream_id);
597-
CHECK(stream);
598-
stream->ReceiveData(1, nullptr, 0, 0);
597+
if (stream)
598+
stream->ReceiveData(1, nullptr, 0, 0);
599599
session()->listener()->OnStreamClose(stream_id, app_error_code);
600600
}
601601

src/quic/node_quic_session.cc

+40-34
Original file line numberDiff line numberDiff line change
@@ -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

761765
void QuicCryptoContext::MemoryInfo(MemoryTracker* tracker) const {
762766
tracker->TrackField("initial_crypto", handshake_[0]);
@@ -1470,8 +1474,6 @@ QuicSession::QuicSession(
14701474

14711475
QuicSession::~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".
16391641
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())
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.
16541687
BaseObjectPtr<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() {
20502083
void 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.
25092516
bool 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())

src/quic/node_quic_session.h

+16-35
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ class JSQuicSessionListener : public QuicSessionListener {
369369
// handshake details on behalf of a QuicSession.
370370
class QuicCryptoContext : public MemoryRetainer {
371371
public:
372+
inline QuicCryptoContext(
373+
QuicSession* session,
374+
BaseObjectPtr<crypto::SecureContext> secure_context,
375+
ngtcp2_crypto_side side,
376+
uint32_t options);
377+
378+
~QuicCryptoContext() override;
379+
372380
inline uint64_t Cancel();
373381

374382
// Outgoing crypto data must be retained in memory until it is
@@ -482,12 +490,6 @@ class QuicCryptoContext : public MemoryRetainer {
482490
SET_SELF_SIZE(QuicCryptoContext)
483491

484492
private:
485-
inline QuicCryptoContext(
486-
QuicSession* session,
487-
BaseObjectPtr<crypto::SecureContext> secure_context,
488-
ngtcp2_crypto_side side,
489-
uint32_t options);
490-
491493
bool SetSecrets(
492494
ngtcp2_crypto_level level,
493495
const uint8_t* rx_secret,
@@ -1038,37 +1040,16 @@ class QuicSession : public AsyncWrap,
10381040

10391041
inline void DecreaseAllocatedSize(size_t size);
10401042

1041-
// Immediately close the QuicSession. All currently open
1042-
// streams are implicitly reset and closed with RESET_STREAM
1043-
// and STOP_SENDING frames transmitted as necessary. A
1044-
// CONNECTION_CLOSE frame will be sent and the session
1045-
// will enter the closing period until either the idle
1046-
// timeout period elapses or until the QuicSession is
1047-
// explicitly destroyed. During the closing period,
1048-
// the only frames that may be transmitted to the peer
1049-
// are repeats of the already sent CONNECTION_CLOSE.
1050-
//
1051-
// The CONNECTION_CLOSE will use the error code set using
1052-
// the most recent call to set_last_error()
1043+
// Triggers an "immediate close" on the QuicSession.
1044+
// This will round trip through JavaScript, causing
1045+
// all currently open streams to be closed and ultimately
1046+
// send a CONNECTION_CLOSE to the connected peer before
1047+
// terminating the connection.
10531048
void ImmediateClose();
10541049

1055-
// Silently, and immediately close the QuicSession. This is
1056-
// generally only done during an idle timeout. That is, per
1057-
// the QUIC specification, if the session remains idle for
1058-
// longer than both the advertised idle timeout and three
1059-
// times the current probe timeout (PTO). In such cases, all
1060-
// currently open streams are implicitly reset and closed
1061-
// without sending corresponding RESET_STREAM and
1062-
// STOP_SENDING frames, the connection state is
1063-
// discarded, and the QuicSession is destroyed without
1064-
// sending a CONNECTION_CLOSE frame.
1065-
//
1066-
// Silent close may also be used to explicitly destroy
1067-
// a QuicSession that has either already entered the
1068-
// closing or draining periods; or in response to user
1069-
// code requests to forcefully terminate a QuicSession
1070-
// without transmitting any additional frames to the
1071-
// peer.
1050+
// Silently and immediately close the QuicSession. This is
1051+
// typically only done during an idle timeout or when sending
1052+
// a retry packet.
10721053
void SilentClose();
10731054

10741055
void PushListener(QuicSessionListener* listener);

0 commit comments

Comments
 (0)