Skip to content

Commit bbc6346

Browse files
jasnellfoxxyz
authored andcommitted
net: add SocketAddress class
Signed-off-by: James M Snell <[email protected]> PR-URL: nodejs#37917 Reviewed-By: Matteo Collina <[email protected]>
1 parent 4d0ffa7 commit bbc6346

10 files changed

+520
-0
lines changed

doc/api/net.md

+45
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,51 @@ added: REPLACEME
135135

136136
The list of rules added to the blocklist.
137137

138+
## Class: `net.SocketAddress`
139+
<!-- YAML
140+
added: REPLACEME
141+
-->
142+
### `new net.SocketAddress([options])`
143+
<!-- YAML
144+
added: REPLACEME
145+
-->
146+
147+
* `options` {Object}
148+
* `address` {string} The network address as either an IPv4 or IPv6 string.
149+
**Default**: `'127.0.0.1'` if `family` is `'ipv4'`; `'::'` if `family` is
150+
`'ipv6'`.
151+
* `family` {string} One of either `'ipv4'` or 'ipv6'`. **Default**: `'ipv4'`.
152+
* `flowlabel` {number} An IPv6 flow-label used only if `family` is `'ipv6'`.
153+
* `port` {number} An IP port.
154+
155+
### `socketaddress.address`
156+
<!-- YAML
157+
added: REPLACEME
158+
-->
159+
160+
* Type {string}
161+
162+
### `socketaddress.family`
163+
<!-- YAML
164+
added: REPLACEME
165+
-->
166+
167+
* Type {string} Either `'ipv4'` or `'ipv6'`.
168+
169+
### `socketaddress.flowlabel`
170+
<!-- YAML
171+
added: REPLACEME
172+
-->
173+
174+
* Type {number}
175+
176+
### `socketaddress.port`
177+
<!-- YAML
178+
added: REPLACEME
179+
-->
180+
181+
* Type {number}
182+
138183
## Class: `net.Server`
139184
<!-- YAML
140185
added: v0.1.90

doc/api/worker_threads.md

+1
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ In particular, the significant differences to `JSON` are:
409409
* {KeyObject}s,
410410
* {MessagePort}s,
411411
* {net.BlockList}s,
412+
* {net.SocketAddress}es,
412413

413414
```js
414415
const { MessageChannel } = require('worker_threads');

lib/internal/socketaddress.js

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
'use strict';
2+
3+
const {
4+
ObjectSetPrototypeOf,
5+
Symbol,
6+
} = primordials;
7+
8+
const {
9+
SocketAddress: _SocketAddress,
10+
AF_INET,
11+
AF_INET6,
12+
} = internalBinding('block_list');
13+
14+
const {
15+
validateObject,
16+
validateString,
17+
validatePort,
18+
validateUint32,
19+
} = require('internal/validators');
20+
21+
const {
22+
codes: {
23+
ERR_INVALID_ARG_VALUE,
24+
},
25+
} = require('internal/errors');
26+
27+
const {
28+
customInspectSymbol: kInspect,
29+
} = require('internal/util');
30+
31+
const { inspect } = require('internal/util/inspect');
32+
33+
const {
34+
JSTransferable,
35+
kClone,
36+
kDeserialize,
37+
} = require('internal/worker/js_transferable');
38+
39+
const kHandle = Symbol('kHandle');
40+
const kDetail = Symbol('kDetail');
41+
42+
class SocketAddress extends JSTransferable {
43+
static isSocketAddress(value) {
44+
return value?.[kHandle] !== undefined;
45+
}
46+
47+
constructor(options = {}) {
48+
super();
49+
validateObject(options, 'options');
50+
const {
51+
family = 'ipv4',
52+
address = (family === 'ipv4' ? '127.0.0.1' : '::'),
53+
port = 0,
54+
flowlabel = 0,
55+
} = options;
56+
57+
let type;
58+
switch (family) {
59+
case 'ipv4':
60+
type = AF_INET;
61+
break;
62+
case 'ipv6':
63+
type = AF_INET6;
64+
break;
65+
default:
66+
throw new ERR_INVALID_ARG_VALUE('options.family', family);
67+
}
68+
69+
validateString(address, 'options.address');
70+
validatePort(port, 'options.port');
71+
validateUint32(flowlabel, 'options.flowlabel', false);
72+
73+
this[kHandle] = new _SocketAddress(address, port, type, flowlabel);
74+
this[kDetail] = this[kHandle].detail({
75+
address: undefined,
76+
port: undefined,
77+
family: undefined,
78+
flowlabel: undefined,
79+
});
80+
}
81+
82+
get address() {
83+
return this[kDetail].address;
84+
}
85+
86+
get port() {
87+
return this[kDetail].port;
88+
}
89+
90+
get family() {
91+
return this[kDetail].family === AF_INET ? 'ipv4' : 'ipv6';
92+
}
93+
94+
get flowlabel() {
95+
// The flow label can be changed internally.
96+
return this[kHandle].flowlabel();
97+
}
98+
99+
[kInspect](depth, options) {
100+
if (depth < 0)
101+
return this;
102+
103+
const opts = {
104+
...options,
105+
depth: options.depth == null ? null : options.depth - 1
106+
};
107+
108+
return `SocketAddress ${inspect(this.toJSON(), opts)}`;
109+
}
110+
111+
[kClone]() {
112+
const handle = this[kHandle];
113+
return {
114+
data: { handle },
115+
deserializeInfo: 'internal/socketaddress:InternalSocketAddress',
116+
};
117+
}
118+
119+
[kDeserialize]({ handle }) {
120+
this[kHandle] = handle;
121+
this[kDetail] = handle.detail({
122+
address: undefined,
123+
port: undefined,
124+
family: undefined,
125+
flowlabel: undefined,
126+
});
127+
}
128+
129+
toJSON() {
130+
return {
131+
address: this.address,
132+
port: this.port,
133+
family: this.family,
134+
flowlabel: this.flowlabel,
135+
};
136+
}
137+
}
138+
139+
class InternalSocketAddress extends JSTransferable {
140+
constructor(handle) {
141+
super();
142+
this[kHandle] = handle;
143+
}
144+
}
145+
146+
InternalSocketAddress.prototype.constructor =
147+
SocketAddress.prototype.construtor;
148+
ObjectSetPrototypeOf(InternalSocketAddress.prototype, SocketAddress.prototype);
149+
150+
module.exports = {
151+
SocketAddress,
152+
InternalSocketAddress,
153+
};

lib/net.js

+6
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ const {
116116
let cluster;
117117
let dns;
118118
let BlockList;
119+
let SocketAddress;
119120

120121
const { clearTimeout } = require('timers');
121122
const { kTimeout } = require('internal/timers');
@@ -1760,6 +1761,11 @@ module.exports = {
17601761
BlockList = BlockList ?? require('internal/blocklist').BlockList;
17611762
return BlockList;
17621763
},
1764+
get SocketAddress() {
1765+
SocketAddress =
1766+
SocketAddress ?? require('internal/socketaddress').SocketAddress;
1767+
return SocketAddress;
1768+
},
17631769
connect,
17641770
createConnection: connect,
17651771
createServer,

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
'lib/internal/repl/await.js',
200200
'lib/internal/repl/history.js',
201201
'lib/internal/repl/utils.js',
202+
'lib/internal/socketaddress.js',
202203
'lib/internal/socket_list.js',
203204
'lib/internal/source_map/prepare_stack_trace.js',
204205
'lib/internal/source_map/source_map.js',

src/env.h

+2
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ constexpr size_t kFsStatsBufferLength =
252252
V(fingerprint256_string, "fingerprint256") \
253253
V(fingerprint_string, "fingerprint") \
254254
V(flags_string, "flags") \
255+
V(flowlabel_string, "flowlabel") \
255256
V(fragment_string, "fragment") \
256257
V(function_string, "function") \
257258
V(get_data_clone_error_string, "_getDataCloneError") \
@@ -433,6 +434,7 @@ constexpr size_t kFsStatsBufferLength =
433434
V(script_context_constructor_template, v8::FunctionTemplate) \
434435
V(secure_context_constructor_template, v8::FunctionTemplate) \
435436
V(shutdown_wrap_template, v8::ObjectTemplate) \
437+
V(socketaddress_constructor_template, v8::FunctionTemplate) \
436438
V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
437439
V(tcp_constructor_template, v8::FunctionTemplate) \
438440
V(tty_constructor_template, v8::FunctionTemplate) \

src/node_errors.h

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void OnFatalError(const char* location, const char* message);
3939
V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \
4040
V(ERR_CRYPTO_UNKNOWN_DH_GROUP, Error) \
4141
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
42+
V(ERR_INVALID_ADDRESS, Error) \
4243
V(ERR_INVALID_ARG_VALUE, TypeError) \
4344
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
4445
V(ERR_INVALID_ARG_TYPE, TypeError) \
@@ -108,6 +109,7 @@ ERRORS_WITH_CODE(V)
108109
V(ERR_CRYPTO_UNKNOWN_DH_GROUP, "Unknown DH group") \
109110
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
110111
"Context not associated with Node.js environment") \
112+
V(ERR_INVALID_ADDRESS, "Invalid socket address") \
111113
V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
112114
V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
113115
V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \

0 commit comments

Comments
 (0)