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: https://github.com/nodejs/node/issues/3306 PR-URL: https://github.com/nodejs/node/pull/3316 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
This commit is contained in:
parent
7dcc4af827
commit
c5c28c3d50
@ -18,9 +18,10 @@ exports.start = function start() {
|
|||||||
process._rawDebug(err.stack || err);
|
process._rawDebug(err.stack || err);
|
||||||
});
|
});
|
||||||
|
|
||||||
agent.listen(process._debugAPI.port, function() {
|
agent.listen(process._debugAPI.port, process._debugAPI.host, function() {
|
||||||
var addr = this.address();
|
const addr = this.address();
|
||||||
process._rawDebug('Debugger listening on port %d', addr.port);
|
const host = net.isIPv6(addr.address) ? `[${addr.address}]` : addr.address;
|
||||||
|
process._rawDebug('Debugger listening on %s:%d', host, addr.port);
|
||||||
process._debugAPI.notifyListen();
|
process._debugAPI.notifyListen();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ using v8::Integer;
|
|||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::Locker;
|
using v8::Locker;
|
||||||
|
using v8::NewStringType;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
@ -69,7 +70,7 @@ Agent::~Agent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Agent::Start(int port, bool wait) {
|
bool Agent::Start(const std::string& host, int port, bool wait) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (state_ == kRunning)
|
if (state_ == kRunning)
|
||||||
@ -85,6 +86,7 @@ bool Agent::Start(int port, bool wait) {
|
|||||||
goto async_init_failed;
|
goto async_init_failed;
|
||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&child_signal_));
|
uv_unref(reinterpret_cast<uv_handle_t*>(&child_signal_));
|
||||||
|
|
||||||
|
host_ = host;
|
||||||
port_ = port;
|
port_ = port;
|
||||||
wait_ = wait;
|
wait_ = wait;
|
||||||
|
|
||||||
@ -207,6 +209,10 @@ void Agent::InitAdaptor(Environment* env) {
|
|||||||
t->GetFunction()->NewInstance(env->context()).ToLocalChecked();
|
t->GetFunction()->NewInstance(env->context()).ToLocalChecked();
|
||||||
api->SetAlignedPointerInInternalField(0, this);
|
api->SetAlignedPointerInInternalField(0, this);
|
||||||
|
|
||||||
|
api->Set(String::NewFromUtf8(isolate, "host",
|
||||||
|
NewStringType::kNormal).ToLocalChecked(),
|
||||||
|
String::NewFromUtf8(isolate, host_.data(), NewStringType::kNormal,
|
||||||
|
host_.size()).ToLocalChecked());
|
||||||
api->Set(String::NewFromUtf8(isolate, "port"), Integer::New(isolate, port_));
|
api->Set(String::NewFromUtf8(isolate, "port"), Integer::New(isolate, port_));
|
||||||
|
|
||||||
env->process_object()->Set(String::NewFromUtf8(isolate, "_debugAPI"), api);
|
env->process_object()->Set(String::NewFromUtf8(isolate, "_debugAPI"), api);
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "v8-debug.h"
|
#include "v8-debug.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// Forward declaration to break recursive dependency chain with src/env.h.
|
// Forward declaration to break recursive dependency chain with src/env.h.
|
||||||
namespace node {
|
namespace node {
|
||||||
@ -75,7 +76,7 @@ class Agent {
|
|||||||
typedef void (*DispatchHandler)(node::Environment* env);
|
typedef void (*DispatchHandler)(node::Environment* env);
|
||||||
|
|
||||||
// Start the debugger agent thread
|
// Start the debugger agent thread
|
||||||
bool Start(int port, bool wait);
|
bool Start(const std::string& host, int port, bool wait);
|
||||||
// Listen for debug events
|
// Listen for debug events
|
||||||
void Enable();
|
void Enable();
|
||||||
// Stop the debugger agent
|
// Stop the debugger agent
|
||||||
@ -114,6 +115,7 @@ class Agent {
|
|||||||
|
|
||||||
State state_;
|
State state_;
|
||||||
|
|
||||||
|
std::string host_;
|
||||||
int port_;
|
int port_;
|
||||||
bool wait_;
|
bool wait_;
|
||||||
|
|
||||||
|
84
src/node.cc
84
src/node.cc
@ -58,6 +58,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||||
@ -140,10 +142,14 @@ static unsigned int preload_module_count = 0;
|
|||||||
static const char** preload_modules = nullptr;
|
static const char** preload_modules = nullptr;
|
||||||
#if HAVE_INSPECTOR
|
#if HAVE_INSPECTOR
|
||||||
static bool use_inspector = false;
|
static bool use_inspector = false;
|
||||||
|
#else
|
||||||
|
static const bool use_inspector = false;
|
||||||
#endif
|
#endif
|
||||||
static bool use_debug_agent = false;
|
static bool use_debug_agent = false;
|
||||||
static bool debug_wait_connect = false;
|
static bool debug_wait_connect = false;
|
||||||
|
static std::string debug_host; // NOLINT(runtime/string)
|
||||||
static int debug_port = 5858;
|
static int debug_port = 5858;
|
||||||
|
static std::string inspector_host; // NOLINT(runtime/string)
|
||||||
static int inspector_port = 9229;
|
static int inspector_port = 9229;
|
||||||
static const int v8_default_thread_pool_size = 4;
|
static const int v8_default_thread_pool_size = 4;
|
||||||
static int v8_thread_pool_size = v8_default_thread_pool_size;
|
static int v8_thread_pool_size = v8_default_thread_pool_size;
|
||||||
@ -202,23 +208,20 @@ static struct {
|
|||||||
platform_ = nullptr;
|
platform_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
void StartInspector(Environment *env, int port, bool wait) {
|
void StartInspector(Environment *env, int port, bool wait) {
|
||||||
|
#if HAVE_INSPECTOR
|
||||||
env->inspector_agent()->Start(platform_, port, wait);
|
env->inspector_agent()->Start(platform_, port, wait);
|
||||||
}
|
|
||||||
#endif // HAVE_INSPECTOR
|
#endif // HAVE_INSPECTOR
|
||||||
|
}
|
||||||
|
|
||||||
v8::Platform* platform_;
|
v8::Platform* platform_;
|
||||||
#else // !NODE_USE_V8_PLATFORM
|
#else // !NODE_USE_V8_PLATFORM
|
||||||
void Initialize(int thread_pool_size) {}
|
void Initialize(int thread_pool_size) {}
|
||||||
void PumpMessageLoop(Isolate* isolate) {}
|
void PumpMessageLoop(Isolate* isolate) {}
|
||||||
void Dispose() {}
|
void Dispose() {}
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
void StartInspector(Environment *env, int port, bool wait) {
|
void StartInspector(Environment *env, int port, bool wait) {
|
||||||
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
|
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
|
||||||
}
|
}
|
||||||
#endif // HAVE_INSPECTOR
|
|
||||||
|
|
||||||
#endif // !NODE_USE_V8_PLATFORM
|
#endif // !NODE_USE_V8_PLATFORM
|
||||||
} v8_platform;
|
} v8_platform;
|
||||||
|
|
||||||
@ -3430,6 +3433,7 @@ static bool ParseDebugOpt(const char* arg) {
|
|||||||
debug_wait_connect = true;
|
debug_wait_connect = true;
|
||||||
port = arg + sizeof("--debug-brk=") - 1;
|
port = arg + sizeof("--debug-brk=") - 1;
|
||||||
} else if (!strncmp(arg, "--debug-port=", sizeof("--debug-port=") - 1)) {
|
} else if (!strncmp(arg, "--debug-port=", sizeof("--debug-port=") - 1)) {
|
||||||
|
// XXX(bnoordhuis) Misnomer, configures port and listen address.
|
||||||
port = arg + sizeof("--debug-port=") - 1;
|
port = arg + sizeof("--debug-port=") - 1;
|
||||||
#if HAVE_INSPECTOR
|
#if HAVE_INSPECTOR
|
||||||
// Specifying both --inspect and --debug means debugging is on, using Chromium
|
// Specifying both --inspect and --debug means debugging is on, using Chromium
|
||||||
@ -3451,24 +3455,49 @@ static bool ParseDebugOpt(const char* arg) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port != nullptr) {
|
if (port == nullptr) {
|
||||||
int port_int = atoi(port);
|
return true;
|
||||||
if (port_int < 1024 || port_int > 65535) {
|
|
||||||
fprintf(stderr, "Debug port must be in range 1024 to 65535.\n");
|
|
||||||
PrintHelp();
|
|
||||||
exit(12);
|
|
||||||
}
|
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
if (use_inspector) {
|
|
||||||
inspector_port = port_int;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
debug_port = port_int;
|
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string* const the_host = use_inspector ? &inspector_host : &debug_host;
|
||||||
|
int* const the_port = use_inspector ? &inspector_port : &debug_port;
|
||||||
|
|
||||||
|
// FIXME(bnoordhuis) Move IPv6 address parsing logic to lib/net.js.
|
||||||
|
// It seems reasonable to support [address]:port notation
|
||||||
|
// in net.Server#listen() and net.Socket#connect().
|
||||||
|
const size_t port_len = strlen(port);
|
||||||
|
if (port[0] == '[' && port[port_len - 1] == ']') {
|
||||||
|
the_host->assign(port + 1, port_len - 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const colon = strrchr(port, ':');
|
||||||
|
if (colon == nullptr) {
|
||||||
|
// Either a port number or a host name. Assume that
|
||||||
|
// if it's not all decimal digits, it's a host name.
|
||||||
|
for (size_t n = 0; port[n] != '\0'; n += 1) {
|
||||||
|
if (port[n] < '0' || port[n] > '9') {
|
||||||
|
*the_host = port;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const bool skip = (colon > port && port[0] == '[' && colon[-1] == ']');
|
||||||
|
the_host->assign(port + skip, colon - skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* endptr;
|
||||||
|
errno = 0;
|
||||||
|
const char* const digits = colon != nullptr ? colon + 1 : port;
|
||||||
|
const long result = strtol(digits, &endptr, 10); // NOLINT(runtime/int)
|
||||||
|
if (errno != 0 || *endptr != '\0' || result < 1024 || result > 65535) {
|
||||||
|
fprintf(stderr, "Debug port must be in range 1024 to 65535.\n");
|
||||||
|
PrintHelp();
|
||||||
|
exit(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
*the_port = static_cast<int>(result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3726,34 +3755,31 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) {
|
|||||||
|
|
||||||
static void StartDebug(Environment* env, bool wait) {
|
static void StartDebug(Environment* env, bool wait) {
|
||||||
CHECK(!debugger_running);
|
CHECK(!debugger_running);
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
if (use_inspector) {
|
if (use_inspector) {
|
||||||
v8_platform.StartInspector(env, inspector_port, wait);
|
v8_platform.StartInspector(env, inspector_port, wait);
|
||||||
debugger_running = true;
|
debugger_running = true;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
|
||||||
env->debugger_agent()->set_dispatch_handler(
|
env->debugger_agent()->set_dispatch_handler(
|
||||||
DispatchMessagesDebugAgentCallback);
|
DispatchMessagesDebugAgentCallback);
|
||||||
debugger_running = env->debugger_agent()->Start(debug_port, wait);
|
debugger_running =
|
||||||
|
env->debugger_agent()->Start(debug_host, debug_port, wait);
|
||||||
if (debugger_running == false) {
|
if (debugger_running == false) {
|
||||||
fprintf(stderr, "Starting debugger on port %d failed\n", debug_port);
|
fprintf(stderr, "Starting debugger on %s:%d failed\n",
|
||||||
|
debug_host.c_str(), debug_port);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Called from the main thread.
|
// Called from the main thread.
|
||||||
static void EnableDebug(Environment* env) {
|
static void EnableDebug(Environment* env) {
|
||||||
CHECK(debugger_running);
|
CHECK(debugger_running);
|
||||||
#if HAVE_INSPECTOR
|
|
||||||
if (use_inspector) {
|
if (use_inspector) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Send message to enable debug in workers
|
// Send message to enable debug in workers
|
||||||
HandleScope handle_scope(env->isolate());
|
HandleScope handle_scope(env->isolate());
|
||||||
|
@ -25,11 +25,8 @@ cluster.schedulingPolicy = cluster.SCHED_RR;
|
|||||||
if (cluster.isMaster) {
|
if (cluster.isMaster) {
|
||||||
let isKilling = false;
|
let isKilling = false;
|
||||||
const handles = require('internal/cluster').handles;
|
const handles = require('internal/cluster').handles;
|
||||||
// FIXME(bnoordhuis) lib/cluster.js scans the execArgv arguments for
|
const address = common.hasIPv6 ? '[::1]' : common.localhostIPv4;
|
||||||
// debugger flags and renumbers any port numbers it sees starting
|
cluster.setupMaster({ execArgv: [`--debug=${address}:${common.PORT}`] });
|
||||||
// from the default port 5858. Add a '.' that circumvents the
|
|
||||||
// scanner but is ignored by atoi(3). Heinous hack.
|
|
||||||
cluster.setupMaster({ execArgv: [`--debug=${common.PORT}.`] });
|
|
||||||
const worker = cluster.fork();
|
const worker = cluster.fork();
|
||||||
worker.once('exit', common.mustCall((code, signal) => {
|
worker.once('exit', common.mustCall((code, signal) => {
|
||||||
assert.strictEqual(code, 0, 'worker did not exit normally');
|
assert.strictEqual(code, 0, 'worker did not exit normally');
|
||||||
|
@ -16,7 +16,8 @@ child.stderr.setEncoding('utf8');
|
|||||||
|
|
||||||
const checkMessages = common.mustCall(() => {
|
const checkMessages = common.mustCall(() => {
|
||||||
for (let port = PORT_MIN; port <= PORT_MAX; port += 1) {
|
for (let port = PORT_MIN; port <= PORT_MAX; port += 1) {
|
||||||
assert(stderr.includes(`Debugger listening on port ${port}`));
|
const re = RegExp(`Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):${port}`);
|
||||||
|
assert(re.test(stderr));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,11 +39,10 @@ function processStderrLine(line) {
|
|||||||
function assertOutputLines() {
|
function assertOutputLines() {
|
||||||
var expectedLines = [
|
var expectedLines = [
|
||||||
'Starting debugger agent.',
|
'Starting debugger agent.',
|
||||||
'Debugger listening on port ' + debugPort
|
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + debugPort,
|
||||||
];
|
];
|
||||||
|
|
||||||
assert.equal(outputLines.length, expectedLines.length);
|
assert.equal(outputLines.length, expectedLines.length);
|
||||||
for (var i = 0; i < expectedLines.length; i++)
|
for (var i = 0; i < expectedLines.length; i++)
|
||||||
assert.equal(outputLines[i], expectedLines[i]);
|
assert(RegExp(expectedLines[i]).test(outputLines[i]));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,9 @@ function kill(child) {
|
|||||||
|
|
||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
const one = RegExp(`Debugger listening on port ${child.test.port}`);
|
const port = child.test.port;
|
||||||
const two = RegExp(`connecting to 127.0.0.1:${child.test.port}`);
|
const one = RegExp(`Debugger listening on (\\[::\\]|0\.0\.0\.0):${port}`);
|
||||||
|
const two = RegExp(`connecting to 127.0.0.1:${port}`);
|
||||||
assert(one.test(child.test.stdout));
|
assert(one.test(child.test.stdout));
|
||||||
assert(two.test(child.test.stdout));
|
assert(two.test(child.test.stdout));
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,11 @@ process.on('exit', function onExit() {
|
|||||||
|
|
||||||
var expectedLines = [
|
var expectedLines = [
|
||||||
'Starting debugger agent.',
|
'Starting debugger agent.',
|
||||||
'Debugger listening on port ' + (port + 0),
|
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 0),
|
||||||
'Starting debugger agent.',
|
'Starting debugger agent.',
|
||||||
'Debugger listening on port ' + (port + 1),
|
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 1),
|
||||||
'Starting debugger agent.',
|
'Starting debugger agent.',
|
||||||
'Debugger listening on port ' + (port + 2),
|
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 2),
|
||||||
];
|
];
|
||||||
|
|
||||||
function assertOutputLines() {
|
function assertOutputLines() {
|
||||||
@ -79,5 +79,5 @@ function assertOutputLines() {
|
|||||||
|
|
||||||
assert.equal(outputLines.length, expectedLines.length);
|
assert.equal(outputLines.length, expectedLines.length);
|
||||||
for (var i = 0; i < expectedLines.length; i++)
|
for (var i = 0; i < expectedLines.length; i++)
|
||||||
assert.equal(outputLines[i], expectedLines[i]);
|
assert(RegExp(expectedLines[i]).test(outputLines[i]));
|
||||||
}
|
}
|
||||||
|
47
test/sequential/test-debug-host-port.js
Normal file
47
test/sequential/test-debug-host-port.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const spawn = require('child_process').spawn;
|
||||||
|
|
||||||
|
let run = () => {};
|
||||||
|
function test(args, re) {
|
||||||
|
const next = run;
|
||||||
|
run = () => {
|
||||||
|
const options = {encoding: 'utf8'};
|
||||||
|
const proc = spawn(process.execPath, args.concat(['-e', '0']), options);
|
||||||
|
let stderr = '';
|
||||||
|
proc.stderr.setEncoding('utf8');
|
||||||
|
proc.stderr.on('data', (data) => {
|
||||||
|
stderr += data;
|
||||||
|
if (re.test(stderr)) proc.kill();
|
||||||
|
});
|
||||||
|
proc.on('exit', common.mustCall(() => {
|
||||||
|
assert(re.test(stderr));
|
||||||
|
next();
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test(['--debug-brk'], /Debugger listening on (\[::\]|0\.0\.0\.0):5858/);
|
||||||
|
test(['--debug-brk=1234'], /Debugger listening on (\[::\]|0\.0\.0\.0):1234/);
|
||||||
|
test(['--debug-brk=127.0.0.1'], /Debugger listening on 127\.0\.0\.1:5858/);
|
||||||
|
test(['--debug-brk=127.0.0.1:1234'], /Debugger listening on 127\.0\.0\.1:1234/);
|
||||||
|
test(['--debug-brk=localhost'],
|
||||||
|
/Debugger listening on (\[::\]|127\.0\.0\.1):5858/);
|
||||||
|
test(['--debug-brk=localhost:1234'],
|
||||||
|
/Debugger listening on (\[::\]|127\.0\.0\.1):1234/);
|
||||||
|
|
||||||
|
if (common.hasIPv6) {
|
||||||
|
test(['--debug-brk=::'], /Debug port must be in range 1024 to 65535/);
|
||||||
|
test(['--debug-brk=::0'], /Debug port must be in range 1024 to 65535/);
|
||||||
|
test(['--debug-brk=::1'], /Debug port must be in range 1024 to 65535/);
|
||||||
|
test(['--debug-brk=[::]'], /Debugger listening on \[::\]:5858/);
|
||||||
|
test(['--debug-brk=[::0]'], /Debugger listening on \[::\]:5858/);
|
||||||
|
test(['--debug-brk=[::]:1234'], /Debugger listening on \[::\]:1234/);
|
||||||
|
test(['--debug-brk=[::0]:1234'], /Debugger listening on \[::\]:1234/);
|
||||||
|
test(['--debug-brk=[::ffff:127.0.0.1]:1234'],
|
||||||
|
/Debugger listening on \[::ffff:127\.0\.0\.1\]:1234/);
|
||||||
|
}
|
||||||
|
|
||||||
|
run(); // Runs tests in reverse order.
|
Loading…
x
Reference in New Issue
Block a user