mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
net: add SocketAddress class
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/37917 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
a4169ce519
commit
daa8a7bbcf
|
|
@ -135,6 +135,51 @@ added: v15.0.0
|
||||||
|
|
||||||
The list of rules added to the blocklist.
|
The list of rules added to the blocklist.
|
||||||
|
|
||||||
|
## Class: `net.SocketAddress`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
### `new net.SocketAddress([options])`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `options` {Object}
|
||||||
|
* `address` {string} The network address as either an IPv4 or IPv6 string.
|
||||||
|
**Default**: `'127.0.0.1'` if `family` is `'ipv4'`; `'::'` if `family` is
|
||||||
|
`'ipv6'`.
|
||||||
|
* `family` {string} One of either `'ipv4'` or 'ipv6'`. **Default**: `'ipv4'`.
|
||||||
|
* `flowlabel` {number} An IPv6 flow-label used only if `family` is `'ipv6'`.
|
||||||
|
* `port` {number} An IP port.
|
||||||
|
|
||||||
|
### `socketaddress.address`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type {string}
|
||||||
|
|
||||||
|
### `socketaddress.family`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type {string} Either `'ipv4'` or `'ipv6'`.
|
||||||
|
|
||||||
|
### `socketaddress.flowlabel`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type {number}
|
||||||
|
|
||||||
|
### `socketaddress.port`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type {number}
|
||||||
|
|
||||||
## Class: `net.Server`
|
## Class: `net.Server`
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.90
|
added: v0.1.90
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,7 @@ In particular, the significant differences to `JSON` are:
|
||||||
* {KeyObject}s,
|
* {KeyObject}s,
|
||||||
* {MessagePort}s,
|
* {MessagePort}s,
|
||||||
* {net.BlockList}s,
|
* {net.BlockList}s,
|
||||||
|
* {net.SocketAddress}es,
|
||||||
* {X509Certificate}s.
|
* {X509Certificate}s.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
|
||||||
153
lib/internal/socketaddress.js
Normal file
153
lib/internal/socketaddress.js
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {
|
||||||
|
ObjectSetPrototypeOf,
|
||||||
|
Symbol,
|
||||||
|
} = primordials;
|
||||||
|
|
||||||
|
const {
|
||||||
|
SocketAddress: _SocketAddress,
|
||||||
|
AF_INET,
|
||||||
|
AF_INET6,
|
||||||
|
} = internalBinding('block_list');
|
||||||
|
|
||||||
|
const {
|
||||||
|
validateObject,
|
||||||
|
validateString,
|
||||||
|
validatePort,
|
||||||
|
validateUint32,
|
||||||
|
} = require('internal/validators');
|
||||||
|
|
||||||
|
const {
|
||||||
|
codes: {
|
||||||
|
ERR_INVALID_ARG_VALUE,
|
||||||
|
},
|
||||||
|
} = require('internal/errors');
|
||||||
|
|
||||||
|
const {
|
||||||
|
customInspectSymbol: kInspect,
|
||||||
|
} = require('internal/util');
|
||||||
|
|
||||||
|
const { inspect } = require('internal/util/inspect');
|
||||||
|
|
||||||
|
const {
|
||||||
|
JSTransferable,
|
||||||
|
kClone,
|
||||||
|
kDeserialize,
|
||||||
|
} = require('internal/worker/js_transferable');
|
||||||
|
|
||||||
|
const kHandle = Symbol('kHandle');
|
||||||
|
const kDetail = Symbol('kDetail');
|
||||||
|
|
||||||
|
class SocketAddress extends JSTransferable {
|
||||||
|
static isSocketAddress(value) {
|
||||||
|
return value?.[kHandle] !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(options = {}) {
|
||||||
|
super();
|
||||||
|
validateObject(options, 'options');
|
||||||
|
const {
|
||||||
|
family = 'ipv4',
|
||||||
|
address = (family === 'ipv4' ? '127.0.0.1' : '::'),
|
||||||
|
port = 0,
|
||||||
|
flowlabel = 0,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
let type;
|
||||||
|
switch (family) {
|
||||||
|
case 'ipv4':
|
||||||
|
type = AF_INET;
|
||||||
|
break;
|
||||||
|
case 'ipv6':
|
||||||
|
type = AF_INET6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ERR_INVALID_ARG_VALUE('options.family', family);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateString(address, 'options.address');
|
||||||
|
validatePort(port, 'options.port');
|
||||||
|
validateUint32(flowlabel, 'options.flowlabel', false);
|
||||||
|
|
||||||
|
this[kHandle] = new _SocketAddress(address, port, type, flowlabel);
|
||||||
|
this[kDetail] = this[kHandle].detail({
|
||||||
|
address: undefined,
|
||||||
|
port: undefined,
|
||||||
|
family: undefined,
|
||||||
|
flowlabel: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get address() {
|
||||||
|
return this[kDetail].address;
|
||||||
|
}
|
||||||
|
|
||||||
|
get port() {
|
||||||
|
return this[kDetail].port;
|
||||||
|
}
|
||||||
|
|
||||||
|
get family() {
|
||||||
|
return this[kDetail].family === AF_INET ? 'ipv4' : 'ipv6';
|
||||||
|
}
|
||||||
|
|
||||||
|
get flowlabel() {
|
||||||
|
// The flow label can be changed internally.
|
||||||
|
return this[kHandle].flowlabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
[kInspect](depth, options) {
|
||||||
|
if (depth < 0)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
...options,
|
||||||
|
depth: options.depth == null ? null : options.depth - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return `SocketAddress ${inspect(this.toJSON(), opts)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
[kClone]() {
|
||||||
|
const handle = this[kHandle];
|
||||||
|
return {
|
||||||
|
data: { handle },
|
||||||
|
deserializeInfo: 'internal/socketaddress:InternalSocketAddress',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[kDeserialize]({ handle }) {
|
||||||
|
this[kHandle] = handle;
|
||||||
|
this[kDetail] = handle.detail({
|
||||||
|
address: undefined,
|
||||||
|
port: undefined,
|
||||||
|
family: undefined,
|
||||||
|
flowlabel: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
address: this.address,
|
||||||
|
port: this.port,
|
||||||
|
family: this.family,
|
||||||
|
flowlabel: this.flowlabel,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InternalSocketAddress extends JSTransferable {
|
||||||
|
constructor(handle) {
|
||||||
|
super();
|
||||||
|
this[kHandle] = handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalSocketAddress.prototype.constructor =
|
||||||
|
SocketAddress.prototype.construtor;
|
||||||
|
ObjectSetPrototypeOf(InternalSocketAddress.prototype, SocketAddress.prototype);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SocketAddress,
|
||||||
|
InternalSocketAddress,
|
||||||
|
};
|
||||||
|
|
@ -122,6 +122,7 @@ const {
|
||||||
let cluster;
|
let cluster;
|
||||||
let dns;
|
let dns;
|
||||||
let BlockList;
|
let BlockList;
|
||||||
|
let SocketAddress;
|
||||||
|
|
||||||
const { clearTimeout } = require('timers');
|
const { clearTimeout } = require('timers');
|
||||||
const { kTimeout } = require('internal/timers');
|
const { kTimeout } = require('internal/timers');
|
||||||
|
|
@ -1751,6 +1752,10 @@ module.exports = {
|
||||||
BlockList ??= require('internal/blocklist').BlockList;
|
BlockList ??= require('internal/blocklist').BlockList;
|
||||||
return BlockList;
|
return BlockList;
|
||||||
},
|
},
|
||||||
|
get SocketAddress() {
|
||||||
|
SocketAddress ??= require('internal/socketaddress').SocketAddress;
|
||||||
|
return SocketAddress;
|
||||||
|
},
|
||||||
connect,
|
connect,
|
||||||
createConnection: connect,
|
createConnection: connect,
|
||||||
createServer,
|
createServer,
|
||||||
|
|
|
||||||
1
node.gyp
1
node.gyp
|
|
@ -212,6 +212,7 @@
|
||||||
'lib/internal/repl/await.js',
|
'lib/internal/repl/await.js',
|
||||||
'lib/internal/repl/history.js',
|
'lib/internal/repl/history.js',
|
||||||
'lib/internal/repl/utils.js',
|
'lib/internal/repl/utils.js',
|
||||||
|
'lib/internal/socketaddress.js',
|
||||||
'lib/internal/socket_list.js',
|
'lib/internal/socket_list.js',
|
||||||
'lib/internal/source_map/prepare_stack_trace.js',
|
'lib/internal/source_map/prepare_stack_trace.js',
|
||||||
'lib/internal/source_map/source_map.js',
|
'lib/internal/source_map/source_map.js',
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,7 @@ constexpr size_t kFsStatsBufferLength =
|
||||||
V(fingerprint256_string, "fingerprint256") \
|
V(fingerprint256_string, "fingerprint256") \
|
||||||
V(fingerprint_string, "fingerprint") \
|
V(fingerprint_string, "fingerprint") \
|
||||||
V(flags_string, "flags") \
|
V(flags_string, "flags") \
|
||||||
|
V(flowlabel_string, "flowlabel") \
|
||||||
V(fragment_string, "fragment") \
|
V(fragment_string, "fragment") \
|
||||||
V(function_string, "function") \
|
V(function_string, "function") \
|
||||||
V(get_data_clone_error_string, "_getDataCloneError") \
|
V(get_data_clone_error_string, "_getDataCloneError") \
|
||||||
|
|
@ -465,6 +466,7 @@ constexpr size_t kFsStatsBufferLength =
|
||||||
V(script_context_constructor_template, v8::FunctionTemplate) \
|
V(script_context_constructor_template, v8::FunctionTemplate) \
|
||||||
V(secure_context_constructor_template, v8::FunctionTemplate) \
|
V(secure_context_constructor_template, v8::FunctionTemplate) \
|
||||||
V(shutdown_wrap_template, v8::ObjectTemplate) \
|
V(shutdown_wrap_template, v8::ObjectTemplate) \
|
||||||
|
V(socketaddress_constructor_template, v8::FunctionTemplate) \
|
||||||
V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
|
V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
|
||||||
V(qlogoutputstream_constructor_template, v8::ObjectTemplate) \
|
V(qlogoutputstream_constructor_template, v8::ObjectTemplate) \
|
||||||
V(tcp_constructor_template, v8::FunctionTemplate) \
|
V(tcp_constructor_template, v8::FunctionTemplate) \
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ void OnFatalError(const char* location, const char* message);
|
||||||
V(ERR_CRYPTO_JOB_INIT_FAILED, Error) \
|
V(ERR_CRYPTO_JOB_INIT_FAILED, Error) \
|
||||||
V(ERR_DLOPEN_FAILED, Error) \
|
V(ERR_DLOPEN_FAILED, Error) \
|
||||||
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
|
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
|
||||||
|
V(ERR_INVALID_ADDRESS, Error) \
|
||||||
V(ERR_INVALID_ARG_VALUE, TypeError) \
|
V(ERR_INVALID_ARG_VALUE, TypeError) \
|
||||||
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
|
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
|
||||||
V(ERR_INVALID_ARG_TYPE, TypeError) \
|
V(ERR_INVALID_ARG_TYPE, TypeError) \
|
||||||
|
|
@ -143,6 +144,7 @@ ERRORS_WITH_CODE(V)
|
||||||
V(ERR_DLOPEN_FAILED, "DLOpen failed") \
|
V(ERR_DLOPEN_FAILED, "DLOpen failed") \
|
||||||
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
|
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
|
||||||
"Context not associated with Node.js environment") \
|
"Context not associated with Node.js environment") \
|
||||||
|
V(ERR_INVALID_ADDRESS, "Invalid socket address") \
|
||||||
V(ERR_INVALID_MODULE, "No such module") \
|
V(ERR_INVALID_MODULE, "No such module") \
|
||||||
V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
|
V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
|
||||||
V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
|
V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "base64-inl.h"
|
#include "base64-inl.h"
|
||||||
#include "base_object-inl.h"
|
#include "base_object-inl.h"
|
||||||
#include "memory_tracker-inl.h"
|
#include "memory_tracker-inl.h"
|
||||||
|
#include "node_errors.h"
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -15,9 +16,11 @@ using v8::Array;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
|
using v8::Int32;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::MaybeLocal;
|
using v8::MaybeLocal;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
|
using v8::Uint32;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -752,6 +755,8 @@ void SocketAddressBlockListWrap::Initialize(
|
||||||
GetConstructorTemplate(env),
|
GetConstructorTemplate(env),
|
||||||
Environment::SetConstructorFunctionFlag::NONE);
|
Environment::SetConstructorFunctionFlag::NONE);
|
||||||
|
|
||||||
|
SocketAddressBase::Initialize(env, target);
|
||||||
|
|
||||||
NODE_DEFINE_CONSTANT(target, AF_INET);
|
NODE_DEFINE_CONSTANT(target, AF_INET);
|
||||||
NODE_DEFINE_CONSTANT(target, AF_INET6);
|
NODE_DEFINE_CONSTANT(target, AF_INET6);
|
||||||
}
|
}
|
||||||
|
|
@ -768,6 +773,144 @@ void SocketAddressBlockListWrap::TransferData::MemoryInfo(
|
||||||
blocklist_->MemoryInfo(tracker);
|
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()) {
|
||||||
|
tmpl = env->NewFunctionTemplate(New);
|
||||||
|
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SocketAddress"));
|
||||||
|
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
||||||
|
SocketAddressBase::kInternalFieldCount);
|
||||||
|
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
|
||||||
|
env->SetProtoMethod(tmpl, "detail", Detail);
|
||||||
|
env->SetProtoMethod(tmpl, "legacyDetail", LegacyDetail);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "flowlabel", GetFlowLabel);
|
||||||
|
env->set_socketaddress_constructor_template(tmpl);
|
||||||
|
}
|
||||||
|
return tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketAddressBase::Initialize(Environment* env, Local<Object> target) {
|
||||||
|
env->SetConstructorFunction(
|
||||||
|
target,
|
||||||
|
"SocketAddress",
|
||||||
|
GetConstructorTemplate(env),
|
||||||
|
Environment::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) {
|
||||||
|
Environment* env = Environment::GetCurrent(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());
|
||||||
|
args.GetReturnValue().Set(base->address_->ToJS(env));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace node
|
||||||
|
|
||||||
NODE_MODULE_CONTEXT_AWARE_INTERNAL(
|
NODE_MODULE_CONTEXT_AWARE_INTERNAL(
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,60 @@ class SocketAddress : public MemoryRetainer {
|
||||||
sockaddr_storage address_;
|
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);
|
||||||
|
|
||||||
|
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>
|
template <typename T>
|
||||||
class SocketAddressLRU : public MemoryRetainer {
|
class SocketAddressLRU : public MemoryRetainer {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
110
test/parallel/test-socketaddress.js
Normal file
110
test/parallel/test-socketaddress.js
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const {
|
||||||
|
ok,
|
||||||
|
strictEqual,
|
||||||
|
throws,
|
||||||
|
} = require('assert');
|
||||||
|
const {
|
||||||
|
SocketAddress,
|
||||||
|
} = require('net');
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress();
|
||||||
|
strictEqual(sa.address, '127.0.0.1');
|
||||||
|
strictEqual(sa.port, 0);
|
||||||
|
strictEqual(sa.family, 'ipv4');
|
||||||
|
strictEqual(sa.flowlabel, 0);
|
||||||
|
|
||||||
|
const mc = new MessageChannel();
|
||||||
|
mc.port1.onmessage = common.mustCall(({ data }) => {
|
||||||
|
ok(SocketAddress.isSocketAddress(data));
|
||||||
|
|
||||||
|
strictEqual(data.address, '127.0.0.1');
|
||||||
|
strictEqual(data.port, 0);
|
||||||
|
strictEqual(data.family, 'ipv4');
|
||||||
|
strictEqual(data.flowlabel, 0);
|
||||||
|
|
||||||
|
mc.port1.close();
|
||||||
|
});
|
||||||
|
mc.port2.postMessage(sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress({});
|
||||||
|
strictEqual(sa.address, '127.0.0.1');
|
||||||
|
strictEqual(sa.port, 0);
|
||||||
|
strictEqual(sa.family, 'ipv4');
|
||||||
|
strictEqual(sa.flowlabel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress({
|
||||||
|
address: '123.123.123.123',
|
||||||
|
});
|
||||||
|
strictEqual(sa.address, '123.123.123.123');
|
||||||
|
strictEqual(sa.port, 0);
|
||||||
|
strictEqual(sa.family, 'ipv4');
|
||||||
|
strictEqual(sa.flowlabel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress({
|
||||||
|
address: '123.123.123.123',
|
||||||
|
port: 80
|
||||||
|
});
|
||||||
|
strictEqual(sa.address, '123.123.123.123');
|
||||||
|
strictEqual(sa.port, 80);
|
||||||
|
strictEqual(sa.family, 'ipv4');
|
||||||
|
strictEqual(sa.flowlabel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress({
|
||||||
|
family: 'ipv6'
|
||||||
|
});
|
||||||
|
strictEqual(sa.address, '::');
|
||||||
|
strictEqual(sa.port, 0);
|
||||||
|
strictEqual(sa.family, 'ipv6');
|
||||||
|
strictEqual(sa.flowlabel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const sa = new SocketAddress({
|
||||||
|
family: 'ipv6',
|
||||||
|
flowlabel: 1,
|
||||||
|
});
|
||||||
|
strictEqual(sa.address, '::');
|
||||||
|
strictEqual(sa.port, 0);
|
||||||
|
strictEqual(sa.family, 'ipv6');
|
||||||
|
strictEqual(sa.flowlabel, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[1, false, 'hello'].forEach((i) => {
|
||||||
|
throws(() => new SocketAddress(i), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[1, false, {}, [], 'test'].forEach((family) => {
|
||||||
|
throws(() => new SocketAddress({ family }), {
|
||||||
|
code: 'ERR_INVALID_ARG_VALUE'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[1, false, {}, []].forEach((address) => {
|
||||||
|
throws(() => new SocketAddress({ address }), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[-1, false, {}, []].forEach((port) => {
|
||||||
|
throws(() => new SocketAddress({ port }), {
|
||||||
|
code: 'ERR_SOCKET_BAD_PORT'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
throws(() => new SocketAddress({ flowlabel: -1 }), {
|
||||||
|
code: 'ERR_OUT_OF_RANGE'
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user