Skip to content

Commit

Permalink
net: add SocketAddress class
Browse files Browse the repository at this point in the history
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: #37917
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
jasnell authored and targos committed Aug 8, 2021
1 parent bccb95f commit 0954c8b
Show file tree
Hide file tree
Showing 10 changed files with 520 additions and 0 deletions.
45 changes: 45 additions & 0 deletions doc/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,51 @@ added: REPLACEME

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`
<!-- YAML
added: v0.1.90
Expand Down
1 change: 1 addition & 0 deletions doc/api/worker_threads.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ In particular, the significant differences to `JSON` are:
* {KeyObject}s,
* {MessagePort}s,
* {net.BlockList}s,
* {net.SocketAddress}es,

```js
const { MessageChannel } = require('worker_threads');
Expand Down
153 changes: 153 additions & 0 deletions lib/internal/socketaddress.js
Original file line number Diff line number Diff line change
@@ -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,
};
6 changes: 6 additions & 0 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const {
let cluster;
let dns;
let BlockList;
let SocketAddress;

const { clearTimeout } = require('timers');
const { kTimeout } = require('internal/timers');
Expand Down Expand Up @@ -1760,6 +1761,11 @@ module.exports = {
BlockList = BlockList ?? require('internal/blocklist').BlockList;
return BlockList;
},
get SocketAddress() {
SocketAddress =
SocketAddress ?? require('internal/socketaddress').SocketAddress;
return SocketAddress;
},
connect,
createConnection: connect,
createServer,
Expand Down
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
'lib/internal/repl/await.js',
'lib/internal/repl/history.js',
'lib/internal/repl/utils.js',
'lib/internal/socketaddress.js',
'lib/internal/socket_list.js',
'lib/internal/source_map/prepare_stack_trace.js',
'lib/internal/source_map/source_map.js',
Expand Down
2 changes: 2 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ constexpr size_t kFsStatsBufferLength =
V(fingerprint256_string, "fingerprint256") \
V(fingerprint_string, "fingerprint") \
V(flags_string, "flags") \
V(flowlabel_string, "flowlabel") \
V(fragment_string, "fragment") \
V(function_string, "function") \
V(get_data_clone_error_string, "_getDataCloneError") \
Expand Down Expand Up @@ -433,6 +434,7 @@ constexpr size_t kFsStatsBufferLength =
V(script_context_constructor_template, v8::FunctionTemplate) \
V(secure_context_constructor_template, v8::FunctionTemplate) \
V(shutdown_wrap_template, v8::ObjectTemplate) \
V(socketaddress_constructor_template, v8::FunctionTemplate) \
V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
V(tcp_constructor_template, v8::FunctionTemplate) \
V(tty_constructor_template, v8::FunctionTemplate) \
Expand Down
2 changes: 2 additions & 0 deletions src/node_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void OnFatalError(const char* location, const char* message);
V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \
V(ERR_CRYPTO_UNKNOWN_DH_GROUP, Error) \
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
V(ERR_INVALID_ADDRESS, Error) \
V(ERR_INVALID_ARG_VALUE, TypeError) \
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
V(ERR_INVALID_ARG_TYPE, TypeError) \
Expand Down Expand Up @@ -108,6 +109,7 @@ ERRORS_WITH_CODE(V)
V(ERR_CRYPTO_UNKNOWN_DH_GROUP, "Unknown DH group") \
V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
"Context not associated with Node.js environment") \
V(ERR_INVALID_ADDRESS, "Invalid socket address") \
V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \
Expand Down
Loading

0 comments on commit 0954c8b

Please sign in to comment.