inspector: Do not crash if the port is n/a · nodejs/node@f789eb3

@@ -165,16 +165,17 @@ class AgentImpl {

165165

~AgentImpl();

166166167167

// Start the inspector agent thread

168-

void Start(v8::Platform* platform, int port, bool wait);

168+

bool Start(v8::Platform* platform, int port, bool wait);

169169

// Stop the inspector agent

170170

void Stop();

171171172172

bool IsStarted();

173-

bool IsConnected() { return connected_; }

173+

bool IsConnected() { return state_ == State::kConnected; }

174174

void WaitForDisconnect();

175175176176

private:

177177

using MessageQueue = std::vector<std::pair<int, String16>>;

178+

enum class State { kNew, kAccepting, kConnected, kDone, kError };

178179179180

static void ThreadCbIO(void* agent);

180181

static void OnSocketConnectionIO(uv_stream_t* server, int status);

@@ -195,6 +196,7 @@ class AgentImpl {

195196

const String16& message);

196197

void SwapBehindLock(MessageQueue* vector1, MessageQueue* vector2);

197198

void PostIncomingMessage(const String16& message);

199+

State ToState(State state);

198200199201

uv_sem_t start_sem_;

200202

ConditionVariable pause_cond_;

@@ -205,8 +207,8 @@ class AgentImpl {

205207206208

int port_;

207209

bool wait_;

208-

bool connected_;

209210

bool shutting_down_;

211+

State state_;

210212

node::Environment* parent_env_;

211213212214

uv_async_t data_written_;

@@ -314,8 +316,8 @@ class V8NodeInspector : public blink::V8Inspector {

314316315317

AgentImpl::AgentImpl(Environment* env) : port_(0),

316318

wait_(false),

317-

connected_(false),

318319

shutting_down_(false),

320+

state_(State::kNew),

319321

parent_env_(env),

320322

client_socket_(nullptr),

321323

inspector_(nullptr),

@@ -334,17 +336,11 @@ AgentImpl::~AgentImpl() {

334336

uv_close(reinterpret_cast<uv_handle_t*>(&data_written_), nullptr);

335337

}

336338337-

void AgentImpl::Start(v8::Platform* platform, int port, bool wait) {

339+

bool AgentImpl::Start(v8::Platform* platform, int port, bool wait) {

338340

auto env = parent_env_;

339341

inspector_ = new V8NodeInspector(this, env, platform);

340-341-

int err;

342-343342

platform_ = platform;

344-345-

err = uv_loop_init(&child_loop_);

346-

CHECK_EQ(err, 0);

347-

err = uv_async_init(env->event_loop(), &data_written_, nullptr);

343+

int err = uv_async_init(env->event_loop(), &data_written_, nullptr);

348344

CHECK_EQ(err, 0);

349345350346

uv_unref(reinterpret_cast<uv_handle_t*>(&data_written_));

@@ -356,21 +352,20 @@ void AgentImpl::Start(v8::Platform* platform, int port, bool wait) {

356352

CHECK_EQ(err, 0);

357353

uv_sem_wait(&start_sem_);

358354355+

if (state_ == State::kError) {

356+

Stop();

357+

return false;

358+

}

359+

state_ = State::kAccepting;

359360

if (wait) {

360361

DispatchMessages();

361362

}

363+

return true;

362364

}

363365364366

void AgentImpl::Stop() {

365-

// TODO(repenaxa): hop on the right thread.

366-

DisconnectAndDisposeIO(client_socket_);

367367

int err = uv_thread_join(&thread_);

368368

CHECK_EQ(err, 0);

369-370-

uv_run(&child_loop_, UV_RUN_NOWAIT);

371-372-

err = uv_loop_close(&child_loop_);

373-

CHECK_EQ(err, 0);

374369

delete inspector_;

375370

}

376371

@@ -429,7 +424,6 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket,

429424

Mutex::ScopedLock scoped_lock(pause_lock_);

430425

if (read > 0) {

431426

String16 str = String16::fromUTF8(buf->base, read);

432-

PostIncomingMessage(str);

433427

// TODO(pfeldman): Instead of blocking execution while debugger

434428

// engages, node should wait for the run callback from the remote client

435429

// and initiate its startup. This is a change to node.cc that should be

@@ -438,11 +432,7 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket,

438432

wait_ = false;

439433

uv_sem_post(&start_sem_);

440434

}

441-442-

platform_->CallOnForegroundThread(parent_env_->isolate(),

443-

new DispatchOnInspectorBackendTask(this));

444-

parent_env_->isolate()->RequestInterrupt(InterruptCallback, this);

445-

uv_async_send(&data_written_);

435+

PostIncomingMessage(str);

446436

} else if (read <= 0) {

447437

// EOF

448438

if (client_socket_ == socket) {

@@ -477,8 +467,10 @@ void AgentImpl::WriteCbIO(uv_async_t* async) {

477467

void AgentImpl::WorkerRunIO() {

478468

sockaddr_in addr;

479469

uv_tcp_t server;

480-

int err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);

481-

CHECK_EQ(0, err);

470+

int err = uv_loop_init(&child_loop_);

471+

CHECK_EQ(err, 0);

472+

err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO);

473+

CHECK_EQ(err, 0);

482474

io_thread_req_.data = this;

483475

uv_tcp_init(&child_loop_, &server);

484476

uv_ip4_addr("0.0.0.0", port_, &addr);

@@ -489,19 +481,26 @@ void AgentImpl::WorkerRunIO() {

489481

err = uv_listen(reinterpret_cast<uv_stream_t*>(&server), 1,

490482

OnSocketConnectionIO);

491483

}

492-

if (err == 0) {

493-

PrintDebuggerReadyMessage(port_);

494-

} else {

484+

if (err != 0) {

495485

fprintf(stderr, "Unable to open devtools socket: %s\n", uv_strerror(err));

496-

ABORT();

486+

state_ = State::kError; // Safe, main thread is waiting on semaphore

487+

uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);

488+

uv_close(reinterpret_cast<uv_handle_t*>(&server), nullptr);

489+

uv_loop_close(&child_loop_);

490+

uv_sem_post(&start_sem_);

491+

return;

497492

}

493+

PrintDebuggerReadyMessage(port_);

498494

if (!wait_) {

499495

uv_sem_post(&start_sem_);

500496

}

501497

uv_run(&child_loop_, UV_RUN_DEFAULT);

502498

uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);

503499

uv_close(reinterpret_cast<uv_handle_t*>(&server), nullptr);

504-

uv_run(&child_loop_, UV_RUN_DEFAULT);

500+

DisconnectAndDisposeIO(client_socket_);

501+

uv_run(&child_loop_, UV_RUN_NOWAIT);

502+

err = uv_loop_close(&child_loop_);

503+

CHECK_EQ(err, 0);

505504

}

506505507506

void AgentImpl::AppendMessage(MessageQueue* queue, int session_id,

@@ -544,16 +543,19 @@ void AgentImpl::DispatchMessages() {

544543

for (const MessageQueue::value_type& pair : tasks) {

545544

const String16& message = pair.second;

546545

if (message == TAG_CONNECT) {

547-

CHECK_EQ(false, connected_);

546+

CHECK_EQ(State::kAccepting, state_);

548547

backend_session_id_++;

549-

connected_ = true;

548+

state_ = State::kConnected;

550549

fprintf(stderr, "Debugger attached.\n");

551550

inspector_->connectFrontend(new ChannelImpl(this));

552551

} else if (message == TAG_DISCONNECT) {

553-

CHECK(connected_);

554-

connected_ = false;

555-

if (!shutting_down_)

552+

CHECK_EQ(State::kConnected, state_);

553+

if (shutting_down_) {

554+

state_ = State::kDone;

555+

} else {

556556

PrintDebuggerReadyMessage(port_);

557+

state_ = State::kAccepting;

558+

}

557559

inspector_->quitMessageLoopOnPause();

558560

inspector_->disconnectFrontend();

559561

} else {

@@ -577,8 +579,8 @@ Agent::~Agent() {

577579

delete impl;

578580

}

579581580-

void Agent::Start(v8::Platform* platform, int port, bool wait) {

581-

impl->Start(platform, port, wait);

582+

bool Agent::Start(v8::Platform* platform, int port, bool wait) {

583+

return impl->Start(platform, port, wait);

582584

}

583585584586

void Agent::Stop() {