1 #if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
2 #include "bindingdata.h"
3 #include <base_object-inl.h>
4 #include <env-inl.h>
5 #include <memory_tracker-inl.h>
6 #include <nghttp3/nghttp3.h>
7 #include <ngtcp2/ngtcp2.h>
8 #include <node.h>
9 #include <node_errors.h>
10 #include <node_external_reference.h>
11 #include <node_mem-inl.h>
12 #include <node_realm-inl.h>
13 #include <v8.h>
14
15 namespace node {
16
17 using v8::Function;
18 using v8::FunctionCallbackInfo;
19 using v8::FunctionTemplate;
20 using v8::Local;
21 using v8::Object;
22 using v8::String;
23 using v8::Value;
24
25 namespace quic {
26
Get(Environment * env)27 BindingData& BindingData::Get(Environment* env) {
28 return *Realm::GetBindingData<BindingData>(env->context());
29 }
30
operator ngtcp2_mem()31 BindingData::operator ngtcp2_mem() {
32 return MakeAllocator();
33 }
34
operator nghttp3_mem()35 BindingData::operator nghttp3_mem() {
36 ngtcp2_mem allocator = *this;
37 nghttp3_mem http3_allocator = {
38 allocator.user_data,
39 allocator.malloc,
40 allocator.free,
41 allocator.calloc,
42 allocator.realloc,
43 };
44 return http3_allocator;
45 }
46
CheckAllocatedSize(size_t previous_size) const47 void BindingData::CheckAllocatedSize(size_t previous_size) const {
48 CHECK_GE(current_ngtcp2_memory_, previous_size);
49 }
50
IncreaseAllocatedSize(size_t size)51 void BindingData::IncreaseAllocatedSize(size_t size) {
52 current_ngtcp2_memory_ += size;
53 }
54
DecreaseAllocatedSize(size_t size)55 void BindingData::DecreaseAllocatedSize(size_t size) {
56 current_ngtcp2_memory_ -= size;
57 }
58
Initialize(Environment * env,Local<Object> target)59 void BindingData::Initialize(Environment* env, Local<Object> target) {
60 SetMethod(env->context(), target, "setCallbacks", SetCallbacks);
61 SetMethod(env->context(), target, "flushPacketFreelist", FlushPacketFreelist);
62 Realm::GetCurrent(env->context())
63 ->AddBindingData<BindingData>(env->context(), target);
64 }
65
RegisterExternalReferences(ExternalReferenceRegistry * registry)66 void BindingData::RegisterExternalReferences(
67 ExternalReferenceRegistry* registry) {
68 registry->Register(SetCallbacks);
69 registry->Register(FlushPacketFreelist);
70 }
71
BindingData(Realm * realm,Local<Object> object)72 BindingData::BindingData(Realm* realm, Local<Object> object)
73 : BaseObject(realm, object) {
74 MakeWeak();
75 }
76
MemoryInfo(MemoryTracker * tracker) const77 void BindingData::MemoryInfo(MemoryTracker* tracker) const {
78 #define V(name, _) tracker->TrackField(#name, name##_callback());
79
80 QUIC_JS_CALLBACKS(V)
81
82 #undef V
83
84 #define V(name, _) tracker->TrackField(#name, name##_string());
85
86 QUIC_STRINGS(V)
87
88 #undef V
89 }
90
91 #define V(name) \
92 void BindingData::set_##name##_constructor_template( \
93 Local<FunctionTemplate> tmpl) { \
94 name##_constructor_template_.Reset(env()->isolate(), tmpl); \
95 } \
96 Local<FunctionTemplate> BindingData::name##_constructor_template() const { \
97 return PersistentToLocal::Default(env()->isolate(), \
98 name##_constructor_template_); \
99 }
100
101 QUIC_CONSTRUCTORS(V)
102
103 #undef V
104
105 #define V(name, _) \
106 void BindingData::set_##name##_callback(Local<Function> fn) { \
107 name##_callback_.Reset(env()->isolate(), fn); \
108 } \
109 Local<Function> BindingData::name##_callback() const { \
110 return PersistentToLocal::Default(env()->isolate(), name##_callback_); \
111 }
112
QUIC_JS_CALLBACKS(V)113 QUIC_JS_CALLBACKS(V)
114
115 #undef V
116
117 #define V(name, value) \
118 Local<String> BindingData::name##_string() const { \
119 if (name##_string_.IsEmpty()) \
120 name##_string_.Set(env()->isolate(), \
121 OneByteString(env()->isolate(), value)); \
122 return name##_string_.Get(env()->isolate()); \
123 }
124
125 QUIC_STRINGS(V)
126
127 #undef V
128
129 #define V(name, value) \
130 Local<String> BindingData::on_##name##_string() const { \
131 if (on_##name##_string_.IsEmpty()) \
132 on_##name##_string_.Set( \
133 env()->isolate(), \
134 FIXED_ONE_BYTE_STRING(env()->isolate(), "on" #value)); \
135 return on_##name##_string_.Get(env()->isolate()); \
136 }
137
138 QUIC_JS_CALLBACKS(V)
139
140 #undef V
141
142 void BindingData::SetCallbacks(const FunctionCallbackInfo<Value>& args) {
143 auto env = Environment::GetCurrent(args);
144 auto isolate = env->isolate();
145 auto& state = BindingData::Get(env);
146 CHECK(args[0]->IsObject());
147 Local<Object> obj = args[0].As<Object>();
148
149 #define V(name, key) \
150 do { \
151 Local<Value> val; \
152 if (!obj->Get(env->context(), state.on_##name##_string()).ToLocal(&val) || \
153 !val->IsFunction()) { \
154 return THROW_ERR_MISSING_ARGS(isolate, "Missing Callback: on" #key); \
155 } \
156 state.set_##name##_callback(val.As<Function>()); \
157 } while (0);
158
159 QUIC_JS_CALLBACKS(V)
160
161 #undef V
162 }
163
FlushPacketFreelist(const FunctionCallbackInfo<Value> & args)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
NgTcp2CallbackScope(Environment * env)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
~NgTcp2CallbackScope()176 NgTcp2CallbackScope::~NgTcp2CallbackScope() {
177 auto& binding = BindingData::Get(env);
178 binding.in_ngtcp2_callback_scope = false;
179 }
180
in_ngtcp2_callback(Environment * env)181 bool NgTcp2CallbackScope::in_ngtcp2_callback(Environment* env) {
182 auto& binding = BindingData::Get(env);
183 return binding.in_ngtcp2_callback_scope;
184 }
185
NgHttp3CallbackScope(Environment * env)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
~NgHttp3CallbackScope()192 NgHttp3CallbackScope::~NgHttp3CallbackScope() {
193 auto& binding = BindingData::Get(env);
194 binding.in_nghttp3_callback_scope = false;
195 }
196
in_nghttp3_callback(Environment * env)197 bool NgHttp3CallbackScope::in_nghttp3_callback(Environment* env) {
198 auto& binding = BindingData::Get(env);
199 return binding.in_nghttp3_callback_scope;
200 }
201
IllegalConstructor(const FunctionCallbackInfo<Value> & args)202 void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
203 THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
204 }
205
206 } // namespace quic
207 } // namespace node
208
209 #endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
210