summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-27 20:07:36 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-27 20:07:36 +0000
commit817498d34ca487bd6c8791ed8efa104b2ab38ebf (patch)
treef86c17561b68ba43118f77e359868dfcba7c3897 /net/socket
parent5407bb916f12047a2186c92b896f81a1e588db06 (diff)
downloadchromium_src-817498d34ca487bd6c8791ed8efa104b2ab38ebf.zip
chromium_src-817498d34ca487bd6c8791ed8efa104b2ab38ebf.tar.gz
chromium_src-817498d34ca487bd6c8791ed8efa104b2ab38ebf.tar.bz2
Revert 87077 - Bind() methods for TCP sockets
BUG=80245 TEST=None Review URL: http://codereview.chromium.org/7004055 TBR=sergeyu@chromium.org Review URL: http://codereview.chromium.org/7082013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87079 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/tcp_client_socket_libevent.cc128
-rw-r--r--net/socket/tcp_client_socket_libevent.h18
-rw-r--r--net/socket/tcp_client_socket_unittest.cc110
-rw-r--r--net/socket/tcp_client_socket_win.cc256
-rw-r--r--net/socket/tcp_client_socket_win.h19
-rw-r--r--net/socket/tcp_server_socket_libevent.cc22
-rw-r--r--net/socket/tcp_server_socket_unittest.cc48
-rw-r--r--net/socket/tcp_server_socket_win.cc22
8 files changed, 157 insertions, 466 deletions
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 222ff94..6e0cb1c 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -70,36 +70,6 @@ void SetTCPKeepAlive(int fd) {
#endif
}
-// Sets socket parameters. Returns the OS error code (or 0 on
-// success).
-int SetupSocket(int socket) {
- if (SetNonBlocking(socket))
- return errno;
-
- // 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);
-
- 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, int* socket) {
- *socket = ::socket(family, SOCK_STREAM, IPPROTO_TCP);
- if (*socket == kInvalidSocket)
- return errno;
- int error = SetupSocket(*socket);
- if (error) {
- if (HANDLE_EINTR(close(*socket)) < 0)
- PLOG(ERROR) << "close";
- *socket = kInvalidSocket;
- return error;
- }
- return 0;
-}
-
int MapConnectError(int os_error) {
switch (os_error) {
case EACCES:
@@ -130,7 +100,6 @@ TCPClientSocketLibevent::TCPClientSocketLibevent(
net::NetLog* net_log,
const net::NetLog::Source& source)
: socket_(kInvalidSocket),
- bound_socket_(kInvalidSocket),
addresses_(addresses),
current_ai_(NULL),
read_watcher_(this),
@@ -157,53 +126,16 @@ TCPClientSocketLibevent::~TCPClientSocketLibevent() {
net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
}
-int TCPClientSocketLibevent::AdoptSocket(int socket) {
+void TCPClientSocketLibevent::AdoptSocket(int socket) {
DCHECK_EQ(socket_, kInvalidSocket);
-
- int error = SetupSocket(socket);
- if (error)
- return MapSystemError(error);
-
socket_ = socket;
-
- // This is to make GetPeerAddress() work. It's up to the caller ensure
- // that |address_| contains a reasonable address for this
- // socket. (i.e. at least match IPv4 vs IPv6!).
+ int error = SetupSocket();
+ DCHECK_EQ(0, error);
+ // This is to make GetPeerAddress work. It's up to the test that is calling
+ // this function to ensure that address_ contains a reasonable address for
+ // this socket. (i.e. at least match IPv4 vs IPv6!).
current_ai_ = addresses_.head();
use_history_.set_was_ever_connected();
-
- return OK;
-}
-
-int TCPClientSocketLibevent::Bind(const IPEndPoint& address) {
- if (current_ai_ != NULL || bind_address_.get()) {
- // Cannot bind the socket if we are already bound connected or
- // connecting.
- return ERR_UNEXPECTED;
- }
-
- sockaddr_storage addr_storage;
- sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
- size_t addr_len = sizeof(addr_storage);
- 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 (HANDLE_EINTR(bind(bound_socket_, addr, addr_len))) {
- error = errno;
- if (HANDLE_EINTR(close(bound_socket_)) < 0)
- PLOG(ERROR) << "close";
- bound_socket_ = kInvalidSocket;
- return MapSystemError(error);
- }
-
- bind_address_.reset(new IPEndPoint(address));
-
- return 0;
}
int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
@@ -280,26 +212,10 @@ int TCPClientSocketLibevent::DoConnect() {
next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
- if (bound_socket_ != kInvalidSocket) {
- DCHECK(bind_address_.get());
- socket_ = bound_socket_;
- bound_socket_ = kInvalidSocket;
- } else {
- // Create a non-blocking socket.
- connect_os_error_ = CreateSocket(current_ai_->ai_family, &socket_);
- if (connect_os_error_)
- 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 = sizeof(addr_storage);
- if (!bind_address_->ToSockAddr(addr, &addr_len))
- return ERR_INVALID_ARGUMENT;
- if (HANDLE_EINTR(bind(socket_, addr, addr_len)))
- return MapSystemError(errno);
- }
- }
+ // Create a non-blocking socket.
+ connect_os_error_ = CreateSocket(current_ai_);
+ if (connect_os_error_)
+ return MapSystemError(connect_os_error_);
// Connect the socket.
if (!use_tcp_fastopen_) {
@@ -544,6 +460,30 @@ bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) {
return rv == 0;
}
+
+int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) {
+ socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (socket_ == kInvalidSocket)
+ return errno;
+ return SetupSocket();
+}
+
+int TCPClientSocketLibevent::SetupSocket() {
+ if (SetNonBlocking(socket_)) {
+ const int err = errno;
+ close(socket_);
+ socket_ = kInvalidSocket;
+ return err;
+ }
+
+ // 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_);
+
+ return 0;
+}
+
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 b9bc557..45f24c2 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -38,10 +38,7 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
// the given socket and then acts as if Connect() had been called. This
// function is used by TCPServerSocket() to adopt accepted connections
// and for testing.
- int AdoptSocket(int socket);
-
- // Binds the socket to a local IP address and port.
- int Bind(const IPEndPoint& address);
+ void AdoptSocket(int socket);
// StreamSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -133,6 +130,12 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
return next_connect_state_ != CONNECT_STATE_NONE;
}
+ // Returns the OS error code (or 0 on success).
+ int CreateSocket(const struct addrinfo* ai);
+
+ // Returns the OS error code (or 0 on success).
+ int SetupSocket();
+
// Helper to add a TCP_CONNECT (end) event to the NetLog.
void LogConnectCompletion(int net_error);
@@ -141,13 +144,6 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
int socket_;
- // Local IP address and port we are bound to. Set to NULL if Bind()
- // was't called (in that cases OS chooses address/port).
- scoped_ptr<IPEndPoint> bind_address_;
-
- // Stores bound socket between Bind() and Connect() calls.
- int bound_socket_;
-
// The list of addresses we should try in order to establish a connection.
AddressList addresses_;
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
deleted file mode 100644
index edb3c20..0000000
--- a/net/socket/tcp_client_socket_unittest.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2011 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.
-
-// This file contains some tests for TCPClientSocket.
-// transport_client_socket_unittest.cc contans some other tests that
-// are common for TCP and other types of sockets.
-
-#include "net/socket/tcp_client_socket.h"
-
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
-#include "net/base/sys_addrinfo.h"
-#include "net/base/test_completion_callback.h"
-#include "net/socket/tcp_server_socket.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-// Try binding a socket to loopback interface and verify that we can
-// still connect to a server on the same interface.
-TEST(TCPClientSocketTest, BindLoopbackToLoopback) {
- IPAddressNumber lo_address;
- ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &lo_address));
-
- TCPServerSocket server(NULL, NetLog::Source());
- ASSERT_EQ(OK, server.Listen(IPEndPoint(lo_address, 0), 1));
- IPEndPoint server_address;
- ASSERT_EQ(OK, server.GetLocalAddress(&server_address));
-
- TCPClientSocket socket(
- AddressList::CreateFromIPAddress(server_address.address(),
- server_address.port()),
- NULL, NetLog::Source());
-
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(lo_address, 0)));
-
- TestCompletionCallback connect_callback;
- EXPECT_EQ(ERR_IO_PENDING, socket.Connect(&connect_callback));
-
- TestCompletionCallback accept_callback;
- scoped_ptr<StreamSocket> accepted_socket;
- int result = server.Accept(&accepted_socket, &accept_callback);
- if (result == ERR_IO_PENDING)
- result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
-
- EXPECT_EQ(OK, connect_callback.WaitForResult());
-}
-
-// Try to bind socket to the loopback interface and connect to an
-// external address, verify that connection fails.
-TEST(TCPClientSocketTest, BindLoopbackToExternal) {
- IPAddressNumber external_ip;
- ASSERT_TRUE(ParseIPLiteralToNumber("72.14.213.105", &external_ip));
- TCPClientSocket socket(AddressList::CreateFromIPAddress(external_ip, 80),
- NULL, NetLog::Source());
-
- IPAddressNumber lo_address;
- ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &lo_address));
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(lo_address, 0)));
-
- TestCompletionCallback connect_callback;
- int result = socket.Connect(&connect_callback);
- if (result == ERR_IO_PENDING)
- result = connect_callback.WaitForResult();
-
- // We may get different errors here on different system, but
- // connect() is not expected to succeed.
- EXPECT_NE(OK, result);
-}
-
-// Bind a socket to the IPv4 loopback interface and try to connect to
-// the IPv6 loopback interface, verify that connection fails.
-TEST(TCPClientSocketTest, BindLoopbackToIPv6) {
- IPAddressNumber ipv6_lo_ip;
- ASSERT_TRUE(ParseIPLiteralToNumber("::1", &ipv6_lo_ip));
- TCPServerSocket server(NULL, NetLog::Source());
- int listen_result = server.Listen(IPEndPoint(ipv6_lo_ip, 0), 1);
- if (listen_result != OK) {
- LOG(ERROR) << "Failed to listen on ::1 - probably because IPv6 is disabled."
- " Skipping the test";
- return;
- }
-
- IPEndPoint server_address;
- ASSERT_EQ(OK, server.GetLocalAddress(&server_address));
- TCPClientSocket socket(
- AddressList::CreateFromIPAddress(server_address.address(),
- server_address.port()),
- NULL, NetLog::Source());
-
- IPAddressNumber ipv4_lo_ip;
- ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &ipv4_lo_ip));
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(ipv4_lo_ip, 0)));
-
- TestCompletionCallback connect_callback;
- int result = socket.Connect(&connect_callback);
- if (result == ERR_IO_PENDING)
- result = connect_callback.WaitForResult();
-
- EXPECT_NE(OK, result);
-}
-
-} // namespace
-
-} // namespace net
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index e6dec8f..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 = sizeof(addr_storage);
- 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 = sizeof(addr_storage);
- 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) {
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index ed71514..0c704e9 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -8,7 +8,6 @@
#include <winsock2.h>
-#include "base/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
@@ -36,10 +35,7 @@ class NET_API TCPClientSocketWin : public StreamSocket,
// the given socket and then acts as if Connect() had been called. This
// function is used by TCPServerSocket() to adopt accepted connections
// and for testing.
- int AdoptSocket(SOCKET socket);
-
- // Binds the socket to a local IP address and port.
- int Bind(const IPEndPoint& address);
+ void AdoptSocket(SOCKET socket);
// StreamSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -87,6 +83,12 @@ class NET_API TCPClientSocketWin : public StreamSocket,
return next_connect_state_ != CONNECT_STATE_NONE;
}
+ // Returns the OS error code (or 0 on success).
+ int CreateSocket(const struct addrinfo* ai);
+
+ // Returns the OS error code (or 0 on success).
+ int SetupSocket();
+
// Called after Connect() has completed with |net_error|.
void LogConnectCompletion(int net_error);
@@ -98,13 +100,6 @@ class NET_API TCPClientSocketWin : public StreamSocket,
SOCKET socket_;
- // Local IP address and port we are bound to. Set to NULL if Bind()
- // was't called (in that cases OS chooses address/port).
- scoped_ptr<IPEndPoint> bind_address_;
-
- // Stores bound socket between Bind() and Connect() calls.
- SOCKET bound_socket_;
-
// The list of addresses we should try in order to establish a connection.
AddressList addresses_;
diff --git a/net/socket/tcp_server_socket_libevent.cc b/net/socket/tcp_server_socket_libevent.cc
index 89119f6..daedbf5 100644
--- a/net/socket/tcp_server_socket_libevent.cc
+++ b/net/socket/tcp_server_socket_libevent.cc
@@ -58,7 +58,7 @@ int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
DCHECK_GT(backlog, 0);
DCHECK_EQ(socket_, kInvalidSocket);
- socket_ = socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
+ socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_ < 0) {
PLOG(ERROR) << "socket() returned an error";
return MapSystemError(errno);
@@ -142,8 +142,8 @@ int TCPServerSocketLibevent::AcceptInternal(
socklen_t addr_len = sizeof(addr_storage);
struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
- int new_socket = HANDLE_EINTR(accept(socket_, addr, &addr_len));
- if (new_socket < 0) {
+ int result = HANDLE_EINTR(accept(socket_, addr, &addr_len));
+ if (result < 0) {
int net_error = MapSystemError(errno);
if (net_error != ERR_IO_PENDING)
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
@@ -153,22 +153,16 @@ int TCPServerSocketLibevent::AcceptInternal(
IPEndPoint address;
if (!address.FromSockAddr(addr, addr_len)) {
NOTREACHED();
- if (HANDLE_EINTR(close(new_socket)) < 0)
+ if (HANDLE_EINTR(close(result)) < 0)
PLOG(ERROR) << "close";
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
return ERR_FAILED;
}
- scoped_ptr<TCPClientSocket> tcp_socket(new TCPClientSocket(
+ TCPClientSocket* tcp_socket = new TCPClientSocket(
AddressList::CreateFromIPAddress(address.address(), address.port()),
- net_log_.net_log(), net_log_.source()));
- int adopt_result = tcp_socket->AdoptSocket(new_socket);
- if (adopt_result != OK) {
- if (HANDLE_EINTR(close(new_socket)) < 0)
- PLOG(ERROR) << "close";
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result);
- return adopt_result;
- }
- socket->reset(tcp_socket.release());
+ net_log_.net_log(), net_log_.source());
+ tcp_socket->AdoptSocket(result);
+ socket->reset(tcp_socket);
net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
make_scoped_refptr(new NetLogStringParameter(
"address", address.ToString())));
diff --git a/net/socket/tcp_server_socket_unittest.cc b/net/socket/tcp_server_socket_unittest.cc
index d08b262..d4abe9d 100644
--- a/net/socket/tcp_server_socket_unittest.cc
+++ b/net/socket/tcp_server_socket_unittest.cc
@@ -26,26 +26,13 @@ class TCPServerSocketTest : public PlatformTest {
: socket_(NULL, NetLog::Source()) {
}
- void SetUpIPv4() {
+ void SetUp() OVERRIDE {
IPEndPoint address;
ParseAddress("127.0.0.1", 0, &address);
ASSERT_EQ(OK, socket_.Listen(address, kListenBacklog));
ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
}
- void SetUpIPv6(bool* success) {
- *success = false;
- IPEndPoint address;
- ParseAddress("::1", 0, &address);
- if (socket_.Listen(address, kListenBacklog) != 0) {
- LOG(ERROR) << "Failed to listen on ::1 - probably because IPv6 is "
- "disabled. Skipping the test";
- return;
- }
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
- *success = true;
- }
-
void ParseAddress(std::string ip_str, int port, IPEndPoint* address) {
IPAddressNumber ip_number;
bool rv = ParseIPLiteralToNumber(ip_str, &ip_number);
@@ -73,8 +60,6 @@ class TCPServerSocketTest : public PlatformTest {
};
TEST_F(TCPServerSocketTest, Accept) {
- ASSERT_NO_FATAL_FAILURE(SetUpIPv4());
-
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(),
NULL, NetLog::Source());
@@ -98,8 +83,6 @@ TEST_F(TCPServerSocketTest, Accept) {
// Test Accept() callback.
TEST_F(TCPServerSocketTest, AcceptAsync) {
- ASSERT_NO_FATAL_FAILURE(SetUpIPv4());
-
TestCompletionCallback accept_callback;
scoped_ptr<StreamSocket> accepted_socket;
@@ -122,8 +105,6 @@ TEST_F(TCPServerSocketTest, AcceptAsync) {
// Accept two connections simultaneously.
TEST_F(TCPServerSocketTest, Accept2Connections) {
- ASSERT_NO_FATAL_FAILURE(SetUpIPv4());
-
TestCompletionCallback accept_callback;
scoped_ptr<StreamSocket> accepted_socket;
@@ -161,33 +142,6 @@ TEST_F(TCPServerSocketTest, Accept2Connections) {
local_address_.address());
}
-TEST_F(TCPServerSocketTest, AcceptIPv6) {
- bool initialized;
- ASSERT_NO_FATAL_FAILURE(SetUpIPv6(&initialized));
- if (!initialized)
- return;
-
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(),
- NULL, NetLog::Source());
- connecting_socket.Connect(&connect_callback);
-
- TestCompletionCallback accept_callback;
- scoped_ptr<StreamSocket> accepted_socket;
- int result = socket_.Accept(&accepted_socket, &accept_callback);
- if (result == ERR_IO_PENDING)
- result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
-
- ASSERT_TRUE(accepted_socket.get() != NULL);
-
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
- local_address_.address());
-
- EXPECT_EQ(OK, connect_callback.WaitForResult());
-}
-
} // namespace
} // namespace net
diff --git a/net/socket/tcp_server_socket_win.cc b/net/socket/tcp_server_socket_win.cc
index 55c2439..a850a8a 100644
--- a/net/socket/tcp_server_socket_win.cc
+++ b/net/socket/tcp_server_socket_win.cc
@@ -46,7 +46,7 @@ int TCPServerSocketWin::Listen(const IPEndPoint& address, int backlog) {
return ERR_FAILED;
}
- socket_ = socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
+ socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_ < 0) {
PLOG(ERROR) << "socket() returned an error";
return MapSystemError(WSAGetLastError());
@@ -126,8 +126,8 @@ int TCPServerSocketWin::AcceptInternal(scoped_ptr<StreamSocket>* socket) {
socklen_t addr_len = sizeof(addr_storage);
struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
- int new_socket = accept(socket_, addr, &addr_len);
- if (new_socket < 0) {
+ int result = accept(socket_, addr, &addr_len);
+ if (result < 0) {
int net_error = MapSystemError(WSAGetLastError());
if (net_error != ERR_IO_PENDING)
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
@@ -137,22 +137,16 @@ int TCPServerSocketWin::AcceptInternal(scoped_ptr<StreamSocket>* socket) {
IPEndPoint address;
if (!address.FromSockAddr(addr, addr_len)) {
NOTREACHED();
- if (closesocket(new_socket) < 0)
+ if (closesocket(result) < 0)
PLOG(ERROR) << "closesocket";
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
return ERR_FAILED;
}
- scoped_ptr<TCPClientSocket> tcp_socket(new TCPClientSocket(
+ TCPClientSocket* tcp_socket = new TCPClientSocket(
AddressList::CreateFromIPAddress(address.address(), address.port()),
- net_log_.net_log(), net_log_.source()));
- int adopt_result = tcp_socket->AdoptSocket(new_socket);
- if (adopt_result != OK) {
- if (closesocket(new_socket) < 0)
- PLOG(ERROR) << "closesocket";
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result);
- return adopt_result;
- }
- socket->reset(tcp_socket.release());
+ net_log_.net_log(), net_log_.source());
+ tcp_socket->AdoptSocket(result);
+ socket->reset(tcp_socket);
net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
make_scoped_refptr(new NetLogStringParameter(
"address", address.ToString())));