summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 07:24:46 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 07:24:46 +0000
commit9c14ff54e675f0179a097a82e51286220b24252d (patch)
tree6e09053324bb47330ab70a1352b40fae3dce6550 /net/socket
parent898abdf0b86ebe7903b0db6ef147c31df9697b7c (diff)
downloadchromium_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.cc48
-rw-r--r--net/socket/tcp_client_socket.h4
-rw-r--r--net/socket/tcp_client_socket_libevent.cc32
-rw-r--r--net/socket/tcp_client_socket_libevent.h2
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_;