• 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([{ 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