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