Skip to content

Commit

Permalink
quic: add more QUIC impl
Browse files Browse the repository at this point in the history
* add BindingData
* add LogStream
* add TransportParams

PR-URL: #47348
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
  • Loading branch information
jasnell authored and MoLow committed Jul 6, 2023
1 parent d0bda90 commit 2484083
Show file tree
Hide file tree
Showing 10 changed files with 1,082 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace node {
V(PROCESSWRAP) \
V(PROMISE) \
V(QUERYWRAP) \
V(QUIC_LOGSTREAM) \
V(SHUTDOWNWRAP) \
V(SIGNALWRAP) \
V(STATWATCHER) \
Expand Down
73 changes: 73 additions & 0 deletions src/base_object_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#ifndef SRC_BASE_OBJECT_TYPES_H_
#define SRC_BASE_OBJECT_TYPES_H_

#include <cinttypes>

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

namespace node {
// List of internalBinding() data wrappers. The first argument should match
// what the class passes to SET_BINDING_ID(), the second argument should match
// the C++ class name.
#define SERIALIZABLE_BINDING_TYPES(V) \
V(encoding_binding_data, encoding_binding::BindingData) \
V(fs_binding_data, fs::BindingData) \
V(v8_binding_data, v8_utils::BindingData) \
V(blob_binding_data, BlobBindingData) \
V(process_binding_data, process::BindingData) \
V(timers_binding_data, timers::BindingData) \
V(url_binding_data, url::BindingData)

#define UNSERIALIZABLE_BINDING_TYPES(V) \
V(http2_binding_data, http2::BindingData) \
V(http_parser_binding_data, http_parser::BindingData) \
V(quic_binding_data, quic::BindingData)

// List of (non-binding) BaseObjects that are serializable in the snapshot.
// The first argument should match what the type passes to
// SET_OBJECT_ID(), the second argument should match the C++ class
// name.
#define SERIALIZABLE_NON_BINDING_TYPES(V) \
V(util_weak_reference, util::WeakReference)

// Helper list of all binding data wrapper types.
#define BINDING_TYPES(V) \
SERIALIZABLE_BINDING_TYPES(V) \
UNSERIALIZABLE_BINDING_TYPES(V)

// Helper list of all BaseObjects that implement snapshot support.
#define SERIALIZABLE_OBJECT_TYPES(V) \
SERIALIZABLE_BINDING_TYPES(V) \
SERIALIZABLE_NON_BINDING_TYPES(V)

#define V(TypeId, NativeType) k_##TypeId,
enum class BindingDataType : uint8_t { BINDING_TYPES(V) kBindingDataTypeCount };
// Make sure that we put the bindings first so that we can also use the enums
// for the bindings as index to the binding data store.
enum class EmbedderObjectType : uint8_t {
BINDING_TYPES(V) SERIALIZABLE_NON_BINDING_TYPES(V)
// We do not need to know about all the unserializable non-binding types for
// now so we do not list them.
kEmbedderObjectTypeCount
};
#undef V

// For now, BaseObjects only need to call this when they implement snapshot
// support.
#define SET_OBJECT_ID(TypeId) \
static constexpr EmbedderObjectType type_int = EmbedderObjectType::k_##TypeId;

// Binding data should call this so that they can be looked up from the binding
// data store.
#define SET_BINDING_ID(TypeId) \
static constexpr BindingDataType binding_type_int = \
BindingDataType::k_##TypeId; \
SET_OBJECT_ID(TypeId) \
static_assert(static_cast<uint8_t>(type_int) == \
static_cast<uint8_t>(binding_type_int));

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_BASE_OBJECT_TYPES_H_
165 changes: 165 additions & 0 deletions src/quic/bindingdata.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
#include "bindingdata.h"
#include <base_object-inl.h>
#include <env-inl.h>
#include <memory_tracker-inl.h>
#include <nghttp3/nghttp3.h>
#include <ngtcp2/ngtcp2.h>
#include <node.h>
#include <node_errors.h>
#include <node_external_reference.h>
#include <node_mem-inl.h>
#include <node_realm-inl.h>
#include <v8.h>

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<BindingData>(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<Object> target) {
SetMethod(env->context(), target, "setCallbacks", SetCallbacks);
Realm::GetCurrent(env->context())
->AddBindingData<BindingData>(env->context(), target);
}

void BindingData::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(SetCallbacks);
}

BindingData::BindingData(Realm* realm, Local<Object> 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<FunctionTemplate> tmpl) { \
name##_constructor_template_.Reset(env()->isolate(), tmpl); \
} \
Local<FunctionTemplate> 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<Function> fn) { \
name##_callback_.Reset(env()->isolate(), fn); \
} \
Local<Function> BindingData::name##_callback() const { \
return PersistentToLocal::Default(env()->isolate(), name##_callback_); \
}

QUIC_JS_CALLBACKS(V)

#undef V

#define V(name, value) \
Local<String> 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<String> 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<Value>& args) {
auto env = Environment::GetCurrent(args);
auto isolate = env->isolate();
BindingData& state = BindingData::Get(env);
CHECK(args[0]->IsObject());
Local<Object> obj = args[0].As<Object>();

#define V(name, key) \
do { \
Local<Value> 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<Function>()); \
} while (0);

QUIC_JS_CALLBACKS(V)

#undef V
}

} // namespace quic
} // namespace node

#endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
Loading

0 comments on commit 2484083

Please sign in to comment.