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 15namespace node { 16 17using v8::Function; 18using v8::FunctionCallbackInfo; 19using v8::FunctionTemplate; 20using v8::Local; 21using v8::Object; 22using v8::String; 23using v8::Value; 24 25namespace quic { 26 27BindingData& BindingData::Get(Environment* env) { 28 return *Realm::GetBindingData<BindingData>(env->context()); 29} 30 31BindingData::operator ngtcp2_mem() { 32 return MakeAllocator(); 33} 34 35BindingData::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 47void BindingData::CheckAllocatedSize(size_t previous_size) const { 48 CHECK_GE(current_ngtcp2_memory_, previous_size); 49} 50 51void BindingData::IncreaseAllocatedSize(size_t size) { 52 current_ngtcp2_memory_ += size; 53} 54 55void BindingData::DecreaseAllocatedSize(size_t size) { 56 current_ngtcp2_memory_ -= size; 57} 58 59void 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 66void BindingData::RegisterExternalReferences( 67 ExternalReferenceRegistry* registry) { 68 registry->Register(SetCallbacks); 69 registry->Register(FlushPacketFreelist); 70} 71 72BindingData::BindingData(Realm* realm, Local<Object> object) 73 : BaseObject(realm, object) { 74 MakeWeak(); 75} 76 77void 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 101QUIC_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 113QUIC_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 125QUIC_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 138QUIC_JS_CALLBACKS(V) 139 140#undef V 141 142void 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 164void 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 170NgTcp2CallbackScope::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 176NgTcp2CallbackScope::~NgTcp2CallbackScope() { 177 auto& binding = BindingData::Get(env); 178 binding.in_ngtcp2_callback_scope = false; 179} 180 181bool NgTcp2CallbackScope::in_ngtcp2_callback(Environment* env) { 182 auto& binding = BindingData::Get(env); 183 return binding.in_ngtcp2_callback_scope; 184} 185 186NgHttp3CallbackScope::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 192NgHttp3CallbackScope::~NgHttp3CallbackScope() { 193 auto& binding = BindingData::Get(env); 194 binding.in_nghttp3_callback_scope = false; 195} 196 197bool NgHttp3CallbackScope::in_nghttp3_callback(Environment* env) { 198 auto& binding = BindingData::Get(env); 199 return binding.in_nghttp3_callback_scope; 200} 201 202void 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