diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 07:24:46 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 07:24:46 +0000 |
commit | 9c14ff54e675f0179a097a82e51286220b24252d (patch) | |
tree | 6e09053324bb47330ab70a1352b40fae3dce6550 /net/socket | |
parent | 898abdf0b86ebe7903b0db6ef147c31df9697b7c (diff) | |
download | chromium_src-9c14ff54e675f0179a097a82e51286220b24252d.zip chromium_src-9c14ff54e675f0179a097a82e51286220b24252d.tar.gz chromium_src-9c14ff54e675f0179a097a82e51286220b24252d.tar.bz2 |
Initial fixes for TCP Fast Open.
* Detect whether or not the system supports TCP Fast Open.
* Don't enable TCP Fast Open if the system does not support/enable it.
* Handle EWOULDBLOCK|EAGAIN by returning ERR_IO_PENDING so the client code knows to retry later (the failed TCP Fast Open sendto() will cause the kernel to do a connect() internally).
There are loads of edge cases this doesn't catch yet. This is only intended for minimal testing, behind a command line flag.
BUG=175623
Review URL: https://chromiumcodereview.appspot.com/12221131
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182951 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r-- | net/socket/tcp_client_socket.cc | 48 | ||||
-rw-r--r-- | net/socket/tcp_client_socket.h | 4 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_libevent.cc | 32 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_libevent.h | 2 |
4 files changed, 63 insertions, 23 deletions
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc index d3d4e20..441d4fe 100644 --- a/net/socket/tcp_client_socket.cc +++ b/net/socket/tcp_client_socket.cc @@ -1,18 +1,58 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/socket/tcp_client_socket.h" +#include "base/file_path.h" +#include "base/file_util.h" + namespace net { +namespace { + +#if defined(OS_LINUX) + +// Checks to see if the system supports TCP FastOpen. Notably, it requires +// kernel support. Additionally, this checks system configuration to ensure that +// it's enabled. +bool SystemSupportsTCPFastOpen() { + static const FilePath::CharType kTCPFastOpenProcFilePath[] = + "/proc/sys/net/ipv4/tcp_fastopen"; + std::string system_enabled_tcp_fastopen; + if (!file_util::ReadFileToString( + base::FilePath(kTCPFastOpenProcFilePath), + &system_enabled_tcp_fastopen)) { + return false; + } + + // As per http://lxr.linux.no/linux+v3.7.7/include/net/tcp.h#L225 + // TFO_CLIENT_ENABLE is the LSB + if (system_enabled_tcp_fastopen.empty() || + (system_enabled_tcp_fastopen[0] & 0x1) == 0) { + return false; + } + + return true; +} + +#else + +bool SystemSupportsTCPFastOpen() { + return false; +} + +#endif + +} + static bool g_tcp_fastopen_enabled = false; -void set_tcp_fastopen_enabled(bool value) { - g_tcp_fastopen_enabled = value; +void SetTCPFastOpenEnabled(bool value) { + g_tcp_fastopen_enabled = value && SystemSupportsTCPFastOpen(); } -bool is_tcp_fastopen_enabled() { +bool IsTCPFastOpenEnabled() { return g_tcp_fastopen_enabled; } diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h index e8a37d7..8a2c0cd 100644 --- a/net/socket/tcp_client_socket.h +++ b/net/socket/tcp_client_socket.h @@ -25,10 +25,10 @@ typedef TCPClientSocketLibevent TCPClientSocket; // Enable/disable experimental TCP FastOpen option. // Not thread safe. Must be called during initialization/startup only. -NET_EXPORT void set_tcp_fastopen_enabled(bool value); +NET_EXPORT void SetTCPFastOpenEnabled(bool value); // Check if the TCP FastOpen option is enabled. -bool is_tcp_fastopen_enabled(); +bool IsTCPFastOpenEnabled(); } // namespace net diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc index d1de66d..564d439 100644 --- a/net/socket/tcp_client_socket_libevent.cc +++ b/net/socket/tcp_client_socket_libevent.cc @@ -136,14 +136,11 @@ TCPClientSocketLibevent::TCPClientSocketLibevent( connect_os_error_(0), net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), previously_disconnected_(false), - use_tcp_fastopen_(false), + use_tcp_fastopen_(IsTCPFastOpenEnabled()), tcp_fastopen_connected_(false), num_bytes_read_(0) { net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, source.ToEventParametersCallback()); - - if (is_tcp_fastopen_enabled()) - use_tcp_fastopen_ = true; } TCPClientSocketLibevent::~TCPClientSocketLibevent() { @@ -520,12 +517,14 @@ int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) { return -1; } - // We have a limited amount of data to send in the SYN packet. - int kMaxFastOpenSendLength = 1420; - - buf_len = std::min(kMaxFastOpenSendLength, buf_len); - - int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN + int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN. +#if defined(OS_LINUX) + // sendto() will fail with EPIPE when the system doesn't support TCP Fast + // Open. Theoretically that shouldn't happen since the caller should check + // for system support on startup, but users may dynamically disable TCP Fast + // Open via sysctl. + flags |= MSG_NOSIGNAL; +#endif // defined(OS_LINUX) nwrite = HANDLE_EINTR(sendto(socket_, buf->data(), buf_len, @@ -535,15 +534,16 @@ int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) { tcp_fastopen_connected_ = true; if (nwrite < 0) { - // Non-blocking mode is returning EINPROGRESS rather than EAGAIN. + DCHECK_NE(EPIPE, errno); + + // If errno == EINPROGRESS, that means the kernel didn't have a cookie + // and would block. The kernel is internally doing a connect() though. + // Remap EINPROGRESS to EAGAIN so we treat this the same as our other + // asynchronous cases. Note that the user buffer has not been copied to + // kernel space. if (errno == EINPROGRESS) errno = EAGAIN; - // Unlike "normal" nonblocking sockets, the data is already queued, - // so tell the app that we've consumed it. - // TODO(wtc): should we test if errno is EAGAIN or EWOULDBLOCK? - // Otherwise, returning buf_len here will mask a real error. - return buf_len; } } else { nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len)); diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h index 0a27c4c..c05877e 100644 --- a/net/socket/tcp_client_socket_libevent.h +++ b/net/socket/tcp_client_socket_libevent.h @@ -191,7 +191,7 @@ class NET_EXPORT_PRIVATE TCPClientSocketLibevent : public StreamSocket, UseHistory use_history_; // Enables experimental TCP FastOpen option. - bool use_tcp_fastopen_; + const bool use_tcp_fastopen_; // True when TCP FastOpen is in use and we have done the connect. bool tcp_fastopen_connected_; |