Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(981)

Side by Side Diff: net/base/tcp_client_socket_pool.cc

Issue 125025: Try to track down a dangling ClientSocketHandle* by upgrading DCHECKs to CHECKs. (Closed)
Patch Set: Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/client_socket_handle.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 29 matching lines...) Expand all
40 ClientSocketFactory* client_socket_factory, 40 ClientSocketFactory* client_socket_factory,
41 TCPClientSocketPool* pool) 41 TCPClientSocketPool* pool)
42 : group_name_(group_name), 42 : group_name_(group_name),
43 handle_(handle), 43 handle_(handle),
44 client_socket_factory_(client_socket_factory), 44 client_socket_factory_(client_socket_factory),
45 ALLOW_THIS_IN_INITIALIZER_LIST( 45 ALLOW_THIS_IN_INITIALIZER_LIST(
46 callback_(this, 46 callback_(this,
47 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)), 47 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)),
48 pool_(pool), 48 pool_(pool),
49 canceled_(false) { 49 canceled_(false) {
50 DCHECK(!ContainsKey(pool_->connecting_socket_map_, handle)); 50 CHECK(!ContainsKey(pool_->connecting_socket_map_, handle));
51 pool_->connecting_socket_map_[handle] = this; 51 pool_->connecting_socket_map_[handle] = this;
52 } 52 }
53 53
54 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { 54 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() {
55 if (!canceled_) 55 if (!canceled_)
56 pool_->connecting_socket_map_.erase(handle_); 56 pool_->connecting_socket_map_.erase(handle_);
57 } 57 }
58 58
59 int TCPClientSocketPool::ConnectingSocket::Connect( 59 int TCPClientSocketPool::ConnectingSocket::Connect(
60 const std::string& host, 60 const std::string& host,
61 int port) { 61 int port) {
62 DCHECK(!canceled_); 62 CHECK(!canceled_);
63 DidStartDnsResolution(host, this); 63 DidStartDnsResolution(host, this);
64 int rv = resolver_.Resolve(host, port, &addresses_, &callback_); 64 int rv = resolver_.Resolve(host, port, &addresses_, &callback_);
65 if (rv != ERR_IO_PENDING) 65 if (rv != ERR_IO_PENDING)
66 rv = OnIOCompleteInternal(rv, true /* synchronous */); 66 rv = OnIOCompleteInternal(rv, true /* synchronous */);
67 return rv; 67 return rv;
68 } 68 }
69 69
70 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) { 70 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) {
71 OnIOCompleteInternal(result, false /* asynchronous */); 71 OnIOCompleteInternal(result, false /* asynchronous */);
72 } 72 }
73 73
74 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal( 74 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal(
75 int result, bool synchronous) { 75 int result, bool synchronous) {
76 DCHECK_NE(result, ERR_IO_PENDING); 76 CHECK(result != ERR_IO_PENDING);
77 77
78 if (canceled_) { 78 if (canceled_) {
79 // We got canceled, so bail out. 79 // We got canceled, so bail out.
80 delete this; 80 delete this;
81 return result; 81 return result;
82 } 82 }
83 83
84 GroupMap::iterator group_it = pool_->group_map_.find(group_name_); 84 GroupMap::iterator group_it = pool_->group_map_.find(group_name_);
85 if (group_it == pool_->group_map_.end()) { 85 if (group_it == pool_->group_map_.end()) {
86 // The request corresponding to this ConnectingSocket has been canceled. 86 // The request corresponding to this ConnectingSocket has been canceled.
(...skipping 16 matching lines...) Expand all
103 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) { 103 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) {
104 it->second.load_state = LOAD_STATE_CONNECTING; 104 it->second.load_state = LOAD_STATE_CONNECTING;
105 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); 105 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_));
106 connect_start_time_ = base::Time::Now(); 106 connect_start_time_ = base::Time::Now();
107 result = socket_->Connect(&callback_); 107 result = socket_->Connect(&callback_);
108 if (result == ERR_IO_PENDING) 108 if (result == ERR_IO_PENDING)
109 return result; 109 return result;
110 } 110 }
111 111
112 if (result == OK) { 112 if (result == OK) {
113 DCHECK(connect_start_time_ != base::Time()); 113 CHECK(connect_start_time_ != base::Time());
114 base::TimeDelta connect_duration = 114 base::TimeDelta connect_duration =
115 base::Time::Now() - connect_start_time_; 115 base::Time::Now() - connect_start_time_;
116 116
117 UMA_HISTOGRAM_CLIPPED_TIMES( 117 UMA_HISTOGRAM_CLIPPED_TIMES(
118 FieldTrial::MakeName( 118 FieldTrial::MakeName(
119 "Net.TCP_Connection_Latency", "DnsImpact").data(), 119 "Net.TCP_Connection_Latency", "DnsImpact").data(),
120 connect_duration, 120 connect_duration,
121 base::TimeDelta::FromMilliseconds(1), 121 base::TimeDelta::FromMilliseconds(1),
122 base::TimeDelta::FromMinutes(10), 122 base::TimeDelta::FromMinutes(10),
123 100); 123 100);
124 } 124 }
125 125
126 // Now, we either succeeded at Connect()'ing, or we failed at host resolution 126 // Now, we either succeeded at Connect()'ing, or we failed at host resolution
127 // or Connect()'ing. Either way, we'll run the callback to alert the client. 127 // or Connect()'ing. Either way, we'll run the callback to alert the client.
128 128
129 Request request = it->second; 129 Request request = it->second;
130 request_map->erase(it); 130 request_map->erase(it);
131 131
132 if (result == OK) { 132 if (result == OK) {
133 request.handle->set_socket(socket_.release()); 133 request.handle->set_socket(socket_.release());
134 request.handle->set_is_reused(false); 134 request.handle->set_is_reused(false);
135 } else { 135 } else {
136 group.active_socket_count--; 136 group.active_socket_count--;
137 137
138 // Delete group if no longer needed. 138 // Delete group if no longer needed.
139 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 139 if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
140 DCHECK(group.pending_requests.empty()); 140 CHECK(group.pending_requests.empty());
141 DCHECK(group.connecting_requests.empty()); 141 CHECK(group.connecting_requests.empty());
142 pool_->group_map_.erase(group_it); 142 pool_->group_map_.erase(group_it);
143 } 143 }
144 } 144 }
145 145
146 if (!synchronous) 146 if (!synchronous)
147 request.callback->Run(result); 147 request.callback->Run(result);
148 delete this; 148 delete this;
149 return result; 149 return result;
150 } 150 }
151 151
152 void TCPClientSocketPool::ConnectingSocket::Cancel() { 152 void TCPClientSocketPool::ConnectingSocket::Cancel() {
153 DCHECK(!canceled_); 153 CHECK(!canceled_);
154 DCHECK(ContainsKey(pool_->connecting_socket_map_, handle_)); 154 CHECK(ContainsKey(pool_->connecting_socket_map_, handle_));
155 pool_->connecting_socket_map_.erase(handle_); 155 pool_->connecting_socket_map_.erase(handle_);
156 canceled_ = true; 156 canceled_ = true;
157 } 157 }
158 158
159 TCPClientSocketPool::TCPClientSocketPool( 159 TCPClientSocketPool::TCPClientSocketPool(
160 int max_sockets_per_group, 160 int max_sockets_per_group,
161 ClientSocketFactory* client_socket_factory) 161 ClientSocketFactory* client_socket_factory)
162 : client_socket_factory_(client_socket_factory), 162 : client_socket_factory_(client_socket_factory),
163 idle_socket_count_(0), 163 idle_socket_count_(0),
164 max_sockets_per_group_(max_sockets_per_group) { 164 max_sockets_per_group_(max_sockets_per_group) {
(...skipping 27 matching lines...) Expand all
192 ClientSocketHandle* handle, 192 ClientSocketHandle* handle,
193 CompletionCallback* callback) { 193 CompletionCallback* callback) {
194 DCHECK(!host.empty()); 194 DCHECK(!host.empty());
195 DCHECK_GE(priority, 0); 195 DCHECK_GE(priority, 0);
196 Group& group = group_map_[group_name]; 196 Group& group = group_map_[group_name];
197 197
198 // Can we make another active socket now? 198 // Can we make another active socket now?
199 if (group.active_socket_count == max_sockets_per_group_) { 199 if (group.active_socket_count == max_sockets_per_group_) {
200 Request r; 200 Request r;
201 r.handle = handle; 201 r.handle = handle;
202 DCHECK(callback); 202 CHECK(callback);
203 r.callback = callback; 203 r.callback = callback;
204 r.priority = priority; 204 r.priority = priority;
205 r.host = host; 205 r.host = host;
206 r.port = port; 206 r.port = port;
207 r.load_state = LOAD_STATE_IDLE; 207 r.load_state = LOAD_STATE_IDLE;
208 InsertRequestIntoQueue(r, &group.pending_requests); 208 InsertRequestIntoQueue(r, &group.pending_requests);
209 return ERR_IO_PENDING; 209 return ERR_IO_PENDING;
210 } 210 }
211 211
212 // OK, we are going to activate one. 212 // OK, we are going to activate one.
(...skipping 15 matching lines...) Expand all
228 // We couldn't find a socket to reuse, so allocate and connect a new one. 228 // We couldn't find a socket to reuse, so allocate and connect a new one.
229 229
230 // First, we need to make sure we aren't already servicing a request for this 230 // First, we need to make sure we aren't already servicing a request for this
231 // handle (which could happen if we requested, canceled, and then requested 231 // handle (which could happen if we requested, canceled, and then requested
232 // with the same handle). 232 // with the same handle).
233 if (ContainsKey(connecting_socket_map_, handle)) 233 if (ContainsKey(connecting_socket_map_, handle))
234 connecting_socket_map_[handle]->Cancel(); 234 connecting_socket_map_[handle]->Cancel();
235 235
236 Request r; 236 Request r;
237 r.handle = handle; 237 r.handle = handle;
238 DCHECK(callback); 238 CHECK(callback);
239 r.callback = callback; 239 r.callback = callback;
240 r.priority = priority; 240 r.priority = priority;
241 r.host = host; 241 r.host = host;
242 r.port = port; 242 r.port = port;
243 r.load_state = LOAD_STATE_RESOLVING_HOST; 243 r.load_state = LOAD_STATE_RESOLVING_HOST;
244 group_map_[group_name].connecting_requests[handle] = r; 244 group_map_[group_name].connecting_requests[handle] = r;
245 245
246 // connecting_socket will delete itself. 246 // connecting_socket will delete itself.
247 ConnectingSocket* connecting_socket = 247 ConnectingSocket* connecting_socket =
248 new ConnectingSocket(group_name, handle, client_socket_factory_, this); 248 new ConnectingSocket(group_name, handle, client_socket_factory_, this);
249 int rv = connecting_socket->Connect(host, port); 249 int rv = connecting_socket->Connect(host, port);
250 return rv; 250 return rv;
251 } 251 }
252 252
253 void TCPClientSocketPool::CancelRequest(const std::string& group_name, 253 void TCPClientSocketPool::CancelRequest(const std::string& group_name,
254 const ClientSocketHandle* handle) { 254 const ClientSocketHandle* handle) {
255 DCHECK(ContainsKey(group_map_, group_name)); 255 CHECK(ContainsKey(group_map_, group_name));
256 256
257 Group& group = group_map_[group_name]; 257 Group& group = group_map_[group_name];
258 258
259 // Search pending_requests for matching handle. 259 // Search pending_requests for matching handle.
260 RequestQueue::iterator it = group.pending_requests.begin(); 260 RequestQueue::iterator it = group.pending_requests.begin();
261 for (; it != group.pending_requests.end(); ++it) { 261 for (; it != group.pending_requests.end(); ++it) {
262 if (it->handle == handle) { 262 if (it->handle == handle) {
263 group.pending_requests.erase(it); 263 group.pending_requests.erase(it);
264 return; 264 return;
265 } 265 }
266 } 266 }
267 267
268 // It's invalid to cancel a non-existent request. 268 // It's invalid to cancel a non-existent request.
269 DCHECK(ContainsKey(group.connecting_requests, handle)); 269 CHECK(ContainsKey(group.connecting_requests, handle));
270 270
271 RequestMap::iterator map_it = group.connecting_requests.find(handle); 271 RequestMap::iterator map_it = group.connecting_requests.find(handle);
272 if (map_it != group.connecting_requests.end()) { 272 if (map_it != group.connecting_requests.end()) {
273 group.connecting_requests.erase(map_it); 273 group.connecting_requests.erase(map_it);
274 group.active_socket_count--; 274 group.active_socket_count--;
275 275
276 // Delete group if no longer needed. 276 // Delete group if no longer needed.
277 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 277 if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
278 DCHECK(group.pending_requests.empty()); 278 CHECK(group.pending_requests.empty());
279 DCHECK(group.connecting_requests.empty()); 279 CHECK(group.connecting_requests.empty());
280 group_map_.erase(group_name); 280 group_map_.erase(group_name);
281 } 281 }
282 } 282 }
283 } 283 }
284 284
285 void TCPClientSocketPool::ReleaseSocket(const std::string& group_name, 285 void TCPClientSocketPool::ReleaseSocket(const std::string& group_name,
286 ClientSocket* socket) { 286 ClientSocket* socket) {
287 // Run this asynchronously to allow the caller to finish before we let 287 // Run this asynchronously to allow the caller to finish before we let
288 // another to begin doing work. This also avoids nasty recursion issues. 288 // another to begin doing work. This also avoids nasty recursion issues.
289 // NOTE: We cannot refer to the handle argument after this method returns. 289 // NOTE: We cannot refer to the handle argument after this method returns.
290 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 290 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
291 this, &TCPClientSocketPool::DoReleaseSocket, group_name, socket)); 291 this, &TCPClientSocketPool::DoReleaseSocket, group_name, socket));
292 } 292 }
293 293
294 void TCPClientSocketPool::CloseIdleSockets() { 294 void TCPClientSocketPool::CloseIdleSockets() {
295 CleanupIdleSockets(true); 295 CleanupIdleSockets(true);
296 } 296 }
297 297
298 int TCPClientSocketPool::IdleSocketCountInGroup( 298 int TCPClientSocketPool::IdleSocketCountInGroup(
299 const std::string& group_name) const { 299 const std::string& group_name) const {
300 GroupMap::const_iterator i = group_map_.find(group_name); 300 GroupMap::const_iterator i = group_map_.find(group_name);
301 DCHECK(i != group_map_.end()); 301 CHECK(i != group_map_.end());
302 302
303 return i->second.idle_sockets.size(); 303 return i->second.idle_sockets.size();
304 } 304 }
305 305
306 LoadState TCPClientSocketPool::GetLoadState( 306 LoadState TCPClientSocketPool::GetLoadState(
307 const std::string& group_name, 307 const std::string& group_name,
308 const ClientSocketHandle* handle) const { 308 const ClientSocketHandle* handle) const {
309 DCHECK(ContainsKey(group_map_, group_name)) << group_name; 309 if (!ContainsKey(group_map_, group_name)) {
310 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name
wtc 2009/06/11 23:58:19 NOTREACHED is a DCHECK.
willchan no longer on Chromium 2009/06/12 00:23:54 i know it's a DCHECK. i want to keep it as a DCHE
311 << " for handle: " << handle;
312 return LOAD_STATE_IDLE;
313 }
310 314
311 // Can't use operator[] since it is non-const. 315 // Can't use operator[] since it is non-const.
312 const Group& group = group_map_.find(group_name)->second; 316 const Group& group = group_map_.find(group_name)->second;
313 317
314 // Search connecting_requests for matching handle. 318 // Search connecting_requests for matching handle.
315 RequestMap::const_iterator map_it = group.connecting_requests.find(handle); 319 RequestMap::const_iterator map_it = group.connecting_requests.find(handle);
316 if (map_it != group.connecting_requests.end()) { 320 if (map_it != group.connecting_requests.end()) {
317 const LoadState load_state = map_it->second.load_state; 321 const LoadState load_state = map_it->second.load_state;
318 DCHECK(load_state == LOAD_STATE_RESOLVING_HOST || 322 CHECK(load_state == LOAD_STATE_RESOLVING_HOST ||
319 load_state == LOAD_STATE_CONNECTING); 323 load_state == LOAD_STATE_CONNECTING);
320 return load_state; 324 return load_state;
321 } 325 }
322 326
323 // Search pending_requests for matching handle. 327 // Search pending_requests for matching handle.
324 RequestQueue::const_iterator it = group.pending_requests.begin(); 328 RequestQueue::const_iterator it = group.pending_requests.begin();
325 for (; it != group.pending_requests.end(); ++it) { 329 for (; it != group.pending_requests.end(); ++it) {
326 if (it->handle == handle) { 330 if (it->handle == handle) {
327 DCHECK_EQ(LOAD_STATE_IDLE, it->load_state); 331 CHECK(LOAD_STATE_IDLE == it->load_state);
328 // TODO(wtc): Add a state for being on the wait list. 332 // TODO(wtc): Add a state for being on the wait list.
329 // See http://www.crbug.com/5077. 333 // See http://www.crbug.com/5077.
330 return LOAD_STATE_IDLE; 334 return LOAD_STATE_IDLE;
331 } 335 }
332 } 336 }
333 337
334 NOTREACHED(); 338 NOTREACHED();
335 return LOAD_STATE_IDLE; 339 return LOAD_STATE_IDLE;
336 } 340 }
337 341
(...skipping 21 matching lines...) Expand all
359 delete j->socket; 363 delete j->socket;
360 j = group.idle_sockets.erase(j); 364 j = group.idle_sockets.erase(j);
361 DecrementIdleCount(); 365 DecrementIdleCount();
362 } else { 366 } else {
363 ++j; 367 ++j;
364 } 368 }
365 } 369 }
366 370
367 // Delete group if no longer needed. 371 // Delete group if no longer needed.
368 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 372 if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
369 DCHECK(group.pending_requests.empty()); 373 CHECK(group.pending_requests.empty());
370 DCHECK(group.connecting_requests.empty()); 374 CHECK(group.connecting_requests.empty());
371 group_map_.erase(i++); 375 group_map_.erase(i++);
372 } else { 376 } else {
373 ++i; 377 ++i;
374 } 378 }
375 } 379 }
376 } 380 }
377 381
378 void TCPClientSocketPool::IncrementIdleCount() { 382 void TCPClientSocketPool::IncrementIdleCount() {
379 if (++idle_socket_count_ == 1) 383 if (++idle_socket_count_ == 1)
380 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, 384 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
381 &TCPClientSocketPool::OnCleanupTimerFired); 385 &TCPClientSocketPool::OnCleanupTimerFired);
382 } 386 }
383 387
384 void TCPClientSocketPool::DecrementIdleCount() { 388 void TCPClientSocketPool::DecrementIdleCount() {
385 if (--idle_socket_count_ == 0) 389 if (--idle_socket_count_ == 0)
386 timer_.Stop(); 390 timer_.Stop();
387 } 391 }
388 392
389 void TCPClientSocketPool::DoReleaseSocket(const std::string& group_name, 393 void TCPClientSocketPool::DoReleaseSocket(const std::string& group_name,
390 ClientSocket* socket) { 394 ClientSocket* socket) {
391 GroupMap::iterator i = group_map_.find(group_name); 395 GroupMap::iterator i = group_map_.find(group_name);
392 DCHECK(i != group_map_.end()); 396 CHECK(i != group_map_.end());
393 397
394 Group& group = i->second; 398 Group& group = i->second;
395 399
396 DCHECK_GT(group.active_socket_count, 0); 400 CHECK(group.active_socket_count > 0);
397 group.active_socket_count--; 401 group.active_socket_count--;
398 402
399 const bool can_reuse = socket->IsConnectedAndIdle(); 403 const bool can_reuse = socket->IsConnectedAndIdle();
400 if (can_reuse) { 404 if (can_reuse) {
401 IdleSocket idle_socket; 405 IdleSocket idle_socket;
402 idle_socket.socket = socket; 406 idle_socket.socket = socket;
403 idle_socket.start_time = base::TimeTicks::Now(); 407 idle_socket.start_time = base::TimeTicks::Now();
404 408
405 group.idle_sockets.push_back(idle_socket); 409 group.idle_sockets.push_back(idle_socket);
406 IncrementIdleCount(); 410 IncrementIdleCount();
407 } else { 411 } else {
408 delete socket; 412 delete socket;
409 } 413 }
410 414
411 // Process one pending request. 415 // Process one pending request.
412 if (!group.pending_requests.empty()) { 416 if (!group.pending_requests.empty()) {
413 Request r = group.pending_requests.front(); 417 Request r = group.pending_requests.front();
414 group.pending_requests.pop_front(); 418 group.pending_requests.pop_front();
415 419
416 int rv = RequestSocket( 420 int rv = RequestSocket(
417 group_name, r.host, r.port, r.priority, r.handle, r.callback); 421 group_name, r.host, r.port, r.priority, r.handle, r.callback);
418 if (rv != ERR_IO_PENDING) 422 if (rv != ERR_IO_PENDING)
419 r.callback->Run(rv); 423 r.callback->Run(rv);
420 return; 424 return;
421 } 425 }
422 426
423 // Delete group if no longer needed. 427 // Delete group if no longer needed.
424 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 428 if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
425 DCHECK(group.pending_requests.empty()); 429 CHECK(group.pending_requests.empty());
426 DCHECK(group.connecting_requests.empty()); 430 CHECK(group.connecting_requests.empty());
427 group_map_.erase(i); 431 group_map_.erase(i);
428 } 432 }
429 } 433 }
430 434
431 } // namespace net 435 } // namespace net
OLDNEW
« no previous file with comments | « net/base/client_socket_handle.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698