| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/socket/client_socket_pool_base.h" | 5 #include "net/socket/client_socket_pool_base.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/format_macros.h" | 8 #include "base/format_macros.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/stats_counters.h" | 10 #include "base/stats_counters.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 base::TimeDelta timeout_duration, | 35 base::TimeDelta timeout_duration, |
| 36 Delegate* delegate, | 36 Delegate* delegate, |
| 37 const BoundNetLog& net_log) | 37 const BoundNetLog& net_log) |
| 38 : group_name_(group_name), | 38 : group_name_(group_name), |
| 39 timeout_duration_(timeout_duration), | 39 timeout_duration_(timeout_duration), |
| 40 delegate_(delegate), | 40 delegate_(delegate), |
| 41 net_log_(net_log), | 41 net_log_(net_log), |
| 42 idle_(true) { | 42 idle_(true) { |
| 43 DCHECK(!group_name.empty()); | 43 DCHECK(!group_name.empty()); |
| 44 DCHECK(delegate); | 44 DCHECK(delegate); |
| 45 net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL); |
| 45 } | 46 } |
| 46 | 47 |
| 47 ConnectJob::~ConnectJob() { | 48 ConnectJob::~ConnectJob() { |
| 48 if (delegate_ && !idle_) { | 49 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL); |
| 49 // If the delegate was not NULLed, then NotifyDelegateOfCompletion has | |
| 50 // not been called yet. If we've started then we are cancelling. | |
| 51 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); | |
| 52 net_log_.EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL); | |
| 53 } | |
| 54 } | 50 } |
| 55 | 51 |
| 56 int ConnectJob::Connect() { | 52 int ConnectJob::Connect() { |
| 57 if (timeout_duration_ != base::TimeDelta()) | 53 if (timeout_duration_ != base::TimeDelta()) |
| 58 timer_.Start(timeout_duration_, this, &ConnectJob::OnTimeout); | 54 timer_.Start(timeout_duration_, this, &ConnectJob::OnTimeout); |
| 59 | 55 |
| 60 net_log_.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, | |
| 61 new NetLogStringParameter("group_name", group_name_)); | |
| 62 idle_ = false; | 56 idle_ = false; |
| 63 | 57 |
| 58 LogConnectStart(); |
| 59 |
| 64 int rv = ConnectInternal(); | 60 int rv = ConnectInternal(); |
| 65 | 61 |
| 66 if (rv != ERR_IO_PENDING) { | 62 if (rv != ERR_IO_PENDING) { |
| 63 LogConnectCompletion(rv); |
| 67 delegate_ = NULL; | 64 delegate_ = NULL; |
| 68 net_log_.EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL); | |
| 69 } | 65 } |
| 70 | 66 |
| 71 return rv; | 67 return rv; |
| 72 } | 68 } |
| 73 | 69 |
| 70 void ConnectJob::set_socket(ClientSocket* socket) { |
| 71 if (socket) { |
| 72 net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET, |
| 73 new NetLogSourceParameter("source_dependency", |
| 74 socket->NetLog().source())); |
| 75 } |
| 76 socket_.reset(socket); |
| 77 } |
| 78 |
| 74 void ConnectJob::NotifyDelegateOfCompletion(int rv) { | 79 void ConnectJob::NotifyDelegateOfCompletion(int rv) { |
| 75 // The delegate will delete |this|. | 80 // The delegate will delete |this|. |
| 76 Delegate *delegate = delegate_; | 81 Delegate *delegate = delegate_; |
| 77 delegate_ = NULL; | 82 delegate_ = NULL; |
| 78 | 83 |
| 79 net_log_.EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL); | 84 LogConnectCompletion(rv); |
| 80 | |
| 81 delegate->OnConnectJobComplete(rv, this); | 85 delegate->OnConnectJobComplete(rv, this); |
| 82 } | 86 } |
| 83 | 87 |
| 84 void ConnectJob::ResetTimer(base::TimeDelta remaining_time) { | 88 void ConnectJob::ResetTimer(base::TimeDelta remaining_time) { |
| 85 timer_.Stop(); | 89 timer_.Stop(); |
| 86 timer_.Start(remaining_time, this, &ConnectJob::OnTimeout); | 90 timer_.Start(remaining_time, this, &ConnectJob::OnTimeout); |
| 87 } | 91 } |
| 88 | 92 |
| 93 void ConnectJob::LogConnectStart() { |
| 94 net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, |
| 95 new NetLogStringParameter("group_name", group_name_)); |
| 96 } |
| 97 |
| 98 void ConnectJob::LogConnectCompletion(int net_error) { |
| 99 scoped_refptr<NetLog::EventParameters> params; |
| 100 if (net_error != OK) |
| 101 params = new NetLogIntegerParameter("net_error", net_error); |
| 102 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, params); |
| 103 } |
| 104 |
| 89 void ConnectJob::OnTimeout() { | 105 void ConnectJob::OnTimeout() { |
| 90 // Make sure the socket is NULL before calling into |delegate|. | 106 // Make sure the socket is NULL before calling into |delegate|. |
| 91 set_socket(NULL); | 107 set_socket(NULL); |
| 92 | 108 |
| 93 net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT, NULL); | 109 net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT, NULL); |
| 94 | 110 |
| 95 NotifyDelegateOfCompletion(ERR_TIMED_OUT); | 111 NotifyDelegateOfCompletion(ERR_TIMED_OUT); |
| 96 } | 112 } |
| 97 | 113 |
| 98 namespace internal { | 114 namespace internal { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 delete idle_socket.socket; | 245 delete idle_socket.socket; |
| 230 } | 246 } |
| 231 | 247 |
| 232 // See if we already have enough connect jobs or sockets that will be released | 248 // See if we already have enough connect jobs or sockets that will be released |
| 233 // soon. | 249 // soon. |
| 234 if (group.HasReleasingSockets()) { | 250 if (group.HasReleasingSockets()) { |
| 235 return ERR_IO_PENDING; | 251 return ERR_IO_PENDING; |
| 236 } | 252 } |
| 237 | 253 |
| 238 // We couldn't find a socket to reuse, so allocate and connect a new one. | 254 // We couldn't find a socket to reuse, so allocate and connect a new one. |
| 239 BoundNetLog job_net_log = BoundNetLog::Make( | |
| 240 request->net_log().net_log(), NetLog::SOURCE_CONNECT_JOB); | |
| 241 request->net_log().BeginEvent( | |
| 242 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID, | |
| 243 new NetLogIntegerParameter("source_id", job_net_log.source().id)); | |
| 244 | |
| 245 scoped_ptr<ConnectJob> connect_job( | 255 scoped_ptr<ConnectJob> connect_job( |
| 246 connect_job_factory_->NewConnectJob(group_name, *request, this, | 256 connect_job_factory_->NewConnectJob(group_name, *request, this)); |
| 247 job_net_log)); | |
| 248 | 257 |
| 249 int rv = connect_job->Connect(); | 258 int rv = connect_job->Connect(); |
| 250 if (rv == OK) { | 259 if (rv == OK) { |
| 251 request->net_log().EndEvent( | 260 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); |
| 252 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID, | |
| 253 new NetLogIntegerParameter("source_id", job_net_log.source().id)); | |
| 254 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */, | 261 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */, |
| 255 handle, base::TimeDelta(), &group, request->net_log()); | 262 handle, base::TimeDelta(), &group, request->net_log()); |
| 256 } else if (rv == ERR_IO_PENDING) { | 263 } else if (rv == ERR_IO_PENDING) { |
| 257 // If we don't have any sockets in this group, set a timer for potentially | 264 // If we don't have any sockets in this group, set a timer for potentially |
| 258 // creating a new one. If the SYN is lost, this backup socket may complete | 265 // creating a new one. If the SYN is lost, this backup socket may complete |
| 259 // before the slow socket, improving end user latency. | 266 // before the slow socket, improving end user latency. |
| 260 if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) { | 267 if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) { |
| 261 group.backup_job = connect_job_factory_->NewConnectJob(group_name, | 268 group.backup_job = connect_job_factory_->NewConnectJob(group_name, |
| 262 *request, | 269 *request, |
| 263 this, | 270 this); |
| 264 job_net_log); | |
| 265 StartBackupSocketTimer(group_name); | 271 StartBackupSocketTimer(group_name); |
| 266 } | 272 } |
| 267 | 273 |
| 268 connecting_socket_count_++; | 274 connecting_socket_count_++; |
| 269 | 275 |
| 270 ConnectJob* job = connect_job.release(); | 276 ConnectJob* job = connect_job.release(); |
| 271 group.jobs.insert(job); | 277 group.jobs.insert(job); |
| 272 } else { | 278 } else { |
| 273 request->net_log().EndEvent( | 279 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); |
| 274 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID, | |
| 275 new NetLogIntegerParameter("source_id", job_net_log.source().id)); | |
| 276 if (group.IsEmpty()) | 280 if (group.IsEmpty()) |
| 277 group_map_.erase(group_name); | 281 group_map_.erase(group_name); |
| 278 } | 282 } |
| 279 | 283 |
| 280 return rv; | 284 return rv; |
| 281 } | 285 } |
| 282 | 286 |
| 287 // static |
| 288 void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest( |
| 289 const NetLog::Source& connect_job_source, const Request* request) { |
| 290 request->net_log().AddEvent( |
| 291 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB, |
| 292 new NetLogSourceParameter("source_dependency", connect_job_source)); |
| 293 } |
| 294 |
| 283 void ClientSocketPoolBaseHelper::StartBackupSocketTimer( | 295 void ClientSocketPoolBaseHelper::StartBackupSocketTimer( |
| 284 const std::string& group_name) { | 296 const std::string& group_name) { |
| 285 CHECK(ContainsKey(group_map_, group_name)); | 297 CHECK(ContainsKey(group_map_, group_name)); |
| 286 Group& group = group_map_[group_name]; | 298 Group& group = group_map_[group_name]; |
| 287 | 299 |
| 288 // Only allow one timer pending to create a backup socket. | 300 // Only allow one timer pending to create a backup socket. |
| 289 if (group.backup_task) | 301 if (group.backup_task) |
| 290 return; | 302 return; |
| 291 | 303 |
| 292 group.backup_task = method_factory_.NewRunnableMethod( | 304 group.backup_task = method_factory_.NewRunnableMethod( |
| (...skipping 12 matching lines...) Expand all Loading... |
| 305 group.backup_task = NULL; | 317 group.backup_task = NULL; |
| 306 | 318 |
| 307 CHECK(group.backup_job); | 319 CHECK(group.backup_job); |
| 308 | 320 |
| 309 // If our backup job is waiting on DNS, or if we can't create any sockets | 321 // If our backup job is waiting on DNS, or if we can't create any sockets |
| 310 // right now due to limits, just reset the timer. | 322 // right now due to limits, just reset the timer. |
| 311 CHECK(group.jobs.size()); | 323 CHECK(group.jobs.size()); |
| 312 if (ReachedMaxSocketsLimit() || | 324 if (ReachedMaxSocketsLimit() || |
| 313 !group.HasAvailableSocketSlot(max_sockets_per_group_) || | 325 !group.HasAvailableSocketSlot(max_sockets_per_group_) || |
| 314 (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) { | 326 (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) { |
| 315 group.backup_job->net_log().AddEvent( | |
| 316 NetLog::TYPE_SOCKET_BACKUP_TIMER_EXTENDED, NULL); | |
| 317 StartBackupSocketTimer(group_name); | 327 StartBackupSocketTimer(group_name); |
| 318 return; | 328 return; |
| 319 } | 329 } |
| 320 | 330 |
| 321 group.backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, | 331 group.backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, |
| 322 NULL); | 332 NULL); |
| 323 SIMPLE_STATS_COUNTER("socket.backup_created"); | 333 SIMPLE_STATS_COUNTER("socket.backup_created"); |
| 324 int rv = group.backup_job->Connect(); | 334 int rv = group.backup_job->Connect(); |
| 325 connecting_socket_count_++; | 335 connecting_socket_count_++; |
| 326 group.jobs.insert(group.backup_job); | 336 group.jobs.insert(group.backup_job); |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 scoped_ptr<ClientSocket> socket(job->ReleaseSocket()); | 586 scoped_ptr<ClientSocket> socket(job->ReleaseSocket()); |
| 577 | 587 |
| 578 BoundNetLog job_log = job->net_log(); | 588 BoundNetLog job_log = job->net_log(); |
| 579 RemoveConnectJob(job, &group); | 589 RemoveConnectJob(job, &group); |
| 580 | 590 |
| 581 if (result == OK) { | 591 if (result == OK) { |
| 582 DCHECK(socket.get()); | 592 DCHECK(socket.get()); |
| 583 if (!group.pending_requests.empty()) { | 593 if (!group.pending_requests.empty()) { |
| 584 scoped_ptr<const Request> r(RemoveRequestFromQueue( | 594 scoped_ptr<const Request> r(RemoveRequestFromQueue( |
| 585 group.pending_requests.begin(), &group.pending_requests)); | 595 group.pending_requests.begin(), &group.pending_requests)); |
| 586 r->net_log().EndEvent( | 596 LogBoundConnectJobToRequest(job_log.source(), r.get()); |
| 587 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID, | |
| 588 new NetLogIntegerParameter("source_id", job_log.source().id)); | |
| 589 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); | |
| 590 HandOutSocket( | 597 HandOutSocket( |
| 591 socket.release(), false /* unused socket */, r->handle(), | 598 socket.release(), false /* unused socket */, r->handle(), |
| 592 base::TimeDelta(), &group, r->net_log()); | 599 base::TimeDelta(), &group, r->net_log()); |
| 600 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); |
| 593 r->callback()->Run(result); | 601 r->callback()->Run(result); |
| 594 } else { | 602 } else { |
| 595 AddIdleSocket(socket.release(), false /* unused socket */, &group); | 603 AddIdleSocket(socket.release(), false /* unused socket */, &group); |
| 596 OnAvailableSocketSlot(group_name, &group); | 604 OnAvailableSocketSlot(group_name, &group); |
| 597 } | 605 } |
| 598 } else { | 606 } else { |
| 599 DCHECK(!socket.get()); | 607 DCHECK(!socket.get()); |
| 600 if (!group.pending_requests.empty()) { | 608 if (!group.pending_requests.empty()) { |
| 601 scoped_ptr<const Request> r(RemoveRequestFromQueue( | 609 scoped_ptr<const Request> r(RemoveRequestFromQueue( |
| 602 group.pending_requests.begin(), &group.pending_requests)); | 610 group.pending_requests.begin(), &group.pending_requests)); |
| 603 r->net_log().EndEvent( | 611 LogBoundConnectJobToRequest(job_log.source(), r.get()); |
| 604 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID, | 612 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, |
| 605 new NetLogIntegerParameter("source_id", job_log.source().id)); | 613 new NetLogIntegerParameter("net_error", result)); |
| 606 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); | |
| 607 r->callback()->Run(result); | 614 r->callback()->Run(result); |
| 608 } | 615 } |
| 609 MaybeOnAvailableSocketSlot(group_name); | 616 MaybeOnAvailableSocketSlot(group_name); |
| 610 } | 617 } |
| 611 } | 618 } |
| 612 | 619 |
| 613 void ClientSocketPoolBaseHelper::OnIPAddressChanged() { | 620 void ClientSocketPoolBaseHelper::OnIPAddressChanged() { |
| 614 CloseIdleSockets(); | 621 CloseIdleSockets(); |
| 615 } | 622 } |
| 616 | 623 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 } | 667 } |
| 661 } | 668 } |
| 662 | 669 |
| 663 void ClientSocketPoolBaseHelper::ProcessPendingRequest( | 670 void ClientSocketPoolBaseHelper::ProcessPendingRequest( |
| 664 const std::string& group_name, Group* group) { | 671 const std::string& group_name, Group* group) { |
| 665 int rv = RequestSocketInternal(group_name, *group->pending_requests.begin()); | 672 int rv = RequestSocketInternal(group_name, *group->pending_requests.begin()); |
| 666 | 673 |
| 667 if (rv != ERR_IO_PENDING) { | 674 if (rv != ERR_IO_PENDING) { |
| 668 scoped_ptr<const Request> r(RemoveRequestFromQueue( | 675 scoped_ptr<const Request> r(RemoveRequestFromQueue( |
| 669 group->pending_requests.begin(), &group->pending_requests)); | 676 group->pending_requests.begin(), &group->pending_requests)); |
| 670 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); | 677 |
| 678 scoped_refptr<NetLog::EventParameters> params; |
| 679 if (rv != OK) |
| 680 params = new NetLogIntegerParameter("net_error", rv); |
| 681 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, params); |
| 671 r->callback()->Run(rv); | 682 r->callback()->Run(rv); |
| 672 if (rv != OK) { | 683 if (rv != OK) { |
| 673 // |group| may be invalid after the callback, we need to search | 684 // |group| may be invalid after the callback, we need to search |
| 674 // |group_map_| again. | 685 // |group_map_| again. |
| 675 MaybeOnAvailableSocketSlot(group_name); | 686 MaybeOnAvailableSocketSlot(group_name); |
| 676 } | 687 } |
| 677 } | 688 } |
| 678 } | 689 } |
| 679 | 690 |
| 680 void ClientSocketPoolBaseHelper::HandOutSocket( | 691 void ClientSocketPoolBaseHelper::HandOutSocket( |
| 681 ClientSocket* socket, | 692 ClientSocket* socket, |
| 682 bool reused, | 693 bool reused, |
| 683 ClientSocketHandle* handle, | 694 ClientSocketHandle* handle, |
| 684 base::TimeDelta idle_time, | 695 base::TimeDelta idle_time, |
| 685 Group* group, | 696 Group* group, |
| 686 const BoundNetLog& net_log) { | 697 const BoundNetLog& net_log) { |
| 687 DCHECK(socket); | 698 DCHECK(socket); |
| 688 handle->set_socket(socket); | 699 handle->set_socket(socket); |
| 689 handle->set_is_reused(reused); | 700 handle->set_is_reused(reused); |
| 690 handle->set_idle_time(idle_time); | 701 handle->set_idle_time(idle_time); |
| 691 | 702 |
| 692 if (reused) { | 703 if (reused) { |
| 693 net_log.AddEvent( | 704 net_log.AddEvent( |
| 694 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, | 705 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, |
| 695 new NetLogIntegerParameter( | 706 new NetLogIntegerParameter( |
| 696 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); | 707 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); |
| 697 } | 708 } |
| 698 | 709 |
| 699 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_SOCKET_ID, | 710 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, |
| 700 new NetLogIntegerParameter( | 711 new NetLogSourceParameter( |
| 701 "source_id", socket->NetLog().source().id)); | 712 "source_dependency", socket->NetLog().source())); |
| 702 | 713 |
| 703 handed_out_socket_count_++; | 714 handed_out_socket_count_++; |
| 704 group->active_socket_count++; | 715 group->active_socket_count++; |
| 705 } | 716 } |
| 706 | 717 |
| 707 void ClientSocketPoolBaseHelper::AddIdleSocket( | 718 void ClientSocketPoolBaseHelper::AddIdleSocket( |
| 708 ClientSocket* socket, bool used, Group* group) { | 719 ClientSocket* socket, bool used, Group* group) { |
| 709 DCHECK(socket); | 720 DCHECK(socket); |
| 710 IdleSocket idle_socket; | 721 IdleSocket idle_socket; |
| 711 idle_socket.socket = socket; | 722 idle_socket.socket = socket; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 742 DCHECK_LE(total, max_sockets_); | 753 DCHECK_LE(total, max_sockets_); |
| 743 if (total < max_sockets_) | 754 if (total < max_sockets_) |
| 744 return false; | 755 return false; |
| 745 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; | 756 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; |
| 746 return true; | 757 return true; |
| 747 } | 758 } |
| 748 | 759 |
| 749 } // namespace internal | 760 } // namespace internal |
| 750 | 761 |
| 751 } // namespace net | 762 } // namespace net |
| OLD | NEW |