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