xref: /third_party/node/src/quic/bindingdata.cc (revision 1cb0ef41)
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