Skip to content

Commit 748e424

Browse files
bnoordhuisMyles Borins
authored and
Myles Borins
committed
debugger: make listen address configurable
`--debug=1.2.3.4:5678` and `--debug=example.com:5678` are now accepted, likewise the `--debug-brk` and `--debug-port` switch. The latter is now something of a misnomer but it's undocumented and for internal use only so it shouldn't matter too much. `--inspect=1.2.3.4:5678` and `--inspect=example.com:5678` are also accepted but don't use the host name yet; they still bind to the default address. Fixes: #3306 PR-URL: #3316 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
1 parent 9a02414 commit 748e424

10 files changed

+124
-28
lines changed

lib/_debug_agent.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ exports.start = function start() {
1818
process._rawDebug(err.stack || err);
1919
});
2020

21-
agent.listen(process._debugAPI.port, function() {
22-
var addr = this.address();
23-
process._rawDebug('Debugger listening on port %d', addr.port);
21+
agent.listen(process._debugAPI.port, process._debugAPI.host, function() {
22+
const addr = this.address();
23+
const host = net.isIPv6(addr.address) ? `[${addr.address}]` : addr.address;
24+
process._rawDebug('Debugger listening on %s:%d', host, addr.port);
2425
process._debugAPI.notifyListen();
2526
});
2627

src/debug-agent.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ using v8::Integer;
4444
using v8::Isolate;
4545
using v8::Local;
4646
using v8::Locker;
47+
using v8::NewStringType;
4748
using v8::Object;
4849
using v8::String;
4950
using v8::Value;
@@ -69,7 +70,7 @@ Agent::~Agent() {
6970
}
7071

7172

72-
bool Agent::Start(int port, bool wait) {
73+
bool Agent::Start(const std::string& host, int port, bool wait) {
7374
int err;
7475

7576
if (state_ == kRunning)
@@ -85,6 +86,7 @@ bool Agent::Start(int port, bool wait) {
8586
goto async_init_failed;
8687
uv_unref(reinterpret_cast<uv_handle_t*>(&child_signal_));
8788

89+
host_ = host;
8890
port_ = port;
8991
wait_ = wait;
9092

@@ -211,6 +213,10 @@ void Agent::InitAdaptor(Environment* env) {
211213
Local<Object> api = t->GetFunction()->NewInstance();
212214
api->SetAlignedPointerInInternalField(0, this);
213215

216+
api->Set(String::NewFromUtf8(isolate, "host",
217+
NewStringType::kNormal).ToLocalChecked(),
218+
String::NewFromUtf8(isolate, host_.data(), NewStringType::kNormal,
219+
host_.size()).ToLocalChecked());
214220
api->Set(String::NewFromUtf8(isolate, "port"), Integer::New(isolate, port_));
215221

216222
env->process_object()->Set(String::NewFromUtf8(isolate, "_debugAPI"), api);

src/debug-agent.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "v8-debug.h"
3131

3232
#include <string.h>
33+
#include <string>
3334

3435
// Forward declaration to break recursive dependency chain with src/env.h.
3536
namespace node {
@@ -73,7 +74,7 @@ class Agent {
7374
typedef void (*DispatchHandler)(node::Environment* env);
7475

7576
// Start the debugger agent thread
76-
bool Start(int port, bool wait);
77+
bool Start(const std::string& host, int port, bool wait);
7778
// Listen for debug events
7879
void Enable();
7980
// Stop the debugger agent
@@ -112,6 +113,7 @@ class Agent {
112113

113114
State state_;
114115

116+
std::string host_;
115117
int port_;
116118
bool wait_;
117119

src/node.cc

+48-8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
#include <stdlib.h>
5959
#include <string.h>
6060
#include <sys/types.h>
61+
62+
#include <string>
6163
#include <vector>
6264

6365
#if defined(NODE_HAVE_I18N_SUPPORT)
@@ -139,6 +141,7 @@ static unsigned int preload_module_count = 0;
139141
static const char** preload_modules = nullptr;
140142
static bool use_debug_agent = false;
141143
static bool debug_wait_connect = false;
144+
static std::string debug_host; // NOLINT(runtime/string)
142145
static int debug_port = 5858;
143146
static bool prof_process = false;
144147
static bool v8_is_profiling = false;
@@ -3288,20 +3291,55 @@ static bool ParseDebugOpt(const char* arg) {
32883291
debug_wait_connect = true;
32893292
port = arg + sizeof("--debug-brk=") - 1;
32903293
} else if (!strncmp(arg, "--debug-port=", sizeof("--debug-port=") - 1)) {
3294+
// XXX(bnoordhuis) Misnomer, configures port and listen address.
32913295
port = arg + sizeof("--debug-port=") - 1;
32923296
} else {
32933297
return false;
32943298
}
32953299

3296-
if (port != nullptr) {
3297-
debug_port = atoi(port);
3298-
if (debug_port < 1024 || debug_port > 65535) {
3299-
fprintf(stderr, "Debug port must be in range 1024 to 65535.\n");
3300-
PrintHelp();
3301-
exit(12);
3300+
if (port == nullptr) {
3301+
return true;
3302+
}
3303+
3304+
std::string* const the_host = &debug_host;
3305+
int* const the_port = &debug_port;
3306+
3307+
// FIXME(bnoordhuis) Move IPv6 address parsing logic to lib/net.js.
3308+
// It seems reasonable to support [address]:port notation
3309+
// in net.Server#listen() and net.Socket#connect().
3310+
const size_t port_len = strlen(port);
3311+
if (port[0] == '[' && port[port_len - 1] == ']') {
3312+
the_host->assign(port + 1, port_len - 2);
3313+
return true;
3314+
}
3315+
3316+
const char* const colon = strrchr(port, ':');
3317+
if (colon == nullptr) {
3318+
// Either a port number or a host name. Assume that
3319+
// if it's not all decimal digits, it's a host name.
3320+
for (size_t n = 0; port[n] != '\0'; n += 1) {
3321+
if (port[n] < '0' || port[n] > '9') {
3322+
*the_host = port;
3323+
return true;
3324+
}
33023325
}
3326+
} else {
3327+
const bool skip = (colon > port && port[0] == '[' && colon[-1] == ']');
3328+
the_host->assign(port + skip, colon - skip);
33033329
}
33043330

3331+
char* endptr;
3332+
errno = 0;
3333+
const char* const digits = colon != nullptr ? colon + 1 : port;
3334+
const long result = strtol(digits, &endptr, 10); // NOLINT(runtime/int)
3335+
if (errno != 0 || *endptr != '\0' || result < 1024 || result > 65535) {
3336+
fprintf(stderr, "Debug port must be in range 1024 to 65535.\n");
3337+
PrintHelp();
3338+
exit(12);
3339+
}
3340+
3341+
*the_port = static_cast<int>(result);
3342+
33053343
return true;
33063344
}
33073345

@@ -3539,9 +3577,11 @@ static void StartDebug(Environment* env, bool wait) {
35393577

35403578
env->debugger_agent()->set_dispatch_handler(
35413579
DispatchMessagesDebugAgentCallback);
3542-
debugger_running = env->debugger_agent()->Start(debug_port, wait);
3580+
debugger_running =
3581+
env->debugger_agent()->Start(debug_host, debug_port, wait);
35433582
if (debugger_running == false) {
3544-
fprintf(stderr, "Starting debugger on port %d failed\n", debug_port);
3583+
fprintf(stderr, "Starting debugger on %s:%d failed\n",
3584+
debug_host.c_str(), debug_port);
35453585
fflush(stderr);
35463586
return;
35473587
}

test/parallel/test-cluster-disconnect-handles.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ cluster.schedulingPolicy = cluster.SCHED_RR;
2525
if (cluster.isMaster) {
2626
let isKilling = false;
2727
const handles = require('internal/cluster').handles;
28-
// FIXME(bnoordhuis) lib/cluster.js scans the execArgv arguments for
29-
// debugger flags and renumbers any port numbers it sees starting
30-
// from the default port 5858. Add a '.' that circumvents the
31-
// scanner but is ignored by atoi(3). Heinous hack.
32-
cluster.setupMaster({ execArgv: [`--debug=${common.PORT}.`] });
28+
const address = common.hasIPv6 ? '[::1]' : common.localhostIPv4;
29+
cluster.setupMaster({ execArgv: [`--debug=${address}:${common.PORT}`] });
3330
const worker = cluster.fork();
3431
worker.once('exit', common.mustCall((code, signal) => {
3532
assert.strictEqual(code, 0, 'worker did not exit normally');

test/parallel/test-debug-port-cluster.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ child.stderr.setEncoding('utf8');
1616

1717
const checkMessages = common.mustCall(() => {
1818
for (let port = PORT_MIN; port <= PORT_MAX; port += 1) {
19-
assert(stderr.includes(`Debugger listening on port ${port}`));
19+
const re = RegExp(`Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):${port}`);
20+
assert(re.test(stderr));
2021
}
2122
});
2223

test/parallel/test-debug-port-from-cmdline.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,10 @@ function processStderrLine(line) {
3939
function assertOutputLines() {
4040
var expectedLines = [
4141
'Starting debugger agent.',
42-
'Debugger listening on port ' + debugPort
42+
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + debugPort,
4343
];
4444

4545
assert.equal(outputLines.length, expectedLines.length);
4646
for (var i = 0; i < expectedLines.length; i++)
47-
assert.equal(outputLines[i], expectedLines[i]);
48-
47+
assert(RegExp(expectedLines[i]).test(outputLines[i]));
4948
}

test/parallel/test-debug-port-numbers.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ function kill(child) {
5252

5353
process.on('exit', function() {
5454
for (const child of children) {
55-
const one = RegExp(`Debugger listening on port ${child.test.port}`);
56-
const two = RegExp(`connecting to 127.0.0.1:${child.test.port}`);
55+
const port = child.test.port;
56+
const one = RegExp(`Debugger listening on (\\[::\\]|0\.0\.0\.0):${port}`);
57+
const two = RegExp(`connecting to 127.0.0.1:${port}`);
5758
assert(one.test(child.test.stdout));
5859
assert(two.test(child.test.stdout));
5960
}

test/parallel/test-debug-signal-cluster.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ process.on('exit', function onExit() {
6565

6666
const expectedLines = [
6767
'Starting debugger agent.',
68-
'Debugger listening on port ' + (port + 0),
68+
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 0),
6969
'Starting debugger agent.',
70-
'Debugger listening on port ' + (port + 1),
70+
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 1),
7171
'Starting debugger agent.',
72-
'Debugger listening on port ' + (port + 2),
72+
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 2),
7373
];
7474

7575
function assertOutputLines() {
@@ -79,5 +79,7 @@ function assertOutputLines() {
7979
outputLines.sort();
8080
expectedLines.sort();
8181

82-
assert.deepStrictEqual(outputLines, expectedLines);
82+
assert.equal(outputLines.length, expectedLines.length);
83+
for (var i = 0; i < expectedLines.length; i++)
84+
assert(RegExp(expectedLines[i]).test(outputLines[i]));
8385
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const spawn = require('child_process').spawn;
6+
7+
let run = () => {};
8+
function test(args, re) {
9+
const next = run;
10+
run = () => {
11+
const options = {encoding: 'utf8'};
12+
const proc = spawn(process.execPath, args.concat(['-e', '0']), options);
13+
let stderr = '';
14+
proc.stderr.setEncoding('utf8');
15+
proc.stderr.on('data', (data) => {
16+
stderr += data;
17+
if (re.test(stderr)) proc.kill();
18+
});
19+
proc.on('exit', common.mustCall(() => {
20+
assert(re.test(stderr));
21+
next();
22+
}));
23+
};
24+
}
25+
26+
test(['--debug-brk'], /Debugger listening on (\[::\]|0\.0\.0\.0):5858/);
27+
test(['--debug-brk=1234'], /Debugger listening on (\[::\]|0\.0\.0\.0):1234/);
28+
test(['--debug-brk=127.0.0.1'], /Debugger listening on 127\.0\.0\.1:5858/);
29+
test(['--debug-brk=127.0.0.1:1234'], /Debugger listening on 127\.0\.0\.1:1234/);
30+
test(['--debug-brk=localhost'],
31+
/Debugger listening on (\[::\]|127\.0\.0\.1):5858/);
32+
test(['--debug-brk=localhost:1234'],
33+
/Debugger listening on (\[::\]|127\.0\.0\.1):1234/);
34+
35+
if (common.hasIPv6) {
36+
test(['--debug-brk=::'], /Debug port must be in range 1024 to 65535/);
37+
test(['--debug-brk=::0'], /Debug port must be in range 1024 to 65535/);
38+
test(['--debug-brk=::1'], /Debug port must be in range 1024 to 65535/);
39+
test(['--debug-brk=[::]'], /Debugger listening on \[::\]:5858/);
40+
test(['--debug-brk=[::0]'], /Debugger listening on \[::\]:5858/);
41+
test(['--debug-brk=[::]:1234'], /Debugger listening on \[::\]:1234/);
42+
test(['--debug-brk=[::0]:1234'], /Debugger listening on \[::\]:1234/);
43+
test(['--debug-brk=[::ffff:127.0.0.1]:1234'],
44+
/Debugger listening on \[::ffff:127\.0\.0\.1\]:1234/);
45+
}
46+
47+
run(); // Runs tests in reverse order.

0 commit comments

Comments
 (0)