1'use strict'; 2const common = require('../common'); 3 4// On some OS X versions, when passing fd's between processes: 5// When the handle associated to a specific file descriptor is closed by the 6// sender process before it's received in the destination, the handle is indeed 7// closed while it should remain opened. In order to fix this behavior, don't 8// close the handle until the `NODE_HANDLE_ACK` is received by the sender. 9// This test is basically `test-cluster-net-send` but creating lots of workers 10// so the issue reproduces on OS X consistently. 11 12if ((process.config.variables.arm_version === '6') || 13 (process.config.variables.arm_version === '7')) 14 common.skip('Too slow for armv6 and armv7 bots'); 15 16const assert = require('assert'); 17const { fork } = require('child_process'); 18const net = require('net'); 19 20const N = 80; 21let messageCallbackCount = 0; 22 23function forkWorker() { 24 const messageCallback = (msg, handle) => { 25 messageCallbackCount++; 26 assert.strictEqual(msg, 'handle'); 27 assert.ok(handle); 28 worker.send('got'); 29 30 let recvData = ''; 31 handle.on('data', common.mustCall((data) => { 32 recvData += data; 33 })); 34 35 handle.on('end', () => { 36 assert.strictEqual(recvData, 'hello'); 37 worker.kill(); 38 }); 39 }; 40 41 const worker = fork(__filename, ['child']); 42 worker.on('error', (err) => { 43 if (/\bEAGAIN\b/.test(err.message)) { 44 forkWorker(); 45 return; 46 } 47 throw err; 48 }); 49 worker.once('message', messageCallback); 50} 51 52if (process.argv[2] !== 'child') { 53 for (let i = 0; i < N; ++i) { 54 forkWorker(); 55 } 56 process.on('exit', () => { assert.strictEqual(messageCallbackCount, N); }); 57} else { 58 let socket; 59 let cbcalls = 0; 60 function socketConnected() { 61 if (++cbcalls === 2) 62 process.send('handle', socket); 63 } 64 65 // As a side-effect, listening for the message event will ref the IPC channel, 66 // so the child process will stay alive as long as it has a parent process/IPC 67 // channel. Once this is done, we can unref our client and server sockets, and 68 // the only thing keeping this worker alive will be IPC. This is important, 69 // because it means a worker with no parent will have no referenced handles, 70 // thus no work to do, and will exit immediately, preventing process leaks. 71 process.on('message', common.mustCall()); 72 73 const server = net.createServer((c) => { 74 process.once('message', (msg) => { 75 assert.strictEqual(msg, 'got'); 76 c.end('hello'); 77 }); 78 socketConnected(); 79 }).unref(); 80 server.listen(0, common.localhostIPv4, () => { 81 const { port } = server.address(); 82 socket = net.connect(port, common.localhostIPv4, socketConnected).unref(); 83 }); 84} 85