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