Skip to content

Commit e74d9f4

Browse files
committed
src: cleanup quic TransportParams class
1 parent 4612c79 commit e74d9f4

File tree

2 files changed

+91
-66
lines changed

2 files changed

+91
-66
lines changed

src/quic/transportparams.cc

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,23 @@ TransportParams::Config::Config(Side side,
3434
Maybe<TransportParams::Options> TransportParams::Options::From(
3535
Environment* env, Local<Value> value) {
3636
if (value.IsEmpty()) {
37-
THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object");
37+
THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object or undefined");
38+
return Nothing<Options>();
39+
} else if (value->IsUndefined()) {
40+
return Just<Options>(kDefault);
41+
} else if (!value->IsObject()) {
42+
THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object or undefined");
3843
return Nothing<Options>();
3944
}
4045

4146
Options options;
42-
auto& state = BindingData::Get(env);
43-
44-
if (value->IsUndefined()) {
45-
return Just<Options>(options);
46-
}
4747

48-
if (!value->IsObject()) {
49-
THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object");
50-
return Nothing<Options>();
51-
}
48+
// TODO(@jasnell): We currently only support version 1 of the transport
49+
// parameters, so the options.transportParamsVersion is hardcoded to that.
50+
// In the future, when we support multiple versions, we will need to
51+
// expose this via the options object.
5252

53+
auto& state = BindingData::Get(env);
5354
auto params = value.As<Object>();
5455

5556
#define SET(name) \
@@ -68,14 +69,20 @@ Maybe<TransportParams::Options> TransportParams::Options::From(
6869

6970
#undef SET
7071

72+
// TODO(@jasnell): We are not yet exposing the ability to set the preferred
73+
// adddress via the options, tho the underlying support is here in the class.
74+
options.preferred_address_ipv4 = std::nullopt;
75+
options.preferred_address_ipv6 = std::nullopt;
76+
7177
return Just<Options>(options);
7278
}
7379

7480
std::string TransportParams::Options::ToString() const {
7581
DebugIndentScope indent;
7682
auto prefix = indent.Prefix();
7783
std::string res("{");
78-
res += prefix + "version: " + std::to_string(transportParamsVersion);
84+
res += prefix +
85+
"version: " + std::to_string(static_cast<int>(transportParamsVersion));
7986
if (preferred_address_ipv4.has_value()) {
8087
res += prefix + "preferred_address_ipv4: " +
8188
preferred_address_ipv4.value().ToString();
@@ -131,36 +138,39 @@ TransportParams::TransportParams(const ngtcp2_transport_params* ptr)
131138
TransportParams::TransportParams(const Config& config, const Options& options)
132139
: TransportParams() {
133140
ngtcp2_transport_params_default(&params_);
134-
params_.active_connection_id_limit = options.active_connection_id_limit;
135-
params_.initial_max_stream_data_bidi_local =
136-
options.initial_max_stream_data_bidi_local;
137-
params_.initial_max_stream_data_bidi_remote =
138-
options.initial_max_stream_data_bidi_remote;
139-
params_.initial_max_stream_data_uni = options.initial_max_stream_data_uni;
140-
params_.initial_max_streams_bidi = options.initial_max_streams_bidi;
141-
params_.initial_max_streams_uni = options.initial_max_streams_uni;
142-
params_.initial_max_data = options.initial_max_data;
143-
params_.max_idle_timeout = options.max_idle_timeout * NGTCP2_SECONDS;
144-
params_.max_ack_delay = options.max_ack_delay;
145-
params_.ack_delay_exponent = options.ack_delay_exponent;
146-
params_.max_datagram_frame_size = options.max_datagram_frame_size;
147-
params_.disable_active_migration = options.disable_active_migration ? 1 : 0;
148-
params_.preferred_addr_present = 0;
149-
params_.stateless_reset_token_present = 0;
150-
params_.retry_scid_present = 0;
141+
#define SET_PARAM(name) params_.name = options.name
142+
#define SET_PARAM_V(name, value) params_.name = value
143+
SET_PARAM(active_connection_id_limit);
144+
SET_PARAM(initial_max_stream_data_bidi_local);
145+
SET_PARAM(initial_max_stream_data_bidi_remote);
146+
SET_PARAM(initial_max_stream_data_uni);
147+
SET_PARAM(initial_max_streams_bidi);
148+
SET_PARAM(initial_max_streams_uni);
149+
SET_PARAM(initial_max_data);
150+
SET_PARAM(max_ack_delay);
151+
SET_PARAM(ack_delay_exponent);
152+
SET_PARAM(max_datagram_frame_size);
153+
SET_PARAM_V(max_idle_timeout, options.max_idle_timeout * NGTCP2_SECONDS);
154+
SET_PARAM_V(disable_active_migration,
155+
options.disable_active_migration ? 1 : 0);
156+
SET_PARAM_V(preferred_addr_present, 0);
157+
SET_PARAM_V(stateless_reset_token_present, 0);
158+
SET_PARAM_V(retry_scid_present, 0);
151159

152160
if (config.side == Side::SERVER) {
153161
// For the server side, the original dcid is always set.
154162
CHECK(config.ocid);
155-
params_.original_dcid = config.ocid;
156-
params_.original_dcid_present = 1;
163+
SET_PARAM_V(original_dcid, config.ocid);
164+
SET_PARAM_V(original_dcid_present, 1);
157165

158166
// The retry_scid is only set if the server validated a retry token.
159167
if (config.retry_scid) {
160-
params_.retry_scid = config.retry_scid;
161-
params_.retry_scid_present = 1;
168+
SET_PARAM_V(retry_scid, config.retry_scid);
169+
SET_PARAM_V(retry_scid_present, 1);
162170
}
163171
}
172+
#undef SET_PARAM
173+
#undef SET_PARAM_V
164174

165175
if (options.preferred_address_ipv4.has_value())
166176
SetPreferredAddress(options.preferred_address_ipv4.value());
@@ -169,33 +179,39 @@ TransportParams::TransportParams(const Config& config, const Options& options)
169179
SetPreferredAddress(options.preferred_address_ipv6.value());
170180
}
171181

172-
TransportParams::TransportParams(const ngtcp2_vec& vec, int version)
182+
TransportParams::TransportParams(const ngtcp2_vec& vec, Version version)
173183
: TransportParams() {
174184
int ret = ngtcp2_transport_params_decode_versioned(
175-
version, &params_, vec.base, vec.len);
185+
static_cast<int>(version), &params_, vec.base, vec.len);
176186

187+
// The only error we should see here is NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM,
188+
// which indicates that the provided data was not valid transport parameters.
189+
// In that case, we set ptr_ to nullptr to indicate that the parameters
190+
// could not be decoded.
177191
if (ret != 0) {
178192
ptr_ = nullptr;
179-
error_ = QuicError::ForNgtcp2Error(ret);
180193
}
181194
}
182195

183-
Store TransportParams::Encode(Environment* env, int version) const {
196+
Store TransportParams::Encode(Environment* env, Version version) const {
184197
if (ptr_ == nullptr) {
185198
return {};
186199
}
187200

188201
// Preflight to see how much storage we'll need.
189-
ssize_t size =
190-
ngtcp2_transport_params_encode_versioned(nullptr, 0, version, &params_);
202+
ssize_t size = ngtcp2_transport_params_encode_versioned(
203+
nullptr, 0, static_cast<int>(version), &params_);
191204
if (size == 0) {
192205
return {};
193206
}
194207

195208
JS_TRY_ALLOCATE_BACKING_OR_RETURN(env, result, size, {});
196209

197210
auto ret = ngtcp2_transport_params_encode_versioned(
198-
static_cast<uint8_t*>(result->Data()), size, version, &params_);
211+
static_cast<uint8_t*>(result->Data()),
212+
size,
213+
static_cast<int>(version),
214+
&params_);
199215

200216
// The ret is the number of bytes written, or a negative error code.
201217
if (ret < 0) return {};
@@ -214,6 +230,7 @@ void TransportParams::SetPreferredAddress(const SocketAddress& address) {
214230
&src->sin_addr,
215231
sizeof(params_.preferred_addr.ipv4.sin_addr));
216232
params_.preferred_addr.ipv4.sin_port = address.port();
233+
params_.preferred_addr.ipv4_present = 1;
217234
return;
218235
}
219236
case AF_INET6: {
@@ -223,6 +240,7 @@ void TransportParams::SetPreferredAddress(const SocketAddress& address) {
223240
&src->sin6_addr,
224241
sizeof(params_.preferred_addr.ipv6.sin6_addr));
225242
params_.preferred_addr.ipv6.sin6_port = address.port();
243+
params_.preferred_addr.ipv6_present = 1;
226244
return;
227245
}
228246
}
@@ -273,10 +291,6 @@ TransportParams::operator bool() const {
273291
return ptr_ != nullptr;
274292
}
275293

276-
const QuicError& TransportParams::error() const {
277-
return error_;
278-
}
279-
280294
void TransportParams::Initialize(Environment* env, Local<Object> target) {
281295
NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_STREAM_DATA);
282296
NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_DATA);

src/quic/transportparams.h

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ class TransportParams final {
2424
public:
2525
static void Initialize(Environment* env, v8::Local<v8::Object> target);
2626

27-
static constexpr int QUIC_TRANSPORT_PARAMS_V1 = NGTCP2_TRANSPORT_PARAMS_V1;
28-
static constexpr int QUIC_TRANSPORT_PARAMS_VERSION =
29-
NGTCP2_TRANSPORT_PARAMS_VERSION;
27+
enum class Version : int {
28+
V1 = NGTCP2_TRANSPORT_PARAMS_V1,
29+
};
30+
3031
static constexpr uint64_t DEFAULT_MAX_STREAM_DATA = 256 * 1024;
3132
static constexpr uint64_t DEFAULT_MAX_DATA = 1 * 1024 * 1024;
3233
static constexpr uint64_t DEFAULT_MAX_IDLE_TIMEOUT = 10; // seconds
@@ -44,69 +45,82 @@ class TransportParams final {
4445
};
4546

4647
struct Options final : public MemoryRetainer {
47-
int transportParamsVersion = QUIC_TRANSPORT_PARAMS_V1;
48+
Version transportParamsVersion = Version::V1;
4849

4950
// Set only on server Sessions, the preferred address communicates the IP
5051
// address and port that the server would prefer the client to use when
5152
// communicating with it. See the QUIC specification for more detail on how
52-
// the preferred address mechanism works.
53+
// the preferred address mechanism works:
54+
// https://www.rfc-editor.org/rfc/rfc9000.html#name-servers-preferred-address
5355
std::optional<SocketAddress> preferred_address_ipv4{};
5456
std::optional<SocketAddress> preferred_address_ipv6{};
5557

5658
// The initial size of the flow control window of locally initiated streams.
5759
// This is the maximum number of bytes that the *remote* endpoint can send
5860
// when the connection is started.
61+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.16.1
5962
uint64_t initial_max_stream_data_bidi_local = DEFAULT_MAX_STREAM_DATA;
6063

6164
// The initial size of the flow control window of remotely initiated
6265
// streams. This is the maximum number of bytes that the remote endpoint can
6366
// send when the connection is started.
67+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.18.1
6468
uint64_t initial_max_stream_data_bidi_remote = DEFAULT_MAX_STREAM_DATA;
6569

6670
// The initial size of the flow control window of remotely initiated
6771
// unidirectional streams. This is the maximum number of bytes that the
6872
// remote endpoint can send when the connection is started.
73+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.20.1
6974
uint64_t initial_max_stream_data_uni = DEFAULT_MAX_STREAM_DATA;
7075

7176
// The initial size of the session-level flow control window.
77+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.14.1
7278
uint64_t initial_max_data = DEFAULT_MAX_DATA;
7379

7480
// The initial maximum number of concurrent bidirectional streams the remote
7581
// endpoint is permitted to open.
82+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.22.1
7683
uint64_t initial_max_streams_bidi = DEFAULT_MAX_STREAMS_BIDI;
7784

7885
// The initial maximum number of concurrent unidirectional streams the
7986
// remote endpoint is permitted to open.
87+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.24.1
8088
uint64_t initial_max_streams_uni = DEFAULT_MAX_STREAMS_UNI;
8189

8290
// The maximum amount of time that a Session is permitted to remain idle
8391
// before it is silently closed and state is discarded.
92+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.4.1
8493
uint64_t max_idle_timeout = DEFAULT_MAX_IDLE_TIMEOUT;
8594

8695
// The maximum number of Connection IDs that the peer can store. A single
8796
// Session may have several connection IDs over it's lifetime.
97+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-6.2.1
8898
uint64_t active_connection_id_limit = DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
8999

90100
// Establishes the exponent used in ACK Delay field in the ACK frame. See
91101
// the QUIC specification for details. This is an advanced option that
92102
// should rarely be modified and only if there is really good reason.
103+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.26.1
93104
uint64_t ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
94105

95106
// The maximum amount of time by which the endpoint will delay sending
96107
// acknowledgements. This is an advanced option that should rarely be
97108
// modified and only if there is a really good reason. It is used to
98109
// determine how long a Session will wait to determine that a packet has
99110
// been lost.
111+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
100112
uint64_t max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
101113

102114
// The maximum size of DATAGRAM frames that the endpoint will accept.
103115
// Setting the value to 0 will disable DATAGRAM support.
116+
// https://datatracker.ietf.org/doc/html/rfc9221#section-3
104117
uint64_t max_datagram_frame_size = kDefaultMaxPacketLength;
105118

106119
// When true, communicates that the Session does not support active
107120
// connection migration. See the QUIC specification for more details on
108121
// connection migration.
109-
// TODO(@jasnell): We currently do not implementation active migration.
122+
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.30.1
123+
// TODO(@jasnell): We currently do not implement active migration.
110124
bool disable_active_migration = true;
111125

112126
static const Options kDefault;
@@ -123,40 +137,37 @@ class TransportParams final {
123137

124138
explicit TransportParams();
125139

126-
// Creates an instance of TransportParams wrapping the existing const
127-
// ngtcp2_transport_params pointer.
140+
// Creates an instance of TransportParams wrapping an existing const
141+
// ngtcp2_transport_params pointer. Instances created this way are
142+
// immutable.
128143
TransportParams(const ngtcp2_transport_params* ptr);
129144

130145
TransportParams(const Config& config, const Options& options);
131146

132147
// Creates an instance of TransportParams by decoding the given buffer.
133-
// If the parameters cannot be successfully decoded, the error()
134-
// property will be set with an appropriate QuicError and the bool()
135-
// operator will return false.
136-
TransportParams(const ngtcp2_vec& buf,
137-
int version = QUIC_TRANSPORT_PARAMS_V1);
148+
// If the parameters cannot be successfully decoded, the bool() operator
149+
// will be false.
150+
TransportParams(const ngtcp2_vec& buf, Version version = Version::V1);
138151

139152
void GenerateSessionTokens(Session* session);
140-
void GenerateStatelessResetToken(const Endpoint& endpoint, const CID& cid);
141-
void GeneratePreferredAddressToken(Session* session);
142-
void SetPreferredAddress(const SocketAddress& address);
143153

144154
operator const ngtcp2_transport_params&() const;
145155
operator const ngtcp2_transport_params*() const;
146156

147157
operator bool() const;
148158

149-
const QuicError& error() const;
150-
151-
// Returns an ArrayBuffer containing the encoded transport parameters.
152-
// If an error occurs during encoding, an empty shared_ptr will be returned
153-
// and the error() property will be set to an appropriate QuicError.
154-
Store Encode(Environment* env, int version = QUIC_TRANSPORT_PARAMS_V1) const;
159+
// Returns a Store containing the encoded transport parameters.
160+
// If an error occurs during encoding, or if the parameters could
161+
// not be encoded, an empty Store will be returned.
162+
Store Encode(Environment* env, Version version = Version::V1) const;
155163

156164
private:
165+
void SetPreferredAddress(const SocketAddress& address);
166+
void GeneratePreferredAddressToken(Session* session);
167+
void GenerateStatelessResetToken(const Endpoint& endpoint, const CID& cid);
168+
157169
ngtcp2_transport_params params_{};
158170
const ngtcp2_transport_params* ptr_;
159-
QuicError error_ = QuicError::TRANSPORT_NO_ERROR;
160171
};
161172

162173
} // namespace node::quic

0 commit comments

Comments
 (0)