Files
node/src/node_sockaddr.cc
Joyee Cheung 5c86f223ae src: use the internal field to determine if an object is a BaseObject
Instead of storing the function template of BaseObject for checking
if an object is BaseObject by calling HasInstance, simply checks
the first internal field of the object, which is always set in the
BaseObject constructor. This is simpler and faster
(there is now no need to iterate over the inheritance for the check).

PR-URL: https://github.com/nodejs/node/pull/47217
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
2023-04-06 00:24:48 +00:00

889 lines
26 KiB
C++

#include "node_sockaddr-inl.h" // NOLINT(build/include)
#include "env-inl.h"
#include "base64-inl.h"
#include "base_object-inl.h"
#include "memory_tracker-inl.h"
#include "node_errors.h"
#include "uv.h"
#include <memory>
#include <string>
#include <vector>
namespace node {
using v8::Array;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Int32;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::Uint32;
using v8::Value;
namespace {
template <typename T, typename F>
SocketAddress FromUVHandle(F fn, const T& handle) {
SocketAddress addr;
int len = sizeof(sockaddr_storage);
if (fn(&handle, addr.storage(), &len) == 0)
CHECK_EQ(static_cast<size_t>(len), addr.length());
else
addr.storage()->sa_family = 0;
return addr;
}
} // namespace
bool SocketAddress::ToSockAddr(
int32_t family,
const char* host,
uint32_t port,
sockaddr_storage* addr) {
switch (family) {
case AF_INET:
return uv_ip4_addr(
host,
port,
reinterpret_cast<sockaddr_in*>(addr)) == 0;
case AF_INET6:
return uv_ip6_addr(
host,
port,
reinterpret_cast<sockaddr_in6*>(addr)) == 0;
default:
UNREACHABLE();
}
}
bool SocketAddress::New(
const char* host,
uint32_t port,
SocketAddress* addr) {
return New(AF_INET, host, port, addr) || New(AF_INET6, host, port, addr);
}
bool SocketAddress::New(
int32_t family,
const char* host,
uint32_t port,
SocketAddress* addr) {
return ToSockAddr(family, host, port,
reinterpret_cast<sockaddr_storage*>(addr->storage()));
}
size_t SocketAddress::Hash::operator()(const SocketAddress& addr) const {
size_t hash = 0;
switch (addr.family()) {
case AF_INET: {
const sockaddr_in* ipv4 =
reinterpret_cast<const sockaddr_in*>(addr.raw());
hash_combine(&hash, ipv4->sin_port, ipv4->sin_addr.s_addr);
break;
}
case AF_INET6: {
const sockaddr_in6* ipv6 =
reinterpret_cast<const sockaddr_in6*>(addr.raw());
const uint64_t* a =
reinterpret_cast<const uint64_t*>(&ipv6->sin6_addr);
hash_combine(&hash, ipv6->sin6_port, a[0], a[1]);
break;
}
default:
UNREACHABLE();
}
return hash;
}
SocketAddress SocketAddress::FromSockName(const uv_tcp_t& handle) {
return FromUVHandle(uv_tcp_getsockname, handle);
}
SocketAddress SocketAddress::FromSockName(const uv_udp_t& handle) {
return FromUVHandle(uv_udp_getsockname, handle);
}
SocketAddress SocketAddress::FromPeerName(const uv_tcp_t& handle) {
return FromUVHandle(uv_tcp_getpeername, handle);
}
SocketAddress SocketAddress::FromPeerName(const uv_udp_t& handle) {
return FromUVHandle(uv_udp_getpeername, handle);
}
namespace {
constexpr uint8_t mask[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
bool is_match_ipv4(
const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in* one_in =
reinterpret_cast<const sockaddr_in*>(one.data());
const sockaddr_in* two_in =
reinterpret_cast<const sockaddr_in*>(two.data());
return memcmp(&one_in->sin_addr, &two_in->sin_addr, sizeof(uint32_t)) == 0;
}
bool is_match_ipv6(
const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in6* one_in =
reinterpret_cast<const sockaddr_in6*>(one.data());
const sockaddr_in6* two_in =
reinterpret_cast<const sockaddr_in6*>(two.data());
return memcmp(&one_in->sin6_addr, &two_in->sin6_addr, 16) == 0;
}
bool is_match_ipv4_ipv6(
const SocketAddress& ipv4,
const SocketAddress& ipv6) {
const sockaddr_in* check_ipv4 =
reinterpret_cast<const sockaddr_in*>(ipv4.data());
const sockaddr_in6* check_ipv6 =
reinterpret_cast<const sockaddr_in6*>(ipv6.data());
const uint8_t* ptr =
reinterpret_cast<const uint8_t*>(&check_ipv6->sin6_addr);
return memcmp(ptr, mask, sizeof(mask)) == 0 &&
memcmp(ptr + sizeof(mask),
&check_ipv4->sin_addr,
sizeof(uint32_t)) == 0;
}
SocketAddress::CompareResult compare_ipv4(
const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in* one_in =
reinterpret_cast<const sockaddr_in*>(one.data());
const sockaddr_in* two_in =
reinterpret_cast<const sockaddr_in*>(two.data());
const uint32_t s_addr_one = ntohl(one_in->sin_addr.s_addr);
const uint32_t s_addr_two = ntohl(two_in->sin_addr.s_addr);
if (s_addr_one < s_addr_two)
return SocketAddress::CompareResult::LESS_THAN;
else if (s_addr_one == s_addr_two)
return SocketAddress::CompareResult::SAME;
else
return SocketAddress::CompareResult::GREATER_THAN;
}
SocketAddress::CompareResult compare_ipv6(
const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in6* one_in =
reinterpret_cast<const sockaddr_in6*>(one.data());
const sockaddr_in6* two_in =
reinterpret_cast<const sockaddr_in6*>(two.data());
int ret = memcmp(&one_in->sin6_addr, &two_in->sin6_addr, 16);
if (ret < 0)
return SocketAddress::CompareResult::LESS_THAN;
else if (ret > 0)
return SocketAddress::CompareResult::GREATER_THAN;
return SocketAddress::CompareResult::SAME;
}
SocketAddress::CompareResult compare_ipv4_ipv6(
const SocketAddress& ipv4,
const SocketAddress& ipv6) {
const sockaddr_in* ipv4_in =
reinterpret_cast<const sockaddr_in*>(ipv4.data());
const sockaddr_in6 * ipv6_in =
reinterpret_cast<const sockaddr_in6*>(ipv6.data());
const uint8_t* ptr =
reinterpret_cast<const uint8_t*>(&ipv6_in->sin6_addr);
if (memcmp(ptr, mask, sizeof(mask)) != 0)
return SocketAddress::CompareResult::NOT_COMPARABLE;
int ret = memcmp(
&ipv4_in->sin_addr,
ptr + sizeof(mask),
sizeof(uint32_t));
if (ret < 0)
return SocketAddress::CompareResult::LESS_THAN;
else if (ret > 0)
return SocketAddress::CompareResult::GREATER_THAN;
return SocketAddress::CompareResult::SAME;
}
bool in_network_ipv4(
const SocketAddress& ip,
const SocketAddress& net,
int prefix) {
uint32_t mask = ((1ull << prefix) - 1) << (32 - prefix);
const sockaddr_in* ip_in =
reinterpret_cast<const sockaddr_in*>(ip.data());
const sockaddr_in* net_in =
reinterpret_cast<const sockaddr_in*>(net.data());
return (htonl(ip_in->sin_addr.s_addr) & mask) ==
(htonl(net_in->sin_addr.s_addr) & mask);
}
bool in_network_ipv6(
const SocketAddress& ip,
const SocketAddress& net,
int prefix) {
// Special case, if prefix == 128, then just do a
// straight comparison.
if (prefix == 128)
return compare_ipv6(ip, net) == SocketAddress::CompareResult::SAME;
uint8_t r = prefix % 8;
int len = (prefix - r) / 8;
uint8_t mask = ((1 << r) - 1) << (8 - r);
const sockaddr_in6* ip_in =
reinterpret_cast<const sockaddr_in6*>(ip.data());
const sockaddr_in6* net_in =
reinterpret_cast<const sockaddr_in6*>(net.data());
if (memcmp(&ip_in->sin6_addr, &net_in->sin6_addr, len) != 0)
return false;
const uint8_t* p1 = reinterpret_cast<const uint8_t*>(
ip_in->sin6_addr.s6_addr);
const uint8_t* p2 = reinterpret_cast<const uint8_t*>(
net_in->sin6_addr.s6_addr);
return (p1[len] & mask) == (p2[len] & mask);
}
bool in_network_ipv4_ipv6(
const SocketAddress& ip,
const SocketAddress& net,
int prefix) {
if (prefix == 128)
return compare_ipv4_ipv6(ip, net) == SocketAddress::CompareResult::SAME;
uint8_t r = prefix % 8;
int len = (prefix - r) / 8;
uint8_t mask = ((1 << r) - 1) << (8 - r);
const sockaddr_in* ip_in =
reinterpret_cast<const sockaddr_in*>(ip.data());
const sockaddr_in6* net_in =
reinterpret_cast<const sockaddr_in6*>(net.data());
uint8_t ip_mask[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0};
uint8_t* ptr = ip_mask;
memcpy(ptr + 12, &ip_in->sin_addr, 4);
if (memcmp(ptr, &net_in->sin6_addr, len) != 0)
return false;
ptr += len;
const uint8_t* p2 = reinterpret_cast<const uint8_t*>(
net_in->sin6_addr.s6_addr);
return (ptr[0] & mask) == (p2[len] & mask);
}
bool in_network_ipv6_ipv4(
const SocketAddress& ip,
const SocketAddress& net,
int prefix) {
if (prefix == 32)
return compare_ipv4_ipv6(net, ip) == SocketAddress::CompareResult::SAME;
uint32_t m = ((1ull << prefix) - 1) << (32 - prefix);
const sockaddr_in6* ip_in =
reinterpret_cast<const sockaddr_in6*>(ip.data());
const sockaddr_in* net_in =
reinterpret_cast<const sockaddr_in*>(net.data());
const uint8_t* ptr =
reinterpret_cast<const uint8_t*>(&ip_in->sin6_addr);
if (memcmp(ptr, mask, sizeof(mask)) != 0)
return false;
ptr += sizeof(mask);
uint32_t check = ReadUint32BE(ptr);
return (check & m) == (htonl(net_in->sin_addr.s_addr) & m);
}
} // namespace
// TODO(@jasnell): The implementations of is_match, compare, and
// is_in_network have not been performance optimized and could
// likely benefit from work on more performant approaches.
bool SocketAddress::is_match(const SocketAddress& other) const {
switch (family()) {
case AF_INET:
switch (other.family()) {
case AF_INET: return is_match_ipv4(*this, other);
case AF_INET6: return is_match_ipv4_ipv6(*this, other);
}
break;
case AF_INET6:
switch (other.family()) {
case AF_INET: return is_match_ipv4_ipv6(other, *this);
case AF_INET6: return is_match_ipv6(*this, other);
}
break;
}
return false;
}
SocketAddress::CompareResult SocketAddress::compare(
const SocketAddress& other) const {
switch (family()) {
case AF_INET:
switch (other.family()) {
case AF_INET: return compare_ipv4(*this, other);
case AF_INET6: return compare_ipv4_ipv6(*this, other);
}
break;
case AF_INET6:
switch (other.family()) {
case AF_INET: {
CompareResult c = compare_ipv4_ipv6(other, *this);
switch (c) {
case SocketAddress::CompareResult::NOT_COMPARABLE:
// Fall through
case SocketAddress::CompareResult::SAME:
return c;
case SocketAddress::CompareResult::GREATER_THAN:
return SocketAddress::CompareResult::LESS_THAN;
case SocketAddress::CompareResult::LESS_THAN:
return SocketAddress::CompareResult::GREATER_THAN;
}
break;
}
case AF_INET6: return compare_ipv6(*this, other);
}
break;
}
return SocketAddress::CompareResult::NOT_COMPARABLE;
}
bool SocketAddress::is_in_network(
const SocketAddress& other,
int prefix) const {
switch (family()) {
case AF_INET:
switch (other.family()) {
case AF_INET: return in_network_ipv4(*this, other, prefix);
case AF_INET6: return in_network_ipv4_ipv6(*this, other, prefix);
}
break;
case AF_INET6:
switch (other.family()) {
case AF_INET: return in_network_ipv6_ipv4(*this, other, prefix);
case AF_INET6: return in_network_ipv6(*this, other, prefix);
}
break;
}
return false;
}
SocketAddressBlockList::SocketAddressBlockList(
std::shared_ptr<SocketAddressBlockList> parent)
: parent_(parent) {}
void SocketAddressBlockList::AddSocketAddress(
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressRule>(address);
rules_.emplace_front(std::move(rule));
address_rules_[*address.get()] = rules_.begin();
}
void SocketAddressBlockList::RemoveSocketAddress(
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
auto it = address_rules_.find(*address.get());
if (it != std::end(address_rules_)) {
rules_.erase(it->second);
address_rules_.erase(it);
}
}
void SocketAddressBlockList::AddSocketAddressRange(
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressRangeRule>(start, end);
rules_.emplace_front(std::move(rule));
}
void SocketAddressBlockList::AddSocketAddressMask(
const std::shared_ptr<SocketAddress>& network,
int prefix) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressMaskRule>(network, prefix);
rules_.emplace_front(std::move(rule));
}
bool SocketAddressBlockList::Apply(
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
for (const auto& rule : rules_) {
if (rule->Apply(address))
return true;
}
return parent_ ? parent_->Apply(address) : false;
}
SocketAddressBlockList::SocketAddressRule::SocketAddressRule(
const std::shared_ptr<SocketAddress>& address_)
: address(address_) {}
SocketAddressBlockList::SocketAddressRangeRule::SocketAddressRangeRule(
const std::shared_ptr<SocketAddress>& start_,
const std::shared_ptr<SocketAddress>& end_)
: start(start_),
end(end_) {}
SocketAddressBlockList::SocketAddressMaskRule::SocketAddressMaskRule(
const std::shared_ptr<SocketAddress>& network_,
int prefix_)
: network(network_),
prefix(prefix_) {}
bool SocketAddressBlockList::SocketAddressRule::Apply(
const std::shared_ptr<SocketAddress>& address) {
return this->address->is_match(*address.get());
}
std::string SocketAddressBlockList::SocketAddressRule::ToString() {
std::string ret = "Address: ";
ret += address->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += address->address();
return ret;
}
bool SocketAddressBlockList::SocketAddressRangeRule::Apply(
const std::shared_ptr<SocketAddress>& address) {
return *address.get() >= *start.get() &&
*address.get() <= *end.get();
}
std::string SocketAddressBlockList::SocketAddressRangeRule::ToString() {
std::string ret = "Range: ";
ret += start->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += start->address();
ret += "-";
ret += end->address();
return ret;
}
bool SocketAddressBlockList::SocketAddressMaskRule::Apply(
const std::shared_ptr<SocketAddress>& address) {
return address->is_in_network(*network.get(), prefix);
}
std::string SocketAddressBlockList::SocketAddressMaskRule::ToString() {
std::string ret = "Subnet: ";
ret += network->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += network->address();
ret += "/" + std::to_string(prefix);
return ret;
}
MaybeLocal<Array> SocketAddressBlockList::ListRules(Environment* env) {
Mutex::ScopedLock lock(mutex_);
std::vector<Local<Value>> rules;
if (!ListRules(env, &rules))
return MaybeLocal<Array>();
return Array::New(env->isolate(), rules.data(), rules.size());
}
bool SocketAddressBlockList::ListRules(
Environment* env,
std::vector<v8::Local<v8::Value>>* rules) {
if (parent_ && !parent_->ListRules(env, rules))
return false;
for (const auto& rule : rules_) {
Local<Value> str;
if (!rule->ToV8String(env).ToLocal(&str))
return false;
rules->push_back(str);
}
return true;
}
void SocketAddressBlockList::MemoryInfo(node::MemoryTracker* tracker) const {
tracker->TrackField("rules", rules_);
}
void SocketAddressBlockList::SocketAddressRule::MemoryInfo(
node::MemoryTracker* tracker) const {
tracker->TrackField("address", address);
}
void SocketAddressBlockList::SocketAddressRangeRule::MemoryInfo(
node::MemoryTracker* tracker) const {
tracker->TrackField("start", start);
tracker->TrackField("end", end);
}
void SocketAddressBlockList::SocketAddressMaskRule::MemoryInfo(
node::MemoryTracker* tracker) const {
tracker->TrackField("network", network);
}
SocketAddressBlockListWrap::SocketAddressBlockListWrap(
Environment* env,
Local<Object> wrap,
std::shared_ptr<SocketAddressBlockList> blocklist)
: BaseObject(env, wrap),
blocklist_(std::move(blocklist)) {
MakeWeak();
}
BaseObjectPtr<SocketAddressBlockListWrap> SocketAddressBlockListWrap::New(
Environment* env) {
Local<Object> obj;
if (!env->blocklist_constructor_template()
->InstanceTemplate()
->NewInstance(env->context()).ToLocal(&obj)) {
return BaseObjectPtr<SocketAddressBlockListWrap>();
}
BaseObjectPtr<SocketAddressBlockListWrap> wrap =
MakeBaseObject<SocketAddressBlockListWrap>(env, obj);
CHECK(wrap);
return wrap;
}
BaseObjectPtr<SocketAddressBlockListWrap> SocketAddressBlockListWrap::New(
Environment* env,
std::shared_ptr<SocketAddressBlockList> blocklist) {
Local<Object> obj;
if (!env->blocklist_constructor_template()
->InstanceTemplate()
->NewInstance(env->context()).ToLocal(&obj)) {
return BaseObjectPtr<SocketAddressBlockListWrap>();
}
BaseObjectPtr<SocketAddressBlockListWrap> wrap =
MakeBaseObject<SocketAddressBlockListWrap>(
env,
obj,
std::move(blocklist));
CHECK(wrap);
return wrap;
}
void SocketAddressBlockListWrap::New(
const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
Environment* env = Environment::GetCurrent(args);
new SocketAddressBlockListWrap(env, args.This());
}
void SocketAddressBlockListWrap::AddAddress(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);
wrap->blocklist_->AddSocketAddress(addr->address());
args.GetReturnValue().Set(true);
}
void SocketAddressBlockListWrap::AddRange(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
CHECK(SocketAddressBase::HasInstance(env, args[1]));
SocketAddressBase* start_addr;
SocketAddressBase* end_addr;
ASSIGN_OR_RETURN_UNWRAP(&start_addr, args[0]);
ASSIGN_OR_RETURN_UNWRAP(&end_addr, args[1]);
// Starting address must come before the end address
if (*start_addr->address().get() > *end_addr->address().get())
return args.GetReturnValue().Set(false);
wrap->blocklist_->AddSocketAddressRange(
start_addr->address(),
end_addr->address());
args.GetReturnValue().Set(true);
}
void SocketAddressBlockListWrap::AddSubnet(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
CHECK(args[1]->IsInt32());
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);
int32_t prefix;
if (!args[1]->Int32Value(env->context()).To(&prefix)) {
return;
}
CHECK_IMPLIES(addr->address()->family() == AF_INET, prefix <= 32);
CHECK_IMPLIES(addr->address()->family() == AF_INET6, prefix <= 128);
CHECK_GE(prefix, 0);
wrap->blocklist_->AddSocketAddressMask(addr->address(), prefix);
args.GetReturnValue().Set(true);
}
void SocketAddressBlockListWrap::Check(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);
args.GetReturnValue().Set(wrap->blocklist_->Apply(addr->address()));
}
void SocketAddressBlockListWrap::GetRules(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
Local<Array> rules;
if (wrap->blocklist_->ListRules(env).ToLocal(&rules))
args.GetReturnValue().Set(rules);
}
void SocketAddressBlockListWrap::MemoryInfo(MemoryTracker* tracker) const {
blocklist_->MemoryInfo(tracker);
}
std::unique_ptr<worker::TransferData>
SocketAddressBlockListWrap::CloneForMessaging() const {
return std::make_unique<TransferData>(this);
}
bool SocketAddressBlockListWrap::HasInstance(
Environment* env,
Local<Value> value) {
return GetConstructorTemplate(env)->HasInstance(value);
}
Local<FunctionTemplate> SocketAddressBlockListWrap::GetConstructorTemplate(
Environment* env) {
Local<FunctionTemplate> tmpl = env->blocklist_constructor_template();
if (tmpl.IsEmpty()) {
Isolate* isolate = env->isolate();
tmpl = NewFunctionTemplate(isolate, SocketAddressBlockListWrap::New);
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "BlockList"));
tmpl->InstanceTemplate()->SetInternalFieldCount(kInternalFieldCount);
SetProtoMethod(isolate, tmpl, "addAddress", AddAddress);
SetProtoMethod(isolate, tmpl, "addRange", AddRange);
SetProtoMethod(isolate, tmpl, "addSubnet", AddSubnet);
SetProtoMethod(isolate, tmpl, "check", Check);
SetProtoMethod(isolate, tmpl, "getRules", GetRules);
env->set_blocklist_constructor_template(tmpl);
}
return tmpl;
}
void SocketAddressBlockListWrap::Initialize(
Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
SetConstructorFunction(context,
target,
"BlockList",
GetConstructorTemplate(env),
SetConstructorFunctionFlag::NONE);
SocketAddressBase::Initialize(env, target);
NODE_DEFINE_CONSTANT(target, AF_INET);
NODE_DEFINE_CONSTANT(target, AF_INET6);
}
BaseObjectPtr<BaseObject> SocketAddressBlockListWrap::TransferData::Deserialize(
Environment* env,
Local<Context> context,
std::unique_ptr<worker::TransferData> self) {
return New(env, std::move(blocklist_));
}
void SocketAddressBlockListWrap::TransferData::MemoryInfo(
MemoryTracker* tracker) const {
blocklist_->MemoryInfo(tracker);
}
bool SocketAddressBase::HasInstance(Environment* env, Local<Value> value) {
return GetConstructorTemplate(env)->HasInstance(value);
}
Local<FunctionTemplate> SocketAddressBase::GetConstructorTemplate(
Environment* env) {
Local<FunctionTemplate> tmpl = env->socketaddress_constructor_template();
if (tmpl.IsEmpty()) {
Isolate* isolate = env->isolate();
tmpl = NewFunctionTemplate(isolate, New);
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SocketAddress"));
tmpl->InstanceTemplate()->SetInternalFieldCount(
SocketAddressBase::kInternalFieldCount);
SetProtoMethod(isolate, tmpl, "detail", Detail);
SetProtoMethod(isolate, tmpl, "legacyDetail", LegacyDetail);
SetProtoMethodNoSideEffect(isolate, tmpl, "flowlabel", GetFlowLabel);
env->set_socketaddress_constructor_template(tmpl);
}
return tmpl;
}
void SocketAddressBase::Initialize(Environment* env, Local<Object> target) {
SetConstructorFunction(env->context(),
target,
"SocketAddress",
GetConstructorTemplate(env),
SetConstructorFunctionFlag::NONE);
}
BaseObjectPtr<SocketAddressBase> SocketAddressBase::Create(
Environment* env,
std::shared_ptr<SocketAddress> address) {
Local<Object> obj;
if (!GetConstructorTemplate(env)
->InstanceTemplate()
->NewInstance(env->context()).ToLocal(&obj)) {
return BaseObjectPtr<SocketAddressBase>();
}
return MakeBaseObject<SocketAddressBase>(env, obj, std::move(address));
}
void SocketAddressBase::New(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args.IsConstructCall());
CHECK(args[0]->IsString()); // address
CHECK(args[1]->IsInt32()); // port
CHECK(args[2]->IsInt32()); // family
CHECK(args[3]->IsUint32()); // flow label
Utf8Value address(env->isolate(), args[0]);
int32_t port = args[1].As<Int32>()->Value();
int32_t family = args[2].As<Int32>()->Value();
uint32_t flow_label = args[3].As<Uint32>()->Value();
std::shared_ptr<SocketAddress> addr = std::make_shared<SocketAddress>();
if (!SocketAddress::New(family, *address, port, addr.get()))
return THROW_ERR_INVALID_ADDRESS(env);
addr->set_flow_label(flow_label);
new SocketAddressBase(env, args.This(), std::move(addr));
}
void SocketAddressBase::Detail(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsObject());
Local<Object> detail = args[0].As<Object>();
SocketAddressBase* base;
ASSIGN_OR_RETURN_UNWRAP(&base, args.Holder());
Local<Value> address;
if (!ToV8Value(env->context(), base->address_->address()).ToLocal(&address))
return;
if (detail->Set(env->context(), env->address_string(), address).IsJust() &&
detail->Set(
env->context(),
env->port_string(),
Int32::New(env->isolate(), base->address_->port())).IsJust() &&
detail->Set(
env->context(),
env->family_string(),
Int32::New(env->isolate(), base->address_->family())).IsJust() &&
detail->Set(
env->context(),
env->flowlabel_string(),
Uint32::New(env->isolate(), base->address_->flow_label()))
.IsJust()) {
args.GetReturnValue().Set(detail);
}
}
void SocketAddressBase::GetFlowLabel(const FunctionCallbackInfo<Value>& args) {
SocketAddressBase* base;
ASSIGN_OR_RETURN_UNWRAP(&base, args.Holder());
args.GetReturnValue().Set(base->address_->flow_label());
}
void SocketAddressBase::LegacyDetail(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBase* base;
ASSIGN_OR_RETURN_UNWRAP(&base, args.Holder());
Local<Object> address;
if (!base->address_->ToJS(env).ToLocal(&address)) return;
args.GetReturnValue().Set(address);
}
SocketAddressBase::SocketAddressBase(
Environment* env,
Local<Object> wrap,
std::shared_ptr<SocketAddress> address)
: BaseObject(env, wrap),
address_(std::move(address)) {
MakeWeak();
}
void SocketAddressBase::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("address", address_);
}
std::unique_ptr<worker::TransferData>
SocketAddressBase::CloneForMessaging() const {
return std::make_unique<TransferData>(this);
}
void SocketAddressBase::TransferData::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("address", address_);
}
BaseObjectPtr<BaseObject> SocketAddressBase::TransferData::Deserialize(
Environment* env,
v8::Local<v8::Context> context,
std::unique_ptr<worker::TransferData> self) {
return SocketAddressBase::Create(env, std::move(address_));
}
} // namespace node
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
block_list, node::SocketAddressBlockListWrap::Initialize)