diff options
author | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 23:15:06 +0000 |
---|---|---|
committer | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 23:15:06 +0000 |
commit | 820b984a7efeb99f6672565483016a9e920ee8b9 (patch) | |
tree | 6a2cf702de516d7dd3bdf43e538ed830026d3e3a | |
parent | 57018f97a1ebf369add876529dc38f270b29bd3f (diff) | |
download | chromium_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
-rw-r--r-- | chrome/browser/extensions/api/socket/socket.cc | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/socket.h | 4 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/socket_api.cc | 47 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/socket_api.h | 34 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/tcp_socket.cc | 12 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/tcp_socket.h | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/api/socket/tcp_socket_unittest.cc | 54 | ||||
-rw-r--r-- | chrome/common/extensions/api/experimental_socket.idl | 25 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/socket/api/background.js | 44 | ||||
-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 |
13 files changed, 314 insertions, 75 deletions
diff --git a/chrome/browser/extensions/api/socket/socket.cc b/chrome/browser/extensions/api/socket/socket.cc index e1e3004..286fbbd6 100644 --- a/chrome/browser/extensions/api/socket/socket.cc +++ b/chrome/browser/extensions/api/socket/socket.cc @@ -74,6 +74,14 @@ void Socket::OnWriteComplete(int result) { WriteData(); } +bool Socket::SetKeepAlive(bool enable, int delay) { + return false; +} + +bool Socket::SetNoDelay(bool no_delay) { + return false; +} + // static bool Socket::StringAndPortToIPEndPoint(const std::string& ip_address_str, int port, diff --git a/chrome/browser/extensions/api/socket/socket.h b/chrome/browser/extensions/api/socket/socket.h index c6ee7e3..60feeeb 100644 --- a/chrome/browser/extensions/api/socket/socket.h +++ b/chrome/browser/extensions/api/socket/socket.h @@ -60,6 +60,10 @@ class Socket : public APIResource { const std::string& address, int port, const CompletionCallback& callback) = 0; + + virtual bool SetKeepAlive(bool enable, int delay); + virtual bool SetNoDelay(bool no_delay); + static bool StringAndPortToAddressList(const std::string& ip_address_str, int port, net::AddressList* address_list); diff --git a/chrome/browser/extensions/api/socket/socket_api.cc b/chrome/browser/extensions/api/socket/socket_api.cc index 98fa6f2..268423b 100644 --- a/chrome/browser/extensions/api/socket/socket_api.cc +++ b/chrome/browser/extensions/api/socket/socket_api.cc @@ -307,4 +307,51 @@ void SocketSendToFunction::OnCompleted(int bytes_written) { AsyncWorkCompleted(); } +SocketSetKeepAliveFunction::SocketSetKeepAliveFunction() + : params_(NULL) { +} + +SocketSetKeepAliveFunction::~SocketSetKeepAliveFunction() {} + +bool SocketSetKeepAliveFunction::Prepare() { + params_ = api::experimental_socket::SetKeepAlive::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void SocketSetKeepAliveFunction::Work() { + bool result = false; + Socket* socket = controller()->GetSocket(params_->socket_id); + if (socket) { + int delay = 0; + if (params_->delay.get()) + delay = *params_->delay; + result = socket->SetKeepAlive(params_->enable, delay); + } else { + error_ = kSocketNotFoundError; + } + result_.reset(Value::CreateBooleanValue(result)); +} + +SocketSetNoDelayFunction::SocketSetNoDelayFunction() + : params_(NULL) { +} + +SocketSetNoDelayFunction::~SocketSetNoDelayFunction() {} + +bool SocketSetNoDelayFunction::Prepare() { + params_ = api::experimental_socket::SetNoDelay::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void SocketSetNoDelayFunction::Work() { + bool result = false; + Socket* socket = controller()->GetSocket(params_->socket_id); + if (socket) + result = socket->SetNoDelay(params_->no_delay); + else + error_ = kSocketNotFoundError; + result_.reset(Value::CreateBooleanValue(result)); +} } // namespace extensions diff --git a/chrome/browser/extensions/api/socket/socket_api.h b/chrome/browser/extensions/api/socket/socket_api.h index de6f685..7f31f00 100644 --- a/chrome/browser/extensions/api/socket/socket_api.h +++ b/chrome/browser/extensions/api/socket/socket_api.h @@ -207,6 +207,40 @@ class SocketSendToFunction : public SocketExtensionFunction { int port_; }; +class SocketSetKeepAliveFunction : public SocketExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("experimental.socket.setKeepAlive") + + SocketSetKeepAliveFunction(); + + protected: + virtual ~SocketSetKeepAliveFunction(); + + // AsyncAPIFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<api::experimental_socket::SetKeepAlive::Params> params_; +}; + +class SocketSetNoDelayFunction : public SocketExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("experimental.socket.setNoDelay") + + SocketSetNoDelayFunction(); + + protected: + virtual ~SocketSetNoDelayFunction(); + + // AsyncAPIFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + + private: + scoped_ptr<api::experimental_socket::SetNoDelay::Params> params_; +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_SOCKET_SOCKET_API_H_ diff --git a/chrome/browser/extensions/api/socket/tcp_socket.cc b/chrome/browser/extensions/api/socket/tcp_socket.cc index 6d3d24d..429c6ac 100644 --- a/chrome/browser/extensions/api/socket/tcp_socket.cc +++ b/chrome/browser/extensions/api/socket/tcp_socket.cc @@ -128,6 +128,18 @@ void TCPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer, callback.Run(net::ERR_FAILED); } +bool TCPSocket::SetKeepAlive(bool enable, int delay) { + if (!socket_.get()) + return false; + return socket_->SetKeepAlive(enable, delay); +} + +bool TCPSocket::SetNoDelay(bool no_delay) { + if (!socket_.get()) + return false; + return socket_->SetNoDelay(no_delay); +} + int TCPSocket::WriteImpl(net::IOBuffer* io_buffer, int io_buffer_size, const net::CompletionCallback& callback) { diff --git a/chrome/browser/extensions/api/socket/tcp_socket.h b/chrome/browser/extensions/api/socket/tcp_socket.h index 08c1f19..a536dbe 100644 --- a/chrome/browser/extensions/api/socket/tcp_socket.h +++ b/chrome/browser/extensions/api/socket/tcp_socket.h @@ -41,6 +41,8 @@ class TCPSocket : public Socket { const std::string& address, int port, const CompletionCallback& callback) OVERRIDE; + virtual bool SetKeepAlive(bool enable, int delay) OVERRIDE; + virtual bool SetNoDelay(bool no_delay) OVERRIDE; static TCPSocket* CreateSocketForTesting( net::TCPClientSocket* tcp_client_socket, diff --git a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc index 7066d6b..3e71115 100644 --- a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc +++ b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc @@ -31,6 +31,8 @@ class MockTCPSocket : public net::TCPClientSocket { const net::CompletionCallback& callback)); MOCK_METHOD3(Write, int(net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback)); + MOCK_METHOD2(SetKeepAlive, bool(bool enable, int delay)); + MOCK_METHOD1(SetNoDelay, bool(bool no_delay)); virtual bool IsConnected() const OVERRIDE { return true; } @@ -165,4 +167,56 @@ TEST(SocketTest, TestTCPSocketBlockedWriteReentry) { } } +TEST(SocketTest, TestTCPSocketSetNoDelay) { + net::AddressList address_list; + MockTCPSocket* tcp_client_socket = new MockTCPSocket(address_list); + MockAPIResourceEventNotifier* notifier = new MockAPIResourceEventNotifier(); + + scoped_ptr<TCPSocket> socket(TCPSocket::CreateSocketForTesting( + tcp_client_socket, notifier)); + + bool no_delay = false; + EXPECT_CALL(*tcp_client_socket, SetNoDelay(_)) + .WillOnce(testing::DoAll(SaveArg<0>(&no_delay), Return(true))); + int result = socket->SetNoDelay(true); + EXPECT_TRUE(result); + EXPECT_TRUE(no_delay); + + EXPECT_CALL(*tcp_client_socket, SetNoDelay(_)) + .WillOnce(testing::DoAll(SaveArg<0>(&no_delay), Return(false))); + + result = socket->SetNoDelay(false); + EXPECT_FALSE(result); + EXPECT_FALSE(no_delay); +} + +TEST(SocketTest, TestTCPSocketSetKeepAlive) { + net::AddressList address_list; + MockTCPSocket* tcp_client_socket = new MockTCPSocket(address_list); + MockAPIResourceEventNotifier* notifier = new MockAPIResourceEventNotifier(); + + scoped_ptr<TCPSocket> socket(TCPSocket::CreateSocketForTesting( + tcp_client_socket, notifier)); + + bool enable = false; + int delay = 0; + EXPECT_CALL(*tcp_client_socket, SetKeepAlive(_, _)) + .WillOnce(testing::DoAll(SaveArg<0>(&enable), + SaveArg<1>(&delay), + Return(true))); + int result = socket->SetKeepAlive(true, 4500); + EXPECT_TRUE(result); + EXPECT_TRUE(enable); + EXPECT_EQ(4500, delay); + + EXPECT_CALL(*tcp_client_socket, SetKeepAlive(_, _)) + .WillOnce(testing::DoAll(SaveArg<0>(&enable), + SaveArg<1>(&delay), + Return(false))); + result = socket->SetKeepAlive(false, 0); + EXPECT_FALSE(result); + EXPECT_FALSE(enable); + EXPECT_EQ(0, delay); +} + } // namespace extensions diff --git a/chrome/common/extensions/api/experimental_socket.idl b/chrome/common/extensions/api/experimental_socket.idl index 17774ed..98e265e 100644 --- a/chrome/common/extensions/api/experimental_socket.idl +++ b/chrome/common/extensions/api/experimental_socket.idl @@ -57,6 +57,10 @@ callback SendToCallback = void (WriteInfo writeInfo); + callback SetKeepAliveCallback = void (boolean result); + + callback SetNoDelayCallback = void (boolean result); + interface Functions { // Creates a socket of the specified type that will connect to the specified // remote machine. @@ -87,7 +91,7 @@ // |socketId| : The socketId. // |address| : The address of the remote machine. // |port| : The port of the remote machine. - // |callback| : Called when the connection attempt is complete. + // |callback| : Called when the bind attempt is complete. static void bind(long socketId, DOMString address, long port, @@ -141,6 +145,25 @@ DOMString address, long port, SendToCallback callback); + + // Enable/disable keep-alive functionality for a TCP connection. + // |socketId| : The socketId. + // |enable| : If true, enable keep-alive functionality. + // |delay| : Set the delay seconds between the last data packet received + // and the first keepalive probe. Default is 0. + // |callback| : Called when the setKeepAlive attempt is complete. + static void setKeepAlive(long socketId, + boolean enable, + optional long delay, + SetKeepAliveCallback callback); + + // Enable/disable Nagle algorithm. + // |socketId| : The socketId. + // |noDelay| : If true, disable Nagle algorithm. + // |callback| : Called when the setNoDelay attempt is complete. + static void setNoDelay(long socketId, + boolean noDelay, + SetNoDelayCallback callback); }; }; diff --git a/chrome/test/data/extensions/api_test/socket/api/background.js b/chrome/test/data/extensions/api_test/socket/api/background.js index 3ed924e..f6a29fd 100644 --- a/chrome/test/data/extensions/api_test/socket/api/background.js +++ b/chrome/test/data/extensions/api_test/socket/api/background.js @@ -64,10 +64,10 @@ function onDataRead(readInfo) { arrayBuffer2String(readInfo.data, function(s) { dataAsString = s; // save this for error reporting - if (s.match(expectedResponsePattern)) { - succeeded = true; - chrome.test.succeed(); - } + var match = !!s.match(expectedResponsePattern); + chrome.test.assertTrue(match, "Received data does not match."); + succeeded = true; + chrome.test.succeed(); }); } @@ -81,15 +81,33 @@ function onWriteOrSendToComplete(writeInfo) { } } -function onConnectOrBindComplete(connectResult) { - if (connectResult == 0) { - string2ArrayBuffer(request, function(arrayBuffer) { - if (protocol == "tcp") - socket.write(socketId, arrayBuffer, onWriteOrSendToComplete); - else - socket.sendTo(socketId, arrayBuffer, address, port, - onWriteOrSendToComplete); - }); +function onConnectOrBindComplete(result) { + chrome.test.assertEq(0, result, "Connect or bind failed."); + if (result == 0) { + var onSetKeepAlive = function(result) { + if (protocol == "tcp") + chrome.test.assertTrue(result, "setKeepAlive failed for TCP."); + else + chrome.test.assertFalse(result, "setKeepAlive did not fail for UDP."); + + string2ArrayBuffer(request, function(arrayBuffer) { + if (protocol == "tcp") + socket.write(socketId, arrayBuffer, onWriteOrSendToComplete); + else + socket.sendTo(socketId, arrayBuffer, address, port, + onWriteOrSendToComplete); + }); + }; + + var onSetNoDelay = function(result) { + if (protocol == "tcp") + chrome.test.assertTrue(result, "setNoDelay failed for TCP."); + else + chrome.test.assertFalse(result, "setNoDelay did not fail for UDP."); + socket.setKeepAlive(socketId, true, 1000, onSetKeepAlive); + }; + + socket.setNoDelay(socketId, true, onSetNoDelay); } } 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 { |