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([{ hints }], 64 () => common.mustNotCall()); 65 for (const fn of hintOptBlocks) { 66 assert.throws(fn, { 67 code: 'ERR_INVALID_OPT_VALUE', 68 name: 'TypeError', 69 message: /The value "\d+" is invalid for option "hints"/ 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, 'localhost', 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 asyncFailToConnect(/* undefined */); 99 }); 100} 101 102function doConnect(args, getCb) { 103 return [ 104 function createConnectionWithCb() { 105 return net.createConnection.apply(net, args.concat(getCb())) 106 .resume(); 107 }, 108 function createConnectionWithoutCb() { 109 return net.createConnection.apply(net, args) 110 .on('connect', getCb()) 111 .resume(); 112 }, 113 function connectWithCb() { 114 return net.connect.apply(net, args.concat(getCb())) 115 .resume(); 116 }, 117 function connectWithoutCb() { 118 return net.connect.apply(net, args) 119 .on('connect', getCb()) 120 .resume(); 121 }, 122 function socketConnectWithCb() { 123 const socket = new net.Socket(); 124 return socket.connect.apply(socket, args.concat(getCb())) 125 .resume(); 126 }, 127 function socketConnectWithoutCb() { 128 const socket = new net.Socket(); 129 return socket.connect.apply(socket, args) 130 .on('connect', getCb()) 131 .resume(); 132 }, 133 ]; 134} 135 136function syncFailToConnect(port, assertErr, optOnly) { 137 if (!optOnly) { 138 // connect(port, cb) and connect(port) 139 const portArgFunctions = doConnect([port], () => common.mustNotCall()); 140 for (const fn of portArgFunctions) { 141 assert.throws(fn, assertErr, `${fn.name}(${port})`); 142 } 143 144 // connect(port, host, cb) and connect(port, host) 145 const portHostArgFunctions = doConnect([port, 'localhost'], 146 () => common.mustNotCall()); 147 for (const fn of portHostArgFunctions) { 148 assert.throws(fn, assertErr, `${fn.name}(${port}, 'localhost')`); 149 } 150 } 151 // connect({port}, cb) and connect({port}) 152 const portOptFunctions = doConnect([{ port }], () => common.mustNotCall()); 153 for (const fn of portOptFunctions) { 154 assert.throws(fn, assertErr, `${fn.name}({port: ${port}})`); 155 } 156 157 // connect({port, host}, cb) and connect({port, host}) 158 const portHostOptFunctions = doConnect([{ port: port, host: 'localhost' }], 159 () => common.mustNotCall()); 160 for (const fn of portHostOptFunctions) { 161 assert.throws(fn, 162 assertErr, 163 `${fn.name}({port: ${port}, host: 'localhost'})`); 164 } 165} 166 167function canConnect(port) { 168 const noop = () => common.mustCall(); 169 170 // connect(port, cb) and connect(port) 171 const portArgFunctions = doConnect([port], noop); 172 for (const fn of portArgFunctions) { 173 fn(); 174 } 175 176 // connect(port, host, cb) and connect(port, host) 177 const portHostArgFunctions = doConnect([port, 'localhost'], noop); 178 for (const fn of portHostArgFunctions) { 179 fn(); 180 } 181 182 // connect({port}, cb) and connect({port}) 183 const portOptFunctions = doConnect([{ port }], noop); 184 for (const fn of portOptFunctions) { 185 fn(); 186 } 187 188 // connect({port, host}, cb) and connect({port, host}) 189 const portHostOptFns = doConnect([{ port, host: 'localhost' }], noop); 190 for (const fn of portHostOptFns) { 191 fn(); 192 } 193} 194 195function asyncFailToConnect(port) { 196 const onError = () => common.mustCall((err) => { 197 const regexp = /^Error: connect E\w+.+$/; 198 assert(regexp.test(String(err)), String(err)); 199 }); 200 201 const dont = () => common.mustNotCall(); 202 // connect(port, cb) and connect(port) 203 const portArgFunctions = doConnect([port], dont); 204 for (const fn of portArgFunctions) { 205 fn().on('error', onError()); 206 } 207 208 // connect({port}, cb) and connect({port}) 209 const portOptFunctions = doConnect([{ port }], dont); 210 for (const fn of portOptFunctions) { 211 fn().on('error', onError()); 212 } 213 214 // connect({port, host}, cb) and connect({port, host}) 215 const portHostOptFns = doConnect([{ port, host: 'localhost' }], dont); 216 for (const fn of portHostOptFns) { 217 fn().on('error', onError()); 218 } 219} 220