net: add SocketAddress class · nodejs/node@daa8a7b

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+

};