Commit b42977ee authored by John Chen's avatar John Chen Committed by Commit Bot

Reland "[ChromeDriver] Listen on both IPv4 & IPv6"

This is a reland of c902850a

Original change's description:
> [ChromeDriver] Listen on both IPv4 & IPv6
> 
> On hosts that support both IPv4 and IPv6, ChromeDriver now listens on
> both protocols.
> 
> Bug: chromedriver:779
> Change-Id: I4a115cc0ca5cf0396acdad8d4c1a72f169120368
> Reviewed-on: https://chromium-review.googlesource.com/1080448
> Reviewed-by: Caleb Rouleau <crouleau@chromium.org>
> Reviewed-by: Jonathon Kereliuk <kereliuk@chromium.org>
> Commit-Queue: John Chen <johnchen@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#564984}

Bug: chromedriver:779
Change-Id: Id8949883a272c33f9c1fc975ba8706f6fca908b4
Reviewed-on: https://chromium-review.googlesource.com/1112159
Commit-Queue: John Chen <johnchen@chromium.org>
Reviewed-by: default avatarCaleb Rouleau <crouleau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571350}
parent fbeb7bf2
......@@ -17,6 +17,7 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
......@@ -77,22 +78,20 @@ class HttpServer : public net::HttpServer::Delegate {
~HttpServer() override {}
bool Start(uint16_t port, bool allow_remote) {
int Start(uint16_t port, bool allow_remote, bool use_ipv4) {
std::unique_ptr<net::ServerSocket> server_socket(
new net::TCPServerSocket(NULL, net::NetLogSource()));
if (ListenOnIPv4(server_socket.get(), port, allow_remote) != net::OK) {
// This will work on an IPv6-only host, but we will be IPv4-only on
// dual-stack hosts.
// TODO(samuong): change this to listen on both IPv4 and IPv6.
VLOG(0) << "listen on IPv4 failed, trying IPv6";
if (ListenOnIPv6(server_socket.get(), port, allow_remote) != net::OK) {
VLOG(1) << "listen on both IPv4 and IPv6 failed, giving up";
return false;
}
int status = use_ipv4
? ListenOnIPv4(server_socket.get(), port, allow_remote)
: ListenOnIPv6(server_socket.get(), port, allow_remote);
if (status != net::OK) {
VLOG(0) << "listen on " << (use_ipv4 ? "IPv4" : "IPv6")
<< " failed with error " << net::ErrorToShortString(status);
return status;
}
server_.reset(new net::HttpServer(std::move(server_socket), this));
net::IPEndPoint address;
return server_->GetLocalAddress(&address) == net::OK;
return server_->GetLocalAddress(&address);
}
// Overridden from net::HttpServer::Delegate:
......@@ -174,24 +173,95 @@ void HandleRequestOnIOThread(
}
base::LazyInstance<base::ThreadLocalPointer<HttpServer>>::DestructorAtExit
lazy_tls_server = LAZY_INSTANCE_INITIALIZER;
lazy_tls_server_ipv4 = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<base::ThreadLocalPointer<HttpServer>>::DestructorAtExit
lazy_tls_server_ipv6 = LAZY_INSTANCE_INITIALIZER;
void StopServerOnIOThread() {
// Note, |server| may be NULL.
HttpServer* server = lazy_tls_server.Pointer()->Get();
lazy_tls_server.Pointer()->Set(NULL);
HttpServer* server = lazy_tls_server_ipv4.Pointer()->Get();
lazy_tls_server_ipv4.Pointer()->Set(NULL);
delete server;
server = lazy_tls_server_ipv6.Pointer()->Get();
lazy_tls_server_ipv6.Pointer()->Set(NULL);
delete server;
}
void StartServerOnIOThread(uint16_t port,
bool allow_remote,
const HttpRequestHandlerFunc& handle_request_func) {
std::unique_ptr<HttpServer> temp_server(new HttpServer(handle_request_func));
if (!temp_server->Start(port, allow_remote)) {
printf("Port not available. Exiting...\n");
std::unique_ptr<HttpServer> temp_server;
temp_server.reset(new HttpServer(handle_request_func));
int ipv6_status = temp_server->Start(port, allow_remote, false);
if (ipv6_status == net::OK) {
lazy_tls_server_ipv6.Pointer()->Set(temp_server.release());
} else if (ipv6_status == net::ERR_ADDRESS_IN_USE) {
printf("IPv6 port not available. Exiting...\n");
exit(1);
}
// In some cases, binding to an IPv6 port also binds to the same IPv4 port.
// The following code determines if it is necessary to bind to IPv4 port.
enum class NeedIPv4 { NOT_NEEDED, UNKNOWN, NEEDED } need_ipv4;
// Dual-protocol bind deosn't work while binding to localhost (!allow_remote).
if (!allow_remote || ipv6_status != net::OK) {
need_ipv4 = NeedIPv4::NEEDED;
} else {
// Currently, the network layer provides no way for us to control dual-protocol
// bind option, or to query the current setting of that option, so we do our
// best to determine the current setting. See https://crbug.com/858892.
#if defined(OS_MACOSX)
need_ipv4 = NeedIPv4::NEEDED;
#elif defined(OS_LINUX)
// On Linux, dual-protocol bind is controlled by a system file.
// ChromeOS builds also have OS_LINUX defined, so the code below applies.
std::string bindv6only;
base::FilePath bindv6only_filename("/proc/sys/net/ipv6/bindv6only");
if (!base::ReadFileToString(bindv6only_filename, &bindv6only)) {
LOG(WARNING) << "Unable to read " << bindv6only_filename << ".";
need_ipv4 = NeedIPv4::UNKNOWN;
} else if (bindv6only == "1\n") {
need_ipv4 = NeedIPv4::NEEDED;
} else if (bindv6only == "0\n") {
need_ipv4 = NeedIPv4::NOT_NEEDED;
} else {
LOG(WARNING) << "Unexpected " << bindv6only_filename << " contents.";
need_ipv4 = NeedIPv4::UNKNOWN;
}
#elif defined(OS_WIN)
// On Windows, the net component always enables dual-protocol bind. See
// https://chromium.googlesource.com/chromium/src/+/69.0.3464.0/net/socket/socket_descriptor.cc#28.
need_ipv4 = NeedIPv4::NOT_NEEDED;
#else
LOG(WARNING)
<< "Running on a platform not officially supported by ChromeDriver.";
need_ipv4 = NeedIPv4::UNKNOWN;
#endif
}
int ipv4_status;
if (need_ipv4 == NeedIPv4::NOT_NEEDED) {
ipv4_status = ipv6_status;
} else {
temp_server.reset(new HttpServer(handle_request_func));
ipv4_status = temp_server->Start(port, allow_remote, true);
if (ipv4_status == net::OK) {
lazy_tls_server_ipv4.Pointer()->Set(temp_server.release());
} else if (ipv4_status == net::ERR_ADDRESS_IN_USE) {
if (need_ipv4 == NeedIPv4::NEEDED) {
printf("IPv4 port not available. Exiting...\n");
exit(1);
} else {
printf("Unable to determine if bind to IPv4 port was successful.\n");
}
}
}
if (ipv4_status != net::OK && ipv6_status != net::OK) {
printf("Unable to start server with either IPv4 or IPv6. Exiting...\n");
exit(1);
}
lazy_tls_server.Pointer()->Set(temp_server.release());
}
void RunServer(uint16_t port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment