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 |