diff options
Diffstat (limited to 'net/socket/tcp_client_socket_pool.cc')
-rw-r--r-- | net/socket/tcp_client_socket_pool.cc | 374 |
1 files changed, 11 insertions, 363 deletions
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc index e0530c3b..f571ef9 100644 --- a/net/socket/tcp_client_socket_pool.cc +++ b/net/socket/tcp_client_socket_pool.cc @@ -5,13 +5,13 @@ #include "net/socket/tcp_client_socket_pool.h" #include "base/compiler_specific.h" -#include "base/field_trial.h" +#include "base/logging.h" #include "base/message_loop.h" #include "base/time.h" -#include "base/stl_util-inl.h" #include "net/base/net_errors.h" #include "net/socket/client_socket_factory.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/client_socket_pool_base.h" #include "net/socket/tcp_client_socket.h" using base::TimeDelta; @@ -33,7 +33,7 @@ const int kIdleTimeout = 300; // 5 minutes. namespace net { -TCPConnectingSocket::TCPConnectingSocket( +TCPConnectJob::TCPConnectJob( const std::string& group_name, const HostResolver::RequestInfo& resolve_info, const ClientSocketHandle* handle, @@ -45,27 +45,27 @@ TCPConnectingSocket::TCPConnectingSocket( client_socket_factory_(client_socket_factory), ALLOW_THIS_IN_INITIALIZER_LIST( callback_(this, - &TCPConnectingSocket::OnIOComplete)), + &TCPConnectJob::OnIOComplete)), pool_(pool), resolver_(pool->GetHostResolver()) {} -TCPConnectingSocket::~TCPConnectingSocket() { +TCPConnectJob::~TCPConnectJob() { // We don't worry about cancelling the host resolution and TCP connect, since // ~SingleRequestHostResolver and ~ClientSocket will take care of it. } -int TCPConnectingSocket::Connect() { +int TCPConnectJob::Connect() { int rv = resolver_.Resolve(resolve_info_, &addresses_, &callback_); if (rv != ERR_IO_PENDING) rv = OnIOCompleteInternal(rv, true /* synchronous */); return rv; } -void TCPConnectingSocket::OnIOComplete(int result) { +void TCPConnectJob::OnIOComplete(int result) { OnIOCompleteInternal(result, false /* asynchronous */); } -int TCPConnectingSocket::OnIOCompleteInternal( +int TCPConnectJob::OnIOCompleteInternal( int result, bool synchronous) { CHECK(result != ERR_IO_PENDING); @@ -123,363 +123,11 @@ int TCPConnectingSocket::OnIOCompleteInternal( return result; } -ClientSocketPoolBase::ClientSocketPoolBase( - int max_sockets_per_group, - HostResolver* host_resolver, - ConnectingSocketFactory* connecting_socket_factory) - : idle_socket_count_(0), - max_sockets_per_group_(max_sockets_per_group), - host_resolver_(host_resolver), - connecting_socket_factory_(connecting_socket_factory) {} - -ClientSocketPoolBase::~ClientSocketPoolBase() { - // Clean up any idle sockets. Assert that we have no remaining active - // sockets or pending requests. They should have all been cleaned up prior - // to the manager being destroyed. - CloseIdleSockets(); - DCHECK(group_map_.empty()); - DCHECK(connecting_socket_map_.empty()); -} - -// InsertRequestIntoQueue inserts the request into the queue based on -// priority. Highest priorities are closest to the front. Older requests are -// prioritized over requests of equal priority. -// -// static -void ClientSocketPoolBase::InsertRequestIntoQueue( - const Request& r, RequestQueue* pending_requests) { - RequestQueue::iterator it = pending_requests->begin(); - while (it != pending_requests->end() && r.priority <= it->priority) - ++it; - pending_requests->insert(it, r); -} - -int ClientSocketPoolBase::RequestSocket( - const std::string& group_name, - const HostResolver::RequestInfo& resolve_info, - int priority, - ClientSocketHandle* handle, - CompletionCallback* callback) { - DCHECK(!resolve_info.hostname().empty()); - DCHECK_GE(priority, 0); - Group& group = group_map_[group_name]; - - CheckSocketCounts(group); - - // Can we make another active socket now? - if (group.active_socket_count == max_sockets_per_group_) { - CHECK(callback); - Request r(handle, callback, priority, resolve_info, LOAD_STATE_IDLE); - InsertRequestIntoQueue(r, &group.pending_requests); - return ERR_IO_PENDING; - } - - // OK, we are going to activate one. - group.active_socket_count++; - - while (!group.idle_sockets.empty()) { - IdleSocket idle_socket = group.idle_sockets.back(); - group.idle_sockets.pop_back(); - DecrementIdleCount(); - if (idle_socket.socket->IsConnectedAndIdle()) { - // We found one we can reuse! - handle->set_socket(idle_socket.socket); - handle->set_is_reused(true); - group.sockets_handed_out_count++; - CheckSocketCounts(group); - return OK; - } - delete idle_socket.socket; - } - - // We couldn't find a socket to reuse, so allocate and connect a new one. - - CHECK(callback); - Request r(handle, callback, priority, resolve_info, - LOAD_STATE_RESOLVING_HOST); - group.connecting_requests[handle] = r; - - CHECK(!ContainsKey(connecting_socket_map_, handle)); - - ConnectingSocket* connecting_socket = - connecting_socket_factory_->NewConnectingSocket(group_name, r, this); - connecting_socket_map_[handle] = connecting_socket; - int rv = connecting_socket->Connect(); - - CheckSocketCounts(group); - return rv; -} - -void ClientSocketPoolBase::CancelRequest(const std::string& group_name, - const ClientSocketHandle* handle) { - CHECK(ContainsKey(group_map_, group_name)); - - Group& group = group_map_[group_name]; - - CheckSocketCounts(group); - - // Search pending_requests for matching handle. - RequestQueue::iterator it = group.pending_requests.begin(); - for (; it != group.pending_requests.end(); ++it) { - if (it->handle == handle) { - group.pending_requests.erase(it); - return; - } - } - - // It's invalid to cancel a non-existent request. - CHECK(ContainsKey(group.connecting_requests, handle)); - - RequestMap::iterator map_it = group.connecting_requests.find(handle); - if (map_it != group.connecting_requests.end()) { - RemoveConnectingSocket(handle); - group.connecting_requests.erase(map_it); - RemoveActiveSocket(group_name, &group); - } -} - -void ClientSocketPoolBase::ReleaseSocket(const std::string& group_name, - ClientSocket* socket) { - // Run this asynchronously to allow the caller to finish before we let - // another to begin doing work. This also avoids nasty recursion issues. - // NOTE: We cannot refer to the handle argument after this method returns. - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &ClientSocketPoolBase::DoReleaseSocket, group_name, socket)); -} - -void ClientSocketPoolBase::CloseIdleSockets() { - CleanupIdleSockets(true); -} - -int ClientSocketPoolBase::IdleSocketCountInGroup( - const std::string& group_name) const { - GroupMap::const_iterator i = group_map_.find(group_name); - CHECK(i != group_map_.end()); - - return i->second.idle_sockets.size(); -} - -LoadState ClientSocketPoolBase::GetLoadState( - const std::string& group_name, - const ClientSocketHandle* handle) const { - if (!ContainsKey(group_map_, group_name)) { - NOTREACHED() << "ClientSocketPool does not contain group: " << group_name - << " for handle: " << handle; - return LOAD_STATE_IDLE; - } - - // Can't use operator[] since it is non-const. - const Group& group = group_map_.find(group_name)->second; - - // Search connecting_requests for matching handle. - RequestMap::const_iterator map_it = group.connecting_requests.find(handle); - if (map_it != group.connecting_requests.end()) { - const LoadState load_state = map_it->second.load_state; - CHECK(load_state == LOAD_STATE_RESOLVING_HOST || - load_state == LOAD_STATE_CONNECTING); - return load_state; - } - - // Search pending_requests for matching handle. - RequestQueue::const_iterator it = group.pending_requests.begin(); - for (; it != group.pending_requests.end(); ++it) { - if (it->handle == handle) { - CHECK(LOAD_STATE_IDLE == it->load_state); - // TODO(wtc): Add a state for being on the wait list. - // See http://www.crbug.com/5077. - return LOAD_STATE_IDLE; - } - } - - NOTREACHED(); - return LOAD_STATE_IDLE; -} - -bool ClientSocketPoolBase::IdleSocket::ShouldCleanup( - base::TimeTicks now) const { - bool timed_out = (now - start_time) >= - base::TimeDelta::FromSeconds(kIdleTimeout); - return timed_out || !socket->IsConnectedAndIdle(); -} - -void ClientSocketPoolBase::CleanupIdleSockets(bool force) { - if (idle_socket_count_ == 0) - return; - - // Current time value. Retrieving it once at the function start rather than - // inside the inner loop, since it shouldn't change by any meaningful amount. - base::TimeTicks now = base::TimeTicks::Now(); - - GroupMap::iterator i = group_map_.begin(); - while (i != group_map_.end()) { - Group& group = i->second; - - std::deque<IdleSocket>::iterator j = group.idle_sockets.begin(); - while (j != group.idle_sockets.end()) { - if (force || j->ShouldCleanup(now)) { - delete j->socket; - j = group.idle_sockets.erase(j); - DecrementIdleCount(); - } else { - ++j; - } - } - - // Delete group if no longer needed. - if (group.active_socket_count == 0 && group.idle_sockets.empty()) { - CHECK(group.pending_requests.empty()); - CHECK(group.connecting_requests.empty()); - group_map_.erase(i++); - } else { - ++i; - } - } -} - -void ClientSocketPoolBase::IncrementIdleCount() { - if (++idle_socket_count_ == 1) - timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, - &ClientSocketPoolBase::OnCleanupTimerFired); -} - -void ClientSocketPoolBase::DecrementIdleCount() { - if (--idle_socket_count_ == 0) - timer_.Stop(); -} - -void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name, - ClientSocket* socket) { - GroupMap::iterator i = group_map_.find(group_name); - CHECK(i != group_map_.end()); - - Group& group = i->second; - - CHECK(group.active_socket_count > 0); - CheckSocketCounts(group); - - group.sockets_handed_out_count--; - - const bool can_reuse = socket->IsConnectedAndIdle(); - if (can_reuse) { - IdleSocket idle_socket; - idle_socket.socket = socket; - idle_socket.start_time = base::TimeTicks::Now(); - - group.idle_sockets.push_back(idle_socket); - IncrementIdleCount(); - } else { - delete socket; - } - - RemoveActiveSocket(group_name, &group); -} - -ClientSocketPoolBase::Request* ClientSocketPoolBase::GetConnectingRequest( - const std::string& group_name, const ClientSocketHandle* handle) { - GroupMap::iterator group_it = group_map_.find(group_name); - if (group_it == group_map_.end()) - return NULL; - - Group& group = group_it->second; - - RequestMap* request_map = &group.connecting_requests; - RequestMap::iterator it = request_map->find(handle); - if (it == request_map->end()) - return NULL; - - return &it->second; -} - -CompletionCallback* ClientSocketPoolBase::OnConnectingRequestComplete( - const std::string& group_name, - const ClientSocketHandle* handle, - bool deactivate, - ClientSocket* socket) { - CHECK((deactivate && !socket) || (!deactivate && socket)); - GroupMap::iterator group_it = group_map_.find(group_name); - CHECK(group_it != group_map_.end()); - Group& group = group_it->second; - - CheckSocketCounts(group); - - RequestMap* request_map = &group.connecting_requests; - - RequestMap::iterator it = request_map->find(handle); - CHECK(it != request_map->end()); - Request request = it->second; - request_map->erase(it); - DCHECK_EQ(request.handle, handle); - - if (deactivate) { - RemoveActiveSocket(group_name, &group); - } else { - request.handle->set_socket(socket); - request.handle->set_is_reused(false); - group.sockets_handed_out_count++; - - CheckSocketCounts(group); - } - - RemoveConnectingSocket(request.handle); - - return request.callback; -} - -// static -void ClientSocketPoolBase::CheckSocketCounts(const Group& group) { - CHECK(group.active_socket_count == - group.sockets_handed_out_count + - static_cast<int>(group.connecting_requests.size())) - << "[active_socket_count: " << group.active_socket_count - << " ] [sockets_handed_out_count: " << group.sockets_handed_out_count - << " ] [connecting_requests size: " << group.connecting_requests.size(); -} - -void ClientSocketPoolBase::RemoveConnectingSocket( - const ClientSocketHandle* handle) { - ConnectingSocketMap::iterator it = connecting_socket_map_.find(handle); - CHECK(it != connecting_socket_map_.end()); - delete it->second; - connecting_socket_map_.erase(it); -} - -void ClientSocketPoolBase::RemoveActiveSocket(const std::string& group_name, - Group* group) { - group->active_socket_count--; - - if (!group->pending_requests.empty()) { - ProcessPendingRequest(group_name, group); - // |group| may no longer be valid after this point. Be careful not to - // access it again. - } else if (group->active_socket_count == 0 && group->idle_sockets.empty()) { - // Delete |group| if no longer needed. |group| will no longer be valid. - DCHECK(group->connecting_requests.empty()); - group_map_.erase(group_name); - } else { - CheckSocketCounts(*group); - } -} - -void ClientSocketPoolBase::ProcessPendingRequest(const std::string& group_name, - Group* group) { - Request r = group->pending_requests.front(); - group->pending_requests.pop_front(); - - int rv = RequestSocket( - group_name, r.resolve_info, r.priority, r.handle, r.callback); - - // |group| may be invalid after RequestSocket. - - if (rv != ERR_IO_PENDING) - r.callback->Run(rv); -} - -ConnectingSocket* -TCPClientSocketPool::TCPConnectingSocketFactory::NewConnectingSocket( +ConnectJob* TCPClientSocketPool::TCPConnectJobFactory::NewConnectJob( const std::string& group_name, const ClientSocketPoolBase::Request& request, ClientSocketPoolBase* pool) const { - return new TCPConnectingSocket( + return new TCPConnectJob( group_name, request.resolve_info, request.handle, client_socket_factory_, pool); } @@ -490,7 +138,7 @@ TCPClientSocketPool::TCPClientSocketPool( ClientSocketFactory* client_socket_factory) : base_(new ClientSocketPoolBase( max_sockets_per_group, host_resolver, - new TCPConnectingSocketFactory(client_socket_factory))) {} + new TCPConnectJobFactory(client_socket_factory))) {} TCPClientSocketPool::~TCPClientSocketPool() {} |