Skip to content

Commit

Permalink
cluster: resolve relative unix socket paths
Browse files Browse the repository at this point in the history
Relative unix sockets paths were previously interpreted relative
to the master's CWD, which was inconsistent with non-cluster behavior.
A test case has been added as well.

PR-URL: #16749
Fixes: #16387
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
laino authored and evanlucas committed Jan 30, 2018
1 parent f81c622 commit 6b687cf
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
12 changes: 11 additions & 1 deletion lib/internal/cluster/child.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';
const assert = require('assert');
const util = require('util');
const path = require('path');
const EventEmitter = require('events');
const Worker = require('internal/cluster/worker');
const { internal, sendHelper } = require('internal/cluster/utils');
Expand Down Expand Up @@ -48,7 +49,14 @@ cluster._setupWorker = function() {

// obj is a net#Server or a dgram#Socket object.
cluster._getServer = function(obj, options, cb) {
const indexesKey = [options.address,
let address = options.address;

// Resolve unix socket paths to absolute paths
if (options.port < 0 && typeof address === 'string' &&
process.platform !== 'win32')
address = path.resolve(address);

const indexesKey = [address,
options.port,
options.addressType,
options.fd ].join(':');
Expand All @@ -64,6 +72,8 @@ cluster._getServer = function(obj, options, cb) {
data: null
}, options);

message.address = address;

// Set custom data on handle (i.e. tls tickets key)
if (obj._getServerData)
message.data = obj._getServerData();
Expand Down
15 changes: 14 additions & 1 deletion lib/internal/cluster/master.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const assert = require('assert');
const { fork } = require('child_process');
const util = require('util');
const path = require('path');
const EventEmitter = require('events');
const RoundRobinHandle = require('internal/cluster/round_robin_handle');
const SharedHandle = require('internal/cluster/shared_handle');
Expand Down Expand Up @@ -276,6 +277,18 @@ function queryServer(worker, message) {
var handle = handles[key];

if (handle === undefined) {
let address = message.address;

// Find shortest path for unix sockets because of the ~100 byte limit
if (message.port < 0 && typeof address === 'string' &&
process.platform !== 'win32') {

address = path.relative(process.cwd(), address);

if (message.address.length < address.length)
address = message.address;
}

var constructor = RoundRobinHandle;
// UDP is exempt from round-robin connection balancing for what should
// be obvious reasons: it's connectionless. There is nothing to send to
Expand All @@ -287,7 +300,7 @@ function queryServer(worker, message) {
}

handles[key] = handle = new constructor(key,
message.address,
address,
message.port,
message.addressType,
message.fd,
Expand Down
44 changes: 44 additions & 0 deletions test/parallel/test-cluster-net-listen-relative-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const cluster = require('cluster');
const net = require('net');
const path = require('path');
const fs = require('fs');

if (common.isWindows)
common.skip('On Windows named pipes live in their own ' +
'filesystem and don\'t have a ~100 byte limit');

// Choose a socket name such that the absolute path would exceed 100 bytes.
const socketDir = './unix-socket-dir';
const socketName = 'A'.repeat(100 - socketDir.length - 1);

// Make sure we're not in a weird environment
assert.strictEqual(path.resolve(socketDir, socketName).length > 100, true,
'absolute socket path should be longer than 100 bytes');

if (cluster.isMaster) {
// ensure that the worker exits peacefully
process.chdir(common.tmpDir);
fs.mkdirSync(socketDir);
cluster.fork().on('exit', common.mustCall(function(statusCode) {
assert.strictEqual(statusCode, 0);

assert.strictEqual(
fs.existsSync(path.join(socketDir, socketName)), false,
'Socket should be removed when the worker exits');
}));
} else {
process.chdir(socketDir);

const server = net.createServer(common.mustNotCall());

server.listen(socketName, common.mustCall(function() {
assert.strictEqual(
fs.existsSync(socketName), true,
'Socket created in CWD');

process.disconnect();
}));
}

0 comments on commit 6b687cf

Please sign in to comment.