mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
quic: refactor QuicSession shared state to use AliasedStruct
PR-URL: https://github.com/nodejs/node/pull/34160 Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
@@ -39,6 +39,7 @@ const {
|
||||
validateQuicEndpointOptions,
|
||||
validateCreateSecureContextOptions,
|
||||
validateQuicSocketConnectOptions,
|
||||
QuicSessionSharedState,
|
||||
} = require('internal/quic/util');
|
||||
const util = require('util');
|
||||
const assert = require('internal/assert');
|
||||
@@ -131,12 +132,6 @@ const {
|
||||
AF_INET,
|
||||
AF_INET6,
|
||||
NGTCP2_DEFAULT_MAX_PKTLEN,
|
||||
IDX_QUIC_SESSION_STATE_MAX_STREAMS_BIDI,
|
||||
IDX_QUIC_SESSION_STATE_MAX_STREAMS_UNI,
|
||||
IDX_QUIC_SESSION_STATE_MAX_DATA_LEFT,
|
||||
IDX_QUIC_SESSION_STATE_HANDSHAKE_CONFIRMED,
|
||||
IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT,
|
||||
IDX_QUIC_SESSION_STATE_BYTES_IN_FLIGHT,
|
||||
IDX_QUIC_SESSION_STATS_CREATED_AT,
|
||||
IDX_QUIC_SESSION_STATS_HANDSHAKE_START_AT,
|
||||
IDX_QUIC_SESSION_STATS_BYTES_RECEIVED,
|
||||
@@ -605,11 +600,11 @@ function createSecureContext(options, init_cb) {
|
||||
}
|
||||
|
||||
function onNewListener(event) {
|
||||
toggleListeners(this[kHandle], event, true);
|
||||
toggleListeners(this[kInternalState].state, event, true);
|
||||
}
|
||||
|
||||
function onRemoveListener(event) {
|
||||
toggleListeners(this[kHandle], event, false);
|
||||
toggleListeners(this[kInternalState].state, event, false);
|
||||
}
|
||||
|
||||
function getStats(obj, idx) {
|
||||
@@ -1651,6 +1646,7 @@ class QuicSession extends EventEmitter {
|
||||
handshakeContinuationHistogram: undefined,
|
||||
highWaterMark: undefined,
|
||||
defaultEncoding: undefined,
|
||||
state: undefined,
|
||||
};
|
||||
|
||||
constructor(socket, options) {
|
||||
@@ -1693,6 +1689,7 @@ class QuicSession extends EventEmitter {
|
||||
this[kHandle] = handle;
|
||||
if (handle !== undefined) {
|
||||
handle[owner_symbol] = this;
|
||||
state.state = new QuicSessionSharedState(handle.state);
|
||||
state.handshakeAckHistogram = new Histogram(handle.ack);
|
||||
state.handshakeContinuationHistogram = new Histogram(handle.rate);
|
||||
} else {
|
||||
@@ -1849,10 +1846,10 @@ class QuicSession extends EventEmitter {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Closing allows any existing QuicStream's to complete
|
||||
// normally but disallows any new QuicStreams from being
|
||||
// opened. Calls to openStream() will fail, and new streams
|
||||
// from the peer will be rejected/ignored.
|
||||
// Closing allows any existing QuicStream's to gracefully
|
||||
// complete while disallowing any new QuicStreams from being
|
||||
// opened (in either direction). Calls to openStream() will
|
||||
// fail, and new streams from the peer will be rejected/ignored.
|
||||
close(callback) {
|
||||
const state = this[kInternalState];
|
||||
if (state.destroyed)
|
||||
@@ -1921,8 +1918,7 @@ class QuicSession extends EventEmitter {
|
||||
if (handle !== undefined) {
|
||||
// Copy the stats for use after destruction
|
||||
state.stats = new BigInt64Array(handle.stats);
|
||||
state.idleTimeout =
|
||||
Boolean(handle.state[IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT]);
|
||||
state.idleTimeout = this[kInternalState].state.idleTimeout;
|
||||
|
||||
// Destroy the underlying QuicSession handle
|
||||
handle.destroy(state.closeCode, state.closeFamily);
|
||||
@@ -1950,8 +1946,8 @@ class QuicSession extends EventEmitter {
|
||||
let bidi = 0;
|
||||
let uni = 0;
|
||||
if (this[kHandle]) {
|
||||
bidi = this[kHandle].state[IDX_QUIC_SESSION_STATE_MAX_STREAMS_BIDI];
|
||||
uni = this[kHandle].state[IDX_QUIC_SESSION_STATE_MAX_STREAMS_UNI];
|
||||
bidi = this[kInternalState].state.maxStreamsBidi;
|
||||
uni = this[kInternalState].state.maxStreamsUni;
|
||||
}
|
||||
return { bidi, uni };
|
||||
}
|
||||
@@ -1961,15 +1957,15 @@ class QuicSession extends EventEmitter {
|
||||
}
|
||||
|
||||
get maxDataLeft() {
|
||||
return this[kHandle]?.state[IDX_QUIC_SESSION_STATE_MAX_DATA_LEFT] || 0;
|
||||
return this[kHandle] ? this[kInternalState].state.maxDataLeft : 0;
|
||||
}
|
||||
|
||||
get bytesInFlight() {
|
||||
return this[kHandle]?.state[IDX_QUIC_SESSION_STATE_BYTES_IN_FLIGHT] || 0;
|
||||
return this[kHandle] ? this[kInternalState].state.bytesInFlight : 0;
|
||||
}
|
||||
|
||||
get blockCount() {
|
||||
return this[kHandle]?.state[IDX_QUIC_SESSION_STATS_BLOCK_COUNT] || 0;
|
||||
return this[kHandle]?.stats[IDX_QUIC_SESSION_STATS_BLOCK_COUNT] || 0;
|
||||
}
|
||||
|
||||
get authenticated() {
|
||||
@@ -2003,8 +1999,9 @@ class QuicSession extends EventEmitter {
|
||||
}
|
||||
|
||||
get handshakeConfirmed() {
|
||||
return Boolean(
|
||||
this[kHandle]?.state[IDX_QUIC_SESSION_STATE_HANDSHAKE_CONFIRMED]);
|
||||
return this[kHandle] ?
|
||||
this[kInternalState].state.handshakeConfirmed :
|
||||
false;
|
||||
}
|
||||
|
||||
get idleTimeout() {
|
||||
@@ -2449,14 +2446,16 @@ class QuicClientSession extends QuicSession {
|
||||
// Listeners may have been added before the handle was created.
|
||||
// Ensure that we toggle those listeners in the handle state.
|
||||
|
||||
if (this.listenerCount('keylog') > 0)
|
||||
toggleListeners(handle, 'keylog', true);
|
||||
const internalState = this[kInternalState];
|
||||
if (this.listenerCount('keylog') > 0) {
|
||||
toggleListeners(internalState.state, 'keylog', true);
|
||||
}
|
||||
|
||||
if (this.listenerCount('pathValidation') > 0)
|
||||
toggleListeners(handle, 'pathValidation', true);
|
||||
toggleListeners(internalState.state, 'pathValidation', true);
|
||||
|
||||
if (this.listenerCount('usePreferredAddress') > 0)
|
||||
toggleListeners(handle, 'usePreferredAddress', true);
|
||||
toggleListeners(internalState.state, 'usePreferredAddress', true);
|
||||
|
||||
this[kMaybeReady](0x2);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@ const {
|
||||
},
|
||||
} = require('internal/errors');
|
||||
|
||||
const {
|
||||
kHandle,
|
||||
} = require('internal/stream_base_commons');
|
||||
|
||||
const endianness = require('os').endianness();
|
||||
|
||||
const assert = require('internal/assert');
|
||||
assert(process.versions.ngtcp2 !== undefined);
|
||||
|
||||
@@ -52,11 +58,19 @@ const {
|
||||
IDX_QUIC_SESSION_MAX_UDP_PAYLOAD_SIZE,
|
||||
IDX_QUIC_SESSION_CC_ALGO,
|
||||
IDX_QUIC_SESSION_CONFIG_COUNT,
|
||||
IDX_QUIC_SESSION_STATE_CERT_ENABLED,
|
||||
IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED,
|
||||
IDX_QUIC_SESSION_STATE_KEYLOG_ENABLED,
|
||||
IDX_QUIC_SESSION_STATE_PATH_VALIDATED_ENABLED,
|
||||
IDX_QUIC_SESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED,
|
||||
|
||||
IDX_QUICSESSION_STATE_KEYLOG_ENABLED,
|
||||
IDX_QUICSESSION_STATE_CLIENT_HELLO_ENABLED,
|
||||
IDX_QUICSESSION_STATE_CERT_ENABLED,
|
||||
IDX_QUICSESSION_STATE_PATH_VALIDATED_ENABLED,
|
||||
IDX_QUICSESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED,
|
||||
IDX_QUICSESSION_STATE_HANDSHAKE_CONFIRMED,
|
||||
IDX_QUICSESSION_STATE_IDLE_TIMEOUT,
|
||||
IDX_QUICSESSION_STATE_MAX_STREAMS_BIDI,
|
||||
IDX_QUICSESSION_STATE_MAX_STREAMS_UNI,
|
||||
IDX_QUICSESSION_STATE_MAX_DATA_LEFT,
|
||||
IDX_QUICSESSION_STATE_BYTES_IN_FLIGHT,
|
||||
|
||||
IDX_HTTP3_QPACK_MAX_TABLE_CAPACITY,
|
||||
IDX_HTTP3_QPACK_BLOCKED_STREAMS,
|
||||
IDX_HTTP3_MAX_HEADER_LIST_SIZE,
|
||||
@@ -756,29 +770,121 @@ function setTransportParams(config) {
|
||||
// communicate that a handler has been added for the optional events
|
||||
// so that the C++ internals know there is an actual listener. The event
|
||||
// will not be emitted if there is no handler.
|
||||
function toggleListeners(handle, event, on) {
|
||||
if (handle === undefined)
|
||||
function toggleListeners(state, event, on) {
|
||||
if (state === undefined)
|
||||
return;
|
||||
const val = on ? 1 : 0;
|
||||
switch (event) {
|
||||
case 'keylog':
|
||||
handle.state[IDX_QUIC_SESSION_STATE_KEYLOG_ENABLED] = val;
|
||||
state.keylogEnabled = on;
|
||||
break;
|
||||
case 'clientHello':
|
||||
handle.state[IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED] = val;
|
||||
state.clientHelloEnabled = on;
|
||||
break;
|
||||
case 'pathValidation':
|
||||
handle.state[IDX_QUIC_SESSION_STATE_PATH_VALIDATED_ENABLED] = val;
|
||||
state.pathValidatedEnabled = on;
|
||||
break;
|
||||
case 'OCSPRequest':
|
||||
handle.state[IDX_QUIC_SESSION_STATE_CERT_ENABLED] = val;
|
||||
state.certEnabled = on;
|
||||
break;
|
||||
case 'usePreferredAddress':
|
||||
handle.state[IDX_QUIC_SESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED] = on;
|
||||
state.usePreferredAddressEnabled = on;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A utility class used to handle reading / modifying shared JS/C++
|
||||
// state associated with a QuicSession
|
||||
class QuicSessionSharedState {
|
||||
constructor(state) {
|
||||
this[kHandle] = Buffer.from(state);
|
||||
}
|
||||
|
||||
get keylogEnabled() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_KEYLOG_ENABLED));
|
||||
}
|
||||
|
||||
set keylogEnabled(on) {
|
||||
this[kHandle]
|
||||
.writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_KEYLOG_ENABLED);
|
||||
}
|
||||
|
||||
get clientHelloEnabled() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_CLIENT_HELLO_ENABLED));
|
||||
}
|
||||
|
||||
set clientHelloEnabled(on) {
|
||||
this[kHandle]
|
||||
.writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_CLIENT_HELLO_ENABLED);
|
||||
}
|
||||
|
||||
get certEnabled() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_CERT_ENABLED));
|
||||
}
|
||||
|
||||
set certEnabled(on) {
|
||||
this[kHandle]
|
||||
.writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_CERT_ENABLED);
|
||||
}
|
||||
|
||||
get pathValidatedEnabled() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_PATH_VALIDATED_ENABLED));
|
||||
}
|
||||
|
||||
set pathValidatedEnabled(on) {
|
||||
this[kHandle]
|
||||
.writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_PATH_VALIDATED_ENABLED);
|
||||
}
|
||||
|
||||
get usePreferredAddressEnabled() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED));
|
||||
}
|
||||
|
||||
set usePreferredAddressEnabled(on) {
|
||||
this[kHandle]
|
||||
.writeUInt8(on ? 1 : 0,
|
||||
IDX_QUICSESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED);
|
||||
}
|
||||
|
||||
get handshakeConfirmed() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_HANDSHAKE_CONFIRMED));
|
||||
}
|
||||
|
||||
get idleTimeout() {
|
||||
return Boolean(this[kHandle]
|
||||
.readUInt8(IDX_QUICSESSION_STATE_IDLE_TIMEOUT));
|
||||
}
|
||||
|
||||
get maxStreamsBidi() {
|
||||
return Number(endianness === 'BE' ?
|
||||
this[kHandle].readBigInt64BE(IDX_QUICSESSION_STATE_MAX_STREAMS_BIDI) :
|
||||
this[kHandle].readBigInt64LE(IDX_QUICSESSION_STATE_MAX_STREAMS_BIDI));
|
||||
}
|
||||
|
||||
get maxStreamsUni() {
|
||||
return Number(endianness === 'BE' ?
|
||||
this[kHandle].readBigInt64BE(IDX_QUICSESSION_STATE_MAX_STREAMS_UNI) :
|
||||
this[kHandle].readBigInt64LE(IDX_QUICSESSION_STATE_MAX_STREAMS_UNI));
|
||||
}
|
||||
|
||||
get maxDataLeft() {
|
||||
return Number(endianness === 'BE' ?
|
||||
this[kHandle].readBigInt64BE(IDX_QUICSESSION_STATE_MAX_DATA_LEFT) :
|
||||
this[kHandle].readBigInt64LE(IDX_QUICSESSION_STATE_MAX_DATA_LEFT));
|
||||
}
|
||||
|
||||
get bytesInFlight() {
|
||||
return Number(endianness === 'BE' ?
|
||||
this[kHandle].readBigInt64BE(IDX_QUICSESSION_STATE_BYTES_IN_FLIGHT) :
|
||||
this[kHandle].readBigInt64LE(IDX_QUICSESSION_STATE_BYTES_IN_FLIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllowUnauthorized,
|
||||
getSocketType,
|
||||
@@ -796,4 +902,5 @@ module.exports = {
|
||||
validateQuicEndpointOptions,
|
||||
validateCreateSecureContextOptions,
|
||||
validateQuicSocketConnectOptions,
|
||||
QuicSessionSharedState,
|
||||
};
|
||||
|
||||
@@ -173,17 +173,6 @@ void Initialize(Local<Object> target,
|
||||
V(IDX_QUIC_SESSION_MAX_ACK_DELAY) \
|
||||
V(IDX_QUIC_SESSION_CC_ALGO) \
|
||||
V(IDX_QUIC_SESSION_CONFIG_COUNT) \
|
||||
V(IDX_QUIC_SESSION_STATE_CERT_ENABLED) \
|
||||
V(IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED) \
|
||||
V(IDX_QUIC_SESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED) \
|
||||
V(IDX_QUIC_SESSION_STATE_PATH_VALIDATED_ENABLED) \
|
||||
V(IDX_QUIC_SESSION_STATE_KEYLOG_ENABLED) \
|
||||
V(IDX_QUIC_SESSION_STATE_MAX_STREAMS_BIDI) \
|
||||
V(IDX_QUIC_SESSION_STATE_MAX_STREAMS_UNI) \
|
||||
V(IDX_QUIC_SESSION_STATE_MAX_DATA_LEFT) \
|
||||
V(IDX_QUIC_SESSION_STATE_BYTES_IN_FLIGHT) \
|
||||
V(IDX_QUIC_SESSION_STATE_HANDSHAKE_CONFIRMED) \
|
||||
V(IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT) \
|
||||
V(MAX_RETRYTOKEN_EXPIRATION) \
|
||||
V(MIN_RETRYTOKEN_EXPIRATION) \
|
||||
V(NGTCP2_APP_NOERROR) \
|
||||
@@ -212,6 +201,11 @@ void Initialize(Local<Object> target,
|
||||
V(ERR_FAILED_TO_CREATE_SESSION) \
|
||||
V(UV_EBADF)
|
||||
|
||||
#define V(id, _, __) \
|
||||
NODE_DEFINE_CONSTANT(constants, IDX_QUICSESSION_STATE_##id);
|
||||
QUICSESSION_SHARED_STATE(V)
|
||||
#undef V
|
||||
|
||||
#define V(name, _, __) \
|
||||
NODE_DEFINE_CONSTANT(constants, IDX_QUIC_SESSION_STATS_##name);
|
||||
SESSION_STATS(V)
|
||||
|
||||
@@ -105,7 +105,7 @@ ngtcp2_crypto_level QuicCryptoContext::write_crypto_level() const {
|
||||
// to a keylog file that can be consumed by tools like Wireshark to intercept
|
||||
// and decrypt QUIC network traffic.
|
||||
void QuicCryptoContext::Keylog(const char* line) {
|
||||
if (UNLIKELY(session_->state_[IDX_QUIC_SESSION_STATE_KEYLOG_ENABLED] == 1))
|
||||
if (UNLIKELY(session_->state_->keylog_enabled))
|
||||
session_->listener()->OnKeylog(line, strlen(line));
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void QuicCryptoContext::OnClientHelloDone() {
|
||||
[&]() { 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;
|
||||
session_->state_->client_hello_enabled = 0;
|
||||
}
|
||||
|
||||
// Following a pause in the handshake for OCSP or client hello, we kickstart
|
||||
@@ -274,14 +274,12 @@ void QuicSession::ExtendMaxStreamsRemoteBidi(uint64_t max_streams) {
|
||||
|
||||
void QuicSession::ExtendMaxStreamsUni(uint64_t max_streams) {
|
||||
Debug(this, "Setting max unidirectional streams to %" PRIu64, max_streams);
|
||||
state_[IDX_QUIC_SESSION_STATE_MAX_STREAMS_UNI] =
|
||||
static_cast<double>(max_streams);
|
||||
state_->max_streams_uni = max_streams;
|
||||
}
|
||||
|
||||
void QuicSession::ExtendMaxStreamsBidi(uint64_t max_streams) {
|
||||
Debug(this, "Setting max bidirectional streams to %" PRIu64, max_streams);
|
||||
state_[IDX_QUIC_SESSION_STATE_MAX_STREAMS_BIDI] =
|
||||
static_cast<double>(max_streams);
|
||||
state_->max_streams_bidi = max_streams;
|
||||
}
|
||||
|
||||
// Extends the stream-level flow control by the given number of bytes.
|
||||
@@ -327,7 +325,7 @@ void QuicSession::HandshakeCompleted() {
|
||||
void QuicSession::HandshakeConfirmed() {
|
||||
Debug(this, "Handshake is confirmed");
|
||||
RecordTimestamp(&QuicSessionStats::handshake_confirmed_at);
|
||||
state_[IDX_QUIC_SESSION_STATE_HANDSHAKE_CONFIRMED] = 1;
|
||||
state_->handshake_confirmed = 1;
|
||||
}
|
||||
|
||||
bool QuicSession::is_handshake_completed() const {
|
||||
@@ -346,7 +344,7 @@ void QuicSession::InitApplication() {
|
||||
// the peer. All existing streams are abandoned and closed.
|
||||
void QuicSession::OnIdleTimeout() {
|
||||
if (!is_destroyed()) {
|
||||
state_[IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT] = 1;
|
||||
state_->idle_timeout = 1;
|
||||
Debug(this, "Idle timeout");
|
||||
Close(QuicSessionListener::SESSION_CLOSE_FLAG_SILENT);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "node_quic_session-inl.h" // NOLINT(build/include)
|
||||
#include "aliased_buffer.h"
|
||||
#include "aliased_struct-inl.h"
|
||||
#include "allocated_buffer-inl.h"
|
||||
#include "debug_utils-inl.h"
|
||||
#include "env-inl.h"
|
||||
@@ -919,10 +920,8 @@ void QuicCryptoContext::EnableTrace() {
|
||||
// when the peer certificate is received, allowing additional tweaks
|
||||
// and verifications to be performed.
|
||||
int QuicCryptoContext::OnClientHello() {
|
||||
if (LIKELY(session_->state_[
|
||||
IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED] == 0)) {
|
||||
if (LIKELY(session_->state_->client_hello_enabled == 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
TLSCallbackScope callback_scope(this);
|
||||
|
||||
@@ -952,7 +951,7 @@ int QuicCryptoContext::OnClientHello() {
|
||||
// function that must be called in order for the TLS handshake to
|
||||
// continue.
|
||||
int QuicCryptoContext::OnOCSP() {
|
||||
if (LIKELY(session_->state_[IDX_QUIC_SESSION_STATE_CERT_ENABLED] == 0)) {
|
||||
if (LIKELY(session_->state_->cert_enabled == 0)) {
|
||||
Debug(session(), "No OCSPRequest handler registered");
|
||||
return 1;
|
||||
}
|
||||
@@ -991,7 +990,7 @@ void QuicCryptoContext::OnOCSPDone(
|
||||
[&]() { 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;
|
||||
session_->state_->cert_enabled = 0;
|
||||
|
||||
if (context) {
|
||||
int err = crypto::UseSNIContext(ssl_, context);
|
||||
@@ -1446,7 +1445,7 @@ QuicSession::QuicSession(
|
||||
idle_(new Timer(socket->env(), [this]() { OnIdleTimeout(); })),
|
||||
retransmit_(new Timer(socket->env(), [this]() { MaybeTimeout(); })),
|
||||
dcid_(dcid),
|
||||
state_(env()->isolate(), IDX_QUIC_SESSION_STATE_COUNT),
|
||||
state_(env()->isolate()),
|
||||
quic_state_(socket->quic_state()) {
|
||||
PushListener(&default_listener_);
|
||||
set_connection_id_strategy(RandomConnectionIDStrategy);
|
||||
@@ -1459,13 +1458,10 @@ QuicSession::QuicSession(
|
||||
options));
|
||||
application_.reset(SelectApplication(this));
|
||||
|
||||
// TODO(@jasnell): For now, the following is a check rather than properly
|
||||
// handled. Before this code moves out of experimental, this should be
|
||||
// properly handled.
|
||||
wrap->DefineOwnProperty(
|
||||
env()->context(),
|
||||
env()->state_string(),
|
||||
state_.GetJSArray(),
|
||||
state_.GetArrayBuffer(),
|
||||
PropertyAttribute::ReadOnly).Check();
|
||||
|
||||
// TODO(@jasnell): memory accounting
|
||||
@@ -1814,7 +1810,7 @@ void QuicSession::PathValidation(
|
||||
|
||||
// Only emit the callback if there is a handler for the pathValidation
|
||||
// event on the JavaScript QuicSession object.
|
||||
if (UNLIKELY(state_[IDX_QUIC_SESSION_STATE_PATH_VALIDATED_ENABLED] == 1)) {
|
||||
if (UNLIKELY(state_->path_validated_enabled == 1)) {
|
||||
listener_->OnPathValidation(
|
||||
res,
|
||||
reinterpret_cast<const sockaddr*>(path->local.addr),
|
||||
@@ -2190,14 +2186,12 @@ void QuicSession::IgnorePreferredAddressStrategy(
|
||||
void QuicSession::UsePreferredAddressStrategy(
|
||||
QuicSession* session,
|
||||
const PreferredAddress& preferred_address) {
|
||||
static constexpr int idx =
|
||||
IDX_QUIC_SESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED;
|
||||
int family = session->socket()->local_address().family();
|
||||
if (preferred_address.Use(family)) {
|
||||
Debug(session, "Using server preferred address");
|
||||
// Emit only if the QuicSession has a usePreferredAddress handler
|
||||
// on the JavaScript side.
|
||||
if (UNLIKELY(session->state_[idx] == 1)) {
|
||||
if (UNLIKELY(session->state_->use_preferred_address_enabled == 1)) {
|
||||
session->listener()->OnUsePreferredAddress(family, preferred_address);
|
||||
}
|
||||
} else {
|
||||
@@ -2550,7 +2544,6 @@ void QuicSession::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("idle", idle_);
|
||||
tracker->TrackField("retransmit", retransmit_);
|
||||
tracker->TrackField("streams", streams_);
|
||||
tracker->TrackField("state", state_);
|
||||
tracker->TrackFieldWithSize("current_ngtcp2_memory", current_ngtcp2_memory_);
|
||||
tracker->TrackField("conn_closebuf", conn_closebuf_);
|
||||
tracker->TrackField("application", application_);
|
||||
@@ -2697,14 +2690,12 @@ void QuicSession::UpdateRecoveryStats() {
|
||||
void QuicSession::UpdateDataStats() {
|
||||
if (is_destroyed())
|
||||
return;
|
||||
state_[IDX_QUIC_SESSION_STATE_MAX_DATA_LEFT] =
|
||||
static_cast<double>(ngtcp2_conn_get_max_data_left(connection()));
|
||||
state_->max_data_left = ngtcp2_conn_get_max_data_left(connection());
|
||||
|
||||
ngtcp2_conn_stat stat;
|
||||
ngtcp2_conn_get_conn_stat(connection(), &stat);
|
||||
|
||||
state_[IDX_QUIC_SESSION_STATE_BYTES_IN_FLIGHT] =
|
||||
static_cast<double>(stat.bytes_in_flight);
|
||||
state_->bytes_in_flight = stat.bytes_in_flight;
|
||||
// The max_bytes_in_flight is a highwater mark that can be used
|
||||
// in performance analysis operations.
|
||||
if (stat.bytes_in_flight > GetStat(&QuicSessionStats::max_bytes_in_flight))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "aliased_buffer.h"
|
||||
#include "aliased_struct.h"
|
||||
#include "async_wrap.h"
|
||||
#include "env.h"
|
||||
#include "handle_wrap.h"
|
||||
@@ -141,67 +142,32 @@ enum QuicClientSessionOptions : uint32_t {
|
||||
QUICCLIENTSESSION_OPTION_RESUME = 0x4
|
||||
};
|
||||
|
||||
#define QUICSESSION_SHARED_STATE(V) \
|
||||
V(KEYLOG_ENABLED, keylog_enabled, uint8_t) \
|
||||
V(CLIENT_HELLO_ENABLED, client_hello_enabled, uint8_t) \
|
||||
V(CERT_ENABLED, cert_enabled, uint8_t) \
|
||||
V(PATH_VALIDATED_ENABLED, path_validated_enabled, uint8_t) \
|
||||
V(USE_PREFERRED_ADDRESS_ENABLED, use_preferred_address_enabled, uint8_t) \
|
||||
V(HANDSHAKE_CONFIRMED, handshake_confirmed, uint8_t) \
|
||||
V(IDLE_TIMEOUT, idle_timeout, uint8_t) \
|
||||
V(MAX_STREAMS_BIDI, max_streams_bidi, uint64_t) \
|
||||
V(MAX_STREAMS_UNI, max_streams_uni, uint64_t) \
|
||||
V(MAX_DATA_LEFT, max_data_left, uint64_t) \
|
||||
V(BYTES_IN_FLIGHT, bytes_in_flight, uint64_t)
|
||||
|
||||
// The QuicSessionState enums are used with the QuicSession's
|
||||
// private state_ array. This is exposed to JavaScript via an
|
||||
// aliased buffer and is used to communicate various types of
|
||||
// state efficiently across the native/JS boundary.
|
||||
enum QuicSessionState : int {
|
||||
// Communicates whether a 'keylog' event listener has been
|
||||
// registered on the JavaScript QuicSession object. The
|
||||
// value will be either 1 or 0. When set to 1, the native
|
||||
// code will emit TLS keylog entries to the JavaScript
|
||||
// side triggering the 'keylog' event once for each line.
|
||||
IDX_QUIC_SESSION_STATE_KEYLOG_ENABLED,
|
||||
|
||||
// Communicates whether a 'clientHello' event listener has
|
||||
// been registered on the JavaScript QuicServerSession.
|
||||
// The value will be either 1 or 0. When set to 1, the
|
||||
// native code will callout to the JavaScript side causing
|
||||
// the 'clientHello' event to be emitted. This is only
|
||||
// used on server QuicSession instances.
|
||||
IDX_QUIC_SESSION_STATE_CLIENT_HELLO_ENABLED,
|
||||
|
||||
// Communicates whether a 'cert' event listener has been
|
||||
// registered on the JavaScript QuicSession. The value will
|
||||
// be either 1 or 0. When set to 1, the native code will
|
||||
// callout to the JavaScript side causing the 'cert' event
|
||||
// to be emitted.
|
||||
IDX_QUIC_SESSION_STATE_CERT_ENABLED,
|
||||
|
||||
// Communicates whether a 'pathValidation' event listener
|
||||
// has been registered on the JavaScript QuicSession. The
|
||||
// value will be either 1 or 0. When set to 1, the native
|
||||
// code will callout to the JavaScript side causing the
|
||||
// 'pathValidation' event to be emitted
|
||||
IDX_QUIC_SESSION_STATE_PATH_VALIDATED_ENABLED,
|
||||
|
||||
// Communicates the current max cumulative number of
|
||||
// bidi and uni streams that may be opened on the session
|
||||
IDX_QUIC_SESSION_STATE_MAX_STREAMS_BIDI,
|
||||
IDX_QUIC_SESSION_STATE_MAX_STREAMS_UNI,
|
||||
|
||||
// Communicates the current maxinum number of bytes that
|
||||
// the local endpoint can send in this connection
|
||||
// (updated immediately after processing sent/received packets)
|
||||
IDX_QUIC_SESSION_STATE_MAX_DATA_LEFT,
|
||||
|
||||
// Communicates the current total number of bytes in flight
|
||||
IDX_QUIC_SESSION_STATE_BYTES_IN_FLIGHT,
|
||||
|
||||
// Communicates whether a 'usePreferredAddress' event listener
|
||||
// has been registered.
|
||||
IDX_QUIC_SESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED,
|
||||
|
||||
IDX_QUIC_SESSION_STATE_HANDSHAKE_CONFIRMED,
|
||||
|
||||
// Communicates whether a session was closed due to idle timeout
|
||||
IDX_QUIC_SESSION_STATE_IDLE_TIMEOUT,
|
||||
|
||||
// Just the number of session state enums for use when
|
||||
// creating the AliasedBuffer.
|
||||
IDX_QUIC_SESSION_STATE_COUNT
|
||||
#define V(_, name, type) type name;
|
||||
struct QuicSessionState {
|
||||
QUICSESSION_SHARED_STATE(V)
|
||||
};
|
||||
#undef V
|
||||
|
||||
#define V(id, name, _) \
|
||||
IDX_QUICSESSION_STATE_##id = offsetof(QuicSessionState, name),
|
||||
enum QuicSessionStateFields {
|
||||
QUICSESSION_SHARED_STATE(V)
|
||||
IDX_QUICSESSION_STATE_END
|
||||
};
|
||||
#undef V
|
||||
|
||||
#define SESSION_STATS(V) \
|
||||
V(CREATED_AT, created_at, "Created At") \
|
||||
@@ -1163,9 +1129,9 @@ class QuicSession : public AsyncWrap,
|
||||
|
||||
private:
|
||||
static void RandomConnectionIDStrategy(
|
||||
QuicSession* session,
|
||||
ngtcp2_cid* cid,
|
||||
size_t cidlen);
|
||||
QuicSession* session,
|
||||
ngtcp2_cid* cid,
|
||||
size_t cidlen);
|
||||
|
||||
// Initialize the QuicSession as a server
|
||||
void InitServer(
|
||||
@@ -1219,8 +1185,8 @@ class QuicSession : public AsyncWrap,
|
||||
inline void HandshakeConfirmed();
|
||||
|
||||
void PathValidation(
|
||||
const ngtcp2_path* path,
|
||||
ngtcp2_path_validation_result res);
|
||||
const ngtcp2_path* path,
|
||||
ngtcp2_path_validation_result res);
|
||||
|
||||
bool ReceivePacket(ngtcp2_path* path, const uint8_t* data, ssize_t nread);
|
||||
|
||||
@@ -1484,7 +1450,7 @@ class QuicSession : public AsyncWrap,
|
||||
|
||||
StreamsMap streams_;
|
||||
|
||||
AliasedFloat64Array state_;
|
||||
AliasedStruct<QuicSessionState> state_;
|
||||
|
||||
struct RemoteTransportParamsDebug {
|
||||
QuicSession* session;
|
||||
|
||||
Reference in New Issue
Block a user