Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debugger: make listen address configurable #3316

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lib/_debug_agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ exports.start = function start() {
process._rawDebug(err.stack || err);
});

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

Expand Down
8 changes: 7 additions & 1 deletion src/debug-agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Locker;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
Expand All @@ -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;

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

host_ = host;
port_ = port;
wait_ = wait;

Expand Down Expand Up @@ -207,6 +209,10 @@ void Agent::InitAdaptor(Environment* env) {
t->GetFunction()->NewInstance(env->context()).ToLocalChecked();
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_));

env->process_object()->Set(String::NewFromUtf8(isolate, "_debugAPI"), api);
Expand Down
4 changes: 3 additions & 1 deletion src/debug-agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "v8-debug.h"

#include <string.h>
#include <string>

// Forward declaration to break recursive dependency chain with src/env.h.
namespace node {
Expand Down Expand Up @@ -75,7 +76,7 @@ class Agent {
typedef void (*DispatchHandler)(node::Environment* env);

// 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
void Enable();
// Stop the debugger agent
Expand Down Expand Up @@ -114,6 +115,7 @@ class Agent {

State state_;

std::string host_;
int port_;
bool wait_;

Expand Down
82 changes: 54 additions & 28 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include <string>
#include <vector>

#if defined(NODE_HAVE_I18N_SUPPORT)
Expand Down Expand Up @@ -140,10 +142,14 @@ static unsigned int preload_module_count = 0;
static const char** preload_modules = nullptr;
#if HAVE_INSPECTOR
static bool use_inspector = false;
#else
static const bool use_inspector = false;
#endif
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static std::string debug_host; // NOLINT(runtime/string)
static int debug_port = 5858;
static std::string inspector_host; // NOLINT(runtime/string)
static int inspector_port = 9229;
static const int v8_default_thread_pool_size = 4;
static int v8_thread_pool_size = v8_default_thread_pool_size;
Expand Down Expand Up @@ -202,23 +208,20 @@ static struct {
platform_ = nullptr;
}

#if HAVE_INSPECTOR
void StartInspector(Environment *env, int port, bool wait) {
#if HAVE_INSPECTOR
env->inspector_agent()->Start(platform_, port, wait);
}
#endif // HAVE_INSPECTOR
}

v8::Platform* platform_;
#else // !NODE_USE_V8_PLATFORM
void Initialize(int thread_pool_size) {}
void PumpMessageLoop(Isolate* isolate) {}
void Dispose() {}
#if HAVE_INSPECTOR
void StartInspector(Environment *env, int port, bool wait) {
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
}
#endif // HAVE_INSPECTOR

#endif // !NODE_USE_V8_PLATFORM
} v8_platform;

Expand Down Expand Up @@ -3430,6 +3433,7 @@ static bool ParseDebugOpt(const char* arg) {
debug_wait_connect = true;
port = arg + sizeof("--debug-brk=") - 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;
#if HAVE_INSPECTOR
// Specifying both --inspect and --debug means debugging is on, using Chromium
Expand All @@ -3451,24 +3455,49 @@ static bool ParseDebugOpt(const char* arg) {
return false;
}

if (port != nullptr) {
int port_int = atoi(port);
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
if (port == nullptr) {
return true;
}

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;
}
}
#endif
} 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;
}

Expand Down Expand Up @@ -3726,34 +3755,31 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) {

static void StartDebug(Environment* env, bool wait) {
CHECK(!debugger_running);
#if HAVE_INSPECTOR
if (use_inspector) {
v8_platform.StartInspector(env, inspector_port, wait);
debugger_running = true;
} else {
#endif
env->debugger_agent()->set_dispatch_handler(
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) {
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);
return;
}
#if HAVE_INSPECTOR
}
#endif
}


// Called from the main thread.
static void EnableDebug(Environment* env) {
CHECK(debugger_running);
#if HAVE_INSPECTOR

if (use_inspector) {
return;
}
#endif

// Send message to enable debug in workers
HandleScope handle_scope(env->isolate());
Expand Down
7 changes: 2 additions & 5 deletions test/parallel/test-cluster-disconnect-handles.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@ cluster.schedulingPolicy = cluster.SCHED_RR;
if (cluster.isMaster) {
let isKilling = false;
const handles = require('internal/cluster').handles;
// FIXME(bnoordhuis) lib/cluster.js scans the execArgv arguments for
// debugger flags and renumbers any port numbers it sees starting
// 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 address = common.hasIPv6 ? '[::1]' : common.localhostIPv4;
cluster.setupMaster({ execArgv: [`--debug=${address}:${common.PORT}`] });
const worker = cluster.fork();
worker.once('exit', common.mustCall((code, signal) => {
assert.strictEqual(code, 0, 'worker did not exit normally');
Expand Down
3 changes: 2 additions & 1 deletion test/parallel/test-debug-port-cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ child.stderr.setEncoding('utf8');

const checkMessages = common.mustCall(() => {
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));
}
});

Expand Down
5 changes: 2 additions & 3 deletions test/parallel/test-debug-port-from-cmdline.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ function processStderrLine(line) {
function assertOutputLines() {
var expectedLines = [
'Starting debugger agent.',
'Debugger listening on port ' + debugPort
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + debugPort,
];

assert.equal(outputLines.length, expectedLines.length);
for (var i = 0; i < expectedLines.length; i++)
assert.equal(outputLines[i], expectedLines[i]);

assert(RegExp(expectedLines[i]).test(outputLines[i]));
}
5 changes: 3 additions & 2 deletions test/parallel/test-debug-port-numbers.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ function kill(child) {

process.on('exit', function() {
for (const child of children) {
const one = RegExp(`Debugger listening on port ${child.test.port}`);
const two = RegExp(`connecting to 127.0.0.1:${child.test.port}`);
const port = 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(two.test(child.test.stdout));
}
Expand Down
8 changes: 4 additions & 4 deletions test/parallel/test-debug-signal-cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ process.on('exit', function onExit() {

var expectedLines = [
'Starting debugger agent.',
'Debugger listening on port ' + (port + 0),
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 0),
'Starting debugger agent.',
'Debugger listening on port ' + (port + 1),
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 1),
'Starting debugger agent.',
'Debugger listening on port ' + (port + 2),
'Debugger listening on (\\[::\\]|0\\.0\\.0\\.0):' + (port + 2),
];

function assertOutputLines() {
Expand All @@ -79,5 +79,5 @@ function assertOutputLines() {

assert.equal(outputLines.length, expectedLines.length);
for (var i = 0; i < expectedLines.length; i++)
assert.equal(outputLines[i], expectedLines[i]);
assert(RegExp(expectedLines[i]).test(outputLines[i]));
}
47 changes: 47 additions & 0 deletions test/sequential/test-debug-host-port.js
Original file line number Diff line number Diff line change
@@ -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.