Skip to content

Commit a301799

Browse files
cjihrigFishrock123
authored andcommitted
child_process: add keepOpen option to send()
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 <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 6d4887c commit a301799

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

doc/api/child_process.markdown

+6-1
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,12 @@ receive the object as the second argument passed to the callback function
803803
registered on the `process.on('message')` event.
804804

805805
The `options` argument, if present, is an object used to parameterize the
806-
sending of certain types of handles.
806+
sending of certain types of handles. `options` supports the following
807+
properties:
808+
809+
* `keepOpen` - A Boolean value that can be used when passing instances of
810+
`net.Socket`. When `true`, the socket is kept open in the sending process.
811+
Defaults to `false`.
807812

808813
The optional `callback` is a function that is invoked after the message is
809814
sent but before the child may have received it. The function is called with a

lib/internal/child_process.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,25 @@ const handleConversion = {
7878
if (firstTime) socket.server._setupSlave(socketList);
7979

8080
// Act like socket is detached
81-
socket.server._connections--;
81+
if (!options.keepOpen)
82+
socket.server._connections--;
8283
}
8384

85+
var handle = socket._handle;
86+
8487
// remove handle from socket object, it will be closed when the socket
8588
// will be sent
86-
var handle = socket._handle;
87-
handle.onread = function() {};
88-
socket._handle = null;
89+
if (!options.keepOpen) {
90+
handle.onread = function() {};
91+
socket._handle = null;
92+
}
8993

9094
return handle;
9195
},
9296

9397
postSend: function(handle, options) {
9498
// Close the Socket handle after sending it
95-
if (handle)
99+
if (handle && !options.keepOpen)
96100
handle.close();
97101
},
98102

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const net = require('net');
6+
7+
if (process.argv[2] !== 'child') {
8+
// The parent process forks a child process, starts a TCP server, and connects
9+
// to the server. The accepted connection is passed to the child process,
10+
// where the socket is written. Then, the child signals the parent process to
11+
// write to the same socket.
12+
let result = '';
13+
14+
process.on('exit', () => {
15+
assert.strictEqual(result, 'childparent');
16+
});
17+
18+
const child = cp.fork(__filename, ['child']);
19+
20+
// Verify that the child exits successfully
21+
child.on('exit', common.mustCall((exitCode, signalCode) => {
22+
assert.strictEqual(exitCode, 0);
23+
assert.strictEqual(signalCode, null);
24+
}));
25+
26+
const server = net.createServer((socket) => {
27+
child.on('message', common.mustCall((msg) => {
28+
assert.strictEqual(msg, 'child_done');
29+
socket.end('parent', () => {
30+
server.close();
31+
child.disconnect();
32+
});
33+
}));
34+
35+
child.send('socket', socket, {keepOpen: true}, common.mustCall((err) => {
36+
assert.ifError(err);
37+
}));
38+
});
39+
40+
server.listen(common.PORT, () => {
41+
const socket = net.connect(common.PORT, common.localhostIPv4);
42+
socket.setEncoding('utf8');
43+
socket.on('data', (data) => result += data);
44+
});
45+
} else {
46+
// The child process receives the socket from the parent, writes data to
47+
// the socket, then signals the parent process to write
48+
process.on('message', common.mustCall((msg, socket) => {
49+
assert.strictEqual(msg, 'socket');
50+
socket.write('child', () => process.send('child_done'));
51+
}));
52+
}

0 commit comments

Comments
 (0)