Skip to content

Commit fe11f6b

Browse files
committed
quic: cleanup QuicSocketFlags, used shared state struct
Some of the flags were no longer being used. Switched to use an AliasedStruct for shared state to avoid extraneous expensive JS=>C++ calls. Removed unused QuicSocket option PR-URL: #34247 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent d08e99d commit fe11f6b

File tree

8 files changed

+137
-159
lines changed

8 files changed

+137
-159
lines changed

doc/api/quic.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1327,17 +1327,17 @@ added: REPLACEME
13271327
-->
13281328

13291329
Emitted when the server busy state has been toggled using
1330-
`quicSocket.serverBusy = true | false`. The callback is invoked with a
1331-
single boolean argument indicating `true` if busy status is enabled,
1332-
`false` otherwise. This event is strictly informational.
1330+
`quicSocket.serverBusy = true | false`. The callback is invoked with no
1331+
arguments. Use the `quicsocket.serverBusy` property to determine the
1332+
current status. This event is strictly informational.
13331333

13341334
```js
13351335
const { createQuicSocket } = require('net');
13361336

13371337
const socket = createQuicSocket();
13381338

1339-
socket.on('busy', (busy) => {
1340-
if (busy)
1339+
socket.on('busy', () => {
1340+
if (socket.serverBusy)
13411341
console.log('Server is busy');
13421342
else
13431343
console.log('Server is not busy');

lib/internal/quic/core.js

+39-47
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ assertCrypto();
1212
const {
1313
Array,
1414
BigInt64Array,
15+
Boolean,
1516
Error,
1617
Map,
1718
Number,
@@ -38,6 +39,7 @@ const {
3839
validateQuicEndpointOptions,
3940
validateCreateSecureContextOptions,
4041
validateQuicSocketConnectOptions,
42+
QuicSocketSharedState,
4143
QuicSessionSharedState,
4244
QLogStream,
4345
} = require('internal/quic/util');
@@ -269,8 +271,8 @@ function onSocketClose(err) {
269271

270272
// Called by the C++ internals when the server busy state of
271273
// the QuicSocket has been changed.
272-
function onSocketServerBusy(on) {
273-
this[owner_symbol][kServerBusy](on);
274+
function onSocketServerBusy() {
275+
this[owner_symbol][kServerBusy]();
274276
}
275277

276278
// Called by the C++ internals when a new server QuicSession has been created.
@@ -845,31 +847,24 @@ class QuicEndpoint {
845847
class QuicSocket extends EventEmitter {
846848
[kInternalState] = {
847849
alpn: undefined,
848-
autoClose: undefined,
849850
client: undefined,
850851
defaultEncoding: undefined,
851852
endpoints: new Set(),
852853
highWaterMark: undefined,
854+
listenPending: false,
853855
lookup: undefined,
854856
server: undefined,
855-
serverBusy: false,
856-
serverListening: false,
857857
serverSecureContext: undefined,
858858
sessions: new Set(),
859859
state: kSocketUnbound,
860-
statelessResetEnabled: true,
860+
sharedState: undefined,
861861
stats: undefined,
862862
};
863863

864864
constructor(options) {
865865
const {
866866
endpoint,
867867

868-
// True if the QuicSocket should automatically enter a graceful shutdown
869-
// if it is not listening as a server and the last QuicClientSession
870-
// closes
871-
autoClose,
872-
873868
// Default configuration for QuicClientSessions
874869
client,
875870

@@ -913,7 +908,6 @@ class QuicSocket extends EventEmitter {
913908

914909
const state = this[kInternalState];
915910

916-
state.autoClose = autoClose;
917911
state.client = client;
918912
state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4);
919913
state.server = server;
@@ -976,6 +970,10 @@ class QuicSocket extends EventEmitter {
976970
if (handle !== undefined) {
977971
handle[owner_symbol] = this;
978972
this[async_id_symbol] = handle.getAsyncId();
973+
this[kInternalState].sharedState =
974+
new QuicSocketSharedState(handle.state);
975+
} else {
976+
this[kInternalState].sharedState = undefined;
979977
}
980978
}
981979

@@ -1081,16 +1079,13 @@ class QuicSocket extends EventEmitter {
10811079
}
10821080

10831081
// Called by the C++ internals to notify when server busy status is toggled.
1084-
[kServerBusy](on) {
1085-
this[kInternalState].serverBusy = on;
1086-
// In a nextTick because the event ends up being
1087-
// emitted synchronously when quicSocket.serverBusy
1088-
// is called.
1082+
[kServerBusy]() {
1083+
const busy = this.serverBusy;
10891084
process.nextTick(() => {
10901085
try {
1091-
this.emit('busy', on);
1086+
this.emit('busy', busy);
10921087
} catch (error) {
1093-
this[kRejections](error, 'busy', on);
1088+
this[kRejections](error, 'busy', busy);
10941089
}
10951090
});
10961091
}
@@ -1161,6 +1156,7 @@ class QuicSocket extends EventEmitter {
11611156
// server and will emit session events whenever a new QuicServerSession
11621157
// is created.
11631158
const state = this[kInternalState];
1159+
state.listenPending = false;
11641160
this[kHandle].listen(
11651161
state.serverSecureContext.context,
11661162
address,
@@ -1225,14 +1221,12 @@ class QuicSocket extends EventEmitter {
12251221
// function.
12261222
listen(options, callback) {
12271223
const state = this[kInternalState];
1228-
if (state.serverListening)
1229-
throw new ERR_QUICSOCKET_LISTENING();
1230-
12311224
if (state.state === kSocketDestroyed ||
12321225
state.state === kSocketClosing) {
12331226
throw new ERR_QUICSOCKET_DESTROYED('listen');
12341227
}
1235-
1228+
if (this.listening || state.listenPending)
1229+
throw new ERR_QUICSOCKET_LISTENING();
12361230
if (typeof options === 'function') {
12371231
callback = options;
12381232
options = {};
@@ -1265,8 +1259,8 @@ class QuicSocket extends EventEmitter {
12651259

12661260
state.highWaterMark = highWaterMark;
12671261
state.defaultEncoding = defaultEncoding;
1268-
state.serverListening = true;
12691262
state.alpn = alpn;
1263+
state.listenPending = true;
12701264

12711265
// If the callback function is provided, it is registered as a
12721266
// handler for the on('session') event and will be called whenever
@@ -1403,10 +1397,8 @@ class QuicSocket extends EventEmitter {
14031397
// listening for new QuicServerSession connections.
14041398
// New initial connection packets for currently unknown
14051399
// DCID's will be ignored.
1406-
if (this[kHandle]) {
1407-
this[kHandle].stopListening();
1408-
}
1409-
state.serverListening = false;
1400+
if (this[kHandle])
1401+
this[kInternalState].sharedState.serverListening = false;
14101402

14111403
// If there are no sessions, calling maybeDestroy
14121404
// will immediately and synchronously destroy the
@@ -1502,7 +1494,7 @@ class QuicSocket extends EventEmitter {
15021494

15031495
// True if listen() has been called successfully
15041496
get listening() {
1505-
return this[kInternalState].serverListening;
1497+
return Boolean(this[kInternalState].sharedState?.serverListening);
15061498
}
15071499

15081500
// True if the QuicSocket is currently waiting on at least one
@@ -1518,12 +1510,27 @@ class QuicSocket extends EventEmitter {
15181510
if (state.state === kSocketDestroyed)
15191511
throw new ERR_QUICSOCKET_DESTROYED('serverBusy');
15201512
validateBoolean(on, 'on');
1521-
if (state.serverBusy !== on)
1522-
this[kHandle].setServerBusy(on);
1513+
if (state.sharedState.serverBusy !== on) {
1514+
state.sharedState.serverBusy = on;
1515+
this[kServerBusy]();
1516+
}
15231517
}
15241518

15251519
get serverBusy() {
1526-
return this[kInternalState].serverBusy;
1520+
return Boolean(this[kInternalState].sharedState?.serverBusy);
1521+
}
1522+
1523+
set statelessResetDisabled(on) {
1524+
const state = this[kInternalState];
1525+
if (state.state === kSocketDestroyed)
1526+
throw new ERR_QUICSOCKET_DESTROYED('statelessResetDisabled');
1527+
validateBoolean(on, 'on');
1528+
if (state.sharedState.statelessResetDisabled !== on)
1529+
state.sharedState.statelessResetDisabled = on;
1530+
}
1531+
1532+
get statelessResetDisabled() {
1533+
return Boolean(this[kInternalState].sharedState?.statelessResetDisabled);
15271534
}
15281535

15291536
get duration() {
@@ -1613,21 +1620,6 @@ class QuicSocket extends EventEmitter {
16131620
}
16141621
this[kHandle].setDiagnosticPacketLoss(rx, tx);
16151622
}
1616-
1617-
get statelessResetEnabled() {
1618-
return this[kInternalState].statelessResetEnabled;
1619-
}
1620-
1621-
set statelessResetEnabled(on) {
1622-
const state = this[kInternalState];
1623-
if (state.state === kSocketDestroyed)
1624-
throw new ERR_QUICSOCKET_DESTROYED('serverBusy');
1625-
validateBoolean(on, 'on');
1626-
if (state.statelessResetEnabled !== on) {
1627-
this[kHandle].enableStatelessReset(on);
1628-
state.statelessResetEnabled = on;
1629-
}
1630-
}
16311623
}
16321624

16331625
class QuicSession extends EventEmitter {

lib/internal/quic/util.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ const {
8282
IDX_QUICSESSION_STATE_MAX_DATA_LEFT,
8383
IDX_QUICSESSION_STATE_BYTES_IN_FLIGHT,
8484

85+
IDX_QUICSOCKET_STATE_SERVER_LISTENING,
86+
IDX_QUICSOCKET_STATE_SERVER_BUSY,
87+
IDX_QUICSOCKET_STATE_STATELESS_RESET_DISABLED,
88+
8589
IDX_HTTP3_QPACK_MAX_TABLE_CAPACITY,
8690
IDX_HTTP3_QPACK_BLOCKED_STREAMS,
8791
IDX_HTTP3_MAX_HEADER_LIST_SIZE,
@@ -514,7 +518,6 @@ function validateQuicSocketOptions(options = {}) {
514518
validateObject(options, 'options');
515519

516520
const {
517-
autoClose = false,
518521
client = {},
519522
disableStatelessReset = false,
520523
endpoint = { port: 0, type: 'udp4' },
@@ -538,7 +541,6 @@ function validateQuicSocketOptions(options = {}) {
538541
validateLookup(lookup);
539542
validateBoolean(validateAddress, 'options.validateAddress');
540543
validateBoolean(validateAddressLRU, 'options.validateAddressLRU');
541-
validateBoolean(autoClose, 'options.autoClose');
542544
validateBoolean(qlog, 'options.qlog');
543545
validateBoolean(disableStatelessReset, 'options.disableStatelessReset');
544546

@@ -576,7 +578,6 @@ function validateQuicSocketOptions(options = {}) {
576578

577579
return {
578580
endpoint,
579-
autoClose,
580581
client,
581582
lookup,
582583
maxConnections,
@@ -803,6 +804,39 @@ function toggleListeners(state, event, on) {
803804
}
804805
}
805806

807+
class QuicSocketSharedState {
808+
constructor(state) {
809+
this[kHandle] = Buffer.from(state);
810+
}
811+
812+
get serverListening() {
813+
return Boolean(this[kHandle]
814+
.readUInt8(IDX_QUICSOCKET_STATE_SERVER_LISTENING));
815+
}
816+
817+
set serverListening(on) {
818+
this[kHandle].writeUInt8(on ? 1 : 0, IDX_QUICSOCKET_STATE_SERVER_LISTENING);
819+
}
820+
821+
get serverBusy() {
822+
return Boolean(this[kHandle].readUInt8(IDX_QUICSOCKET_STATE_SERVER_BUSY));
823+
}
824+
825+
set serverBusy(on) {
826+
this[kHandle].writeUInt8(on ? 1 : 0, IDX_QUICSOCKET_STATE_SERVER_BUSY);
827+
}
828+
829+
get statelessResetDisabled() {
830+
return Boolean(this[kHandle]
831+
.readUInt8(IDX_QUICSOCKET_STATE_STATELESS_RESET_DISABLED));
832+
}
833+
834+
set statelessResetDisabled(on) {
835+
this[kHandle].writeUInt8(on ? 1 : 0,
836+
IDX_QUICSOCKET_STATE_STATELESS_RESET_DISABLED);
837+
}
838+
}
839+
806840
// A utility class used to handle reading / modifying shared JS/C++
807841
// state associated with a QuicSession
808842
class QuicSessionSharedState {
@@ -938,6 +972,7 @@ module.exports = {
938972
validateQuicEndpointOptions,
939973
validateCreateSecureContextOptions,
940974
validateQuicSocketConnectOptions,
975+
QuicSocketSharedState,
941976
QuicSessionSharedState,
942977
QLogStream,
943978
};

src/quic/node_quic.cc

+5
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ void Initialize(Local<Object> target,
205205
QUICSESSION_SHARED_STATE(V)
206206
#undef V
207207

208+
#define V(id, _, __) \
209+
NODE_DEFINE_CONSTANT(constants, IDX_QUICSOCKET_STATE_##id);
210+
QUICSOCKET_SHARED_STATE(V)
211+
#undef V
212+
208213
#define V(name, _, __) \
209214
NODE_DEFINE_CONSTANT(constants, IDX_QUIC_SESSION_STATS_##name);
210215
SESSION_STATS(V)

src/quic/node_quic_socket-inl.h

+3-22
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,6 @@ void QuicSocket::DisassociateStatelessResetToken(
9090
token_map_.erase(token);
9191
}
9292

93-
// StopListening is called when the QuicSocket is no longer
94-
// accepting new server connections. Typically, this is called
95-
// when the QuicSocket enters a graceful closing state where
96-
// existing sessions are allowed to close naturally but new
97-
// sessions are rejected.
98-
void QuicSocket::StopListening() {
99-
if (is_server_listening()) {
100-
Debug(this, "Stop listening");
101-
set_server_listening(false);
102-
// It is important to not call ReceiveStop here as there
103-
// is ongoing traffic being exchanged by the peers.
104-
}
105-
}
106-
10793
void QuicSocket::ReceiveStart() {
10894
for (const auto& endpoint : endpoints_)
10995
CHECK_EQ(endpoint->ReceiveStart(), 0);
@@ -157,8 +143,8 @@ size_t QuicSocket::GetCurrentStatelessResetCounter(const SocketAddress& addr) {
157143

158144
void QuicSocket::ServerBusy(bool on) {
159145
Debug(this, "Turning Server Busy Response %s", on ? "on" : "off");
160-
set_server_busy(on);
161-
listener_->OnServerBusy(on);
146+
state_->server_busy = on ? 1 : 0;
147+
listener_->OnServerBusy();
162148
}
163149

164150
bool QuicSocket::is_diagnostic_packet_loss(double prob) const {
@@ -173,11 +159,6 @@ void QuicSocket::set_diagnostic_packet_loss(double rx, double tx) {
173159
tx_loss_ = tx;
174160
}
175161

176-
bool QuicSocket::EnableStatelessReset(bool on) {
177-
set_stateless_reset_disabled(!on);
178-
return !is_stateless_reset_disabled();
179-
}
180-
181162
void QuicSocket::set_validated_address(const SocketAddress& addr) {
182163
if (has_option_validate_address_lru()) {
183164
// Remove the oldest item if we've hit the LRU limit
@@ -215,7 +196,7 @@ void QuicSocket::AddEndpoint(
215196
if (preferred || endpoints_.empty())
216197
preferred_endpoint_ = endpoint_;
217198
endpoints_.emplace_back(endpoint_);
218-
if (is_server_listening())
199+
if (state_->server_listening)
219200
endpoint_->ReceiveStart();
220201
}
221202

0 commit comments

Comments
 (0)