Skip to content

Commit

Permalink
child_process: add keepOpen option to send()
Browse files Browse the repository at this point in the history
This option allows an instance of net.Socket to be kept open in
the sending process.

Fixes: #4271
PR-URL: #5283
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
cjihrig authored and Fishrock123 committed Mar 8, 2016
1 parent 6d4887c commit a301799
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
7 changes: 6 additions & 1 deletion doc/api/child_process.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,12 @@ receive the object as the second argument passed to the callback function
registered on the `process.on('message')` event.

The `options` argument, if present, is an object used to parameterize the
sending of certain types of handles.
sending of certain types of handles. `options` supports the following
properties:

* `keepOpen` - A Boolean value that can be used when passing instances of
`net.Socket`. When `true`, the socket is kept open in the sending process.
Defaults to `false`.

The optional `callback` is a function that is invoked after the message is
sent but before the child may have received it. The function is called with a
Expand Down
14 changes: 9 additions & 5 deletions lib/internal/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,25 @@ const handleConversion = {
if (firstTime) socket.server._setupSlave(socketList);

// Act like socket is detached
socket.server._connections--;
if (!options.keepOpen)
socket.server._connections--;
}

var handle = socket._handle;

// remove handle from socket object, it will be closed when the socket
// will be sent
var handle = socket._handle;
handle.onread = function() {};
socket._handle = null;
if (!options.keepOpen) {
handle.onread = function() {};
socket._handle = null;
}

return handle;
},

postSend: function(handle, options) {
// Close the Socket handle after sending it
if (handle)
if (handle && !options.keepOpen)
handle.close();
},

Expand Down
52 changes: 52 additions & 0 deletions test/parallel/test-child-process-send-keep-open.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
const net = require('net');

if (process.argv[2] !== 'child') {
// The parent process forks a child process, starts a TCP server, and connects
// to the server. The accepted connection is passed to the child process,
// where the socket is written. Then, the child signals the parent process to
// write to the same socket.
let result = '';

process.on('exit', () => {
assert.strictEqual(result, 'childparent');
});

const child = cp.fork(__filename, ['child']);

// Verify that the child exits successfully
child.on('exit', common.mustCall((exitCode, signalCode) => {
assert.strictEqual(exitCode, 0);
assert.strictEqual(signalCode, null);
}));

const server = net.createServer((socket) => {
child.on('message', common.mustCall((msg) => {
assert.strictEqual(msg, 'child_done');
socket.end('parent', () => {
server.close();
child.disconnect();
});
}));

child.send('socket', socket, {keepOpen: true}, common.mustCall((err) => {
assert.ifError(err);
}));
});

server.listen(common.PORT, () => {
const socket = net.connect(common.PORT, common.localhostIPv4);
socket.setEncoding('utf8');
socket.on('data', (data) => result += data);
});
} else {
// The child process receives the socket from the parent, writes data to
// the socket, then signals the parent process to write
process.on('message', common.mustCall((msg, socket) => {
assert.strictEqual(msg, 'socket');
socket.write('child', () => process.send('child_done'));
}));
}

0 comments on commit a301799

Please sign in to comment.