Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Ostroukhov <eostroukhov@chromium.org>2017-06-05 20:17:20 +0300
committerEugene Ostroukhov <eostroukhov@chromium.org>2017-06-16 19:46:36 +0300
commit6e2c29bcabb0507262167494a1fd9bc583cae690 (patch)
tree79259629957c8d686efa9a0d180a9a419cf2dfcb /src/inspector_socket_server.cc
parentb7473c2117d5b43e4ed5ccbe069d5fe91918289e (diff)
inspector: perform DNS lookup for host
PR-URL: https://github.com/nodejs/node/pull/13478 Fixes: https://github.com/nodejs/node/issues/13477 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'src/inspector_socket_server.cc')
-rw-r--r--src/inspector_socket_server.cc382
1 files changed, 256 insertions, 126 deletions
diff --git a/src/inspector_socket_server.cc b/src/inspector_socket_server.cc
index f3e56b6ceb5..cdc907ee9b2 100644
--- a/src/inspector_socket_server.cc
+++ b/src/inspector_socket_server.cc
@@ -12,6 +12,28 @@
namespace node {
namespace inspector {
+// Function is declared in inspector_io.h so the rest of the node does not
+// depend on inspector_socket_server.h
+std::string FormatWsAddress(const std::string& host, int port,
+ const std::string& target_id,
+ bool include_protocol) {
+ // Host is valid (socket was bound) so colon means it's a v6 IP address
+ bool v6 = host.find(':') != std::string::npos;
+ std::ostringstream url;
+ if (include_protocol)
+ url << "ws://";
+ if (v6) {
+ url << '[';
+ }
+ url << host;
+ if (v6) {
+ url << ']';
+ }
+ url << ':' << port << '/' << target_id;
+ return url.str();
+}
+
+
namespace {
static const uint8_t PROTOCOL_JSON[] = {
@@ -24,12 +46,6 @@ void Escape(std::string* string) {
}
}
-std::string GetWsUrl(const std::string& host, int port, const std::string& id) {
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s:%d/%s", host.c_str(), port, id.c_str());
- return buf;
-}
-
std::string MapToString(const std::map<std::string, std::string>& object) {
bool first = true;
std::ostringstream json;
@@ -82,8 +98,8 @@ void PrintDebuggerReadyMessage(const std::string& host,
return;
}
for (const std::string& id : ids) {
- fprintf(out, "Debugger listening on ws://%s\n",
- GetWsUrl(host, port, id).c_str());
+ fprintf(out, "Debugger listening on %s\n",
+ FormatWsAddress(host, port, id, true).c_str());
}
fprintf(out, "For help see %s\n",
"https://nodejs.org/en/docs/inspector");
@@ -151,24 +167,6 @@ int GetSocketHost(uv_tcp_t* socket, std::string* out_host) {
*out_host = ip;
return err;
}
-
-int GetPort(uv_tcp_t* socket, int* out_port) {
- sockaddr_storage addr;
- int len = sizeof(addr);
- int err = uv_tcp_getsockname(socket,
- reinterpret_cast<struct sockaddr*>(&addr),
- &len);
- if (err != 0)
- return err;
- int port;
- if (addr.ss_family == AF_INET6)
- port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
- else
- port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
- *out_port = ntohs(port);
- return err;
-}
-
} // namespace
@@ -211,34 +209,77 @@ class Closer {
class SocketSession {
public:
- SocketSession(InspectorSocketServer* server, int id);
+ static int Accept(InspectorSocketServer* server, int server_port,
+ uv_stream_t* server_socket);
+ void Send(const std::string& message);
void Close();
- void Declined() { state_ = State::kDeclined; }
+
+ int id() const { return id_; }
+ bool IsForTarget(const std::string& target_id) const {
+ return target_id_ == target_id;
+ }
+ static int ServerPortForClient(InspectorSocket* client) {
+ return From(client)->server_port_;
+ }
+
+ private:
+ SocketSession(InspectorSocketServer* server, int server_port);
static SocketSession* From(InspectorSocket* socket) {
return node::ContainerOf(&SocketSession::socket_, socket);
}
+
+ enum class State { kHttp, kWebSocket, kClosing, kEOF, kDeclined };
+ static bool HandshakeCallback(InspectorSocket* socket,
+ enum inspector_handshake_event state,
+ const std::string& path);
+ static void ReadCallback(uv_stream_t* stream, ssize_t read,
+ const uv_buf_t* buf);
+ static void CloseCallback(InspectorSocket* socket, int code);
+
void FrontendConnected();
- InspectorSocketServer* GetServer() { return server_; }
- int Id() { return id_; }
- void Send(const std::string& message);
+ void SetDeclined() { state_ = State::kDeclined; }
void SetTargetId(const std::string& target_id) {
CHECK(target_id_.empty());
target_id_ = target_id;
}
- InspectorSocket* Socket() { return &socket_; }
- const std::string TargetId() { return target_id_; }
- private:
- enum class State { kHttp, kWebSocket, kClosing, kEOF, kDeclined };
- static void CloseCallback(InspectorSocket* socket, int code);
- static void ReadCallback(uv_stream_t* stream, ssize_t read,
- const uv_buf_t* buf);
- void OnRemoteDataIO(ssize_t read, const uv_buf_t* buf);
const int id_;
InspectorSocket socket_;
InspectorSocketServer* server_;
std::string target_id_;
State state_;
+ const int server_port_;
+};
+
+class ServerSocket {
+ public:
+ static int Listen(InspectorSocketServer* inspector_server,
+ sockaddr* addr, uv_loop_t* loop);
+ void Close() {
+ uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_),
+ SocketClosedCallback);
+ }
+ int port() const { return port_; }
+
+ private:
+ explicit ServerSocket(InspectorSocketServer* server)
+ : tcp_socket_(uv_tcp_t()), server_(server), port_(-1) {}
+ template<typename UvHandle>
+ static ServerSocket* FromTcpSocket(UvHandle* socket) {
+ return node::ContainerOf(&ServerSocket::tcp_socket_,
+ reinterpret_cast<uv_tcp_t*>(socket));
+ }
+
+ static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status);
+ static void SocketClosedCallback(uv_handle_t* tcp_socket);
+ static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) {
+ delete FromTcpSocket(tcp_socket_);
+ }
+ int DetectPort();
+
+ uv_tcp_t tcp_socket_;
+ InspectorSocketServer* server_;
+ int port_;
};
InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
@@ -249,58 +290,29 @@ InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
delegate_(delegate),
host_(host),
port_(port),
- server_(uv_tcp_t()),
closer_(nullptr),
next_session_id_(0),
out_(out) {
state_ = ServerState::kNew;
}
-// static
-bool InspectorSocketServer::HandshakeCallback(InspectorSocket* socket,
- inspector_handshake_event event,
- const std::string& path) {
- InspectorSocketServer* server = SocketSession::From(socket)->GetServer();
- const std::string& id = path.empty() ? path : path.substr(1);
- switch (event) {
- case kInspectorHandshakeHttpGet:
- return server->RespondToGet(socket, path);
- case kInspectorHandshakeUpgrading:
- return server->SessionStarted(SocketSession::From(socket), id);
- case kInspectorHandshakeUpgraded:
- SocketSession::From(socket)->FrontendConnected();
- return true;
- case kInspectorHandshakeFailed:
- server->SessionTerminated(SocketSession::From(socket));
- return false;
- default:
- UNREACHABLE();
- return false;
- }
-}
-
bool InspectorSocketServer::SessionStarted(SocketSession* session,
const std::string& id) {
- bool connected = false;
- if (TargetExists(id)) {
- connected = delegate_->StartSession(session->Id(), id);
- }
- if (connected) {
- connected_sessions_[session->Id()] = session;
- session->SetTargetId(id);
+ if (TargetExists(id) && delegate_->StartSession(session->id(), id)) {
+ connected_sessions_[session->id()] = session;
+ return true;
} else {
- session->Declined();
+ return false;
}
- return connected;
}
void InspectorSocketServer::SessionTerminated(SocketSession* session) {
- int id = session->Id();
+ int id = session->id();
if (connected_sessions_.erase(id) != 0) {
delegate_->EndSession(id);
if (connected_sessions_.empty()) {
- if (state_ == ServerState::kRunning) {
- PrintDebuggerReadyMessage(host_, port_,
+ if (state_ == ServerState::kRunning && !server_sockets_.empty()) {
+ PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
delegate_->GetTargetIds(), out_);
}
if (state_ == ServerState::kStopped) {
@@ -311,8 +323,8 @@ void InspectorSocketServer::SessionTerminated(SocketSession* session) {
delete session;
}
-bool InspectorSocketServer::RespondToGet(InspectorSocket* socket,
- const std::string& path) {
+bool InspectorSocketServer::HandleGetRequest(InspectorSocket* socket,
+ const std::string& path) {
const char* command = MatchPathSegment(path.c_str(), "/json");
if (command == nullptr)
return false;
@@ -354,21 +366,22 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
bool connected = false;
for (const auto& session : connected_sessions_) {
- if (session.second->TargetId() == id) {
+ if (session.second->IsForTarget(id)) {
connected = true;
break;
}
}
if (!connected) {
std::string host;
+ int port = SocketSession::ServerPortForClient(socket);
GetSocketHost(&socket->tcp, &host);
- std::string address = GetWsUrl(host, port_, id);
std::ostringstream frontend_url;
frontend_url << "chrome-devtools://devtools/bundled";
frontend_url << "/inspector.html?experiments=true&v8only=true&ws=";
- frontend_url << address;
+ frontend_url << FormatWsAddress(host, port, id, false);
target_map["devtoolsFrontendUrl"] += frontend_url.str();
- target_map["webSocketDebuggerUrl"] = "ws://" + address;
+ target_map["webSocketDebuggerUrl"] =
+ FormatWsAddress(host, port, id, true);
}
}
SendHttpResponse(socket, MapsToString(response));
@@ -376,30 +389,44 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
bool InspectorSocketServer::Start() {
CHECK_EQ(state_, ServerState::kNew);
- sockaddr_in addr;
- uv_tcp_init(loop_, &server_);
- uv_ip4_addr(host_.c_str(), port_, &addr);
- int err = uv_tcp_bind(&server_,
- reinterpret_cast<const struct sockaddr*>(&addr), 0);
- if (err == 0)
- err = GetPort(&server_, &port_);
- if (err == 0) {
- err = uv_listen(reinterpret_cast<uv_stream_t*>(&server_), 1,
- SocketConnectedCallback);
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICSERV;
+ hints.ai_socktype = SOCK_STREAM;
+ uv_getaddrinfo_t req;
+ const std::string port_string = std::to_string(port_);
+ int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
+ port_string.c_str(), &hints);
+ if (err < 0) {
+ if (out_ != NULL) {
+ fprintf(out_, "Unable to resolve \"%s\": %s\n", host_.c_str(),
+ uv_strerror(err));
+ }
+ return false;
}
- if (err == 0 && connected_sessions_.empty()) {
- state_ = ServerState::kRunning;
- PrintDebuggerReadyMessage(host_, port_, delegate_->GetTargetIds(), out_);
+ for (addrinfo* address = req.addrinfo; address != nullptr;
+ address = address->ai_next) {
+ err = ServerSocket::Listen(this, address->ai_addr, loop_);
}
- if (err != 0 && connected_sessions_.empty()) {
+ uv_freeaddrinfo(req.addrinfo);
+
+ if (!connected_sessions_.empty()) {
+ return true;
+ }
+ // We only show error if we failed to start server on all addresses. We only
+ // show one error, for the last address.
+ if (server_sockets_.empty()) {
if (out_ != NULL) {
fprintf(out_, "Starting inspector on %s:%d failed: %s\n",
host_.c_str(), port_, uv_strerror(err));
fflush(out_);
}
- uv_close(reinterpret_cast<uv_handle_t*>(&server_), nullptr);
return false;
}
+ state_ = ServerState::kRunning;
+ // getaddrinfo sorts the addresses, so the first port is most relevant.
+ PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
+ delegate_->GetTargetIds(), out_);
return true;
}
@@ -411,7 +438,8 @@ void InspectorSocketServer::Stop(ServerCallback cb) {
closer_->AddCallback(cb);
closer_->IncreaseExpectedCount();
state_ = ServerState::kStopping;
- uv_close(reinterpret_cast<uv_handle_t*>(&server_), ServerClosedCallback);
+ for (ServerSocket* server_socket : server_sockets_)
+ server_socket->Close();
closer_->NotifyIfDone();
}
@@ -434,37 +462,41 @@ void InspectorSocketServer::Send(int session_id, const std::string& message) {
}
}
-// static
-void InspectorSocketServer::ServerClosedCallback(uv_handle_t* server) {
- InspectorSocketServer* socket_server = InspectorSocketServer::From(server);
- CHECK_EQ(socket_server->state_, ServerState::kStopping);
- if (socket_server->closer_) {
- socket_server->closer_->DecreaseExpectedCount();
+void InspectorSocketServer::ServerSocketListening(ServerSocket* server_socket) {
+ server_sockets_.push_back(server_socket);
+}
+
+void InspectorSocketServer::ServerSocketClosed(ServerSocket* server_socket) {
+ CHECK_EQ(state_, ServerState::kStopping);
+
+ server_sockets_.erase(std::remove(server_sockets_.begin(),
+ server_sockets_.end(), server_socket),
+ server_sockets_.end());
+ if (!server_sockets_.empty())
+ return;
+
+ if (closer_ != nullptr) {
+ closer_->DecreaseExpectedCount();
}
- if (socket_server->connected_sessions_.empty()) {
- socket_server->delegate_->ServerDone();
+ if (connected_sessions_.empty()) {
+ delegate_->ServerDone();
}
- socket_server->state_ = ServerState::kStopped;
+ state_ = ServerState::kStopped;
}
-// static
-void InspectorSocketServer::SocketConnectedCallback(uv_stream_t* server,
- int status) {
- if (status == 0) {
- InspectorSocketServer* socket_server = InspectorSocketServer::From(server);
- // Memory is freed when the socket closes.
- SocketSession* session =
- new SocketSession(socket_server, socket_server->next_session_id_++);
- if (inspector_accept(server, session->Socket(), HandshakeCallback) != 0) {
- delete session;
- }
+int InspectorSocketServer::Port() const {
+ if (!server_sockets_.empty()) {
+ return server_sockets_[0]->port();
}
+ return port_;
}
// InspectorSession tracking
-SocketSession::SocketSession(InspectorSocketServer* server, int id)
- : id_(id), server_(server),
- state_(State::kHttp) { }
+SocketSession::SocketSession(InspectorSocketServer* server, int server_port)
+ : id_(server->GenerateSessionId()),
+ server_(server),
+ state_(State::kHttp),
+ server_port_(server_port) { }
void SocketSession::Close() {
CHECK_NE(state_, State::kClosing);
@@ -473,6 +505,49 @@ void SocketSession::Close() {
}
// static
+int SocketSession::Accept(InspectorSocketServer* server, int server_port,
+ uv_stream_t* server_socket) {
+ // Memory is freed when the socket closes.
+ SocketSession* session = new SocketSession(server, server_port);
+ int err = inspector_accept(server_socket, &session->socket_,
+ HandshakeCallback);
+ if (err != 0) {
+ delete session;
+ }
+ return err;
+}
+
+// static
+bool SocketSession::HandshakeCallback(InspectorSocket* socket,
+ inspector_handshake_event event,
+ const std::string& path) {
+ SocketSession* session = SocketSession::From(socket);
+ InspectorSocketServer* server = session->server_;
+ const std::string& id = path.empty() ? path : path.substr(1);
+ switch (event) {
+ case kInspectorHandshakeHttpGet:
+ return server->HandleGetRequest(socket, path);
+ case kInspectorHandshakeUpgrading:
+ if (server->SessionStarted(session, id)) {
+ session->SetTargetId(id);
+ return true;
+ } else {
+ session->SetDeclined();
+ return false;
+ }
+ case kInspectorHandshakeUpgraded:
+ session->FrontendConnected();
+ return true;
+ case kInspectorHandshakeFailed:
+ server->SessionTerminated(session);
+ return false;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+// static
void SocketSession::CloseCallback(InspectorSocket* socket, int code) {
SocketSession* session = SocketSession::From(socket);
CHECK_EQ(State::kClosing, session->state_);
@@ -489,14 +564,12 @@ void SocketSession::FrontendConnected() {
void SocketSession::ReadCallback(uv_stream_t* stream, ssize_t read,
const uv_buf_t* buf) {
InspectorSocket* socket = inspector_from_stream(stream);
- SocketSession::From(socket)->OnRemoteDataIO(read, buf);
-}
-
-void SocketSession::OnRemoteDataIO(ssize_t read, const uv_buf_t* buf) {
+ SocketSession* session = SocketSession::From(socket);
if (read > 0) {
- server_->Delegate()->MessageReceived(id_, std::string(buf->base, read));
+ session->server_->MessageReceived(session->id_,
+ std::string(buf->base, read));
} else {
- Close();
+ session->Close();
}
if (buf != nullptr && buf->base != nullptr)
delete[] buf->base;
@@ -506,5 +579,62 @@ void SocketSession::Send(const std::string& message) {
inspector_write(&socket_, message.data(), message.length());
}
+// ServerSocket implementation
+int ServerSocket::DetectPort() {
+ sockaddr_storage addr;
+ int len = sizeof(addr);
+ int err = uv_tcp_getsockname(&tcp_socket_,
+ reinterpret_cast<struct sockaddr*>(&addr), &len);
+ if (err != 0)
+ return err;
+ int port;
+ if (addr.ss_family == AF_INET6)
+ port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
+ else
+ port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
+ port_ = ntohs(port);
+ return err;
+}
+
+// static
+int ServerSocket::Listen(InspectorSocketServer* inspector_server,
+ sockaddr* addr, uv_loop_t* loop) {
+ ServerSocket* server_socket = new ServerSocket(inspector_server);
+ uv_tcp_t* server = &server_socket->tcp_socket_;
+ CHECK_EQ(0, uv_tcp_init(loop, server));
+ int err = uv_tcp_bind(server, addr, 0);
+ if (err == 0) {
+ err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 1,
+ ServerSocket::SocketConnectedCallback);
+ }
+ if (err == 0) {
+ err = server_socket->DetectPort();
+ }
+ if (err == 0) {
+ inspector_server->ServerSocketListening(server_socket);
+ } else {
+ uv_close(reinterpret_cast<uv_handle_t*>(server), FreeOnCloseCallback);
+ }
+ return err;
+}
+
+// static
+void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket,
+ int status) {
+ if (status == 0) {
+ ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
+ // Memory is freed when the socket closes.
+ SocketSession::Accept(server_socket->server_, server_socket->port_,
+ tcp_socket);
+ }
+}
+
+// static
+void ServerSocket::SocketClosedCallback(uv_handle_t* tcp_socket) {
+ ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
+ server_socket->server_->ServerSocketClosed(server_socket);
+ delete server_socket;
+}
+
} // namespace inspector
} // namespace node