Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(846)

Unified Diff: net/socket/tcp_client_socket.cc

Issue 23881002: Windows only: Move client socket functionality from TCPClientSocket into TCPSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/socket/tcp_client_socket.cc
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index a91d33d24c8cb453f9f314e2b980a37d981d7a62..af1c555caa0bd3ac175cb5d816f114b21ea5bae5 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -4,8 +4,14 @@
#include "net/socket/tcp_client_socket.h"
+#include "base/callback_helpers.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
namespace net {
@@ -56,4 +62,312 @@ bool IsTCPFastOpenEnabled() {
return g_tcp_fastopen_enabled;
}
+#if defined(OS_WIN)
+
+TCPClientSocket::TCPClientSocket(const AddressList& addresses,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source)
+ : socket_(new TCPSocket(net_log, source)),
+ addresses_(addresses),
+ current_address_index_(-1),
+ next_connect_state_(CONNECT_STATE_NONE),
+ previously_disconnected_(false) {
+}
+
+TCPClientSocket::TCPClientSocket(scoped_ptr<TCPSocket> connected_socket,
+ const IPEndPoint& peer_address)
+ : socket_(connected_socket.Pass()),
+ addresses_(AddressList(peer_address)),
+ current_address_index_(0),
+ next_connect_state_(CONNECT_STATE_NONE),
+ previously_disconnected_(false) {
+ DCHECK(socket_);
+
+ socket_->SetDefaultOptionsForClient();
+ use_history_.set_was_ever_connected();
+}
+
+TCPClientSocket::~TCPClientSocket() {
+}
+
+int TCPClientSocket::Bind(const IPEndPoint& address) {
+ if (current_address_index_ >= 0 || bind_address_) {
+ // Cannot bind the socket if we are already connected or connecting.
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+ }
+
+ int result = OK;
+ if (!socket_->IsValid()) {
+ result = OpenSocket(address.GetFamily());
+ if (result != OK)
+ return result;
+ }
+
+ result = socket_->Bind(address);
+ if (result != OK)
+ return result;
+
+ bind_address_.reset(new IPEndPoint(address));
+ return OK;
+}
+
+int TCPClientSocket::Connect(const CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+
+ // If connecting or already connected, then just return OK.
+ if (socket_->IsValid() && current_address_index_ >= 0)
+ return OK;
+
+ socket_->StartLoggingMultipleConnectAttempts(addresses_);
+
+ // We will try to connect to each address in addresses_. Start with the
+ // first one in the list.
+ next_connect_state_ = CONNECT_STATE_CONNECT;
+ current_address_index_ = 0;
+
+ int rv = DoConnectLoop(OK);
+ if (rv == ERR_IO_PENDING) {
+ connect_callback_ = callback;
+ } else {
+ socket_->EndLoggingMultipleConnectAttempts(rv);
+ }
+
+ return rv;
+}
+
+int TCPClientSocket::DoConnectLoop(int result) {
+ DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
+
+ int rv = result;
+ do {
+ ConnectState state = next_connect_state_;
+ next_connect_state_ = CONNECT_STATE_NONE;
+ switch (state) {
+ case CONNECT_STATE_CONNECT:
+ DCHECK_EQ(OK, rv);
+ rv = DoConnect();
+ break;
+ case CONNECT_STATE_CONNECT_COMPLETE:
+ rv = DoConnectComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "bad state " << state;
+ rv = ERR_UNEXPECTED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
+
+ return rv;
+}
+
+int TCPClientSocket::DoConnect() {
+ DCHECK_GE(current_address_index_, 0);
+ DCHECK_LT(current_address_index_, static_cast<int>(addresses_.size()));
+
+ const IPEndPoint& endpoint = addresses_[current_address_index_];
+
+ if (previously_disconnected_) {
+ use_history_.Reset();
+ previously_disconnected_ = false;
+ }
+
+ next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
+
+ if (socket_->IsValid()) {
+ DCHECK(bind_address_);
+ } else {
+ int result = OpenSocket(endpoint.GetFamily());
+ if (result != OK)
+ return result;
+
+ if (bind_address_) {
+ result = socket_->Bind(*bind_address_);
+ if (result != OK) {
+ socket_->Close();
+ return result;
+ }
+ }
+ }
+
+ // |socket_| is owned by this class and the callback won't be run once
+ // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
+ return socket_->Connect(endpoint,
+ base::Bind(&TCPClientSocket::DidCompleteConnect,
+ base::Unretained(this)));
+}
+
+int TCPClientSocket::DoConnectComplete(int result) {
+ if (result == OK) {
+ use_history_.set_was_ever_connected();
+ return OK; // Done!
+ }
+
+ // Close whatever partially connected socket we currently have.
+ DoDisconnect();
+
+ // Try to fall back to the next address in the list.
+ if (current_address_index_ + 1 < static_cast<int>(addresses_.size())) {
+ next_connect_state_ = CONNECT_STATE_CONNECT;
+ ++current_address_index_;
+ return OK;
+ }
+
+ // Otherwise there is nothing to fall back to, so give up.
+ return result;
+}
+
+void TCPClientSocket::Disconnect() {
+ DoDisconnect();
+ current_address_index_ = -1;
+ bind_address_.reset();
+}
+
+void TCPClientSocket::DoDisconnect() {
+ // If connecting or already connected, record that the socket has been
+ // disconnected.
+ previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0;
+ socket_->Close();
+}
+
+bool TCPClientSocket::IsConnected() const {
+ return socket_->IsConnected();
+}
+
+bool TCPClientSocket::IsConnectedAndIdle() const {
+ return socket_->IsConnectedAndIdle();
+}
+
+int TCPClientSocket::GetPeerAddress(IPEndPoint* address) const {
+ return socket_->GetPeerAddress(address);
+}
+
+int TCPClientSocket::GetLocalAddress(IPEndPoint* address) const {
+ DCHECK(address);
+
+ if (!socket_->IsValid()) {
+ if (bind_address_) {
+ *address = *bind_address_;
+ return OK;
+ }
+ return ERR_SOCKET_NOT_CONNECTED;
+ }
+
+ return socket_->GetLocalAddress(address);
+}
+
+const BoundNetLog& TCPClientSocket::NetLog() const {
+ return socket_->net_log();
+}
+
+void TCPClientSocket::SetSubresourceSpeculation() {
+ use_history_.set_subresource_speculation();
+}
+
+void TCPClientSocket::SetOmniboxSpeculation() {
+ use_history_.set_omnibox_speculation();
+}
+
+bool TCPClientSocket::WasEverUsed() const {
+ return use_history_.was_used_to_convey_data();
+}
+
+bool TCPClientSocket::UsingTCPFastOpen() const {
+ return socket_->UsingTCPFastOpen();
+}
+
+bool TCPClientSocket::WasNpnNegotiated() const {
+ return false;
+}
+
+NextProto TCPClientSocket::GetNegotiatedProtocol() const {
+ return kProtoUnknown;
+}
+
+bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
+ return false;
+}
+
+int TCPClientSocket::Read(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+
+ // |socket_| is owned by this class and the callback won't be run once
+ // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
+ CompletionCallback read_callback = base::Bind(
+ &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback);
+ int result = socket_->Read(buf, buf_len, read_callback);
+ if (result > 0)
+ use_history_.set_was_used_to_convey_data();
+
+ return result;
+}
+
+int TCPClientSocket::Write(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+
+ // |socket_| is owned by this class and the callback won't be run once
+ // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
+ CompletionCallback write_callback = base::Bind(
+ &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback);
+ int result = socket_->Write(buf, buf_len, write_callback);
+ if (result > 0)
+ use_history_.set_was_used_to_convey_data();
+
+ return result;
+}
+
+bool TCPClientSocket::SetReceiveBufferSize(int32 size) {
+ return socket_->SetReceiveBufferSize(size);
+}
+
+bool TCPClientSocket::SetSendBufferSize(int32 size) {
+ return socket_->SetSendBufferSize(size);
+}
+
+bool TCPClientSocket::SetKeepAlive(bool enable, int delay) {
+ return socket_->SetKeepAlive(enable, delay);
+}
+
+bool TCPClientSocket::SetNoDelay(bool no_delay) {
+ return socket_->SetNoDelay(no_delay);
+}
+
+void TCPClientSocket::DidCompleteConnect(int result) {
+ DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
+ DCHECK_NE(result, ERR_IO_PENDING);
+ DCHECK(!connect_callback_.is_null());
+
+ result = DoConnectLoop(result);
+ if (result != ERR_IO_PENDING) {
+ socket_->EndLoggingMultipleConnectAttempts(result);
+ base::ResetAndReturn(&connect_callback_).Run(result);
+ }
+}
+
+void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback,
+ int result) {
+ if (result > 0)
+ use_history_.set_was_used_to_convey_data();
+
+ callback.Run(result);
+}
+
+int TCPClientSocket::OpenSocket(AddressFamily family) {
+ DCHECK(!socket_->IsValid());
+
+ int result = socket_->Open(family);
+ if (result != OK)
+ return result;
+
+ socket_->SetDefaultOptionsForClient();
+
+ return OK;
+}
+
+#endif
+
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698