Skip to content

Commit e9d6c4b

Browse files
author
laino
committed
cluster: correctly handle relative unix socket paths
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. Fixes: nodejs#16387
1 parent 17db46c commit e9d6c4b

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

lib/internal/cluster/child.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
const assert = require('assert');
33
const util = require('util');
4+
const path = require('path');
45
const EventEmitter = require('events');
56
const Worker = require('internal/cluster/worker');
67
const { internal, sendHelper } = require('internal/cluster/utils');
@@ -48,7 +49,14 @@ cluster._setupWorker = function() {
4849

4950
// obj is a net#Server or a dgram#Socket object.
5051
cluster._getServer = function(obj, options, cb) {
51-
const indexesKey = [options.address,
52+
let address = options.address;
53+
54+
// Resolve unix socket paths to absolute paths
55+
if (options.port < 0 && typeof address === 'string' &&
56+
process.platform !== 'win32')
57+
address = path.resolve(address);
58+
59+
const indexesKey = [address,
5260
options.port,
5361
options.addressType,
5462
options.fd ].join(':');
@@ -64,6 +72,8 @@ cluster._getServer = function(obj, options, cb) {
6472
data: null
6573
}, options);
6674

75+
message.address = address;
76+
6777
// Set custom data on handle (i.e. tls tickets key)
6878
if (obj._getServerData)
6979
message.data = obj._getServerData();

lib/internal/cluster/master.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const assert = require('assert');
33
const { fork } = require('child_process');
44
const util = require('util');
5+
const path = require('path');
56
const EventEmitter = require('events');
67
const RoundRobinHandle = require('internal/cluster/round_robin_handle');
78
const SharedHandle = require('internal/cluster/shared_handle');
@@ -275,6 +276,18 @@ function queryServer(worker, message) {
275276
var handle = handles[key];
276277

277278
if (handle === undefined) {
279+
let address = message.address;
280+
281+
// Find shortest path for unix sockets because of the ~100 byte limit
282+
if (message.port < 0 && typeof address === 'string' &&
283+
process.platform !== 'win32') {
284+
285+
address = path.relative(process.cwd(), address);
286+
287+
if (message.address.length < address.length)
288+
address = message.address;
289+
}
290+
278291
var constructor = RoundRobinHandle;
279292
// UDP is exempt from round-robin connection balancing for what should
280293
// be obvious reasons: it's connectionless. There is nothing to send to
@@ -286,7 +299,7 @@ function queryServer(worker, message) {
286299
}
287300

288301
handles[key] = handle = new constructor(key,
289-
message.address,
302+
address,
290303
message.port,
291304
message.addressType,
292305
message.fd,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
const path = require('path');
7+
const fs = require('fs');
8+
9+
// Ref:
10+
// https://github.com/nodejs/node/issues/16387
11+
// https://github.com/nodejs/node/pull/16749
12+
13+
if (common.isWindows)
14+
common.skip('On Windows named pipes live in their own ' +
15+
'filesystem and don\'t have a ~100 byte limit');
16+
17+
// Choose a socket name such that the absolute path would exceed 100 bytes.
18+
const socketDir = './unix-socket-dir';
19+
const socketName = 'A'.repeat(100 - socketDir.length - 1);
20+
21+
// Make sure we're not in a weird environment
22+
assert.strictEqual(path.resolve(socketDir, socketName).length > 100, true,
23+
'absolute socket path should be longer than 100 bytes');
24+
25+
if (cluster.isMaster) {
26+
// ensure that the worker exits peacefully
27+
process.chdir(common.tmpDir);
28+
fs.mkdirSync(socketDir);
29+
cluster.fork().on('exit', common.mustCall(function(statusCode) {
30+
assert.strictEqual(statusCode, 0);
31+
32+
assert.strictEqual(
33+
fs.existsSync(path.join(socketDir, socketName)), false,
34+
'Socket should be removed when the worker exits');
35+
}));
36+
} else {
37+
process.chdir(socketDir);
38+
39+
const server = net.createServer(common.mustNotCall());
40+
41+
server.listen(socketName, common.mustCall(function() {
42+
assert.strictEqual(
43+
fs.existsSync(socketName), true,
44+
'Socket created in CWD');
45+
46+
process.disconnect();
47+
}));
48+
}

0 commit comments

Comments
 (0)