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 net = require('net');
|
||||||
var dgram = require('dgram');
|
var dgram = require('dgram');
|
||||||
var Process = process.binding('process_wrap').Process;
|
var Process = process.binding('process_wrap').Process;
|
||||||
|
var assert = require('assert');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var constants; // if (!constants) constants = process.binding('constants');
|
var constants; // if (!constants) constants = process.binding('constants');
|
||||||
|
|
||||||
@ -321,6 +322,7 @@ function handleMessage(target, message, handle) {
|
|||||||
|
|
||||||
function setupChannel(target, channel) {
|
function setupChannel(target, channel) {
|
||||||
target._channel = channel;
|
target._channel = channel;
|
||||||
|
target._handleQueue = null;
|
||||||
|
|
||||||
var decoder = new StringDecoder('utf8');
|
var decoder = new StringDecoder('utf8');
|
||||||
var jsonBuffer = '';
|
var jsonBuffer = '';
|
||||||
@ -358,8 +360,22 @@ function setupChannel(target, channel) {
|
|||||||
|
|
||||||
// handlers will go through this
|
// handlers will go through this
|
||||||
target.on('internalMessage', function(message, handle) {
|
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;
|
if (message.cmd !== 'NODE_HANDLE') return;
|
||||||
|
|
||||||
|
// Acknowledge handle receival.
|
||||||
|
target.send({ cmd: 'NODE_HANDLE_ACK' });
|
||||||
|
|
||||||
var obj = handleConversion[message.type];
|
var obj = handleConversion[message.type];
|
||||||
|
|
||||||
// Update simultaneous accepts on Windows
|
// Update simultaneous accepts on Windows
|
||||||
@ -389,6 +405,7 @@ function setupChannel(target, channel) {
|
|||||||
// this message will be handled by an internalMessage event handler
|
// this message will be handled by an internalMessage event handler
|
||||||
message = {
|
message = {
|
||||||
cmd: 'NODE_HANDLE',
|
cmd: 'NODE_HANDLE',
|
||||||
|
type: null,
|
||||||
msg: message
|
msg: message
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -407,6 +424,12 @@ function setupChannel(target, channel) {
|
|||||||
throw new TypeError("This handle type can't be sent");
|
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];
|
var obj = handleConversion[message.type];
|
||||||
|
|
||||||
// convert TCP object to native handle object
|
// convert TCP object to native handle object
|
||||||
@ -416,6 +439,10 @@ function setupChannel(target, channel) {
|
|||||||
if (obj.simultaneousAccepts) {
|
if (obj.simultaneousAccepts) {
|
||||||
net._setSimultaneousAccepts(handle);
|
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';
|
var string = JSON.stringify(message) + '\n';
|
||||||
@ -426,6 +453,8 @@ function setupChannel(target, channel) {
|
|||||||
'write',
|
'write',
|
||||||
'cannot write to IPC channel.');
|
'cannot write to IPC channel.');
|
||||||
this.emit('error', er);
|
this.emit('error', er);
|
||||||
|
} else if (handle && !this._handleQueue) {
|
||||||
|
this._handleQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj && obj.postSend) {
|
if (obj && obj.postSend) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user