1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23const common = require('../common'); 24const assert = require('assert'); 25const dns = require('dns'); 26const net = require('net'); 27 28// Test wrong type of ports 29{ 30 const portTypeError = { 31 code: 'ERR_INVALID_ARG_TYPE', 32 name: 'TypeError' 33 }; 34 35 syncFailToConnect(true, portTypeError); 36 syncFailToConnect(false, portTypeError); 37 syncFailToConnect([], portTypeError, true); 38 syncFailToConnect({}, portTypeError, true); 39 syncFailToConnect(null, portTypeError); 40} 41 42// Test out of range ports 43{ 44 const portRangeError = { 45 code: 'ERR_SOCKET_BAD_PORT', 46 name: 'RangeError' 47 }; 48 49 syncFailToConnect('', portRangeError); 50 syncFailToConnect(' ', portRangeError); 51 syncFailToConnect('0x', portRangeError, true); 52 syncFailToConnect('-0x1', portRangeError, true); 53 syncFailToConnect(NaN, portRangeError); 54 syncFailToConnect(Infinity, portRangeError); 55 syncFailToConnect(-1, portRangeError); 56 syncFailToConnect(65536, portRangeError); 57} 58 59// Test invalid hints 60{ 61 // connect({hint}, cb) and connect({hint}) 62 const hints = (dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL) + 42; 63 const hintOptBlocks = doConnect([{ port: 42, hints }], 64 () => common.mustNotCall()); 65 for (const fn of hintOptBlocks) { 66 assert.throws(fn, { 67 code: 'ERR_INVALID_ARG_VALUE', 68 name: 'TypeError', 69 message: /The argument 'hints' is invalid\. Received \d+/ 70 }); 71 } 72} 73 74// Test valid combinations of connect(port) and connect(port, host) 75{ 76 const expectedConnections = 72; 77 let serverConnected = 0; 78 79 const server = net.createServer(common.mustCall((socket) => { 80 socket.end('ok'); 81 if (++serverConnected === expectedConnections) { 82 server.close(); 83 } 84 }, expectedConnections)); 85 86 server.listen(0, common.localhostIPv4, common.mustCall(() => { 87 const port = server.address().port; 88 89 // Total connections = 3 * 4(canConnect) * 6(doConnect) = 72 90 canConnect(port); 91 canConnect(String(port)); 92 canConnect(`0x${port.toString(16)}`); 93 })); 94 95 // Try connecting to random ports, but do so once the server is closed 96 server.on('close', () => { 97 asyncFailToConnect(0); 98 }); 99} 100 101function doConnect(args, getCb) { 102 return [ 103 function createConnectionWithCb() { 104 return net.createConnection.apply(net, args.concat(getCb())) 105 .resume(); 106 }, 107 function createConnectionWithoutCb() { 108 return net.createConnection.apply(net, args) 109 .on('connect', getCb()) 110 .resume(); 111 }, 112 function connectWithCb() { 113 return net.connect.apply(net, args.concat(getCb())) 114 .resume(); 115 }, 116 function connectWithoutCb() { 117 return net.connect.apply(net, args) 118 .on('connect', getCb()) 119 .resume(); 120 }, 121 function socketConnectWithCb() { 122 const socket = new net.Socket(); 123 return socket.connect.apply(socket, args.concat(getCb())) 124 .resume(); 125 }, 126 function socketConnectWithoutCb() { 127 const socket = new net.Socket(); 128 return socket.connect.apply(socket, args) 129 .on('connect', getCb()) 130 .resume(); 131 }, 132 ]; 133} 134 135function syncFailToConnect(port, assertErr, optOnly) { 136 const family = 4; 137 if (!optOnly) { 138 // connect(port, cb) and connect(port) 139 const portArgFunctions = doConnect([{ port, family }], 140 () => common.mustNotCall()); 141 for (const fn of portArgFunctions) { 142 assert.throws(fn, assertErr, `${fn.name}(${port})`); 143 } 144 145 // connect(port, host, cb) and connect(port, host) 146 const portHostArgFunctions = doConnect([{ port, 147 host: 'localhost', 148 family }], 149 () => common.mustNotCall()); 150 for (const fn of portHostArgFunctions) { 151 assert.throws(fn, assertErr, `${fn.name}(${port}, 'localhost')`); 152 } 153 } 154 // connect({port}, cb) and connect({port}) 155 const portOptFunctions = doConnect([{ port, family }], 156 () => common.mustNotCall()); 157 for (const fn of portOptFunctions) { 158 assert.throws(fn, assertErr, `${fn.name}({port: ${port}})`); 159 } 160 161 // connect({port, host}, cb) and connect({port, host}) 162 const portHostOptFunctions = doConnect([{ port: port, 163 host: 'localhost', 164 family: family }], 165 () => common.mustNotCall()); 166 for (const fn of portHostOptFunctions) { 167 assert.throws(fn, 168 assertErr, 169 `${fn.name}({port: ${port}, host: 'localhost'})`); 170 } 171} 172 173function canConnect(port) { 174 const noop = () => common.mustCall(); 175 const family = 4; 176 177 // connect(port, cb) and connect(port) 178 const portArgFunctions = doConnect([{ port, family }], noop); 179 for (const fn of portArgFunctions) { 180 fn(); 181 } 182 183 // connect(port, host, cb) and connect(port, host) 184 const portHostArgFunctions = doConnect([{ port, host: 'localhost', family }], 185 noop); 186 for (const fn of portHostArgFunctions) { 187 fn(); 188 } 189 190 // connect({port}, cb) and connect({port}) 191 const portOptFunctions = doConnect([{ port, family }], noop); 192 for (const fn of portOptFunctions) { 193 fn(); 194 } 195 196 // connect({port, host}, cb) and connect({port, host}) 197 const portHostOptFns = doConnect([{ port, host: 'localhost', family }], 198 noop); 199 for (const fn of portHostOptFns) { 200 fn(); 201 } 202} 203 204function asyncFailToConnect(port) { 205 const onError = () => common.mustCall((err) => { 206 const regexp = /^Error: connect E\w+.+$/; 207 assert.match(String(err), regexp); 208 }); 209 210 const dont = () => common.mustNotCall(); 211 const family = 4; 212 // connect(port, cb) and connect(port) 213 const portArgFunctions = doConnect([{ port, family }], dont); 214 for (const fn of portArgFunctions) { 215 fn().on('error', onError()); 216 } 217 218 // connect({port}, cb) and connect({port}) 219 const portOptFunctions = doConnect([{ port, family }], dont); 220 for (const fn of portOptFunctions) { 221 fn().on('error', onError()); 222 } 223 224 // connect({port, host}, cb) and connect({port, host}) 225 const portHostOptFns = doConnect([{ port, host: 'localhost', family }], 226 dont); 227 for (const fn of portHostOptFns) { 228 fn().on('error', onError()); 229 } 230} 231