summaryrefslogtreecommitdiffstats
path: root/net/socket/tcp_client_socket_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket/tcp_client_socket_win.cc')
-rw-r--r--net/socket/tcp_client_socket_win.cc256
1 files changed, 92 insertions, 164 deletions
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index b04e29e..469fffd 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -29,109 +29,6 @@ namespace net {
namespace {
-bool SetSocketReceiveBufferSize(SOCKET socket, int32 size) {
- int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
- reinterpret_cast<const char*>(&size), sizeof(size));
- DCHECK(!rv) << "Could not set socket receive buffer size: " << GetLastError();
- return rv == 0;
-}
-
-bool SetSocketSendBufferSize(SOCKET socket, int32 size) {
- int rv = setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
- reinterpret_cast<const char*>(&size), sizeof(size));
- DCHECK(!rv) << "Could not set socket send buffer size: " << GetLastError();
- return rv == 0;
-}
-
-// Sets socket parameters. Returns the OS error code (or 0 on
-// success).
-int SetupSocket(SOCKET socket) {
- // Increase the socket buffer sizes from the default sizes for WinXP. In
- // performance testing, there is substantial benefit by increasing from 8KB
- // to 64KB.
- // See also:
- // http://support.microsoft.com/kb/823764/EN-US
- // On Vista, if we manually set these sizes, Vista turns off its receive
- // window auto-tuning feature.
- // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx
- // Since Vista's auto-tune is better than any static value we can could set,
- // only change these on pre-vista machines.
- int32 major_version, minor_version, fix_version;
- base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
- &fix_version);
- if (major_version < 6) {
- const int32 kSocketBufferSize = 64 * 1024;
- SetSocketReceiveBufferSize(socket, kSocketBufferSize);
- 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.
- return 0;
-}
-
-// Creates a new socket and sets default parameters for it. Returns
-// the OS error code (or 0 on success).
-int CreateSocket(int family, SOCKET* socket) {
- *socket = WSASocket(family, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
- WSA_FLAG_OVERLAPPED);
- if (*socket == INVALID_SOCKET) {
- int os_error = WSAGetLastError();
- LOG(ERROR) << "WSASocket failed: " << os_error;
- return os_error;
- }
- int error = SetupSocket(*socket);
- if (error) {
- if (closesocket(*socket) < 0)
- PLOG(ERROR) << "closesocket";
- *socket = INVALID_SOCKET;
- return error;
- }
- return 0;
-}
-
int MapConnectError(int os_error) {
switch (os_error) {
// connect fails with WSAEACCES when Windows Firewall blocks the
@@ -316,7 +213,6 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
net::NetLog* net_log,
const net::NetLog::Source& source)
: socket_(INVALID_SOCKET),
- bound_socket_(INVALID_SOCKET),
addresses_(addresses),
current_ai_(NULL),
waiting_read_(false),
@@ -339,52 +235,16 @@ TCPClientSocketWin::~TCPClientSocketWin() {
net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
}
-int TCPClientSocketWin::AdoptSocket(SOCKET socket) {
+void TCPClientSocketWin::AdoptSocket(SOCKET socket) {
DCHECK_EQ(socket_, INVALID_SOCKET);
-
- int error = SetupSocket(socket);
- if (error)
- return MapSystemError(error);
-
socket_ = socket;
+ int error = SetupSocket();
+ DCHECK_EQ(0, error);
core_ = new Core(this);
current_ai_ = addresses_.head();
use_history_.set_was_ever_connected();
-
- return OK;
-}
-
-int TCPClientSocketWin::Bind(const IPEndPoint& address) {
- if (current_ai_ != NULL || bind_address_.get()) {
- // Cannot bind the socket if we are already connected or connecting.
- return ERR_UNEXPECTED;
- }
-
- sockaddr_storage addr_storage;
- sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
- size_t addr_len;
- if (!address.ToSockAddr(addr, &addr_len))
- return ERR_INVALID_ARGUMENT;
-
- // Create |bound_socket_| and try to bound it to |address|.
- int error = CreateSocket(address.GetFamily(), &bound_socket_);
- if (error)
- return MapSystemError(error);
-
- if (bind(bound_socket_, addr, addr_len)) {
- error = errno;
- if (closesocket(bound_socket_) < 0)
- PLOG(ERROR) << "closesocket";
- bound_socket_ = INVALID_SOCKET;
- return MapSystemError(error);
- }
-
- bind_address_.reset(new IPEndPoint(address));
-
- return 0;
}
-
int TCPClientSocketWin::Connect(CompletionCallback* callback) {
DCHECK(CalledOnValidThread());
@@ -456,25 +316,9 @@ int TCPClientSocketWin::DoConnect() {
next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
- if (bound_socket_ != INVALID_SOCKET) {
- DCHECK(bind_address_.get());
- socket_ = bound_socket_;
- bound_socket_ = INVALID_SOCKET;
- } else {
- connect_os_error_ = CreateSocket(ai->ai_family, &socket_);
- if (connect_os_error_ != 0)
- return MapSystemError(connect_os_error_);
-
- if (bind_address_.get()) {
- sockaddr_storage addr_storage;
- sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
- size_t addr_len;
- if (!bind_address_->ToSockAddr(addr, &addr_len))
- return ERR_INVALID_ARGUMENT;
- if (bind(socket_, addr, addr_len))
- return MapSystemError(errno);
- }
- }
+ connect_os_error_ = CreateSocket(ai);
+ if (connect_os_error_ != 0)
+ return MapSystemError(connect_os_error_);
DCHECK(!core_);
core_ = new Core(this);
@@ -763,12 +607,96 @@ int TCPClientSocketWin::Write(IOBuffer* buf,
bool TCPClientSocketWin::SetReceiveBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
- return SetSocketReceiveBufferSize(socket_, size);
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
+ reinterpret_cast<const char*>(&size), sizeof(size));
+ DCHECK(!rv) << "Could not set socket receive buffer size: " << GetLastError();
+ return rv == 0;
}
bool TCPClientSocketWin::SetSendBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
- return SetSocketSendBufferSize(socket_, size);
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
+ reinterpret_cast<const char*>(&size), sizeof(size));
+ DCHECK(!rv) << "Could not set socket send buffer size: " << GetLastError();
+ return rv == 0;
+}
+
+int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) {
+ socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0,
+ WSA_FLAG_OVERLAPPED);
+ if (socket_ == INVALID_SOCKET) {
+ int os_error = WSAGetLastError();
+ LOG(ERROR) << "WSASocket failed: " << os_error;
+ return os_error;
+ }
+ return SetupSocket();
+}
+
+int TCPClientSocketWin::SetupSocket() {
+ // Increase the socket buffer sizes from the default sizes for WinXP. In
+ // performance testing, there is substantial benefit by increasing from 8KB
+ // to 64KB.
+ // See also:
+ // http://support.microsoft.com/kb/823764/EN-US
+ // On Vista, if we manually set these sizes, Vista turns off its receive
+ // window auto-tuning feature.
+ // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx
+ // Since Vista's auto-tune is better than any static value we can could set,
+ // only change these on pre-vista machines.
+ int32 major_version, minor_version, fix_version;
+ base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
+ &fix_version);
+ if (major_version < 6) {
+ const int32 kSocketBufferSize = 64 * 1024;
+ SetReceiveBufferSize(kSocketBufferSize);
+ SetSendBufferSize(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.
+ return 0;
}
void TCPClientSocketWin::LogConnectCompletion(int net_error) {