summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-29 23:15:06 +0000
committerpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-29 23:15:06 +0000
commit820b984a7efeb99f6672565483016a9e920ee8b9 (patch)
tree6a2cf702de516d7dd3bdf43e538ed830026d3e3a /net
parent57018f97a1ebf369add876529dc38f270b29bd3f (diff)
downloadchromium_src-820b984a7efeb99f6672565483016a9e920ee8b9.zip
chromium_src-820b984a7efeb99f6672565483016a9e920ee8b9.tar.gz
chromium_src-820b984a7efeb99f6672565483016a9e920ee8b9.tar.bz2
Add socket.setKeepAlive() and socket.setNoDelay().
BUG=124950,124951 TEST=unit_tests --gtest_filter=SocketTest.* TEST=browser_tests --gtest_filter=SocketApiTest.* Review URL: https://chromiumcodereview.appspot.com/10453012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139416 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/socket/tcp_client_socket_libevent.cc46
-rw-r--r--net/socket/tcp_client_socket_libevent.h3
-rw-r--r--net/socket/tcp_client_socket_win.cc107
-rw-r--r--net/socket/tcp_client_socket_win.h3
4 files changed, 98 insertions, 61 deletions
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 972d75d..5254c1f 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -32,37 +32,39 @@ namespace net {
namespace {
const int kInvalidSocket = -1;
+const int kTCPKeepAliveSeconds = 45;
-// DisableNagle turns off buffering in the kernel. By default, TCP sockets will
-// wait up to 200ms for more data to complete a packet before transmitting.
+// SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets
+// will wait up to 200ms for more data to complete a packet before transmitting.
// After calling this function, the kernel will not wait. See TCP_NODELAY in
// `man 7 tcp`.
-int DisableNagle(int fd) {
- int on = 1;
- return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+bool SetTCPNoDelay(int fd, bool no_delay) {
+ int on = no_delay ? 1 : 0;
+ int error = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on,
+ sizeof(on));
+ return error == 0;
}
// SetTCPKeepAlive sets SO_KEEPALIVE.
-void SetTCPKeepAlive(int fd) {
- int optval = 1;
- socklen_t optlen = sizeof(optval);
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)) {
+bool SetTCPKeepAlive(int fd, bool enable, int delay) {
+ int on = enable ? 1 : 0;
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) {
PLOG(ERROR) << "Failed to set SO_KEEPALIVE on fd: " << fd;
- return;
+ return false;
}
#if defined(OS_LINUX)
// Set seconds until first TCP keep alive.
- optval = 45;
- if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen)) {
+ if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) {
PLOG(ERROR) << "Failed to set TCP_KEEPIDLE on fd: " << fd;
- return;
+ return false;
}
// Set seconds between TCP keep alives.
- if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen)) {
+ if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &delay, sizeof(delay))) {
PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd;
- return;
+ return false;
}
#endif
+ return true;
}
// Sets socket parameters. Returns the OS error code (or 0 on
@@ -73,8 +75,8 @@ int SetupSocket(int socket) {
// This mirrors the behaviour on Windows. See the comment in
// tcp_client_socket_win.cc after searching for "NODELAY".
- DisableNagle(socket); // If DisableNagle fails, we don't care.
- SetTCPKeepAlive(socket);
+ SetTCPNoDelay(socket, true); // If SetTCPNoDelay fails, we don't care.
+ SetTCPKeepAlive(socket, true, kTCPKeepAliveSeconds);
return 0;
}
@@ -560,6 +562,16 @@ bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) {
return rv == 0;
}
+bool TCPClientSocketLibevent::SetKeepAlive(bool enable, int delay) {
+ int socket = socket_ != kInvalidSocket ? socket_ : bound_socket_;
+ return SetTCPKeepAlive(socket, enable, delay);
+}
+
+bool TCPClientSocketLibevent::SetNoDelay(bool no_delay) {
+ int socket = socket_ != kInvalidSocket ? socket_ : bound_socket_;
+ return SetTCPNoDelay(socket, no_delay);
+}
+
void TCPClientSocketLibevent::LogConnectCompletion(int net_error) {
if (net_error == OK)
UpdateConnectionTypeHistograms(CONNECTION_ANY);
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index b984649..f66c8c1 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -70,6 +70,9 @@ class NET_EXPORT_PRIVATE TCPClientSocketLibevent : public StreamSocket,
virtual bool SetReceiveBufferSize(int32 size) OVERRIDE;
virtual bool SetSendBufferSize(int32 size) OVERRIDE;
+ virtual bool SetKeepAlive(bool enable, int delay);
+ virtual bool SetNoDelay(bool no_delay);
+
private:
// State machine for connecting the socket.
enum ConnectState {
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 4990887..6ffd821 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -27,6 +27,8 @@ namespace net {
namespace {
+const int kTCPKeepAliveSeconds = 45;
+
bool SetSocketReceiveBufferSize(SOCKET socket, int32 size) {
int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
reinterpret_cast<const char*>(&size), sizeof(size));
@@ -41,6 +43,57 @@ bool SetSocketSendBufferSize(SOCKET socket, int32 size) {
return rv == 0;
}
+// Disable Nagle.
+// The Nagle implementation on windows is governed by RFC 896. The idea
+// behind Nagle is to reduce small packets on the network. When Nagle is
+// enabled, if a partial packet has been sent, the TCP stack will disallow
+// further *partial* packets until an ACK has been received from the other
+// side. Good applications should always strive to send as much data as
+// possible and avoid partial-packet sends. However, in most real world
+// applications, there are edge cases where this does not happen, and two
+// partial packets may be sent back to back. For a browser, it is NEVER
+// a benefit to delay for an RTT before the second packet is sent.
+//
+// As a practical example in Chromium today, consider the case of a small
+// POST. I have verified this:
+// Client writes 649 bytes of header (partial packet #1)
+// Client writes 50 bytes of POST data (partial packet #2)
+// In the above example, with Nagle, a RTT delay is inserted between these
+// two sends due to nagle. RTTs can easily be 100ms or more. The best
+// fix is to make sure that for POSTing data, we write as much data as
+// possible and minimize partial packets. We will fix that. But disabling
+// Nagle also ensure we don't run into this delay in other edge cases.
+// See also:
+// http://technet.microsoft.com/en-us/library/bb726981.aspx
+bool DisableNagle(SOCKET socket, bool disable) {
+ BOOL val = disable ? TRUE : FALSE;
+ int rv = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
+ reinterpret_cast<const char*>(&val),
+ sizeof(val));
+ DCHECK(!rv) << "Could not disable nagle";
+ return rv == 0;
+}
+
+// Enable TCP Keep-Alive to prevent NAT routers from timing out TCP
+// connections. See http://crbug.com/27400 for details.
+bool SetTCPKeepAlive(SOCKET socket, BOOL enable, int delay_secs) {
+ int delay = delay_secs * 1000;
+ struct tcp_keepalive keepalive_vals = {
+ enable ? 1 : 0, // TCP keep-alive on.
+ delay, // Delay seconds before sending first TCP keep-alive packet.
+ delay, // Delay seconds between sending TCP keep-alive packets.
+ };
+ DWORD bytes_returned = 0xABAB;
+ int rv = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &keepalive_vals,
+ sizeof(keepalive_vals), NULL, 0,
+ &bytes_returned, NULL, NULL);
+ DCHECK(!rv) << "Could not enable TCP Keep-Alive for socket: " << socket
+ << " [error: " << WSAGetLastError() << "].";
+
+ // Disregard any failure in disabling nagle or enabling TCP Keep-Alive.
+ return rv == 0;
+}
+
// Sets socket parameters. Returns the OS error code (or 0 on
// success).
int SetupSocket(SOCKET socket) {
@@ -60,50 +113,8 @@ int SetupSocket(SOCKET socket) {
SetSocketSendBufferSize(socket, kSocketBufferSize);
}
- // Disable Nagle.
- // The Nagle implementation on windows is governed by RFC 896. The idea
- // behind Nagle is to reduce small packets on the network. When Nagle is
- // enabled, if a partial packet has been sent, the TCP stack will disallow
- // further *partial* packets until an ACK has been received from the other
- // side. Good applications should always strive to send as much data as
- // possible and avoid partial-packet sends. However, in most real world
- // applications, there are edge cases where this does not happen, and two
- // partil packets may be sent back to back. For a browser, it is NEVER
- // a benefit to delay for an RTT before the second packet is sent.
- //
- // As a practical example in Chromium today, consider the case of a small
- // POST. I have verified this:
- // Client writes 649 bytes of header (partial packet #1)
- // Client writes 50 bytes of POST data (partial packet #2)
- // In the above example, with Nagle, a RTT delay is inserted between these
- // two sends due to nagle. RTTs can easily be 100ms or more. The best
- // fix is to make sure that for POSTing data, we write as much data as
- // possible and minimize partial packets. We will fix that. But disabling
- // Nagle also ensure we don't run into this delay in other edge cases.
- // See also:
- // http://technet.microsoft.com/en-us/library/bb726981.aspx
- const BOOL kDisableNagle = TRUE;
- int rv = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
- reinterpret_cast<const char*>(&kDisableNagle),
- sizeof(kDisableNagle));
- DCHECK(!rv) << "Could not disable nagle";
-
- // Enable TCP Keep-Alive to prevent NAT routers from timing out TCP
- // connections. See http://crbug.com/27400 for details.
-
- struct tcp_keepalive keepalive_vals = {
- 1, // TCP keep-alive on.
- 45000, // Wait 45s until sending first TCP keep-alive packet.
- 45000, // Wait 45s between sending TCP keep-alive packets.
- };
- DWORD bytes_returned = 0xABAB;
- rv = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &keepalive_vals,
- sizeof(keepalive_vals), NULL, 0,
- &bytes_returned, NULL, NULL);
- DCHECK(!rv) << "Could not enable TCP Keep-Alive for socket: " << socket
- << " [error: " << WSAGetLastError() << "].";
-
- // Disregard any failure in disabling nagle or enabling TCP Keep-Alive.
+ DisableNagle(socket, true);
+ SetTCPKeepAlive(socket, true, kTCPKeepAliveSeconds);
return 0;
}
@@ -782,6 +793,14 @@ bool TCPClientSocketWin::SetSendBufferSize(int32 size) {
return SetSocketSendBufferSize(socket_, size);
}
+bool TCPClientSocketWin::SetKeepAlive(bool enable, int delay) {
+ return SetTCPKeepAlive(socket_, enable, delay);
+}
+
+bool TCPClientSocketWin::SetNoDelay(bool no_delay) {
+ return DisableNagle(socket_, no_delay);
+}
+
void TCPClientSocketWin::LogConnectCompletion(int net_error) {
if (net_error == OK)
UpdateConnectionTypeHistograms(CONNECTION_ANY);
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index c17a0b9..14720ae 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -68,6 +68,9 @@ class NET_EXPORT TCPClientSocketWin : public StreamSocket,
virtual bool SetReceiveBufferSize(int32 size);
virtual bool SetSendBufferSize(int32 size);
+ virtual bool SetKeepAlive(bool enable, int delay);
+ virtual bool SetNoDelay(bool no_delay);
+
private:
// State machine for connecting the socket.
enum ConnectState {