Skip to content

Commit 1c3d741

Browse files
committed
quic: add more QUIC implementation
* add TLSContext * quic: add stat collection utilities * add Packet * add NgTcp2CallbackScope/NgHttp3CallbackScope PR-URL: #47494 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
1 parent 17c9aa2 commit 1c3d741

11 files changed

+1484
-8
lines changed

node.gyp

+4
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,20 @@
341341
'src/quic/cid.cc',
342342
'src/quic/data.cc',
343343
'src/quic/logstream.cc',
344+
'src/quic/packet.cc',
344345
'src/quic/preferredaddress.cc',
345346
'src/quic/sessionticket.cc',
347+
'src/quic/tlscontext.cc',
346348
'src/quic/tokens.cc',
347349
'src/quic/transportparams.cc',
348350
'src/quic/bindingdata.h',
349351
'src/quic/cid.h',
350352
'src/quic/data.h',
351353
'src/quic/logstream.h',
354+
'src/quic/packet.h',
352355
'src/quic/preferredaddress.h',
353356
'src/quic/sessionticket.h',
357+
'src/quic/tlscontext.h',
354358
'src/quic/tokens.h',
355359
'src/quic/transportparams.h',
356360
],

src/async_wrap.h

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ namespace node {
6161
V(PROMISE) \
6262
V(QUERYWRAP) \
6363
V(QUIC_LOGSTREAM) \
64+
V(QUIC_PACKET) \
6465
V(SHUTDOWNWRAP) \
6566
V(SIGNALWRAP) \
6667
V(STATWATCHER) \

src/node_errors.h

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
6363
V(ERR_DLOPEN_FAILED, Error) \
6464
V(ERR_ENCODING_INVALID_ENCODED_DATA, TypeError) \
6565
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
66+
V(ERR_ILLEGAL_CONSTRUCTOR, Error) \
6667
V(ERR_INVALID_ADDRESS, Error) \
6768
V(ERR_INVALID_ARG_VALUE, TypeError) \
6869
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
@@ -156,6 +157,7 @@ ERRORS_WITH_CODE(V)
156157
V(ERR_DLOPEN_FAILED, "DLOpen failed") \
157158
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
158159
"Context not associated with Node.js environment") \
160+
V(ERR_ILLEGAL_CONSTRUCTOR, "Illegal constructor") \
159161
V(ERR_INVALID_ADDRESS, "Invalid socket address") \
160162
V(ERR_INVALID_MODULE, "No such module") \
161163
V(ERR_INVALID_STATE, "Invalid state") \

src/quic/bindingdata.cc

+45-1
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,15 @@ void BindingData::DecreaseAllocatedSize(size_t size) {
5858

5959
void BindingData::Initialize(Environment* env, Local<Object> target) {
6060
SetMethod(env->context(), target, "setCallbacks", SetCallbacks);
61+
SetMethod(env->context(), target, "flushPacketFreelist", FlushPacketFreelist);
6162
Realm::GetCurrent(env->context())
6263
->AddBindingData<BindingData>(env->context(), target);
6364
}
6465

6566
void BindingData::RegisterExternalReferences(
6667
ExternalReferenceRegistry* registry) {
6768
registry->Register(SetCallbacks);
69+
registry->Register(FlushPacketFreelist);
6870
}
6971

7072
BindingData::BindingData(Realm* realm, Local<Object> object)
@@ -140,7 +142,7 @@ QUIC_JS_CALLBACKS(V)
140142
void BindingData::SetCallbacks(const FunctionCallbackInfo<Value>& args) {
141143
auto env = Environment::GetCurrent(args);
142144
auto isolate = env->isolate();
143-
BindingData& state = BindingData::Get(env);
145+
auto& state = BindingData::Get(env);
144146
CHECK(args[0]->IsObject());
145147
Local<Object> obj = args[0].As<Object>();
146148

@@ -159,6 +161,48 @@ void BindingData::SetCallbacks(const FunctionCallbackInfo<Value>& args) {
159161
#undef V
160162
}
161163

164+
void BindingData::FlushPacketFreelist(const FunctionCallbackInfo<Value>& args) {
165+
auto env = Environment::GetCurrent(args);
166+
auto& state = BindingData::Get(env);
167+
state.packet_freelist.clear();
168+
}
169+
170+
NgTcp2CallbackScope::NgTcp2CallbackScope(Environment* env) : env(env) {
171+
auto& binding = BindingData::Get(env);
172+
CHECK(!binding.in_ngtcp2_callback_scope);
173+
binding.in_ngtcp2_callback_scope = true;
174+
}
175+
176+
NgTcp2CallbackScope::~NgTcp2CallbackScope() {
177+
auto& binding = BindingData::Get(env);
178+
binding.in_ngtcp2_callback_scope = false;
179+
}
180+
181+
bool NgTcp2CallbackScope::in_ngtcp2_callback(Environment* env) {
182+
auto& binding = BindingData::Get(env);
183+
return binding.in_ngtcp2_callback_scope;
184+
}
185+
186+
NgHttp3CallbackScope::NgHttp3CallbackScope(Environment* env) : env(env) {
187+
auto& binding = BindingData::Get(env);
188+
CHECK(!binding.in_nghttp3_callback_scope);
189+
binding.in_nghttp3_callback_scope = true;
190+
}
191+
192+
NgHttp3CallbackScope::~NgHttp3CallbackScope() {
193+
auto& binding = BindingData::Get(env);
194+
binding.in_nghttp3_callback_scope = false;
195+
}
196+
197+
bool NgHttp3CallbackScope::in_nghttp3_callback(Environment* env) {
198+
auto& binding = BindingData::Get(env);
199+
return binding.in_nghttp3_callback_scope;
200+
}
201+
202+
void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
203+
THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
204+
}
205+
162206
} // namespace quic
163207
} // namespace node
164208

src/quic/bindingdata.h

+44-7
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
#include <node.h>
1313
#include <node_mem.h>
1414
#include <v8.h>
15+
#include <vector>
1516

1617
namespace node {
1718
namespace quic {
1819

1920
class Endpoint;
21+
class Packet;
2022

2123
enum class Side {
2224
CLIENT = NGTCP2_CRYPTO_SIDE_CLIENT,
@@ -64,23 +66,37 @@ constexpr size_t kDefaultMaxPacketLength = NGTCP2_MAX_UDP_PAYLOAD_SIZE;
6466
#define QUIC_STRINGS(V) \
6567
V(ack_delay_exponent, "ackDelayExponent") \
6668
V(active_connection_id_limit, "activeConnectionIDLimit") \
69+
V(alpn, "alpn") \
70+
V(ca, "ca") \
71+
V(certs, "certs") \
72+
V(crl, "crl") \
73+
V(ciphers, "ciphers") \
6774
V(disable_active_migration, "disableActiveMigration") \
75+
V(enable_tls_trace, "tlsTrace") \
6876
V(endpoint, "Endpoint") \
6977
V(endpoint_udp, "Endpoint::UDP") \
78+
V(groups, "groups") \
79+
V(hostname, "hostname") \
7080
V(http3_alpn, &NGHTTP3_ALPN_H3[1]) \
7181
V(initial_max_data, "initialMaxData") \
7282
V(initial_max_stream_data_bidi_local, "initialMaxStreamDataBidiLocal") \
7383
V(initial_max_stream_data_bidi_remote, "initialMaxStreamDataBidiRemote") \
7484
V(initial_max_stream_data_uni, "initialMaxStreamDataUni") \
7585
V(initial_max_streams_bidi, "initialMaxStreamsBidi") \
7686
V(initial_max_streams_uni, "initialMaxStreamsUni") \
87+
V(keylog, "keylog") \
88+
V(keys, "keys") \
7789
V(logstream, "LogStream") \
7890
V(max_ack_delay, "maxAckDelay") \
7991
V(max_datagram_frame_size, "maxDatagramFrameSize") \
8092
V(max_idle_timeout, "maxIdleTimeout") \
8193
V(packetwrap, "PacketWrap") \
94+
V(reject_unauthorized, "rejectUnauthorized") \
95+
V(request_peer_certificate, "requestPeerCertificate") \
8296
V(session, "Session") \
83-
V(stream, "Stream")
97+
V(session_id_ctx, "sessionIDContext") \
98+
V(stream, "Stream") \
99+
V(verify_hostname_identity, "verifyHostnameIdentity")
84100

85101
// =============================================================================
86102
// The BindingState object holds state for the internalBinding('quic') binding
@@ -115,12 +131,14 @@ class BindingData final
115131
// bridge out to the JS API.
116132
static void SetCallbacks(const v8::FunctionCallbackInfo<v8::Value>& args);
117133

118-
// TODO(@jasnell) This will be added when Endpoint is implemented.
119-
// // A set of listening Endpoints. We maintain this to ensure that the
120-
// Endpoint
121-
// // cannot be gc'd while it is still listening and there are active
122-
// // connections.
123-
// std::unordered_map<Endpoint*, BaseObjectPtr<Endpoint>> listening_endpoints;
134+
std::vector<BaseObjectPtr<BaseObject>> packet_freelist;
135+
136+
// Purge the packet free list to free up memory.
137+
static void FlushPacketFreelist(
138+
const v8::FunctionCallbackInfo<v8::Value>& args);
139+
140+
bool in_ngtcp2_callback_scope = false;
141+
bool in_nghttp3_callback_scope = false;
124142

125143
// The following set up various storage and accessors for common strings,
126144
// construction templates, and callbacks stored on the BindingData. These
@@ -166,6 +184,25 @@ class BindingData final
166184
#undef V
167185
};
168186

187+
void IllegalConstructor(const v8::FunctionCallbackInfo<v8::Value>& args);
188+
189+
// The ngtcp2 and nghttp3 callbacks have certain restrictions
190+
// that forbid re-entry. We provide the following scopes for
191+
// use in those to help protect against it.
192+
struct NgTcp2CallbackScope {
193+
Environment* env;
194+
explicit NgTcp2CallbackScope(Environment* env);
195+
~NgTcp2CallbackScope();
196+
static bool in_ngtcp2_callback(Environment* env);
197+
};
198+
199+
struct NgHttp3CallbackScope {
200+
Environment* env;
201+
explicit NgHttp3CallbackScope(Environment* env);
202+
~NgHttp3CallbackScope();
203+
static bool in_nghttp3_callback(Environment* env);
204+
};
205+
169206
} // namespace quic
170207
} // namespace node
171208

src/quic/defs.h

+48
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
#pragma once
22

3+
#include <aliased_struct.h>
34
#include <env.h>
45
#include <node_errors.h>
6+
#include <uv.h>
57
#include <v8.h>
68

79
namespace node {
810
namespace quic {
911

12+
template <typename Opt, std::string Opt::*member>
13+
bool SetOption(Environment* env,
14+
Opt* options,
15+
const v8::Local<v8::Object>& object,
16+
const v8::Local<v8::String>& name) {
17+
v8::Local<v8::Value> value;
18+
if (!object->Get(env->context(), name).ToLocal(&value)) return false;
19+
if (!value->IsUndefined()) {
20+
Utf8Value utf8(env->isolate(), value);
21+
options->*member = *utf8;
22+
}
23+
return true;
24+
}
25+
1026
template <typename Opt, bool Opt::*member>
1127
bool SetOption(Environment* env,
1228
Opt* options,
@@ -50,5 +66,37 @@ bool SetOption(Environment* env,
5066
return true;
5167
}
5268

69+
// Utilities used to update the stats for Endpoint, Session, and Stream
70+
// objects. The stats themselves are maintained in an AliasedStruct within
71+
// each of the relevant classes.
72+
73+
template <typename Stats, uint64_t Stats::*member>
74+
void IncrementStat(Stats* stats, uint64_t amt = 1) {
75+
stats->*member += amt;
76+
}
77+
78+
template <typename Stats, uint64_t Stats::*member>
79+
void RecordTimestampStat(Stats* stats) {
80+
stats->*member = uv_hrtime();
81+
}
82+
83+
template <typename Stats, uint64_t Stats::*member>
84+
void SetStat(Stats* stats, uint64_t val) {
85+
stats->*member = val;
86+
}
87+
88+
template <typename Stats, uint64_t Stats::*member>
89+
uint64_t GetStat(Stats* stats) {
90+
return stats->*member;
91+
}
92+
93+
#define STAT_INCREMENT(Type, name) IncrementStat<Type, &Type::name>(&stats_);
94+
#define STAT_INCREMENT_N(Type, name, amt) \
95+
IncrementStat<Type, &Type::name>(&stats_, amt);
96+
#define STAT_RECORD_TIMESTAMP(Type, name) \
97+
RecordTimestampStat<Type, &Type::name>(&stats_);
98+
#define STAT_SET(Type, name, val) SetStat<Type, &Type::name>(&stats_, val);
99+
#define STAT_GET(Type, name) GetStat<Type, &Type::name>(&stats_);
100+
53101
} // namespace quic
54102
} // namespace node

0 commit comments

Comments
 (0)