summaryrefslogtreecommitdiffstats
path: root/net/base/client_socket_pool.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/base/client_socket_pool.cc')
-rw-r--r--net/base/client_socket_pool.cc273
1 files changed, 33 insertions, 240 deletions
diff --git a/net/base/client_socket_pool.cc b/net/base/client_socket_pool.cc
index 9f14fe7..4171b0c 100644
--- a/net/base/client_socket_pool.cc
+++ b/net/base/client_socket_pool.cc
@@ -4,16 +4,10 @@
#include "net/base/client_socket_pool.h"
-#include "base/compiler_specific.h"
-#include "base/field_trial.h"
#include "base/message_loop.h"
-#include "base/time.h"
-#include "base/stl_util-inl.h"
-#include "net/base/client_socket_factory.h"
+#include "net/base/client_socket.h"
#include "net/base/client_socket_handle.h"
-#include "net/base/dns_resolution_observer.h"
#include "net/base/net_errors.h"
-#include "net/base/tcp_client_socket.h"
using base::TimeDelta;
@@ -34,123 +28,8 @@ const int kIdleTimeout = 300; // 5 minutes.
namespace net {
-ClientSocketPool::ConnectingSocket::ConnectingSocket(
- const std::string& group_name,
- const ClientSocketHandle* handle,
- ClientSocketFactory* client_socket_factory,
- ClientSocketPool* pool)
- : group_name_(group_name),
- handle_(handle),
- client_socket_factory_(client_socket_factory),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- callback_(this,
- &ClientSocketPool::ConnectingSocket::OnIOComplete)),
- pool_(pool) {}
-
-ClientSocketPool::ConnectingSocket::~ConnectingSocket() {}
-
-int ClientSocketPool::ConnectingSocket::Connect(
- const std::string& host,
- int port,
- CompletionCallback* callback) {
- DidStartDnsResolution(host, this);
- int rv = resolver_.Resolve(host, port, &addresses_, &callback_);
- if (rv == OK) {
- // TODO(willchan): This code is broken. It should be fixed, but the code
- // path is impossible in the current implementation since the host resolver
- // always dumps the request to a worker pool, so it cannot complete
- // synchronously.
- connect_start_time_ = base::Time::Now();
- rv = socket_->Connect(&callback_);
- }
- return rv;
-}
-
-ClientSocket* ClientSocketPool::ConnectingSocket::ReleaseSocket() {
- return socket_.release();
-}
-
-void ClientSocketPool::ConnectingSocket::OnIOComplete(int result) {
- DCHECK_NE(result, ERR_IO_PENDING);
-
- GroupMap::iterator group_it = pool_->group_map_.find(group_name_);
- if (group_it == pool_->group_map_.end()) {
- // The request corresponding to this ConnectingSocket has been canceled.
- // Stop bothering with it.
- delete this;
- return;
- }
-
- Group& group = group_it->second;
-
- RequestMap* request_map = &group.connecting_requests;
- RequestMap::iterator it = request_map->find(handle_);
- if (it == request_map->end()) {
- // The request corresponding to this ConnectingSocket has been canceled.
- // Stop bothering with it.
- group.active_socket_count--;
-
- // Delete group if no longer needed.
- if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
- DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
- pool_->group_map_.erase(group_it);
- }
- delete this;
- return;
- }
-
- if (result == OK) {
- if (it->second.load_state == LOAD_STATE_RESOLVING_HOST) {
- it->second.load_state = LOAD_STATE_CONNECTING;
- socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_));
- connect_start_time_ = base::Time::Now();
- result = socket_->Connect(&callback_);
- if (result == ERR_IO_PENDING)
- return;
- } else {
- DCHECK(connect_start_time_ != base::Time());
- base::TimeDelta connect_duration =
- base::Time::Now() - connect_start_time_;
-
- UMA_HISTOGRAM_CLIPPED_TIMES(
- FieldTrial::MakeName(
- "Net.TCP_Connection_Latency", "DnsImpact").data(),
- connect_duration,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 100);
- }
- }
-
- // Now, we either succeeded at Connect()'ing, or we failed at host resolution
- // or Connect()'ing. Either way, we'll run the callback to alert the client.
-
- Request request = it->second;
- request_map->erase(it);
-
- if (result == OK) {
- request.handle->set_socket(socket_.release());
- request.handle->set_is_reused(false);
- } else {
- group.active_socket_count--;
-
- // Delete group if no longer needed.
- if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
- DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
- pool_->group_map_.erase(group_it);
- }
- }
-
- request.callback->Run(result);
- delete this;
-}
-
-ClientSocketPool::ClientSocketPool(int max_sockets_per_group,
- ClientSocketFactory* client_socket_factory)
- : client_socket_factory_(client_socket_factory),
- idle_socket_count_(0),
+ClientSocketPool::ClientSocketPool(int max_sockets_per_group)
+ : idle_socket_count_(0),
max_sockets_per_group_(max_sockets_per_group) {
}
@@ -175,15 +54,10 @@ void ClientSocketPool::InsertRequestIntoQueue(const Request& r,
pending_requests->insert(it, r);
}
-int ClientSocketPool::RequestSocket(const std::string& group_name,
- const std::string& host,
- int port,
+int ClientSocketPool::RequestSocket(ClientSocketHandle* handle,
int priority,
- ClientSocketHandle* handle,
CompletionCallback* callback) {
- DCHECK(!host.empty());
- DCHECK_GE(priority, 0);
- Group& group = group_map_[group_name];
+ Group& group = group_map_[handle->group_name_];
// Can we make another active socket now?
if (group.active_socket_count == max_sockets_per_group_) {
@@ -192,9 +66,6 @@ int ClientSocketPool::RequestSocket(const std::string& group_name,
DCHECK(callback);
r.callback = callback;
r.priority = priority;
- r.host = host;
- r.port = port;
- r.load_state = LOAD_STATE_IDLE;
InsertRequestIntoQueue(r, &group.pending_requests);
return ERR_IO_PENDING;
}
@@ -202,91 +73,49 @@ int ClientSocketPool::RequestSocket(const std::string& group_name,
// OK, we are going to activate one.
group.active_socket_count++;
+ // Use idle sockets in LIFO order because they're more likely to be
+ // still reusable.
while (!group.idle_sockets.empty()) {
IdleSocket idle_socket = group.idle_sockets.back();
group.idle_sockets.pop_back();
DecrementIdleCount();
- if (idle_socket.socket->IsConnectedAndIdle()) {
+ if ((*idle_socket.ptr)->IsConnectedAndIdle()) {
// We found one we can reuse!
- handle->set_socket(idle_socket.socket);
- handle->set_is_reused(true);
+ handle->socket_ = idle_socket.ptr;
return OK;
}
- delete idle_socket.socket;
+ delete idle_socket.ptr;
}
- // We couldn't find a socket to reuse, so allocate and connect a new one.
- scoped_ptr<ConnectingSocket> connecting_socket(
- new ConnectingSocket(group_name, handle, client_socket_factory_, this));
- int rv = connecting_socket->Connect(host, port, callback);
- if (rv == OK) {
- handle->set_socket(connecting_socket->ReleaseSocket());
- handle->set_is_reused(false);
- } else if (rv == ERR_IO_PENDING) {
- // The ConnectingSocket will delete itself.
- connecting_socket.release();
- Request r;
- r.handle = handle;
- DCHECK(callback);
- r.callback = callback;
- r.priority = priority;
- r.host = host;
- r.port = port;
- r.load_state = LOAD_STATE_RESOLVING_HOST;
- group_map_[group_name].connecting_requests[handle] = r;
- } else {
- group.active_socket_count--;
-
- // Delete group if no longer needed.
- if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
- DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
- group_map_.erase(group_name);
- }
- }
-
- return rv;
+ handle->socket_ = new ClientSocketPtr();
+ return OK;
}
-void ClientSocketPool::CancelRequest(const std::string& group_name,
- const ClientSocketHandle* handle) {
- DCHECK(ContainsKey(group_map_, group_name));
+void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) {
+ Group& group = group_map_[handle->group_name_];
- Group& group = group_map_[group_name];
+ // In order for us to be canceling a pending request, we must have active
+ // sockets equaling the limit. NOTE: The correctness of the code doesn't
+ // require this assertion.
+ DCHECK(group.active_socket_count == max_sockets_per_group_);
// Search pending_requests for matching handle.
- RequestQueue::iterator it = group.pending_requests.begin();
+ std::deque<Request>::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.
- DCHECK(ContainsKey(group.connecting_requests, handle));
-
- RequestMap::iterator map_it = group.connecting_requests.find(handle);
- if (map_it != group.connecting_requests.end()) {
- group.connecting_requests.erase(map_it);
- group.active_socket_count--;
-
- // Delete group if no longer needed.
- if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
- DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
- group_map_.erase(group_name);
+ break;
}
}
}
-void ClientSocketPool::ReleaseSocket(const std::string& group_name,
- ClientSocket* socket) {
+void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) {
// 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, &ClientSocketPool::DoReleaseSocket, group_name, socket));
+ this, &ClientSocketPool::DoReleaseSocket, handle->group_name_,
+ handle->socket_));
}
void ClientSocketPool::CloseIdleSockets() {
@@ -301,42 +130,10 @@ int ClientSocketPool::IdleSocketCountInGroup(
return i->second.idle_sockets.size();
}
-LoadState ClientSocketPool::GetLoadState(
- const std::string& group_name,
- const ClientSocketHandle* handle) const {
- DCHECK(ContainsKey(group_map_, group_name)) << group_name;
-
- // 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;
- DCHECK(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) {
- DCHECK_EQ(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 ClientSocketPool::IdleSocket::ShouldCleanup(base::TimeTicks now) const {
bool timed_out = (now - start_time) >=
base::TimeDelta::FromSeconds(kIdleTimeout);
- return timed_out || !socket->IsConnectedAndIdle();
+ return timed_out || !(*ptr)->IsConnectedAndIdle();
}
void ClientSocketPool::CleanupIdleSockets(bool force) {
@@ -354,7 +151,7 @@ void ClientSocketPool::CleanupIdleSockets(bool force) {
std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
while (j != group.idle_sockets.end()) {
if (force || j->ShouldCleanup(now)) {
- delete j->socket;
+ delete j->ptr;
j = group.idle_sockets.erase(j);
DecrementIdleCount();
} else {
@@ -365,7 +162,6 @@ void ClientSocketPool::CleanupIdleSockets(bool force) {
// Delete group if no longer needed.
if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
group_map_.erase(i++);
} else {
++i;
@@ -385,43 +181,40 @@ void ClientSocketPool::DecrementIdleCount() {
}
void ClientSocketPool::DoReleaseSocket(const std::string& group_name,
- ClientSocket* socket) {
+ ClientSocketPtr* ptr) {
GroupMap::iterator i = group_map_.find(group_name);
DCHECK(i != group_map_.end());
Group& group = i->second;
- DCHECK_GT(group.active_socket_count, 0);
+ DCHECK(group.active_socket_count > 0);
group.active_socket_count--;
- const bool can_reuse = socket->IsConnectedAndIdle();
+ bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle();
if (can_reuse) {
IdleSocket idle_socket;
- idle_socket.socket = socket;
+ idle_socket.ptr = ptr;
idle_socket.start_time = base::TimeTicks::Now();
group.idle_sockets.push_back(idle_socket);
IncrementIdleCount();
} else {
- delete socket;
+ delete ptr;
}
// Process one pending request.
if (!group.pending_requests.empty()) {
Request r = group.pending_requests.front();
group.pending_requests.pop_front();
-
- int rv = RequestSocket(
- group_name, r.host, r.port, r.priority, r.handle, r.callback);
- if (rv != ERR_IO_PENDING)
- r.callback->Run(rv);
+ int rv = RequestSocket(r.handle, r.priority, NULL);
+ DCHECK(rv == OK);
+ r.callback->Run(rv);
return;
}
// Delete group if no longer needed.
if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
DCHECK(group.pending_requests.empty());
- DCHECK(group.connecting_requests.empty());
group_map_.erase(i);
}
}