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 |