| // Copyright (c) 2012 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. | |
| #include "net/socket/client_socket_handle.h" | |
| #include "base/bind.h" | |
| #include "base/bind_helpers.h" | |
| #include "base/compiler_specific.h" | |
| #include "base/metrics/histogram.h" | |
| #include "base/logging.h" | |
| #include "net/base/net_errors.h" | |
| #include "net/socket/client_socket_pool.h" | |
| #include "net/socket/client_socket_pool_histograms.h" | |
| namespace net { | |
| ClientSocketHandle::ClientSocketHandle() | |
| : is_initialized_(false), | |
| pool_(NULL), | |
| layered_pool_(NULL), | |
| is_reused_(false), | |
| ALLOW_THIS_IN_INITIALIZER_LIST(callback_( | |
| base::Bind(&ClientSocketHandle::OnIOComplete, | |
| base::Unretained(this)))), | |
| is_ssl_error_(false) {} | |
| ClientSocketHandle::~ClientSocketHandle() { | |
| Reset(); | |
| } | |
| void ClientSocketHandle::Reset() { | |
| ResetInternal(true); | |
| ResetErrorState(); | |
| } | |
| void ClientSocketHandle::ResetInternal(bool cancel) { | |
| if (group_name_.empty()) // Was Init called? | |
| return; | |
| if (is_initialized()) { | |
| // Because of http://crbug.com/37810 we may not have a pool, but have | |
| // just a raw socket. | |
| socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE); | |
| if (pool_) | |
| // If we've still got a socket, release it back to the ClientSocketPool so | |
| // it can be deleted or reused. | |
| pool_->ReleaseSocket(group_name_, release_socket(), pool_id_); | |
| } else if (cancel) { | |
| // If we did not get initialized yet, we've got a socket request pending. | |
| // Cancel it. | |
| pool_->CancelRequest(group_name_, this); | |
| } | |
| is_initialized_ = false; | |
| group_name_.clear(); | |
| is_reused_ = false; | |
| user_callback_.Reset(); | |
| if (layered_pool_) { | |
| pool_->RemoveLayeredPool(layered_pool_); | |
| layered_pool_ = NULL; | |
| } | |
| pool_ = NULL; | |
| idle_time_ = base::TimeDelta(); | |
| init_time_ = base::TimeTicks(); | |
| setup_time_ = base::TimeDelta(); | |
| pool_id_ = -1; | |
| } | |
| void ClientSocketHandle::ResetErrorState() { | |
| is_ssl_error_ = false; | |
| ssl_error_response_info_ = HttpResponseInfo(); | |
| pending_http_proxy_connection_.reset(); | |
| } | |
| LoadState ClientSocketHandle::GetLoadState() const { | |
| CHECK(!is_initialized()); | |
| CHECK(!group_name_.empty()); | |
| // Because of http://crbug.com/37810 we may not have a pool, but have | |
| // just a raw socket. | |
| if (!pool_) | |
| return LOAD_STATE_IDLE; | |
| return pool_->GetLoadState(group_name_, this); | |
| } | |
| bool ClientSocketHandle::IsPoolStalled() const { | |
| return pool_->IsStalled(); | |
| } | |
| void ClientSocketHandle::AddLayeredPool(LayeredPool* layered_pool) { | |
| CHECK(layered_pool); | |
| CHECK(!layered_pool_); | |
| if (pool_) { | |
| pool_->AddLayeredPool(layered_pool); | |
| layered_pool_ = layered_pool; | |
| } | |
| } | |
| void ClientSocketHandle::RemoveLayeredPool(LayeredPool* layered_pool) { | |
| CHECK(layered_pool); | |
| CHECK(layered_pool_); | |
| if (pool_) { | |
| pool_->RemoveLayeredPool(layered_pool); | |
| layered_pool_ = NULL; | |
| } | |
| } | |
| void ClientSocketHandle::OnIOComplete(int result) { | |
| CompletionCallback callback = user_callback_; | |
| user_callback_.Reset(); | |
| HandleInitCompletion(result); | |
| callback.Run(result); | |
| } | |
| void ClientSocketHandle::HandleInitCompletion(int result) { | |
| CHECK_NE(ERR_IO_PENDING, result); | |
| if (result != OK) { | |
| if (!socket_.get()) | |
| ResetInternal(false); // Nothing to cancel since the request failed. | |
| else | |
| is_initialized_ = true; | |
| return; | |
| } | |
| is_initialized_ = true; | |
| CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value."; | |
| setup_time_ = base::TimeTicks::Now() - init_time_; | |
| ClientSocketPoolHistograms* histograms = pool_->histograms(); | |
| histograms->AddSocketType(reuse_type()); | |
| switch (reuse_type()) { | |
| case ClientSocketHandle::UNUSED: | |
| histograms->AddRequestTime(setup_time()); | |
| break; | |
| case ClientSocketHandle::UNUSED_IDLE: | |
| histograms->AddUnusedIdleTime(idle_time()); | |
| break; | |
| case ClientSocketHandle::REUSED_IDLE: | |
| histograms->AddReusedIdleTime(idle_time()); | |
| break; | |
| default: | |
| NOTREACHED(); | |
| break; | |
| } | |
| // Broadcast that the socket has been acquired. | |
| // TODO(eroman): This logging is not complete, in particular set_socket() and | |
| // release() socket. It ends up working though, since those methods are being | |
| // used to layer sockets (and the destination sources are the same). | |
| DCHECK(socket_.get()); | |
| socket_->NetLog().BeginEvent( | |
| NetLog::TYPE_SOCKET_IN_USE, | |
| requesting_source_.ToEventParametersCallback()); | |
| } | |
| } // namespace net |