• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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