| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| 'use strict'; |
| const common = require('../common'); |
| const assert = require('assert'); |
| const dns = require('dns'); |
| const net = require('net'); |
| |
| // Test wrong type of ports |
| { |
| const portTypeError = common.expectsError({ |
| code: 'ERR_INVALID_ARG_TYPE', |
| type: TypeError |
| }, 96); |
| |
| syncFailToConnect(true, portTypeError); |
| syncFailToConnect(false, portTypeError); |
| syncFailToConnect([], portTypeError, true); |
| syncFailToConnect({}, portTypeError, true); |
| syncFailToConnect(null, portTypeError); |
| } |
| |
| // Test out of range ports |
| { |
| const portRangeError = common.expectsError({ |
| code: 'ERR_SOCKET_BAD_PORT', |
| type: RangeError |
| }, 168); |
| |
| syncFailToConnect('', portRangeError); |
| syncFailToConnect(' ', portRangeError); |
| syncFailToConnect('0x', portRangeError, true); |
| syncFailToConnect('-0x1', portRangeError, true); |
| syncFailToConnect(NaN, portRangeError); |
| syncFailToConnect(Infinity, portRangeError); |
| syncFailToConnect(-1, portRangeError); |
| syncFailToConnect(65536, portRangeError); |
| } |
| |
| // Test invalid hints |
| { |
| // connect({hint}, cb) and connect({hint}) |
| const hints = (dns.ADDRCONFIG | dns.V4MAPPED) + 42; |
| const hintOptBlocks = doConnect([{ hints }], |
| () => common.mustNotCall()); |
| for (const fn of hintOptBlocks) { |
| common.expectsError(fn, { |
| code: 'ERR_INVALID_OPT_VALUE', |
| type: TypeError, |
| message: /The value "\d+" is invalid for option "hints"/ |
| }); |
| } |
| } |
| |
| // Test valid combinations of connect(port) and connect(port, host) |
| { |
| const expectedConnections = 72; |
| let serverConnected = 0; |
| |
| const server = net.createServer(common.mustCall((socket) => { |
| socket.end('ok'); |
| if (++serverConnected === expectedConnections) { |
| server.close(); |
| } |
| }, expectedConnections)); |
| |
| server.listen(0, 'localhost', common.mustCall(() => { |
| const port = server.address().port; |
| |
| // Total connections = 3 * 4(canConnect) * 6(doConnect) = 72 |
| canConnect(port); |
| canConnect(String(port)); |
| canConnect(`0x${port.toString(16)}`); |
| })); |
| |
| // Try connecting to random ports, but do so once the server is closed |
| server.on('close', () => { |
| asyncFailToConnect(0); |
| asyncFailToConnect(/* undefined */); |
| }); |
| } |
| |
| function doConnect(args, getCb) { |
| return [ |
| function createConnectionWithCb() { |
| return net.createConnection.apply(net, args.concat(getCb())) |
| .resume(); |
| }, |
| function createConnectionWithoutCb() { |
| return net.createConnection.apply(net, args) |
| .on('connect', getCb()) |
| .resume(); |
| }, |
| function connectWithCb() { |
| return net.connect.apply(net, args.concat(getCb())) |
| .resume(); |
| }, |
| function connectWithoutCb() { |
| return net.connect.apply(net, args) |
| .on('connect', getCb()) |
| .resume(); |
| }, |
| function socketConnectWithCb() { |
| const socket = new net.Socket(); |
| return socket.connect.apply(socket, args.concat(getCb())) |
| .resume(); |
| }, |
| function socketConnectWithoutCb() { |
| const socket = new net.Socket(); |
| return socket.connect.apply(socket, args) |
| .on('connect', getCb()) |
| .resume(); |
| } |
| ]; |
| } |
| |
| function syncFailToConnect(port, assertErr, optOnly) { |
| if (!optOnly) { |
| // connect(port, cb) and connect(port) |
| const portArgFunctions = doConnect([port], () => common.mustNotCall()); |
| for (const fn of portArgFunctions) { |
| assert.throws(fn, assertErr, `${fn.name}(${port})`); |
| } |
| |
| // connect(port, host, cb) and connect(port, host) |
| const portHostArgFunctions = doConnect([port, 'localhost'], |
| () => common.mustNotCall()); |
| for (const fn of portHostArgFunctions) { |
| assert.throws(fn, assertErr, `${fn.name}(${port}, 'localhost')`); |
| } |
| } |
| // connect({port}, cb) and connect({port}) |
| const portOptFunctions = doConnect([{ port }], () => common.mustNotCall()); |
| for (const fn of portOptFunctions) { |
| assert.throws(fn, assertErr, `${fn.name}({port: ${port}})`); |
| } |
| |
| // connect({port, host}, cb) and connect({port, host}) |
| const portHostOptFunctions = doConnect([{ port: port, host: 'localhost' }], |
| () => common.mustNotCall()); |
| for (const fn of portHostOptFunctions) { |
| assert.throws(fn, |
| assertErr, |
| `${fn.name}({port: ${port}, host: 'localhost'})`); |
| } |
| } |
| |
| function canConnect(port) { |
| const noop = () => common.mustCall(); |
| |
| // connect(port, cb) and connect(port) |
| const portArgFunctions = doConnect([port], noop); |
| for (const fn of portArgFunctions) { |
| fn(); |
| } |
| |
| // connect(port, host, cb) and connect(port, host) |
| const portHostArgFunctions = doConnect([port, 'localhost'], noop); |
| for (const fn of portHostArgFunctions) { |
| fn(); |
| } |
| |
| // connect({port}, cb) and connect({port}) |
| const portOptFunctions = doConnect([{ port }], noop); |
| for (const fn of portOptFunctions) { |
| fn(); |
| } |
| |
| // connect({port, host}, cb) and connect({port, host}) |
| const portHostOptFns = doConnect([{ port, host: 'localhost' }], noop); |
| for (const fn of portHostOptFns) { |
| fn(); |
| } |
| } |
| |
| function asyncFailToConnect(port) { |
| const onError = () => common.mustCall((err) => { |
| const regexp = /^Error: connect E\w+.+$/; |
| assert(regexp.test(String(err)), String(err)); |
| }); |
| |
| const dont = () => common.mustNotCall(); |
| // connect(port, cb) and connect(port) |
| const portArgFunctions = doConnect([port], dont); |
| for (const fn of portArgFunctions) { |
| fn().on('error', onError()); |
| } |
| |
| // connect({port}, cb) and connect({port}) |
| const portOptFunctions = doConnect([{ port }], dont); |
| for (const fn of portOptFunctions) { |
| fn().on('error', onError()); |
| } |
| |
| // connect({port, host}, cb) and connect({port, host}) |
| const portHostOptFns = doConnect([{ port, host: 'localhost' }], dont); |
| for (const fn of portHostOptFns) { |
| fn().on('error', onError()); |
| } |
| } |