child_process: acknowledge sent handles
Fix race-condition when multiple handles are sent and SCM_RIGHTS messages are gets merged by OS by avoiding sending multiple handles at once! fix #4885
This commit is contained in:
parent
4716dc662d
commit
5902bc45c5
@ -24,6 +24,7 @@ var EventEmitter = require('events').EventEmitter;
|
||||
var net = require('net');
|
||||
var dgram = require('dgram');
|
||||
var Process = process.binding('process_wrap').Process;
|
||||
var assert = require('assert');
|
||||
var util = require('util');
|
||||
var constants; // if (!constants) constants = process.binding('constants');
|
||||
|
||||
@ -321,6 +322,7 @@ function handleMessage(target, message, handle) {
|
||||
|
||||
function setupChannel(target, channel) {
|
||||
target._channel = channel;
|
||||
target._handleQueue = null;
|
||||
|
||||
var decoder = new StringDecoder('utf8');
|
||||
var jsonBuffer = '';
|
||||
@ -358,8 +360,22 @@ function setupChannel(target, channel) {
|
||||
|
||||
// handlers will go through this
|
||||
target.on('internalMessage', function(message, handle) {
|
||||
// Once acknowledged - continue sending handles.
|
||||
if (message.cmd === 'NODE_HANDLE_ACK') {
|
||||
assert(Array.isArray(target._handleQueue));
|
||||
var queue = target._handleQueue;
|
||||
target._handleQueue = null;
|
||||
queue.forEach(function(args) {
|
||||
target.send(args.message, args.handle);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.cmd !== 'NODE_HANDLE') return;
|
||||
|
||||
// Acknowledge handle receival.
|
||||
target.send({ cmd: 'NODE_HANDLE_ACK' });
|
||||
|
||||
var obj = handleConversion[message.type];
|
||||
|
||||
// Update simultaneous accepts on Windows
|
||||
@ -389,6 +405,7 @@ function setupChannel(target, channel) {
|
||||
// this message will be handled by an internalMessage event handler
|
||||
message = {
|
||||
cmd: 'NODE_HANDLE',
|
||||
type: null,
|
||||
msg: message
|
||||
};
|
||||
|
||||
@ -407,6 +424,12 @@ function setupChannel(target, channel) {
|
||||
throw new TypeError("This handle type can't be sent");
|
||||
}
|
||||
|
||||
// Queue-up message and handle if we haven't received ACK yet.
|
||||
if (this._handleQueue) {
|
||||
this._handleQueue.push({ message: message.msg, handle: handle });
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = handleConversion[message.type];
|
||||
|
||||
// convert TCP object to native handle object
|
||||
@ -416,6 +439,10 @@ function setupChannel(target, channel) {
|
||||
if (obj.simultaneousAccepts) {
|
||||
net._setSimultaneousAccepts(handle);
|
||||
}
|
||||
} else if (this._handleQueue) {
|
||||
// Queue request anyway to avoid out-of-order messages.
|
||||
this._handleQueue.push({ message: message, handle: null });
|
||||
return;
|
||||
}
|
||||
|
||||
var string = JSON.stringify(message) + '\n';
|
||||
@ -426,6 +453,8 @@ function setupChannel(target, channel) {
|
||||
'write',
|
||||
'cannot write to IPC channel.');
|
||||
this.emit('error', er);
|
||||
} else if (handle && !this._handleQueue) {
|
||||
this._handleQueue = [];
|
||||
}
|
||||
|
||||
if (obj && obj.postSend) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user