Index: net/socket/tcp_socket_libevent.cc |
diff --git a/net/socket/tcp_socket_libevent.cc b/net/socket/tcp_socket_libevent.cc |
index 444e3c04231ce3f5279e56dad7e43d557d7bc86e..9d8ea7b153daefa63607b9addf3e49241827d903 100644 |
--- a/net/socket/tcp_socket_libevent.cc |
+++ b/net/socket/tcp_socket_libevent.cc |
@@ -13,6 +13,8 @@ |
#include "base/metrics/histogram.h" |
#include "base/metrics/stats_counters.h" |
#include "base/posix/eintr_wrapper.h" |
+#include "base/task_runner_util.h" |
+#include "base/threading/worker_pool.h" |
#include "net/base/address_list.h" |
#include "net/base/connection_type_histograms.h" |
#include "net/base/io_buffer.h" |
@@ -28,6 +30,12 @@ |
#define TCPI_OPT_SYN_DATA 32 |
#endif |
+// True if OS supports TCP FastOpen. |
+bool g_tcp_fastopen_supported = false; |
+// True if OS supports TCP FastOpen and is turned on for all connections. |
+// TODO(jri): Change global variable to param in HttpNetworkSession::Params. |
+bool g_tcp_fastopen_enabled = false; |
+ |
namespace net { |
namespace { |
@@ -69,13 +77,62 @@ bool SetTCPKeepAlive(int fd, bool enable, int delay) { |
return true; |
} |
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+// Checks if the kernel supports TCP FastOpen. |
+bool SystemSupportsTCPFastOpen() { |
+ static const base::FilePath::CharType kTCPFastOpenProcFilePath[] = |
+ "/proc/sys/net/ipv4/tcp_fastopen"; |
+ std::string system_supports_tcp_fastopen; |
+ if (!base::ReadFileToString(base::FilePath(kTCPFastOpenProcFilePath), |
+ &system_supports_tcp_fastopen)) { |
+ return false; |
+ } |
+ // The read from /proc should return '1' if TCP FastOpen is enabled in the OS. |
+ if (system_supports_tcp_fastopen.empty() || |
+ (system_supports_tcp_fastopen[0] != '1')) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void CallbackForTCPFastOpenCheck(bool user_enabled, |
+ bool system_supported) { |
+ g_tcp_fastopen_supported = system_supported; |
+ if (user_enabled) { |
+ g_tcp_fastopen_enabled = system_supported; |
+ } |
+} |
+#endif |
+ |
+// Check if TCP FastOpen option is supported by the OS. |
+bool IsTCPFastOpenSupported() { |
+ return g_tcp_fastopen_supported; |
+} |
+ |
+// Check if TCP FastOpen option is enabled. |
+bool IsTCPFastOpenEnabled() { |
+ return g_tcp_fastopen_enabled; |
+} |
+ |
} // namespace |
//----------------------------------------------------------------------------- |
+// This is asynchronous because it needs to do file IO, and it isn't allowed to |
+// do that on the IO thread. |
+void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) { |
Randy Smith (Not in Mondays)
2014/08/19 18:25:43
This looks to be called on all platforms but not d
Jana
2014/08/22 03:35:19
Ah -- Great catch! Yes, it is not defined... will
|
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+ base::PostTaskAndReplyWithResult( |
+ base::WorkerPool::GetTaskRunner(/*task_is_slow=*/false), |
+ FROM_HERE, |
+ base::Bind(SystemSupportsTCPFastOpen), |
+ base::Bind(CallbackForTCPFastOpenCheck, user_enabled)); |
+#endif |
+} |
+ |
TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, |
const NetLog::Source& source) |
- : use_tcp_fastopen_(IsTCPFastOpenEnabled()), |
+ : use_tcp_fastopen_if_supported_(IsTCPFastOpenEnabled()), |
tcp_fastopen_connected_(false), |
fast_open_status_(FAST_OPEN_STATUS_UNKNOWN), |
logging_multiple_connect_attempts_(false), |
@@ -167,7 +224,7 @@ int TCPSocketLibevent::Connect(const IPEndPoint& address, |
if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
return ERR_ADDRESS_INVALID; |
- if (use_tcp_fastopen_) { |
+ if (use_tcp_fastopen_if_supported_) { |
// With TCP FastOpen, we pretend that the socket is connected. |
DCHECK(!tcp_fastopen_connected_); |
socket_->SetPeerAddress(storage); |
@@ -186,7 +243,7 @@ bool TCPSocketLibevent::IsConnected() const { |
if (!socket_) |
return false; |
- if (use_tcp_fastopen_ && !tcp_fastopen_connected_ && |
+ if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_ && |
socket_->HasPeerAddress()) { |
// With TCP FastOpen, we pretend that the socket is connected. |
// This allows GetPeerAddress() to return peer_address_. |
@@ -235,7 +292,7 @@ int TCPSocketLibevent::Write(IOBuffer* buf, |
// ownership of buf to socket. |
base::Unretained(this), make_scoped_refptr(buf), callback); |
int rv; |
- if (use_tcp_fastopen_ && !tcp_fastopen_connected_) { |
+ if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_) { |
rv = TcpFastOpenWrite(buf, buf_len, write_callback); |
} else { |
rv = socket_->Write(buf, buf_len, write_callback); |
@@ -366,7 +423,12 @@ void TCPSocketLibevent::Close() { |
} |
bool TCPSocketLibevent::UsingTCPFastOpen() const { |
- return use_tcp_fastopen_; |
+ return use_tcp_fastopen_if_supported_; |
+} |
+ |
+void TCPSocketLibevent::EnableTCPFastOpen() { |
+ if (!use_tcp_fastopen_if_supported_ && IsTCPFastOpenSupported()) |
+ use_tcp_fastopen_if_supported_ = true; |
} |
bool TCPSocketLibevent::IsValid() const { |
@@ -495,7 +557,7 @@ void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf, |
const CompletionCallback& callback, |
int rv) { |
DCHECK_NE(ERR_IO_PENDING, rv); |
- // Records fast open status regardless of error in asynchronous case. |
+ // Records TCP FastOpen status regardless of error in asynchronous case. |
// TODO(rdsmith,jri): Change histogram name to indicate it could be called on |
// error. |
RecordFastOpenStatus(); |
@@ -590,14 +652,14 @@ int TCPSocketLibevent::TcpFastOpenWrite( |
} |
void TCPSocketLibevent::RecordFastOpenStatus() { |
- if (use_tcp_fastopen_ && |
+ if (use_tcp_fastopen_if_supported_ && |
(fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN || |
fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) { |
DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_); |
bool getsockopt_success(false); |
bool server_acked_data(false); |
#if defined(TCP_INFO) |
- // Probe to see the if the socket used TCP Fast Open. |
+ // Probe to see the if the socket used TCP FastOpen. |
tcp_info info; |
socklen_t info_len = sizeof(tcp_info); |
getsockopt_success = |