• 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 fork = require('child_process').fork;
26const net = require('net');
27const count = 12;
28
29if (process.argv[2] === 'child') {
30  const sockets = [];
31
32  process.on('message', common.mustCall((m, socket) => {
33    function sendClosed(id) {
34      process.send({ id: id, status: 'closed' });
35    }
36
37    if (m.cmd === 'new') {
38      assert(socket);
39      assert(socket instanceof net.Socket, 'should be a net.Socket');
40      sockets.push(socket);
41    }
42
43    if (m.cmd === 'close') {
44      assert.strictEqual(socket, undefined);
45      if (sockets[m.id].destroyed) {
46        // Workaround for https://github.com/nodejs/node/issues/2610
47        sendClosed(m.id);
48        // End of workaround. When bug is fixed, this code can be used instead:
49        // throw new Error('socket destroyed unexpectedly!');
50      } else {
51        sockets[m.id].once('close', sendClosed.bind(null, m.id));
52        sockets[m.id].destroy();
53      }
54    }
55  }));
56
57} else {
58  const child = fork(process.argv[1], ['child']);
59
60  child.on('exit', common.mustCall((code, signal) => {
61    if (!subprocessKilled) {
62      assert.fail('subprocess died unexpectedly! ' +
63                  `code: ${code} signal: ${signal}`);
64    }
65  }));
66
67  const server = net.createServer();
68  const sockets = [];
69
70  server.on('connection', common.mustCall((socket) => {
71    child.send({ cmd: 'new' }, socket);
72    sockets.push(socket);
73
74    if (sockets.length === count) {
75      closeSockets(0);
76    }
77  }, count));
78
79  const onClose = common.mustCall(count);
80
81  server.on('listening', common.mustCall(() => {
82    let j = count;
83    while (j--) {
84      const client = net.connect(server.address().port, '127.0.0.1');
85      client.on('close', onClose);
86    }
87  }));
88
89  let subprocessKilled = false;
90  function closeSockets(i) {
91    if (i === count) {
92      subprocessKilled = true;
93      server.close();
94      child.kill();
95      return;
96    }
97
98    child.once('message', common.mustCall((m) => {
99      assert.strictEqual(m.status, 'closed');
100      server.getConnections(common.mustSucceed((num) => {
101        assert.strictEqual(num, count - (i + 1));
102        closeSockets(i + 1);
103      }));
104    }));
105    child.send({ id: i, cmd: 'close' });
106  }
107
108  server.on('close', common.mustCall());
109
110  server.listen(0, '127.0.0.1');
111}
112