| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/tcp_client_socket_pool.h" | 5 #include "net/base/tcp_client_socket_pool.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/field_trial.h" | 8 #include "base/field_trial.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 const ClientSocketHandle* handle, | 38 const ClientSocketHandle* handle, |
| 39 ClientSocketFactory* client_socket_factory, | 39 ClientSocketFactory* client_socket_factory, |
| 40 TCPClientSocketPool* pool) | 40 TCPClientSocketPool* pool) |
| 41 : group_name_(group_name), | 41 : group_name_(group_name), |
| 42 handle_(handle), | 42 handle_(handle), |
| 43 client_socket_factory_(client_socket_factory), | 43 client_socket_factory_(client_socket_factory), |
| 44 ALLOW_THIS_IN_INITIALIZER_LIST( | 44 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 45 callback_(this, | 45 callback_(this, |
| 46 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)), | 46 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)), |
| 47 pool_(pool), | 47 pool_(pool), |
| 48 resolver_(pool->GetHostResolver()) {} | 48 resolver_(pool->GetHostResolver()), |
| 49 canceled_(false) { |
| 50 CHECK(!ContainsKey(pool_->connecting_socket_map_, handle)); |
| 51 pool_->connecting_socket_map_[handle] = this; |
| 52 } |
| 49 | 53 |
| 50 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { | 54 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { |
| 51 // We don't worry about cancelling the host resolution and TCP connect, since | 55 if (!canceled_) |
| 52 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. | 56 pool_->connecting_socket_map_.erase(handle_); |
| 53 } | 57 } |
| 54 | 58 |
| 55 int TCPClientSocketPool::ConnectingSocket::Connect( | 59 int TCPClientSocketPool::ConnectingSocket::Connect( |
| 56 const HostResolver::RequestInfo& resolve_info) { | 60 const HostResolver::RequestInfo& resolve_info) { |
| 61 CHECK(!canceled_); |
| 57 int rv = resolver_.Resolve(resolve_info, &addresses_, &callback_); | 62 int rv = resolver_.Resolve(resolve_info, &addresses_, &callback_); |
| 58 if (rv != ERR_IO_PENDING) | 63 if (rv != ERR_IO_PENDING) |
| 59 rv = OnIOCompleteInternal(rv, true /* synchronous */); | 64 rv = OnIOCompleteInternal(rv, true /* synchronous */); |
| 60 return rv; | 65 return rv; |
| 61 } | 66 } |
| 62 | 67 |
| 63 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) { | 68 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) { |
| 64 OnIOCompleteInternal(result, false /* asynchronous */); | 69 OnIOCompleteInternal(result, false /* asynchronous */); |
| 65 } | 70 } |
| 66 | 71 |
| 67 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal( | 72 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal( |
| 68 int result, bool synchronous) { | 73 int result, bool synchronous) { |
| 69 CHECK(result != ERR_IO_PENDING); | 74 CHECK(result != ERR_IO_PENDING); |
| 70 | 75 |
| 76 if (canceled_) { |
| 77 // We got canceled, so bail out. |
| 78 delete this; |
| 79 return result; |
| 80 } |
| 81 |
| 71 GroupMap::iterator group_it = pool_->group_map_.find(group_name_); | 82 GroupMap::iterator group_it = pool_->group_map_.find(group_name_); |
| 72 CHECK(group_it != pool_->group_map_.end()); | 83 if (group_it == pool_->group_map_.end()) { |
| 84 // The request corresponding to this ConnectingSocket has been canceled. |
| 85 // Stop bothering with it. |
| 86 delete this; |
| 87 return result; |
| 88 } |
| 73 | 89 |
| 74 Group& group = group_it->second; | 90 Group& group = group_it->second; |
| 75 | 91 |
| 76 RequestMap* request_map = &group.connecting_requests; | 92 RequestMap* request_map = &group.connecting_requests; |
| 77 RequestMap::iterator it = request_map->find(handle_); | 93 RequestMap::iterator it = request_map->find(handle_); |
| 78 CHECK(it != request_map->end()); | 94 if (it == request_map->end()) { |
| 95 // The request corresponding to this ConnectingSocket has been canceled. |
| 96 // Stop bothering with it. |
| 97 delete this; |
| 98 return result; |
| 99 } |
| 79 | 100 |
| 80 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) { | 101 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) { |
| 81 it->second.load_state = LOAD_STATE_CONNECTING; | 102 it->second.load_state = LOAD_STATE_CONNECTING; |
| 82 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); | 103 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); |
| 83 connect_start_time_ = base::Time::Now(); | 104 connect_start_time_ = base::Time::Now(); |
| 84 result = socket_->Connect(&callback_); | 105 result = socket_->Connect(&callback_); |
| 85 if (result == ERR_IO_PENDING) | 106 if (result == ERR_IO_PENDING) |
| 86 return result; | 107 return result; |
| 87 } | 108 } |
| 88 | 109 |
| 89 if (result == OK) { | 110 if (result == OK) { |
| 90 CHECK(it->second.load_state == LOAD_STATE_CONNECTING); | |
| 91 CHECK(connect_start_time_ != base::Time()); | 111 CHECK(connect_start_time_ != base::Time()); |
| 92 base::TimeDelta connect_duration = | 112 base::TimeDelta connect_duration = |
| 93 base::Time::Now() - connect_start_time_; | 113 base::Time::Now() - connect_start_time_; |
| 94 | 114 |
| 95 UMA_HISTOGRAM_CLIPPED_TIMES("Net.TCP_Connection_Latency", | 115 UMA_HISTOGRAM_CLIPPED_TIMES("Net.TCP_Connection_Latency", |
| 96 connect_duration, | 116 connect_duration, |
| 97 base::TimeDelta::FromMilliseconds(1), | 117 base::TimeDelta::FromMilliseconds(1), |
| 98 base::TimeDelta::FromMinutes(10), | 118 base::TimeDelta::FromMinutes(10), |
| 99 100); | 119 100); |
| 100 } | 120 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 114 // Delete group if no longer needed. | 134 // Delete group if no longer needed. |
| 115 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 135 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
| 116 CHECK(group.pending_requests.empty()); | 136 CHECK(group.pending_requests.empty()); |
| 117 CHECK(group.connecting_requests.empty()); | 137 CHECK(group.connecting_requests.empty()); |
| 118 pool_->group_map_.erase(group_it); | 138 pool_->group_map_.erase(group_it); |
| 119 } | 139 } |
| 120 } | 140 } |
| 121 | 141 |
| 122 if (!synchronous) | 142 if (!synchronous) |
| 123 request.callback->Run(result); | 143 request.callback->Run(result); |
| 124 pool_->RemoveConnectingSocket(handle_); // will delete |this|. | 144 delete this; |
| 125 return result; | 145 return result; |
| 126 } | 146 } |
| 127 | 147 |
| 148 void TCPClientSocketPool::ConnectingSocket::Cancel() { |
| 149 CHECK(!canceled_); |
| 150 CHECK(ContainsKey(pool_->connecting_socket_map_, handle_)); |
| 151 pool_->connecting_socket_map_.erase(handle_); |
| 152 canceled_ = true; |
| 153 } |
| 154 |
| 128 TCPClientSocketPool::TCPClientSocketPool( | 155 TCPClientSocketPool::TCPClientSocketPool( |
| 129 int max_sockets_per_group, | 156 int max_sockets_per_group, |
| 130 HostResolver* host_resolver, | 157 HostResolver* host_resolver, |
| 131 ClientSocketFactory* client_socket_factory) | 158 ClientSocketFactory* client_socket_factory) |
| 132 : client_socket_factory_(client_socket_factory), | 159 : client_socket_factory_(client_socket_factory), |
| 133 idle_socket_count_(0), | 160 idle_socket_count_(0), |
| 134 max_sockets_per_group_(max_sockets_per_group), | 161 max_sockets_per_group_(max_sockets_per_group), |
| 135 host_resolver_(host_resolver) { | 162 host_resolver_(host_resolver) { |
| 136 } | 163 } |
| 137 | 164 |
| 138 TCPClientSocketPool::~TCPClientSocketPool() { | 165 TCPClientSocketPool::~TCPClientSocketPool() { |
| 139 // Clean up any idle sockets. Assert that we have no remaining active | 166 // Clean up any idle sockets. Assert that we have no remaining active |
| 140 // sockets or pending requests. They should have all been cleaned up prior | 167 // sockets or pending requests. They should have all been cleaned up prior |
| 141 // to the manager being destroyed. | 168 // to the manager being destroyed. |
| 142 CloseIdleSockets(); | 169 CloseIdleSockets(); |
| 143 DCHECK(group_map_.empty()); | 170 DCHECK(group_map_.empty()); |
| 144 DCHECK(connecting_socket_map_.empty()); | |
| 145 } | 171 } |
| 146 | 172 |
| 147 // InsertRequestIntoQueue inserts the request into the queue based on | 173 // InsertRequestIntoQueue inserts the request into the queue based on |
| 148 // priority. Highest priorities are closest to the front. Older requests are | 174 // priority. Highest priorities are closest to the front. Older requests are |
| 149 // prioritized over requests of equal priority. | 175 // prioritized over requests of equal priority. |
| 150 // | 176 // |
| 151 // static | 177 // static |
| 152 void TCPClientSocketPool::InsertRequestIntoQueue( | 178 void TCPClientSocketPool::InsertRequestIntoQueue( |
| 153 const Request& r, RequestQueue* pending_requests) { | 179 const Request& r, RequestQueue* pending_requests) { |
| 154 RequestQueue::iterator it = pending_requests->begin(); | 180 RequestQueue::iterator it = pending_requests->begin(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 // We found one we can reuse! | 212 // We found one we can reuse! |
| 187 handle->set_socket(idle_socket.socket); | 213 handle->set_socket(idle_socket.socket); |
| 188 handle->set_is_reused(true); | 214 handle->set_is_reused(true); |
| 189 return OK; | 215 return OK; |
| 190 } | 216 } |
| 191 delete idle_socket.socket; | 217 delete idle_socket.socket; |
| 192 } | 218 } |
| 193 | 219 |
| 194 // We couldn't find a socket to reuse, so allocate and connect a new one. | 220 // We couldn't find a socket to reuse, so allocate and connect a new one. |
| 195 | 221 |
| 222 // First, we need to make sure we aren't already servicing a request for this |
| 223 // handle (which could happen if we requested, canceled, and then requested |
| 224 // with the same handle). |
| 225 if (ContainsKey(connecting_socket_map_, handle)) |
| 226 connecting_socket_map_[handle]->Cancel(); |
| 227 |
| 196 CHECK(callback); | 228 CHECK(callback); |
| 197 Request r(handle, callback, priority, resolve_info, | 229 Request r(handle, callback, priority, resolve_info, |
| 198 LOAD_STATE_RESOLVING_HOST); | 230 LOAD_STATE_RESOLVING_HOST); |
| 199 group_map_[group_name].connecting_requests[handle] = r; | 231 group_map_[group_name].connecting_requests[handle] = r; |
| 200 | 232 |
| 201 CHECK(!ContainsKey(connecting_socket_map_, handle)); | 233 // connecting_socket will delete itself. |
| 202 | |
| 203 ConnectingSocket* connecting_socket = | 234 ConnectingSocket* connecting_socket = |
| 204 new ConnectingSocket(group_name, handle, client_socket_factory_, this); | 235 new ConnectingSocket(group_name, handle, client_socket_factory_, this); |
| 205 connecting_socket_map_[handle] = connecting_socket; | |
| 206 int rv = connecting_socket->Connect(resolve_info); | 236 int rv = connecting_socket->Connect(resolve_info); |
| 207 return rv; | 237 return rv; |
| 208 } | 238 } |
| 209 | 239 |
| 210 void TCPClientSocketPool::CancelRequest(const std::string& group_name, | 240 void TCPClientSocketPool::CancelRequest(const std::string& group_name, |
| 211 const ClientSocketHandle* handle) { | 241 const ClientSocketHandle* handle) { |
| 212 CHECK(ContainsKey(group_map_, group_name)); | 242 CHECK(ContainsKey(group_map_, group_name)); |
| 213 | 243 |
| 214 Group& group = group_map_[group_name]; | 244 Group& group = group_map_[group_name]; |
| 215 | 245 |
| 216 // Search pending_requests for matching handle. | 246 // Search pending_requests for matching handle. |
| 217 RequestQueue::iterator it = group.pending_requests.begin(); | 247 RequestQueue::iterator it = group.pending_requests.begin(); |
| 218 for (; it != group.pending_requests.end(); ++it) { | 248 for (; it != group.pending_requests.end(); ++it) { |
| 219 if (it->handle == handle) { | 249 if (it->handle == handle) { |
| 220 group.pending_requests.erase(it); | 250 group.pending_requests.erase(it); |
| 221 return; | 251 return; |
| 222 } | 252 } |
| 223 } | 253 } |
| 224 | 254 |
| 225 // It's invalid to cancel a non-existent request. | 255 // It's invalid to cancel a non-existent request. |
| 226 CHECK(ContainsKey(group.connecting_requests, handle)); | 256 CHECK(ContainsKey(group.connecting_requests, handle)); |
| 227 | 257 |
| 228 RequestMap::iterator map_it = group.connecting_requests.find(handle); | 258 RequestMap::iterator map_it = group.connecting_requests.find(handle); |
| 229 if (map_it != group.connecting_requests.end()) { | 259 if (map_it != group.connecting_requests.end()) { |
| 230 RemoveConnectingSocket(handle); | |
| 231 | |
| 232 group.connecting_requests.erase(map_it); | 260 group.connecting_requests.erase(map_it); |
| 233 group.active_socket_count--; | 261 group.active_socket_count--; |
| 234 | 262 |
| 235 // Delete group if no longer needed. | 263 // Delete group if no longer needed. |
| 236 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 264 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
| 237 CHECK(group.pending_requests.empty()); | 265 CHECK(group.pending_requests.empty()); |
| 238 CHECK(group.connecting_requests.empty()); | 266 CHECK(group.connecting_requests.empty()); |
| 239 group_map_.erase(group_name); | 267 group_map_.erase(group_name); |
| 240 } | 268 } |
| 241 } | 269 } |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 } | 412 } |
| 385 | 413 |
| 386 // Delete group if no longer needed. | 414 // Delete group if no longer needed. |
| 387 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 415 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
| 388 CHECK(group.pending_requests.empty()); | 416 CHECK(group.pending_requests.empty()); |
| 389 CHECK(group.connecting_requests.empty()); | 417 CHECK(group.connecting_requests.empty()); |
| 390 group_map_.erase(i); | 418 group_map_.erase(i); |
| 391 } | 419 } |
| 392 } | 420 } |
| 393 | 421 |
| 394 void TCPClientSocketPool::RemoveConnectingSocket( | |
| 395 const ClientSocketHandle* handle) { | |
| 396 ConnectingSocketMap::iterator it = connecting_socket_map_.find(handle); | |
| 397 CHECK(it != connecting_socket_map_.end()); | |
| 398 delete it->second; | |
| 399 connecting_socket_map_.erase(it); | |
| 400 } | |
| 401 | |
| 402 } // namespace net | 422 } // namespace net |
| OLD | NEW |