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