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