#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC #include "bindingdata.h" #include #include #include #include #include #include #include #include #include #include #include namespace node { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Local; using v8::Object; using v8::String; using v8::Value; namespace quic { BindingData& BindingData::Get(Environment* env) { return *Realm::GetBindingData(env->context()); } BindingData::operator ngtcp2_mem() { return MakeAllocator(); } BindingData::operator nghttp3_mem() { ngtcp2_mem allocator = *this; nghttp3_mem http3_allocator = { allocator.user_data, allocator.malloc, allocator.free, allocator.calloc, allocator.realloc, }; return http3_allocator; } void BindingData::CheckAllocatedSize(size_t previous_size) const { CHECK_GE(current_ngtcp2_memory_, previous_size); } void BindingData::IncreaseAllocatedSize(size_t size) { current_ngtcp2_memory_ += size; } void BindingData::DecreaseAllocatedSize(size_t size) { current_ngtcp2_memory_ -= size; } void BindingData::Initialize(Environment* env, Local target) { SetMethod(env->context(), target, "setCallbacks", SetCallbacks); SetMethod(env->context(), target, "flushPacketFreelist", FlushPacketFreelist); Realm::GetCurrent(env->context()) ->AddBindingData(env->context(), target); } void BindingData::RegisterExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(SetCallbacks); registry->Register(FlushPacketFreelist); } BindingData::BindingData(Realm* realm, Local object) : BaseObject(realm, object) { MakeWeak(); } void BindingData::MemoryInfo(MemoryTracker* tracker) const { #define V(name, _) tracker->TrackField(#name, name##_callback()); QUIC_JS_CALLBACKS(V) #undef V #define V(name, _) tracker->TrackField(#name, name##_string()); QUIC_STRINGS(V) #undef V } #define V(name) \ void BindingData::set_##name##_constructor_template( \ Local tmpl) { \ name##_constructor_template_.Reset(env()->isolate(), tmpl); \ } \ Local BindingData::name##_constructor_template() const { \ return PersistentToLocal::Default(env()->isolate(), \ name##_constructor_template_); \ } QUIC_CONSTRUCTORS(V) #undef V #define V(name, _) \ void BindingData::set_##name##_callback(Local fn) { \ name##_callback_.Reset(env()->isolate(), fn); \ } \ Local BindingData::name##_callback() const { \ return PersistentToLocal::Default(env()->isolate(), name##_callback_); \ } QUIC_JS_CALLBACKS(V) #undef V #define V(name, value) \ Local BindingData::name##_string() const { \ if (name##_string_.IsEmpty()) \ name##_string_.Set(env()->isolate(), \ OneByteString(env()->isolate(), value)); \ return name##_string_.Get(env()->isolate()); \ } QUIC_STRINGS(V) #undef V #define V(name, value) \ Local BindingData::on_##name##_string() const { \ if (on_##name##_string_.IsEmpty()) \ on_##name##_string_.Set( \ env()->isolate(), \ FIXED_ONE_BYTE_STRING(env()->isolate(), "on" #value)); \ return on_##name##_string_.Get(env()->isolate()); \ } QUIC_JS_CALLBACKS(V) #undef V void BindingData::SetCallbacks(const FunctionCallbackInfo& args) { auto env = Environment::GetCurrent(args); auto isolate = env->isolate(); auto& state = BindingData::Get(env); CHECK(args[0]->IsObject()); Local obj = args[0].As(); #define V(name, key) \ do { \ Local val; \ if (!obj->Get(env->context(), state.on_##name##_string()).ToLocal(&val) || \ !val->IsFunction()) { \ return THROW_ERR_MISSING_ARGS(isolate, "Missing Callback: on" #key); \ } \ state.set_##name##_callback(val.As()); \ } while (0); QUIC_JS_CALLBACKS(V) #undef V } void BindingData::FlushPacketFreelist(const FunctionCallbackInfo& args) { auto env = Environment::GetCurrent(args); auto& state = BindingData::Get(env); state.packet_freelist.clear(); } NgTcp2CallbackScope::NgTcp2CallbackScope(Environment* env) : env(env) { auto& binding = BindingData::Get(env); CHECK(!binding.in_ngtcp2_callback_scope); binding.in_ngtcp2_callback_scope = true; } NgTcp2CallbackScope::~NgTcp2CallbackScope() { auto& binding = BindingData::Get(env); binding.in_ngtcp2_callback_scope = false; } bool NgTcp2CallbackScope::in_ngtcp2_callback(Environment* env) { auto& binding = BindingData::Get(env); return binding.in_ngtcp2_callback_scope; } NgHttp3CallbackScope::NgHttp3CallbackScope(Environment* env) : env(env) { auto& binding = BindingData::Get(env); CHECK(!binding.in_nghttp3_callback_scope); binding.in_nghttp3_callback_scope = true; } NgHttp3CallbackScope::~NgHttp3CallbackScope() { auto& binding = BindingData::Get(env); binding.in_nghttp3_callback_scope = false; } bool NgHttp3CallbackScope::in_nghttp3_callback(Environment* env) { auto& binding = BindingData::Get(env); return binding.in_nghttp3_callback_scope; } void IllegalConstructor(const FunctionCallbackInfo& args) { THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args)); } } // namespace quic } // namespace node #endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC