From b5bf5bb20f35372a81a83c830a01353925e11701 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 1 Jul 2020 07:29:19 -0700 Subject: [PATCH] quic: refactor native object flags for better readability Use is_* and set_* pattern for native object flags to improve readability in the code. PR-URL: https://github.com/nodejs/node/pull/34160 Reviewed-By: Anna Henningsen --- lib/internal/quic/core.js | 8 +- src/quic/node_quic_default_application.cc | 2 +- src/quic/node_quic_http3_application.cc | 2 +- src/quic/node_quic_session-inl.h | 43 +++---- src/quic/node_quic_session.cc | 110 +++++++++--------- src/quic/node_quic_session.h | 134 ++++++++++------------ src/quic/node_quic_socket-inl.h | 20 ++-- src/quic/node_quic_socket.cc | 15 ++- src/quic/node_quic_socket.h | 87 +++++++------- src/quic/node_quic_stream-inl.h | 33 +----- src/quic/node_quic_stream.cc | 12 +- src/quic/node_quic_stream.h | 67 +++++------ 12 files changed, 234 insertions(+), 299 deletions(-) diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index 446bec3761374b..90727194246450 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -966,9 +966,11 @@ class QuicSocket extends EventEmitter { state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4); state.server = server; - const socketOptions = - (validateAddress ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS : 0) | - (validateAddressLRU ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU : 0); + let socketOptions = 0; + if (validateAddress) + socketOptions |= (1 << QUICSOCKET_OPTIONS_VALIDATE_ADDRESS); + if (validateAddressLRU) + socketOptions |= (1 << QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU); this[kSetHandle]( new QuicSocketHandle( diff --git a/src/quic/node_quic_default_application.cc b/src/quic/node_quic_default_application.cc index 4c253b3787727b..5af8dc098d6027 100644 --- a/src/quic/node_quic_default_application.cc +++ b/src/quic/node_quic_default_application.cc @@ -92,7 +92,7 @@ bool DefaultApplication::ReceiveStreamData( BaseObjectPtr stream = session()->FindStream(stream_id); if (!stream) { // Shutdown the stream explicitly if the session is being closed. - if (session()->is_gracefully_closing()) { + if (session()->is_graceful_closing()) { ngtcp2_conn_shutdown_stream( session()->connection(), stream_id, diff --git a/src/quic/node_quic_http3_application.cc b/src/quic/node_quic_http3_application.cc index 44f874cf7aeb8f..7dc41a392e54df 100644 --- a/src/quic/node_quic_http3_application.cc +++ b/src/quic/node_quic_http3_application.cc @@ -603,7 +603,7 @@ BaseObjectPtr Http3Application::FindOrCreateStream( int64_t stream_id) { BaseObjectPtr stream = session()->FindStream(stream_id); if (!stream) { - if (session()->is_gracefully_closing()) { + if (session()->is_graceful_closing()) { nghttp3_conn_close_stream(connection(), stream_id, NGTCP2_ERR_CLOSING); return {}; } diff --git a/src/quic/node_quic_session-inl.h b/src/quic/node_quic_session-inl.h index 5acb8a2e9350ef..339df8210f4a09 100644 --- a/src/quic/node_quic_session-inl.h +++ b/src/quic/node_quic_session-inl.h @@ -112,7 +112,10 @@ void QuicCryptoContext::Keylog(const char* line) { void QuicCryptoContext::OnClientHelloDone() { // Continue the TLS handshake when this function exits // otherwise it will stall and fail. - TLSHandshakeScope handshake(this, &in_client_hello_); + TLSHandshakeScope handshake_scope( + this, + [&]() { set_in_client_hello(false); }); + // Disable the callback at this point so we don't loop continuously session_->state_[IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED] = 0; } @@ -129,8 +132,8 @@ void QuicCryptoContext::ResumeHandshake() { // For 0RTT, this sets the TLS session data from the given buffer. bool QuicCryptoContext::set_session(crypto::SSLSessionPointer session) { if (side_ == NGTCP2_CRYPTO_SIDE_CLIENT && session != nullptr) { - early_data_ = - SSL_SESSION_get_max_early_data(session.get()) == 0xffffffffUL; + set_early_data( + SSL_SESSION_get_max_early_data(session.get()) == 0xffffffffUL); } return crypto::SetTLSSession(ssl_, std::move(session)); } @@ -186,7 +189,7 @@ std::string QuicCryptoContext::selected_alpn() const { bool QuicCryptoContext::early_data() const { return - (early_data_ && + (is_early_data() && SSL_get_early_data_status(ssl_.get()) == SSL_EARLY_DATA_ACCEPTED) || SSL_get_max_early_data(ssl_.get()) == 0xffffffffUL; } @@ -300,13 +303,13 @@ void QuicSession::ExtendOffset(size_t amount) { // Copies the local transport params into the given struct for serialization. void QuicSession::GetLocalTransportParams(ngtcp2_transport_params* params) { - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); ngtcp2_conn_get_local_transport_params(connection(), params); } // Gets the QUIC version negotiated for this QuicSession uint32_t QuicSession::negotiated_version() const { - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); return ngtcp2_conn_get_negotiated_version(connection()); } @@ -328,7 +331,7 @@ void QuicSession::HandshakeConfirmed() { } bool QuicSession::is_handshake_completed() const { - DCHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + DCHECK(!is_destroyed()); return ngtcp2_conn_get_handshake_completed(connection()); } @@ -342,7 +345,7 @@ void QuicSession::InitApplication() { // immediately closed without attempting to send any additional data to // the peer. All existing streams are abandoned and closed. void QuicSession::OnIdleTimeout() { - if (!is_flag_set(QUICSESSION_FLAG_DESTROYED)) { + if (!is_destroyed()) { state_[IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT] = 1; Debug(this, "Idle timeout"); SilentClose(); @@ -359,7 +362,7 @@ void QuicSession::GetConnectionCloseInfo() { // Removes the given connection id from the QuicSession. void QuicSession::RemoveConnectionID(const QuicCID& cid) { - if (!is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (!is_destroyed()) DisassociateCID(cid); } @@ -440,24 +443,12 @@ SessionTicketAppData::Status QuicSession::GetSessionTicketAppData( return application_->GetSessionTicketAppData(app_data, flag); } -bool QuicSession::is_gracefully_closing() const { - return is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING); -} - -bool QuicSession::is_destroyed() const { - return is_flag_set(QUICSESSION_FLAG_DESTROYED); -} - -bool QuicSession::is_stateless_reset() const { - return is_flag_set(QUICSESSION_FLAG_STATELESS_RESET); -} - bool QuicSession::is_server() const { return crypto_context_->side() == NGTCP2_CRYPTO_SIDE_SERVER; } void QuicSession::StartGracefulClose() { - set_flag(QUICSESSION_FLAG_GRACEFUL_CLOSING); + set_graceful_closing(); RecordTimestamp(&QuicSessionStats::closing_at); } @@ -511,15 +502,15 @@ bool QuicSession::SendPacket( } void QuicSession::set_local_address(const ngtcp2_addr* addr) { - DCHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + DCHECK(!is_destroyed()); ngtcp2_conn_set_local_addr(connection(), addr); } // Set the transport parameters received from the remote peer void QuicSession::set_remote_transport_params() { - DCHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + DCHECK(!is_destroyed()); ngtcp2_conn_get_remote_transport_params(connection(), &transport_params_); - set_flag(QUICSESSION_FLAG_HAS_TRANSPORT_PARAMS); + set_transport_params_set(); } void QuicSession::StopIdleTimer() { @@ -537,7 +528,7 @@ void QuicSession::StopRetransmitTimer() { // parameter is an array of versions supported by the remote peer. void QuicSession::VersionNegotiation(const uint32_t* sv, size_t nsv) { CHECK(!is_server()); - if (!is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (!is_destroyed()) listener()->OnVersionNegotiation(NGTCP2_PROTO_VER, sv, nsv); } diff --git a/src/quic/node_quic_session.cc b/src/quic/node_quic_session.cc index d513b163cda7f1..d28f97cdba8fb8 100644 --- a/src/quic/node_quic_session.cc +++ b/src/quic/node_quic_session.cc @@ -648,8 +648,7 @@ void JSQuicSessionListener::OnSessionTicket(int size, SSL_SESSION* sess) { argv[0] = session_ticket.ToBuffer().ToLocalChecked(); } - if (session()->is_flag_set( - QuicSession::QUICSESSION_FLAG_HAS_TRANSPORT_PARAMS)) { + if (session()->is_transport_params_set()) { argv[1] = Buffer::Copy( env, reinterpret_cast(&session()->transport_params_), @@ -923,15 +922,9 @@ int QuicCryptoContext::OnClientHello() { TLSCallbackScope callback_scope(this); - // Not an error but does suspend the handshake until we're ready to go. - // A callback function is passed to the JavaScript function below that - // must be called in order to turn QUICSESSION_FLAG_CLIENT_HELLO_CB_RUNNING - // off. Once that callback is invoked, the TLS Handshake will resume. - // It is recommended that the user not take a long time to invoke the - // callback in order to avoid stalling out the QUIC connection. - if (in_client_hello_) + if (is_in_client_hello()) return -1; - in_client_hello_ = true; + set_in_client_hello(); QuicCryptoContext* ctx = session_->crypto_context(); session_->listener()->OnClientHello( @@ -943,7 +936,7 @@ int QuicCryptoContext::OnClientHello() { // handshake is ready to proceed. When the OnClientHello callback // is called above, it may be resolved synchronously or asynchronously. // In case it is resolved synchronously, we need the check below. - return in_client_hello_ ? -1 : 0; + return is_in_client_hello() ? -1 : 0; } // The OnCert callback provides an opportunity to prompt the server to @@ -965,9 +958,9 @@ int QuicCryptoContext::OnOCSP() { // As in node_crypto.cc, this is not an error, but does suspend the // handshake to continue when OnOCSP is complete. - if (in_ocsp_request_) + if (is_in_ocsp_request()) return -1; - in_ocsp_request_ = true; + set_in_ocsp_request(); session_->listener()->OnCert(session_->crypto_context()->servername()); @@ -975,7 +968,7 @@ int QuicCryptoContext::OnOCSP() { // request to be completed. When the OnCert handler is invoked // above, it can be resolve synchronously or asynchonously. If // resolved synchronously, we need the check below. - return in_ocsp_request_ ? -1 : 1; + return is_in_ocsp_request() ? -1 : 1; } // The OnCertDone function is called by the QuicSessionOnCertDone @@ -989,7 +982,9 @@ void QuicCryptoContext::OnOCSPDone( ocsp_response->IsArrayBufferView() ? "Yes" : "No"); // Continue the TLS handshake when this function exits // otherwise it will stall and fail. - TLSHandshakeScope handshake_scope(this, &in_ocsp_request_); + TLSHandshakeScope handshake_scope( + this, + [&]() { set_in_ocsp_request(false); }); // Disable the callback at this point so we don't loop continuously session_->state_[IDX_QUIC_SESSION_STATE_CERT_ENABLED] = 0; @@ -1137,9 +1132,9 @@ bool QuicCryptoContext::InitiateKeyUpdate() { // There's no user code that should be able to run while UpdateKey // is running, but we need to gate on it just to be safe. - auto leave = OnScopeLeave([&]() { in_key_update_ = false; }); - CHECK(!in_key_update_); - in_key_update_ = true; + auto leave = OnScopeLeave([&]() { set_in_key_update(false); }); + CHECK(!is_in_key_update()); + set_in_key_update(); Debug(session(), "Initiating Key Update"); session_->IncrementStat(&QuicSessionStats::keyupdate_count); @@ -1549,7 +1544,7 @@ void QuicSession::AckedStreamDataOffset( // It is possible for the QuicSession to have been destroyed but not yet // deconstructed. In such cases, we want to ignore the callback as there // is nothing to do but wait for further cleanup to happen. - if (LIKELY(!is_flag_set(QUICSESSION_FLAG_DESTROYED))) { + if (LIKELY(!is_destroyed())) { Debug(this, "Received acknowledgement for %" PRIu64 " bytes of stream %" PRId64 " data", @@ -1602,7 +1597,7 @@ void QuicSession::AddToSocket(QuicSocket* socket) { // Add the given QuicStream to this QuicSession's collection of streams. All // streams added must be removed before the QuicSession instance is freed. void QuicSession::AddStream(BaseObjectPtr stream) { - DCHECK(!is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)); + DCHECK(!is_graceful_closing()); Debug(this, "Adding stream %" PRId64 " to session", stream->id()); streams_.emplace(stream->id(), stream); @@ -1642,9 +1637,9 @@ void QuicSession::AddStream(BaseObjectPtr stream) { // not immediately torn down, but is allowed to drain // properly per the QUIC spec description of "immediate close". void QuicSession::ImmediateClose() { - if (is_flag_set(QUICSESSION_FLAG_CLOSING)) + if (is_closing() || is_silent_closing()) return; - set_flag(QUICSESSION_FLAG_CLOSING); + set_closing(); QuicError err = last_error(); Debug(this, "Immediate close with code %" PRIu64 " (%s)", @@ -1657,9 +1652,9 @@ void QuicSession::ImmediateClose() { // Creates a new stream object and passes it off to the javascript side. // This has to be called from within a handlescope/contextscope. BaseObjectPtr QuicSession::CreateStream(int64_t stream_id) { - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); - CHECK(!is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)); - CHECK(!is_flag_set(QUICSESSION_FLAG_CLOSING)); + CHECK(!is_destroyed()); + CHECK(!is_graceful_closing()); + CHECK(!is_closing()); BaseObjectPtr stream = QuicStream::New(this, stream_id); CHECK(stream); @@ -1671,7 +1666,7 @@ BaseObjectPtr QuicSession::CreateStream(int64_t stream_id) { // the QuicSession instance will be generally unusable but most // likely will not be immediately freed. void QuicSession::Destroy() { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return; // If we're not in the closing or draining periods, @@ -1689,9 +1684,9 @@ void QuicSession::Destroy() { CHECK(streams_.empty()); // Mark the session destroyed. - set_flag(QUICSESSION_FLAG_DESTROYED); - set_flag(QUICSESSION_FLAG_CLOSING, false); - set_flag(QUICSESSION_FLAG_GRACEFUL_CLOSING, false); + set_destroyed(); + set_closing(false); + set_graceful_closing(false); // Stop and free the idle and retransmission timers if they are active. StopIdleTimer(); @@ -1714,9 +1709,8 @@ bool QuicSession::GetNewConnectionID( ngtcp2_cid* cid, uint8_t* token, size_t cidlen) { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return false; - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); CHECK_NOT_NULL(connection_id_strategy_); connection_id_strategy_(this, cid, cidlen); QuicCID cid_(cid); @@ -1739,7 +1733,7 @@ void QuicSession::HandleError() { // which determines whether or not we need to retransmit data to // to packet loss or ack delay. void QuicSession::MaybeTimeout() { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return; uint64_t now = uv_hrtime(); bool transmit = false; @@ -1759,16 +1753,16 @@ void QuicSession::MaybeTimeout() { } bool QuicSession::OpenBidirectionalStream(int64_t* stream_id) { - DCHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); - DCHECK(!is_flag_set(QUICSESSION_FLAG_CLOSING)); - DCHECK(!is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)); + DCHECK(!is_destroyed()); + DCHECK(!is_closing()); + DCHECK(!is_graceful_closing()); return ngtcp2_conn_open_bidi_stream(connection(), stream_id, nullptr) == 0; } bool QuicSession::OpenUnidirectionalStream(int64_t* stream_id) { - DCHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); - DCHECK(!is_flag_set(QUICSESSION_FLAG_CLOSING)); - DCHECK(!is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)); + DCHECK(!is_destroyed()); + DCHECK(!is_closing()); + DCHECK(!is_graceful_closing()); if (ngtcp2_conn_open_uni_stream(connection(), stream_id, nullptr)) return false; ngtcp2_conn_shutdown_stream_read(connection(), *stream_id, 0); @@ -1808,8 +1802,8 @@ void QuicSession::PathValidation( // closing or draining period has started, this is a non-op. void QuicSession::Ping() { if (Ngtcp2CallbackScope::InNgtcp2CallbackScope(this) || - is_flag_set(QUICSESSION_FLAG_DESTROYED) || - is_flag_set(QUICSESSION_FLAG_CLOSING) || + is_destroyed() || + is_closing() || is_in_closing_period() || is_in_draining_period()) { return; @@ -1830,7 +1824,7 @@ bool QuicSession::Receive( const SocketAddress& local_addr, const SocketAddress& remote_addr, unsigned int flags) { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) { + if (is_destroyed()) { Debug(this, "Ignoring packet because session is destroyed"); return false; } @@ -1840,7 +1834,7 @@ bool QuicSession::Receive( // Closing period starts once ngtcp2 has detected that the session // is being shutdown locally. Note that this is different that the - // is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING) function, which + // is_graceful_closing() function, which // indicates a graceful shutdown that allows the session and streams // to finish naturally. When is_in_closing_period is true, ngtcp2 is // actively in the process of shutting down the connection and a @@ -1944,7 +1938,7 @@ bool QuicSession::ReceivePacket( // If the QuicSession has been destroyed, we're not going // to process any more packets for it. - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return true; uint64_t now = uv_hrtime(); @@ -2001,7 +1995,7 @@ bool QuicSession::ReceiveStreamData( if (UNLIKELY(!(flags & NGTCP2_STREAM_DATA_FLAG_FIN) && datalen == 0)) return true; - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return false; HandleScope scope(env()->isolate()); @@ -2101,7 +2095,7 @@ bool QuicSession::SendConnectionClose() { // Do not send any frames at all if we're in the draining period // or in the middle of a silent close - if (is_in_draining_period() || is_flag_set(QUICSESSION_FLAG_SILENT_CLOSE)) + if (is_in_draining_period() || is_silent_closing()) return true; // The specific handling of connection close varies for client @@ -2204,7 +2198,7 @@ void QuicSession::UsePreferredAddressStrategy( // Passes a serialized packet to the associated QuicSocket. bool QuicSession::SendPacket(std::unique_ptr packet) { - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); CHECK(!is_in_draining_period()); // There's nothing to send. @@ -2262,7 +2256,7 @@ void QuicSession::SendPendingData() { // session resumption. int QuicSession::set_session(SSL_SESSION* session) { CHECK(!is_server()); - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); int size = i2d_SSL_SESSION(session, nullptr); if (size > SecureContext::kMaxSessionSize) return 0; @@ -2274,9 +2268,9 @@ int QuicSession::set_session(SSL_SESSION* session) { // TODO(@jasnell): This will be revisited. bool QuicSession::set_socket(QuicSocket* socket, bool nat_rebinding) { CHECK(!is_server()); - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); - if (is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)) + if (is_graceful_closing()) return false; if (socket == nullptr || socket == socket_.get()) @@ -2340,9 +2334,9 @@ void QuicSession::ResumeStream(int64_t stream_id) { // notify the JavaScript side and destroy the connection with // a flag set that indicates stateless reset. void QuicSession::SilentClose() { - CHECK(!is_flag_set(QUICSESSION_FLAG_SILENT_CLOSE)); - set_flag(QUICSESSION_FLAG_SILENT_CLOSE); - set_flag(QUICSESSION_FLAG_CLOSING); + CHECK(!is_silent_closing()); + set_silent_closing(); + set_closing(); QuicError err = last_error(); Debug(this, @@ -2364,7 +2358,7 @@ void QuicSession::SilentClose() { // multiple times. On client QuicSession instances, we only ever // serialize the connection close once. bool QuicSession::StartClosingPeriod() { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return false; if (is_in_closing_period()) return true; @@ -2403,7 +2397,7 @@ bool QuicSession::StartClosingPeriod() { // Called by ngtcp2 when a stream has been closed. If the stream does // not exist, the close is ignored. void QuicSession::StreamClose(int64_t stream_id, uint64_t app_error_code) { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return; Debug(this, "Closing stream %" PRId64 " with code %" PRIu64, @@ -2419,7 +2413,7 @@ void QuicSession::StreamClose(int64_t stream_id, uint64_t app_error_code) { // a stream commitment attack. The only exception is shutting the // stream down explicitly if we are in a graceful close period. void QuicSession::StreamOpen(int64_t stream_id) { - if (is_flag_set(QUICSESSION_FLAG_GRACEFUL_CLOSING)) { + if (is_graceful_closing()) { ngtcp2_conn_shutdown_stream( connection(), stream_id, @@ -2451,7 +2445,7 @@ void QuicSession::StreamReset( int64_t stream_id, uint64_t final_size, uint64_t app_error_code) { - if (is_flag_set(QUICSESSION_FLAG_DESTROYED)) + if (is_destroyed()) return; Debug(this, @@ -2514,7 +2508,7 @@ void QuicSession::UpdateIdleTimer() { // serialize stream data that is being sent initially. bool QuicSession::WritePackets(const char* diagnostic_label) { CHECK(!Ngtcp2CallbackScope::InNgtcp2CallbackScope(this)); - CHECK(!is_flag_set(QUICSESSION_FLAG_DESTROYED)); + CHECK(!is_destroyed()); // During the draining period, we must not send any frames at all. if (is_in_draining_period()) @@ -3269,7 +3263,7 @@ int QuicSession::OnStatelessReset( QuicSession* session = static_cast(user_data); if (UNLIKELY(session->is_destroyed())) return NGTCP2_ERR_CALLBACK_FAILURE; - session->set_flag(QUICSESSION_FLAG_STATELESS_RESET); + session->set_stateless_reset(); return 0; } diff --git a/src/quic/node_quic_session.h b/src/quic/node_quic_session.h index 1e9341beecfe05..8c22fe3bdab534 100644 --- a/src/quic/node_quic_session.h +++ b/src/quic/node_quic_session.h @@ -358,6 +358,13 @@ class JSQuicSessionListener : public QuicSessionListener { friend class QuicSession; }; +#define QUICCRYPTOCONTEXT_FLAGS(V) \ + V(IN_TLS_CALLBACK, in_tls_callback) \ + V(IN_KEY_UPDATE, in_key_update) \ + V(IN_OCSP_RESPONSE, in_ocsp_request) \ + V(IN_CLIENT_HELLO, in_client_hello) \ + V(EARLY_DATA, early_data) + // The QuicCryptoContext class encapsulates all of the crypto/TLS // handshake details on behalf of a QuicSession. class QuicCryptoContext : public MemoryRetainer { @@ -440,6 +447,18 @@ class QuicCryptoContext : public MemoryRetainer { options_ &= ~option; } +#define V(id, name) \ + inline bool is_##name() const { \ + return flags_ & (1 << QUICCRYPTOCONTEXT_FLAG_##id); } \ + inline void set_##name(bool on = true) { \ + if (on) \ + flags_ |= (1 << QUICCRYPTOCONTEXT_FLAG_##id); \ + else \ + flags_ &= ~(1 << QUICCRYPTOCONTEXT_FLAG_##id); \ + } + QUICCRYPTOCONTEXT_FLAGS(V) +#undef V + inline bool set_session(crypto::SSLSessionPointer session); inline void set_tls_alert(int err); @@ -480,29 +499,32 @@ class QuicCryptoContext : public MemoryRetainer { ngtcp2_crypto_side side_; crypto::SSLPointer ssl_; QuicBuffer handshake_[3]; - bool in_tls_callback_ = false; - bool in_key_update_ = false; - bool in_ocsp_request_ = false; - bool in_client_hello_ = false; - bool early_data_ = false; uint32_t options_; + uint32_t flags_ = 0; v8::Global ocsp_response_; crypto::BIOPointer bio_trace_; +#define V(id, _) QUICCRYPTOCONTEXT_FLAG_##id, + enum QuicCryptoContextFlags : uint32_t { + QUICCRYPTOCONTEXT_FLAGS(V) + QUICCRYPTOCONTEXT_FLAG_COUNT + }; +#undef V + class TLSCallbackScope { public: explicit TLSCallbackScope(QuicCryptoContext* context) : context_(context) { - context_->in_tls_callback_ = true; + context_->set_in_tls_callback(); } ~TLSCallbackScope() { - context_->in_tls_callback_ = false; + context_->set_in_tls_callback(false); } static bool is_in_callback(QuicCryptoContext* context) { - return context->in_tls_callback_; + return context->is_in_tls_callback(); } private: @@ -511,17 +533,18 @@ class QuicCryptoContext : public MemoryRetainer { class TLSHandshakeScope { public: + using DoneCB = std::function; TLSHandshakeScope( QuicCryptoContext* context, - bool* monitor) : + DoneCB done) : context_(context), - monitor_(monitor) {} + done_(done) {} ~TLSHandshakeScope() { if (!is_handshake_suspended()) return; - *monitor_ = false; + done_(); // Only continue the TLS handshake if we are not currently running // synchronously within the TLS handshake function. This can happen // when the callback function passed to the clientHello and cert @@ -533,12 +556,12 @@ class QuicCryptoContext : public MemoryRetainer { private: bool is_handshake_suspended() const { - return context_->in_ocsp_request_ || context_->in_client_hello_; + return context_->is_in_ocsp_request() || context_->is_in_client_hello(); } QuicCryptoContext* context_; - bool* monitor_; + DoneCB done_; }; friend class QuicSession; @@ -663,6 +686,17 @@ class QuicApplication : public MemoryRetainer, size_t max_header_length_ = 0; }; +// QUICSESSION_FLAGS are converted into is_{name}() and set_{name}(bool on) +// accessors on the QuicSession class. +#define QUICSESSION_FLAGS(V) \ + V(CLOSING, closing) \ + V(GRACEFUL_CLOSING, graceful_closing) \ + V(DESTROYED, destroyed) \ + V(TRANSPORT_PARAMS_SET, transport_params_set) \ + V(NGTCP2_CALLBACK, in_ngtcp2_callback) \ + V(SILENT_CLOSE, silent_closing) \ + V(STATELESS_RESET, stateless_reset) + // The QuicSession class is an virtual class that serves as // the basis for both client and server QuicSession. // It implements the functionality that is shared for both @@ -801,15 +835,14 @@ class QuicSession : public AsyncWrap, inline bool allow_early_data() const; - // Returns true if StartGracefulClose() has been called and the - // QuicSession is currently in the process of a graceful close. - inline bool is_gracefully_closing() const; - - // Returns true if Destroy() has been called and the - // QuicSession is no longer usable. - inline bool is_destroyed() const; - - inline bool is_stateless_reset() const; +#define V(id, name) \ + bool is_##name() const { return flags_ & (1 << QUICSESSION_FLAG_##id); } \ + void set_##name(bool on = true) { \ + if (on) flags_ |= (1 << QUICSESSION_FLAG_##id); \ + else flags_ &= ~(1 << QUICSESSION_FLAG_##id); \ + } + QUICSESSION_FLAGS(V) +#undef V // Returns true if the QuicSession has entered the // closing period following a call to ImmediateClose. @@ -1089,15 +1122,15 @@ class QuicSession : public AsyncWrap, explicit Ngtcp2CallbackScope(QuicSession* session) : session_(session) { CHECK(session_); CHECK(!InNgtcp2CallbackScope(session)); - session_->set_flag(QUICSESSION_FLAG_NGTCP2_CALLBACK); + session_->set_in_ngtcp2_callback(); } ~Ngtcp2CallbackScope() { - session_->set_flag(QUICSESSION_FLAG_NGTCP2_CALLBACK, false); + session_->set_in_ngtcp2_callback(false); } static bool InNgtcp2CallbackScope(QuicSession* session) { - return session->is_flag_set(QUICSESSION_FLAG_NGTCP2_CALLBACK); + return session->is_in_ngtcp2_callback(); } private: @@ -1356,55 +1389,12 @@ class QuicSession : public AsyncWrap, bool StartClosingPeriod(); +#define V(id, _) QUICSESSION_FLAG_##id, enum QuicSessionFlags : uint32_t { - // Initial state when a QuicSession is created but nothing yet done. - QUICSESSION_FLAG_INITIAL = 0x1, - - // Set while the QuicSession is in the process of an Immediate - // or silent close. - QUICSESSION_FLAG_CLOSING = 0x2, - - // Set while the QuicSession is in the process of a graceful close. - QUICSESSION_FLAG_GRACEFUL_CLOSING = 0x4, - - // Set when the QuicSession has been destroyed (but not - // yet freed) - QUICSESSION_FLAG_DESTROYED = 0x8, - - QUICSESSION_FLAG_HAS_TRANSPORT_PARAMS = 0x10, - - // Set while the QuicSession is executing an ngtcp2 callback - QUICSESSION_FLAG_NGTCP2_CALLBACK = 0x100, - - // Set if the QuicSession is in the middle of a silent close - // (that is, a CONNECTION_CLOSE should not be sent) - QUICSESSION_FLAG_SILENT_CLOSE = 0x200, - - QUICSESSION_FLAG_HANDSHAKE_RX = 0x400, - QUICSESSION_FLAG_HANDSHAKE_TX = 0x800, - QUICSESSION_FLAG_HANDSHAKE_KEYS = - QUICSESSION_FLAG_HANDSHAKE_RX | - QUICSESSION_FLAG_HANDSHAKE_TX, - QUICSESSION_FLAG_SESSION_RX = 0x1000, - QUICSESSION_FLAG_SESSION_TX = 0x2000, - QUICSESSION_FLAG_SESSION_KEYS = - QUICSESSION_FLAG_SESSION_RX | - QUICSESSION_FLAG_SESSION_TX, - - // Set if the QuicSession was closed due to stateless reset - QUICSESSION_FLAG_STATELESS_RESET = 0x4000 + QUICSESSION_FLAGS(V) + QUICSESSION_FLAG_COUNT }; - - void set_flag(QuicSessionFlags flag, bool on = true) { - if (on) - flags_ |= flag; - else - flags_ &= ~flag; - } - - bool is_flag_set(QuicSessionFlags flag) const { - return (flags_ & flag) == flag; - } +#undef V void IncrementConnectionCloseAttempts() { if (connection_close_attempts_ < kMaxSizeT) diff --git a/src/quic/node_quic_socket-inl.h b/src/quic/node_quic_socket-inl.h index 38f3ad927180f0..bcc85d82314f22 100644 --- a/src/quic/node_quic_socket-inl.h +++ b/src/quic/node_quic_socket-inl.h @@ -96,9 +96,9 @@ void QuicSocket::DisassociateStatelessResetToken( // existing sessions are allowed to close naturally but new // sessions are rejected. void QuicSocket::StopListening() { - if (is_flag_set(QUICSOCKET_FLAGS_SERVER_LISTENING)) { + if (is_server_listening()) { Debug(this, "Stop listening"); - set_flag(QUICSOCKET_FLAGS_SERVER_LISTENING, false); + set_server_listening(false); // It is important to not call ReceiveStop here as there // is ongoing traffic being exchanged by the peers. } @@ -155,9 +155,9 @@ size_t QuicSocket::GetCurrentStatelessResetCounter(const SocketAddress& addr) { return it == std::end(reset_counts_) ? 0 : it->second; } -void QuicSocket::set_server_busy(bool on) { +void QuicSocket::ServerBusy(bool on) { Debug(this, "Turning Server Busy Response %s", on ? "on" : "off"); - set_flag(QUICSOCKET_FLAGS_SERVER_BUSY, on); + set_server_busy(on); listener_->OnServerBusy(on); } @@ -174,14 +174,12 @@ void QuicSocket::set_diagnostic_packet_loss(double rx, double tx) { } bool QuicSocket::ToggleStatelessReset() { - set_flag( - QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET, - !is_flag_set(QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET)); - return !is_flag_set(QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET); + set_stateless_reset_disabled(!is_stateless_reset_disabled()); + return !is_stateless_reset_disabled(); } void QuicSocket::set_validated_address(const SocketAddress& addr) { - if (is_option_set(QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU)) { + if (has_option_validate_address_lru()) { // Remove the oldest item if we've hit the LRU limit validated_addrs_.push_back(SocketAddress::Hash()(addr)); if (validated_addrs_.size() > kMaxValidateAddressLru) @@ -190,7 +188,7 @@ void QuicSocket::set_validated_address(const SocketAddress& addr) { } bool QuicSocket::is_validated_address(const SocketAddress& addr) const { - if (is_option_set(QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU)) { + if (has_option_validate_address_lru()) { auto res = std::find(std::begin(validated_addrs_), std::end(validated_addrs_), SocketAddress::Hash()(addr)); @@ -217,7 +215,7 @@ void QuicSocket::AddEndpoint( if (preferred || endpoints_.empty()) preferred_endpoint_ = endpoint_; endpoints_.emplace_back(endpoint_); - if (is_flag_set(QUICSOCKET_FLAGS_SERVER_LISTENING)) + if (is_server_listening()) endpoint_->ReceiveStart(); } diff --git a/src/quic/node_quic_socket.cc b/src/quic/node_quic_socket.cc index e3112887d8e4fb..6ebdb30ef8a250 100644 --- a/src/quic/node_quic_socket.cc +++ b/src/quic/node_quic_socket.cc @@ -267,7 +267,7 @@ QuicSocket::QuicSocket( EntropySource(token_secret_, kTokenSecretLen); if (disable_stateless_reset) - set_flag(QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET); + set_stateless_reset_disabled(); // Set the session reset secret to the one provided or random. // Note that a random secret is going to make it exceedingly @@ -316,13 +316,13 @@ void QuicSocket::Listen( const std::string& alpn, uint32_t options) { CHECK(sc); - CHECK(!is_flag_set(QUICSOCKET_FLAGS_SERVER_LISTENING)); + CHECK(!is_server_listening()); Debug(this, "Starting to listen"); server_session_config_.Set(quic_state(), preferred_address); server_secure_context_ = sc; server_alpn_ = alpn; server_options_ = options; - set_flag(QUICSOCKET_FLAGS_SERVER_LISTENING); + set_server_listening(); RecordTimestamp(&QuicSocketStats::listen_at); ReceiveStart(); } @@ -737,7 +737,7 @@ BaseObjectPtr QuicSocket::AcceptInitialPacket( QuicCID ocid; // If the QuicSocket is not listening, the paket will be ignored. - if (!is_flag_set(QUICSOCKET_FLAGS_SERVER_LISTENING)) { + if (!is_server_listening()) { Debug(this, "QuicSocket is not listening"); return {}; } @@ -762,7 +762,7 @@ BaseObjectPtr QuicSocket::AcceptInitialPacket( // Else, check to see if the number of connections total for this QuicSocket // has been exceeded. If the count has been exceeded, shutdown the connection // immediately after the initial keys are installed. - if (UNLIKELY(is_flag_set(QUICSOCKET_FLAGS_SERVER_BUSY)) || + if (UNLIKELY(is_server_busy()) || sessions_.size() >= max_connections_ || GetCurrentSocketAddressCounter(remote_addr) >= max_connections_per_host_) { @@ -786,8 +786,7 @@ BaseObjectPtr QuicSocket::AcceptInitialPacket( if (!is_validated_address(remote_addr)) { switch (hd.type) { case NGTCP2_PKT_INITIAL: - if (is_option_set(QUICSOCKET_OPTIONS_VALIDATE_ADDRESS) || - hd.token.len > 0) { + if (has_option_validate_address() || hd.token.len > 0) { Debug(this, "Performing explicit address validation"); if (hd.token.len == 0) { Debug(this, "No retry token was detected. Generating one"); @@ -1124,7 +1123,7 @@ void QuicSocketSetServerBusy(const FunctionCallbackInfo& args) { QuicSocket* socket; ASSIGN_OR_RETURN_UNWRAP(&socket, args.Holder()); CHECK_EQ(args.Length(), 1); - socket->set_server_busy(args[0]->IsTrue()); + socket->ServerBusy(args[0]->IsTrue()); } void QuicSocketToggleStatelessReset(const FunctionCallbackInfo& args) { diff --git a/src/quic/node_quic_socket.h b/src/quic/node_quic_socket.h index 2fcf0fb7f19d31..a9d4058fb7a1e0 100644 --- a/src/quic/node_quic_socket.h +++ b/src/quic/node_quic_socket.h @@ -36,17 +36,23 @@ namespace quic { class QuicSocket; class QuicEndpoint; +#define QUICSOCKET_OPTIONS(V) \ + V(VALIDATE_ADDRESS, validate_address) \ + V(VALIDATE_ADDRESS_LRU, validate_address_lru) + +#define V(id, _) QUICSOCKET_OPTIONS_##id, enum QuicSocketOptions : uint32_t { - // When enabled the QuicSocket will validate the address - // using a RETRY packet to the peer. - QUICSOCKET_OPTIONS_VALIDATE_ADDRESS = 0x1, - - // When enabled, and the VALIDATE_ADDRESS option is also - // set, the QuicSocket will use an LRU cache to track - // validated addresses. Address validation will be skipped - // if the address is currently in the cache. - QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU = 0x2, + QUICSOCKET_OPTIONS(V) + QUICSOCKET_OPTIONS_COUNT }; +#undef V + +#define QUICSOCKET_FLAGS(V) \ + V(GRACEFUL_CLOSE, graceful_closing) \ + V(WAITING_FOR_CALLBACKS, waiting_for_callbacks) \ + V(SERVER_LISTENING, server_listening) \ + V(SERVER_BUSY, server_busy) \ + V(DISABLE_STATELESS_RESET, stateless_reset_disabled) #define SOCKET_STATS(V) \ V(CREATED_AT, created_at, "Created At") \ @@ -351,7 +357,25 @@ class QuicSocket : public AsyncWrap, std::unique_ptr packet, BaseObjectPtr session = BaseObjectPtr()); - inline void set_server_busy(bool on); +#define V(id, name) \ + inline bool is_##name() const { \ + return flags_ & (1 << QUICSOCKET_FLAG_##id); } \ + inline void set_##name(bool on = true) { \ + if (on) \ + flags_ |= (1 << QUICSOCKET_FLAG_##id); \ + else \ + flags_ &= ~(1 << QUICSOCKET_FLAG_##id); \ + } + QUICSOCKET_FLAGS(V) +#undef V + +#define V(id, name) \ + bool has_option_##name() const { \ + return options_ & (1 << QUICSOCKET_OPTIONS_##id); } + QUICSOCKET_OPTIONS(V) +#undef V + + inline void ServerBusy(bool on); inline void set_diagnostic_packet_loss(double rx = 0.0, double tx = 0.0); @@ -489,43 +513,12 @@ class QuicSocket : public AsyncWrap, // and the current packet should be artificially considered lost. inline bool is_diagnostic_packet_loss(double prob) const; - bool is_stateless_reset_disabled() { - return is_flag_set(QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET); - } - +#define V(id, _) QUICSOCKET_FLAG_##id, enum QuicSocketFlags : uint32_t { - QUICSOCKET_FLAGS_NONE = 0x0, - - // Indicates that the QuicSocket has entered a graceful - // closing phase, indicating that no additional - QUICSOCKET_FLAGS_GRACEFUL_CLOSE = 0x1, - QUICSOCKET_FLAGS_WAITING_FOR_CALLBACKS = 0x2, - QUICSOCKET_FLAGS_SERVER_LISTENING = 0x4, - QUICSOCKET_FLAGS_SERVER_BUSY = 0x8, - QUICSOCKET_FLAGS_DISABLE_STATELESS_RESET = 0x10 + QUICSOCKET_FLAGS(V) + QUICSOCKET_FLAG_COUNT }; - - void set_flag(QuicSocketFlags flag, bool on = true) { - if (on) - flags_ |= flag; - else - flags_ &= ~flag; - } - - bool is_flag_set(QuicSocketFlags flag) const { - return flags_ & flag; - } - - void set_option(QuicSocketOptions option, bool on = true) { - if (on) - options_ |= option; - else - options_ &= ~option; - } - - bool is_option_set(QuicSocketOptions option) const { - return options_ & option; - } +#undef V ngtcp2_mem alloc_info_; @@ -533,8 +526,8 @@ class QuicSocket : public AsyncWrap, SocketAddress::Map> bound_endpoints_; BaseObjectWeakPtr preferred_endpoint_; - uint32_t flags_ = QUICSOCKET_FLAGS_NONE; - uint32_t options_; + uint32_t flags_ = 0; + uint32_t options_ = 0; uint32_t server_options_; size_t max_connections_ = DEFAULT_MAX_CONNECTIONS; diff --git a/src/quic/node_quic_stream-inl.h b/src/quic/node_quic_stream-inl.h index 546e867ee2db7e..e253875c4d3389 100644 --- a/src/quic/node_quic_stream-inl.h +++ b/src/quic/node_quic_stream-inl.h @@ -23,31 +23,16 @@ QuicStreamOrigin QuicStream::origin() const { QUIC_STREAM_CLIENT; } -bool QuicStream::is_flag_set(int32_t flag) const { - return flags_ & (1 << flag); -} - -void QuicStream::set_flag(int32_t flag, bool on) { - if (on) - flags_ |= (1 << flag); - else - flags_ &= ~(1 << flag); -} - void QuicStream::set_final_size(uint64_t final_size) { // Only set the final size once. - if (is_flag_set(QUICSTREAM_FLAG_FIN)) { + if (is_fin()) { CHECK_LE(final_size, GetStat(&QuicStreamStats::final_size)); return; } - set_flag(QUICSTREAM_FLAG_FIN); + set_fin(true); SetStat(&QuicStreamStats::final_size, final_size); } -bool QuicStream::is_destroyed() const { - return is_flag_set(QUICSTREAM_FLAG_DESTROYED); -} - bool QuicStream::was_ever_writable() const { if (direction() == QUIC_STREAM_UNIDIRECTIONAL) { return session_->is_server() ? @@ -72,17 +57,11 @@ bool QuicStream::was_ever_readable() const { } bool QuicStream::is_readable() const { - return was_ever_readable() && !is_flag_set(QUICSTREAM_FLAG_READ_CLOSED); -} - -void QuicStream::set_fin_sent() { - CHECK(!is_writable()); - set_flag(QUICSTREAM_FLAG_FIN_SENT); + return was_ever_readable() && !is_read_closed(); } bool QuicStream::is_write_finished() const { - return is_flag_set(QUICSTREAM_FLAG_FIN_SENT) && - streambuf_.length() == 0; + return is_fin_sent() && streambuf_.length() == 0; } bool QuicStream::SubmitInformation(v8::Local headers) { @@ -143,7 +122,7 @@ void QuicStream::ResetStream(uint64_t app_error_code) { session()->connection(), stream_id_, app_error_code); - set_flag(QUICSTREAM_FLAG_READ_CLOSED); + set_read_closed(); streambuf_.Cancel(); streambuf_.End(); } @@ -156,7 +135,7 @@ void QuicStream::StopSending(uint64_t app_error_code) { session()->connection(), stream_id_, app_error_code); - set_flag(QUICSTREAM_FLAG_READ_CLOSED); + set_read_closed(); } void QuicStream::Schedule(Queue* queue) { diff --git a/src/quic/node_quic_stream.cc b/src/quic/node_quic_stream.cc index ba447e760d206a..3b4e7286945957 100644 --- a/src/quic/node_quic_stream.cc +++ b/src/quic/node_quic_stream.cc @@ -124,8 +124,8 @@ void QuicStream::Destroy(QuicError* error) { QuicSession::SendSessionScope send_scope(session()); - set_flag(QUICSTREAM_FLAG_DESTROYED); - set_flag(QUICSTREAM_FLAG_READ_CLOSED); + set_read_closed(); + set_destroyed(); // In case this stream is scheduled for sending, remove it // from the schedule queue @@ -234,8 +234,8 @@ bool QuicStream::IsClosing() { int QuicStream::ReadStart() { CHECK(!is_destroyed()); CHECK(is_readable()); - set_flag(QUICSTREAM_FLAG_READ_STARTED); - set_flag(QUICSTREAM_FLAG_READ_PAUSED, false); + set_read_started(); + set_read_paused(false); IncrementStat( &QuicStreamStats::max_offset, inbound_consumed_data_while_paused_); @@ -246,7 +246,7 @@ int QuicStream::ReadStart() { int QuicStream::ReadStop() { CHECK(!is_destroyed()); CHECK(is_readable()); - set_flag(QUICSTREAM_FLAG_READ_PAUSED); + set_read_paused(); return 0; } @@ -348,7 +348,7 @@ void QuicStream::ReceiveData( datalen -= avail; // Capture read_paused before EmitRead in case user code callbacks // alter the state when EmitRead is called. - bool read_paused = is_flag_set(QUICSTREAM_FLAG_READ_PAUSED); + bool read_paused = is_read_paused(); EmitRead(avail, buf); // Reading can be paused while we are processing. If that's // the case, we still want to acknowledge the current bytes diff --git a/src/quic/node_quic_stream.h b/src/quic/node_quic_stream.h index 0d0809c74df0ed..53a8cdaea52d51 100644 --- a/src/quic/node_quic_stream.h +++ b/src/quic/node_quic_stream.h @@ -78,30 +78,13 @@ struct QuicStreamStatsTraits { static void ToString(const Base& ptr, Fn&& add_field); }; -enum QuicStreamStates : uint32_t { - // QuicStream is fully open. Readable and Writable - QUICSTREAM_FLAG_INITIAL = 0, - - // QuicStream Read State is closed because a final stream frame - // has been received from the peer or the QuicStream is unidirectional - // outbound only (i.e. it was never readable) - QUICSTREAM_FLAG_READ_CLOSED, - - // JavaScript side has switched into flowing mode (Readable side) - QUICSTREAM_FLAG_READ_STARTED, - - // JavaScript side has paused the flow of data (Readable side) - QUICSTREAM_FLAG_READ_PAUSED, - - // QuicStream has received a final stream frame (Readable side) - QUICSTREAM_FLAG_FIN, - - // QuicStream has sent a final stream frame (Writable side) - QUICSTREAM_FLAG_FIN_SENT, - - // QuicStream has been destroyed - QUICSTREAM_FLAG_DESTROYED -}; +#define QUICSTREAM_FLAGS(V) \ + V(READ_CLOSED, read_closed) \ + V(READ_STARTED, read_started) \ + V(READ_PAUSED, read_paused) \ + V(FIN, fin) \ + V(FIN_SENT, fin_sent) \ + V(DESTROYED, destroyed) enum QuicStreamDirection { // The QuicStream is readable and writable in both directions @@ -228,9 +211,6 @@ class QuicStream : public AsyncWrap, // or the server. inline QuicStreamOrigin origin() const; - // The QuicStream has been destroyed and is no longer usable. - inline bool is_destroyed() const; - // A QuicStream will not be writable if: // - The streambuf_ is ended // - It is a Unidirectional stream originating from the peer @@ -241,13 +221,6 @@ class QuicStream : public AsyncWrap, // - It is a Unidirectional stream originating from the local peer. inline bool is_readable() const; - // Records the fact that a final stream frame has been - // serialized and sent to the peer. There still may be - // unacknowledged data in the outbound queue, but no - // additional frames may be sent for the stream other - // than reset stream. - inline void set_fin_sent(); - // IsWriteFinished will return true if a final stream frame // has been sent and all data has been acknowledged (the // send buffer is empty). @@ -342,6 +315,18 @@ class QuicStream : public AsyncWrap, // Required for StreamBase int ReadStop() override; +#define V(id, name) \ + inline bool is_##name() const { \ + return flags_ & (1 << QUICSTREAM_FLAG_##id); } \ + inline void set_##name(bool on = true) { \ + if (on) \ + flags_ |= (1 << QUICSTREAM_FLAG_##id); \ + else \ + flags_ &= ~(1 << QUICSTREAM_FLAG_##id); \ + } + QUICSTREAM_FLAGS(V) +#undef V + // Required for StreamBase int DoShutdown(ShutdownWrap* req_wrap) override; @@ -363,10 +348,6 @@ class QuicStream : public AsyncWrap, size_t max_count_hint) override; private: - inline bool is_flag_set(int32_t flag) const; - - inline void set_flag(int32_t flag, bool on = true); - // WasEverWritable returns true if it is a bidirectional stream, // or a Unidirectional stream originating from the local peer. // If was_ever_writable() is false, then no stream frames should @@ -380,12 +361,20 @@ class QuicStream : public AsyncWrap, void IncrementStats(size_t datalen); +#define V(id, _) QUICSTREAM_FLAG_##id, + enum QuicStreamStates : uint32_t { + QUICSTREAM_FLAGS(V) + QUICSTREAM_FLAG_COUNT + }; +#undef V + BaseObjectWeakPtr session_; QuicBuffer streambuf_; int64_t stream_id_ = 0; int64_t push_id_ = 0; - uint32_t flags_ = QUICSTREAM_FLAG_INITIAL; + uint32_t flags_ = 0; + size_t inbound_consumed_data_while_paused_ = 0; std::vector> headers_;