| 'use strict'; |
| const common = require('../common'); |
| |
| // Before https://github.com/nodejs/node/pull/2847 a child process trying |
| // (asynchronously) to use the closed channel to it's creator caused a segfault. |
| |
| const assert = require('assert'); |
| const cluster = require('cluster'); |
| const net = require('net'); |
| |
| if (!cluster.isMaster) { |
| // Exit on first received handle to leave the queue non-empty in master |
| process.on('message', function() { |
| process.exit(1); |
| }); |
| return; |
| } |
| |
| const server = net |
| .createServer(function(s) { |
| if (common.isWindows) { |
| s.on('error', function(err) { |
| // Prevent possible ECONNRESET errors from popping up |
| if (err.code !== 'ECONNRESET') throw err; |
| }); |
| } |
| setTimeout(function() { |
| s.destroy(); |
| }, 100); |
| }) |
| .listen(0, function() { |
| const worker = cluster.fork(); |
| |
| worker.on('error', function(err) { |
| if ( |
| err.code !== 'ECONNRESET' && |
| err.code !== 'ECONNREFUSED' && |
| err.code !== 'EMFILE' |
| ) { |
| throw err; |
| } |
| }); |
| |
| function send(callback) { |
| const s = net.connect(server.address().port, function() { |
| worker.send({}, s, callback); |
| }); |
| |
| // https://github.com/nodejs/node/issues/3635#issuecomment-157714683 |
| // ECONNREFUSED or ECONNRESET errors can happen if this connection is |
| // still establishing while the server has already closed. |
| // EMFILE can happen if the worker __and__ the server had already closed. |
| s.on('error', function(err) { |
| if ( |
| err.code !== 'ECONNRESET' && |
| err.code !== 'ECONNREFUSED' && |
| err.code !== 'EMFILE' |
| ) { |
| throw err; |
| } |
| }); |
| } |
| |
| worker.process.once( |
| 'close', |
| common.mustCall(function() { |
| // Otherwise the crash on `channel.fd` access may happen |
| assert.strictEqual(worker.process.channel, null); |
| server.close(); |
| }) |
| ); |
| |
| worker.on('online', function() { |
| send(function(err) { |
| assert.ifError(err); |
| send(function(err) { |
| // Ignore errors when sending the second handle because the worker |
| // may already have exited. |
| if (err && err.code !== 'ERR_IPC_CHANNEL_CLOSED' && |
| err.code !== 'ECONNRESET' && |
| err.code !== 'ECONNREFUSED' && |
| err.code !== 'EMFILE') { |
| throw err; |
| } |
| }); |
| }); |
| }); |
| }); |