diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/socket/tcp_client_socket_libevent.cc | 46 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_libevent.h | 3 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_win.cc | 107 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_win.h | 3 |
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 { |