#ifndef SRC_NODE_SOCKADDR_H_
#define SRC_NODE_SOCKADDR_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "env.h"
#include "memory_tracker.h"
#include "base_object.h"
#include "node.h"
#include "node_worker.h"
#include "uv.h"
#include "v8.h"
#include <memory>
#include <string>
#include <list>
#include <unordered_map>
namespace node {
class Environment;
class SocketAddress : public MemoryRetainer {
public:
enum class CompareResult {
NOT_COMPARABLE = -2,
LESS_THAN,
SAME,
GREATER_THAN
};
struct Hash {
size_t operator()(const SocketAddress& addr) const;
};
inline bool operator==(const SocketAddress& other) const;
inline bool operator!=(const SocketAddress& other) const;
inline bool operator<(const SocketAddress& other) const;
inline bool operator>(const SocketAddress& other) const;
inline bool operator<=(const SocketAddress& other) const;
inline bool operator>=(const SocketAddress& other) const;
inline static bool is_numeric_host(const char* hostname);
inline static bool is_numeric_host(const char* hostname, int family);
// Returns true if converting {family, host, port} to *addr succeeded.
static bool ToSockAddr(
int32_t family,
const char* host,
uint32_t port,
sockaddr_storage* addr);
// Returns true if converting {family, host, port} to *addr succeeded.
static bool New(
int32_t family,
const char* host,
uint32_t port,
SocketAddress* addr);
static bool New(
const char* host,
uint32_t port,
SocketAddress* addr);
// Returns the port for an IPv4 or IPv6 address.
inline static int GetPort(const sockaddr* addr);
inline static int GetPort(const sockaddr_storage* addr);
// Returns the numeric host as a string for an IPv4 or IPv6 address.
inline static std::string GetAddress(const sockaddr* addr);
inline static std::string GetAddress(const sockaddr_storage* addr);
// Returns the struct length for an IPv4, IPv6 or UNIX domain.
inline static size_t GetLength(const sockaddr* addr);
inline static size_t GetLength(const sockaddr_storage* addr);
SocketAddress() = default;
inline explicit SocketAddress(const sockaddr* addr);
inline SocketAddress(const SocketAddress& addr);
inline SocketAddress& operator=(const sockaddr* other);
inline SocketAddress& operator=(const SocketAddress& other);
inline const sockaddr& operator*() const;
inline const sockaddr* operator->() const;
inline const sockaddr* data() const;
inline const uint8_t* raw() const;
inline sockaddr* storage();
inline size_t length() const;
inline int family() const;
inline std::string address() const;
inline int port() const;
// Returns true if the given other SocketAddress is a match
// for this one. The addresses are a match if:
// 1. They are the same family and match identically
// 2. They are different family but match semantically (
// for instance, an IPv4 address in IPv6 notation)
bool is_match(const SocketAddress& other) const;
// Compares this SocketAddress to the given other SocketAddress.
CompareResult compare(const SocketAddress& other) const;
// Returns true if this SocketAddress is within the subnet
// identified by the given network address and CIDR prefix.
bool is_in_network(const SocketAddress& network, int prefix) const;
// If the SocketAddress is an IPv6 address, returns the
// current value of the IPv6 flow label, if set. Otherwise
// returns 0.
inline uint32_t flow_label() const;
// If the SocketAddress is an IPv6 address, sets the
// current value of the IPv6 flow label. If not an
// IPv6 address, set_flow_label is a non-op. It
// is important to note that the flow label,
// while represented as an uint32_t, the flow
// label is strictly limited to 20 bits, and
// this will assert if any value larger than
// 20-bits is specified.
inline void set_flow_label(uint32_t label = 0);
inline void Update(uint8_t* data, size_t len);
inline void Update(const sockaddr* data, size_t len);
static SocketAddress FromSockName(const uv_udp_t& handle);
static SocketAddress FromSockName(const uv_tcp_t& handle);
static SocketAddress FromPeerName(const uv_udp_t& handle);
static SocketAddress FromPeerName(const uv_tcp_t& handle);
inline v8::MaybeLocal<v8::Object> ToJS(
Environment* env,
v8::Local<v8::Object> obj = v8::Local<v8::Object>()) const;
inline std::string ToString() const;
SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(SocketAddress)
SET_SELF_SIZE(SocketAddress)
template <typename T>
using Map = std::unordered_map<SocketAddress, T, Hash>;
private:
sockaddr_storage address_;
};
class SocketAddressBase : public BaseObject {
public:
static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
static void Initialize(Environment* env, v8::Local<v8::Object> target);
static BaseObjectPtr<SocketAddressBase> Create(
Environment* env,
std::shared_ptr<SocketAddress> address);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Detail(const v8::FunctionCallbackInfo<v8::Value>& args);
static void LegacyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetFlowLabel(const v8::FunctionCallbackInfo<v8::Value>& args);
SocketAddressBase(
Environment* env,
v8::Local<v8::Object> wrap,
std::shared_ptr<SocketAddress> address);
inline const std::shared_ptr<SocketAddress>& address() const {
return address_;
}
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBase)
SET_SELF_SIZE(SocketAddressBase)
TransferMode GetTransferMode() const override {
return TransferMode::kCloneable;
}
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
class TransferData : public worker::TransferData {
public:
inline explicit TransferData(const SocketAddressBase* wrap)
: address_(wrap->address_) {}
inline explicit TransferData(std::shared_ptr<SocketAddress> address)
: address_(std::move(address)) {}
BaseObjectPtr<BaseObject> Deserialize(
Environment* env,
v8::Local<v8::Context> context,
std::unique_ptr<worker::TransferData> self) override;
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBase::TransferData)
SET_SELF_SIZE(TransferData)
private:
std::shared_ptr<SocketAddress> address_;
};
private:
std::shared_ptr<SocketAddress> address_;
};
template <typename T>
class SocketAddressLRU : public MemoryRetainer {
public:
using Type = typename T::Type;
inline explicit SocketAddressLRU(size_t max_size);
// If the item already exists, returns a reference to
// the existing item, adjusting items position in the
// LRU. If the item does not exist, emplaces the item
// and returns the new item.
Type* Upsert(const SocketAddress& address);
// Returns a reference to the item if it exists, or
// nullptr. The position in the LRU is not modified.
Type* Peek(const SocketAddress& address) const;
size_t size() const { return map_.size(); }
size_t max_size() const { return max_size_; }
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressLRU)
SET_SELF_SIZE(SocketAddressLRU)
private:
using Pair = std::pair<SocketAddress, Type>;
using Iterator = typename std::list<Pair>::iterator;
void CheckExpired();
std::list<Pair> list_;
SocketAddress::Map<Iterator> map_;
size_t max_size_;
};
// A BlockList is used to evaluate whether a given
// SocketAddress should be accepted for inbound or
// outbound network activity.
class SocketAddressBlockList : public MemoryRetainer {
public:
explicit SocketAddressBlockList(
std::shared_ptr<SocketAddressBlockList> parent = {});
~SocketAddressBlockList() = default;
void AddSocketAddress(const std::shared_ptr<SocketAddress>& address);
void RemoveSocketAddress(const std::shared_ptr<SocketAddress>& address);
void AddSocketAddressRange(
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end);
void AddSocketAddressMask(
const std::shared_ptr<SocketAddress>& address,
int prefix);
bool Apply(const std::shared_ptr<SocketAddress>& address);
size_t size() const { return rules_.size(); }
v8::MaybeLocal<v8::Array> ListRules(Environment* env);
struct Rule : public MemoryRetainer {
virtual bool Apply(const std::shared_ptr<SocketAddress>& address) = 0;
inline v8::MaybeLocal<v8::Value> ToV8String(Environment* env);
virtual std::string ToString() = 0;
};
struct SocketAddressRule final : Rule {
std::shared_ptr<SocketAddress> address;
explicit SocketAddressRule(const std::shared_ptr<SocketAddress>& address);
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;
void MemoryInfo(node::MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressRule)
SET_SELF_SIZE(SocketAddressRule)
};
struct SocketAddressRangeRule final : Rule {
std::shared_ptr<SocketAddress> start;
std::shared_ptr<SocketAddress> end;
SocketAddressRangeRule(
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end);
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;
void MemoryInfo(node::MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressRangeRule)
SET_SELF_SIZE(SocketAddressRangeRule)
};
struct SocketAddressMaskRule final : Rule {
std::shared_ptr<SocketAddress> network;
int prefix;
SocketAddressMaskRule(
const std::shared_ptr<SocketAddress>& address,
int prefix);
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;
void MemoryInfo(node::MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressMaskRule)
SET_SELF_SIZE(SocketAddressMaskRule)
};
void MemoryInfo(node::MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBlockList)
SET_SELF_SIZE(SocketAddressBlockList)
private:
bool ListRules(
Environment* env,
std::vector<v8::Local<v8::Value>>* vec);
std::shared_ptr<SocketAddressBlockList> parent_;
std::list<std::unique_ptr<Rule>> rules_;
SocketAddress::Map<std::list<std::unique_ptr<Rule>>::iterator> address_rules_;
Mutex mutex_;
};
class SocketAddressBlockListWrap : public BaseObject {
public:
static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv);
static BaseObjectPtr<SocketAddressBlockListWrap> New(Environment* env);
static BaseObjectPtr<SocketAddressBlockListWrap> New(
Environment* env,
std::shared_ptr<SocketAddressBlockList> blocklist);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AddAddress(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AddRange(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AddSubnet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Check(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetRules(const v8::FunctionCallbackInfo<v8::Value>& args);
SocketAddressBlockListWrap(
Environment* env,
v8::Local<v8::Object> wrap,
std::shared_ptr<SocketAddressBlockList> blocklist =
std::make_shared<SocketAddressBlockList>());
void MemoryInfo(node::MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap)
SET_SELF_SIZE(SocketAddressBlockListWrap)
TransferMode GetTransferMode() const override {
return TransferMode::kCloneable;
}
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
class TransferData : public worker::TransferData {
public:
inline explicit TransferData(const SocketAddressBlockListWrap* wrap)
: blocklist_(wrap->blocklist_) {}
inline explicit TransferData(
std::shared_ptr<SocketAddressBlockList> blocklist)
: blocklist_(std::move(blocklist)) {}
BaseObjectPtr<BaseObject> Deserialize(
Environment* env,
v8::Local<v8::Context> context,
std::unique_ptr<worker::TransferData> self) override;
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap::TransferData)
SET_SELF_SIZE(TransferData)
private:
std::shared_ptr<SocketAddressBlockList> blocklist_;
};
private:
std::shared_ptr<SocketAddressBlockList> blocklist_;
};
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_SOCKADDR_H_
|