Skip to content

Commit cc6ec2f

Browse files
bnoordhuisjasnell
authored andcommitted
inspector: bind to random port with --inspect=0
Allow binding to a randomly assigned port number with `--inspect=0` or `--inspect-brk=0`. PR-URL: #5025 Refs: #4419 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Sam Roberts <[email protected]>
1 parent a2d4954 commit cc6ec2f

6 files changed

+99
-4
lines changed

src/inspector_io.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ InspectorIo::InspectorIo(Environment* env, v8::Platform* platform,
175175
io_thread_req_(), platform_(platform),
176176
dispatching_messages_(false), session_id_(0),
177177
script_name_(path),
178-
wait_for_connect_(wait_for_connect) {
178+
wait_for_connect_(wait_for_connect), port_(-1) {
179179
main_thread_req_ = new AsyncAndAgent({uv_async_t(), env->inspector_agent()});
180180
CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_->first,
181181
InspectorIo::MainThreadAsyncCb));
@@ -298,6 +298,7 @@ void InspectorIo::WorkerRunIO() {
298298
uv_sem_post(&start_sem_);
299299
return;
300300
}
301+
port_ = server.port(); // Safe, main thread is waiting on semaphore.
301302
if (!wait_for_connect_) {
302303
uv_sem_post(&start_sem_);
303304
}

src/inspector_io.h

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class InspectorIo {
6868
uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);
6969
}
7070

71+
int port() const { return port_; }
72+
7173
private:
7274
template <typename Action>
7375
using MessageQueue =
@@ -129,6 +131,7 @@ class InspectorIo {
129131
std::string script_path_;
130132
const std::string id_;
131133
const bool wait_for_connect_;
134+
int port_;
132135

133136
friend class DispatchMessagesTask;
134137
friend class IoSessionDelegate;

src/node.cc

+13-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
#include "node_i18n.h"
4141
#endif
4242

43+
#if HAVE_INSPECTOR
44+
#include "inspector_io.h"
45+
#endif
46+
4347
#if defined HAVE_DTRACE || defined HAVE_ETW
4448
#include "node_dtrace.h"
4549
#endif
@@ -3048,7 +3052,15 @@ static Local<Object> GetFeatures(Environment* env) {
30483052

30493053
static void DebugPortGetter(Local<Name> property,
30503054
const PropertyCallbackInfo<Value>& info) {
3051-
info.GetReturnValue().Set(debug_options.port());
3055+
int port = debug_options.port();
3056+
#if HAVE_INSPECTOR
3057+
if (port == 0) {
3058+
Environment* env = Environment::GetCurrent(info);
3059+
if (env->inspector_agent()->IsStarted())
3060+
port = env->inspector_agent()->io()->port();
3061+
}
3062+
#endif // HAVE_INSPECTOR
3063+
info.GetReturnValue().Set(port);
30523064
}
30533065

30543066

src/node_debug_options.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ int parse_and_validate_port(const std::string& port) {
2121
char* endptr;
2222
errno = 0;
2323
const long result = strtol(port.c_str(), &endptr, 10); // NOLINT(runtime/int)
24-
if (errno != 0 || *endptr != '\0'|| result < 1024 || result > 65535) {
25-
fprintf(stderr, "Debug port must be in range 1024 to 65535.\n");
24+
if (errno != 0 || *endptr != '\0'||
25+
(result != 0 && result < 1024) || result > 65535) {
26+
fprintf(stderr, "Debug port must be 0 or in range 1024 to 65535.\n");
2627
exit(12);
2728
}
2829
return static_cast<int>(result);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Flags: --inspect=0
2+
'use strict';
3+
4+
const common = require('../common');
5+
const assert = require('assert');
6+
const cluster = require('cluster');
7+
8+
if (cluster.isMaster) {
9+
const ports = [];
10+
for (const worker of [cluster.fork(),
11+
cluster.fork(),
12+
cluster.fork()]) {
13+
worker.on('message', common.mustCall((message) => {
14+
ports.push(message.debugPort);
15+
worker.kill();
16+
}));
17+
worker.send('debugPort');
18+
}
19+
process.on('exit', () => {
20+
ports.sort();
21+
assert.strictEqual(ports.length, 3);
22+
assert(ports.every((port) => port > 0));
23+
assert(ports.every((port) => port < 65536));
24+
assert.strictEqual(ports[0] + 1, ports[1]); // Ports should be consecutive.
25+
assert.strictEqual(ports[1] + 1, ports[2]);
26+
});
27+
} else {
28+
process.on('message', (message) => {
29+
if (message === 'debugPort')
30+
process.send({ debugPort: process.debugPort });
31+
});
32+
}
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const { mustCall } = require('../common');
4+
const assert = require('assert');
5+
const { URL } = require('url');
6+
const { spawn } = require('child_process');
7+
8+
function test(arg) {
9+
const args = [arg, '-p', 'process.debugPort'];
10+
const proc = spawn(process.execPath, args);
11+
proc.stdout.setEncoding('utf8');
12+
proc.stderr.setEncoding('utf8');
13+
let stdout = '';
14+
let stderr = '';
15+
proc.stdout.on('data', (data) => stdout += data);
16+
proc.stderr.on('data', (data) => stderr += data);
17+
proc.stdout.on('close', assert.ifError);
18+
proc.stderr.on('close', assert.ifError);
19+
let port = '';
20+
proc.stderr.on('data', () => {
21+
if (!stderr.includes('\n')) return;
22+
assert(/Debugger listening on (.+)/.test(stderr));
23+
port = new URL(RegExp.$1).port;
24+
assert(+port > 0);
25+
});
26+
if (/inspect-brk/.test(arg)) {
27+
proc.stderr.on('data', () => {
28+
if (stderr.includes('\n') && !proc.killed) proc.kill();
29+
});
30+
} else {
31+
let onclose = () => {
32+
onclose = () => assert.strictEqual(port, stdout.trim());
33+
};
34+
proc.stdout.on('close', mustCall(() => onclose()));
35+
proc.stderr.on('close', mustCall(() => onclose()));
36+
proc.on('exit', mustCall((exitCode) => assert.strictEqual(exitCode, 0)));
37+
}
38+
}
39+
40+
test('--inspect=0');
41+
test('--inspect=127.0.0.1:0');
42+
test('--inspect=localhost:0');
43+
44+
test('--inspect-brk=0');
45+
test('--inspect-brk=127.0.0.1:0');
46+
test('--inspect-brk=localhost:0');

0 commit comments

Comments
 (0)