Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/metrics/stats_counters.h" | 11 #include "base/metrics/stats_counters.h" |
| 12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
| 17 #include "net/base/net_log.h" | 17 #include "net/base/net_log.h" |
| 18 #include "net/socket/client_socket_handle.h" | |
| 19 | 18 |
| 20 using base::TimeDelta; | 19 using base::TimeDelta; |
| 21 | 20 |
| 22 namespace net { | 21 namespace net { |
| 23 | 22 |
| 24 namespace { | 23 namespace { |
| 25 | 24 |
| 26 // Indicate whether we should enable idle socket cleanup timer. When timer is | 25 // Indicate whether we should enable idle socket cleanup timer. When timer is |
| 27 // disabled, sockets are closed next time a socket request is made. | 26 // disabled, sockets are closed next time a socket request is made. |
| 28 bool g_cleanup_timer_enabled = true; | 27 bool g_cleanup_timer_enabled = true; |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 | 393 |
| 395 // We couldn't find a socket to reuse, and there's space to allocate one, | 394 // We couldn't find a socket to reuse, and there's space to allocate one, |
| 396 // so allocate and connect a new one. | 395 // so allocate and connect a new one. |
| 397 scoped_ptr<ConnectJob> connect_job( | 396 scoped_ptr<ConnectJob> connect_job( |
| 398 connect_job_factory_->NewConnectJob(group_name, request, this)); | 397 connect_job_factory_->NewConnectJob(group_name, request, this)); |
| 399 | 398 |
| 400 int rv = connect_job->Connect(); | 399 int rv = connect_job->Connect(); |
| 401 if (rv == OK) { | 400 if (rv == OK) { |
| 402 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); | 401 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); |
| 403 if (!preconnecting) { | 402 if (!preconnecting) { |
| 404 HandOutSocket(connect_job->PassSocket(), false /* not reused */, | 403 HandOutSocket(connect_job->PassSocket(), ClientSocketHandle::UNUSED, |
| 405 connect_job->connect_timing(), handle, base::TimeDelta(), | 404 connect_job->connect_timing(), handle, base::TimeDelta(), |
| 406 group, request.net_log()); | 405 group, request.net_log()); |
| 407 } else { | 406 } else { |
| 408 AddIdleSocket(connect_job->PassSocket(), group); | 407 AddIdleSocket(connect_job->PassSocket(), group); |
| 409 } | 408 } |
| 410 } else if (rv == ERR_IO_PENDING) { | 409 } else if (rv == ERR_IO_PENDING) { |
| 411 // If we don't have any sockets in this group, set a timer for potentially | 410 // If we don't have any sockets in this group, set a timer for potentially |
| 412 // creating a new one. If the SYN is lost, this backup socket may complete | 411 // creating a new one. If the SYN is lost, this backup socket may complete |
| 413 // before the slow socket, improving end user latency. | 412 // before the slow socket, improving end user latency. |
| 414 if (connect_backup_jobs_enabled_ && group->IsEmpty()) { | 413 if (connect_backup_jobs_enabled_ && group->IsEmpty()) { |
| 415 group->StartBackupJobTimer(group_name, this); | 414 group->StartBackupJobTimer(group_name, this); |
| 416 } | 415 } |
| 417 | 416 |
| 418 connecting_socket_count_++; | 417 connecting_socket_count_++; |
| 419 | 418 |
| 420 group->AddJob(connect_job.Pass(), preconnecting); | 419 group->AddJob(connect_job.Pass(), preconnecting); |
| 421 } else { | 420 } else { |
| 422 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); | 421 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); |
| 423 scoped_ptr<StreamSocket> error_socket; | 422 scoped_ptr<StreamSocket> error_socket; |
| 424 if (!preconnecting) { | 423 if (!preconnecting) { |
| 425 DCHECK(handle); | 424 DCHECK(handle); |
| 426 connect_job->GetAdditionalErrorState(handle); | 425 connect_job->GetAdditionalErrorState(handle); |
| 427 error_socket = connect_job->PassSocket(); | 426 error_socket = connect_job->PassSocket(); |
| 428 } | 427 } |
| 429 if (error_socket) { | 428 if (error_socket) { |
| 430 HandOutSocket(error_socket.Pass(), false /* not reused */, | 429 HandOutSocket(error_socket.Pass(), ClientSocketHandle::UNUSED, |
| 431 connect_job->connect_timing(), handle, base::TimeDelta(), | 430 connect_job->connect_timing(), handle, base::TimeDelta(), |
| 432 group, request.net_log()); | 431 group, request.net_log()); |
| 433 } else if (group->IsEmpty()) { | 432 } else if (group->IsEmpty()) { |
| 434 RemoveGroup(group_name); | 433 RemoveGroup(group_name); |
| 435 } | 434 } |
| 436 } | 435 } |
| 437 | 436 |
| 438 return rv; | 437 return rv; |
| 439 } | 438 } |
| 440 | 439 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 469 | 468 |
| 470 if (idle_socket_it == idle_sockets->end() && !idle_sockets->empty()) | 469 if (idle_socket_it == idle_sockets->end() && !idle_sockets->empty()) |
| 471 idle_socket_it = idle_sockets->begin(); | 470 idle_socket_it = idle_sockets->begin(); |
| 472 | 471 |
| 473 if (idle_socket_it != idle_sockets->end()) { | 472 if (idle_socket_it != idle_sockets->end()) { |
| 474 DecrementIdleCount(); | 473 DecrementIdleCount(); |
| 475 base::TimeDelta idle_time = | 474 base::TimeDelta idle_time = |
| 476 base::TimeTicks::Now() - idle_socket_it->start_time; | 475 base::TimeTicks::Now() - idle_socket_it->start_time; |
| 477 IdleSocket idle_socket = *idle_socket_it; | 476 IdleSocket idle_socket = *idle_socket_it; |
| 478 idle_sockets->erase(idle_socket_it); | 477 idle_sockets->erase(idle_socket_it); |
| 478 // TODO(davidben): If |idle_time| is under some low watermark, consider | |
| 479 // treating as UNUSED rather than UNUSED_IDLE. This will avoid | |
| 480 // HttpNetworkTransaction retrying on some errors. | |
| 481 ClientSocketHandle::SocketReuseType reuse_type = | |
| 482 idle_socket.socket->WasEverUsed() ? | |
| 483 ClientSocketHandle::REUSED_IDLE : | |
| 484 ClientSocketHandle::UNUSED_IDLE; | |
|
mmenke
2014/03/18 14:29:17
optional: May be easier to read if the last two l
davidben
2014/03/18 15:08:12
Done.
| |
| 479 HandOutSocket( | 485 HandOutSocket( |
| 480 scoped_ptr<StreamSocket>(idle_socket.socket), | 486 scoped_ptr<StreamSocket>(idle_socket.socket), |
| 481 idle_socket.socket->WasEverUsed(), | 487 reuse_type, |
| 482 LoadTimingInfo::ConnectTiming(), | 488 LoadTimingInfo::ConnectTiming(), |
| 483 request.handle(), | 489 request.handle(), |
| 484 idle_time, | 490 idle_time, |
| 485 group, | 491 group, |
| 486 request.net_log()); | 492 request.net_log()); |
| 487 return true; | 493 return true; |
| 488 } | 494 } |
| 489 | 495 |
| 490 return false; | 496 return false; |
| 491 } | 497 } |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 871 // RemoveConnectJob(job, _) must be called by all branches below; | 877 // RemoveConnectJob(job, _) must be called by all branches below; |
| 872 // otherwise, |job| will be leaked. | 878 // otherwise, |job| will be leaked. |
| 873 | 879 |
| 874 if (result == OK) { | 880 if (result == OK) { |
| 875 DCHECK(socket.get()); | 881 DCHECK(socket.get()); |
| 876 RemoveConnectJob(job, group); | 882 RemoveConnectJob(job, group); |
| 877 scoped_ptr<const Request> request = group->PopNextPendingRequest(); | 883 scoped_ptr<const Request> request = group->PopNextPendingRequest(); |
| 878 if (request) { | 884 if (request) { |
| 879 LogBoundConnectJobToRequest(job_log.source(), *request); | 885 LogBoundConnectJobToRequest(job_log.source(), *request); |
| 880 HandOutSocket( | 886 HandOutSocket( |
| 881 socket.Pass(), false /* unused socket */, connect_timing, | 887 socket.Pass(), ClientSocketHandle::UNUSED, connect_timing, |
| 882 request->handle(), base::TimeDelta(), group, request->net_log()); | 888 request->handle(), base::TimeDelta(), group, request->net_log()); |
| 883 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL); | 889 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL); |
| 884 InvokeUserCallbackLater(request->handle(), request->callback(), result); | 890 InvokeUserCallbackLater(request->handle(), request->callback(), result); |
| 885 } else { | 891 } else { |
| 886 AddIdleSocket(socket.Pass(), group); | 892 AddIdleSocket(socket.Pass(), group); |
| 887 OnAvailableSocketSlot(group_name, group); | 893 OnAvailableSocketSlot(group_name, group); |
| 888 CheckForStalledSocketGroups(); | 894 CheckForStalledSocketGroups(); |
| 889 } | 895 } |
| 890 } else { | 896 } else { |
| 891 // If we got a socket, it must contain error information so pass that | 897 // If we got a socket, it must contain error information so pass that |
| 892 // up so that the caller can retrieve it. | 898 // up so that the caller can retrieve it. |
| 893 bool handed_out_socket = false; | 899 bool handed_out_socket = false; |
| 894 scoped_ptr<const Request> request = group->PopNextPendingRequest(); | 900 scoped_ptr<const Request> request = group->PopNextPendingRequest(); |
| 895 if (request) { | 901 if (request) { |
| 896 LogBoundConnectJobToRequest(job_log.source(), *request); | 902 LogBoundConnectJobToRequest(job_log.source(), *request); |
| 897 job->GetAdditionalErrorState(request->handle()); | 903 job->GetAdditionalErrorState(request->handle()); |
| 898 RemoveConnectJob(job, group); | 904 RemoveConnectJob(job, group); |
| 899 if (socket.get()) { | 905 if (socket.get()) { |
| 900 handed_out_socket = true; | 906 handed_out_socket = true; |
| 901 HandOutSocket(socket.Pass(), false /* unused socket */, | 907 HandOutSocket(socket.Pass(), ClientSocketHandle::UNUSED, |
| 902 connect_timing, request->handle(), base::TimeDelta(), | 908 connect_timing, request->handle(), base::TimeDelta(), |
| 903 group, request->net_log()); | 909 group, request->net_log()); |
| 904 } | 910 } |
| 905 request->net_log().EndEventWithNetErrorCode( | 911 request->net_log().EndEventWithNetErrorCode( |
| 906 NetLog::TYPE_SOCKET_POOL, result); | 912 NetLog::TYPE_SOCKET_POOL, result); |
| 907 InvokeUserCallbackLater(request->handle(), request->callback(), result); | 913 InvokeUserCallbackLater(request->handle(), request->callback(), result); |
| 908 } else { | 914 } else { |
| 909 RemoveConnectJob(job, group); | 915 RemoveConnectJob(job, group); |
| 910 } | 916 } |
| 911 if (!handed_out_socket) { | 917 if (!handed_out_socket) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 956 if (group->IsEmpty()) | 962 if (group->IsEmpty()) |
| 957 RemoveGroup(group_name); | 963 RemoveGroup(group_name); |
| 958 | 964 |
| 959 request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv); | 965 request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv); |
| 960 InvokeUserCallbackLater(request->handle(), request->callback(), rv); | 966 InvokeUserCallbackLater(request->handle(), request->callback(), rv); |
| 961 } | 967 } |
| 962 } | 968 } |
| 963 | 969 |
| 964 void ClientSocketPoolBaseHelper::HandOutSocket( | 970 void ClientSocketPoolBaseHelper::HandOutSocket( |
| 965 scoped_ptr<StreamSocket> socket, | 971 scoped_ptr<StreamSocket> socket, |
| 966 bool reused, | 972 ClientSocketHandle::SocketReuseType reuse_type, |
| 967 const LoadTimingInfo::ConnectTiming& connect_timing, | 973 const LoadTimingInfo::ConnectTiming& connect_timing, |
| 968 ClientSocketHandle* handle, | 974 ClientSocketHandle* handle, |
| 969 base::TimeDelta idle_time, | 975 base::TimeDelta idle_time, |
| 970 Group* group, | 976 Group* group, |
| 971 const BoundNetLog& net_log) { | 977 const BoundNetLog& net_log) { |
| 972 DCHECK(socket); | 978 DCHECK(socket); |
| 973 handle->SetSocket(socket.Pass()); | 979 handle->SetSocket(socket.Pass()); |
| 974 handle->set_is_reused(reused); | 980 handle->set_reuse_type(reuse_type); |
| 975 handle->set_idle_time(idle_time); | 981 handle->set_idle_time(idle_time); |
| 976 handle->set_pool_id(pool_generation_number_); | 982 handle->set_pool_id(pool_generation_number_); |
| 977 handle->set_connect_timing(connect_timing); | 983 handle->set_connect_timing(connect_timing); |
| 978 | 984 |
| 979 if (reused) { | 985 if (handle->is_reused()) { |
| 980 net_log.AddEvent( | 986 net_log.AddEvent( |
| 981 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, | 987 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, |
| 982 NetLog::IntegerCallback( | 988 NetLog::IntegerCallback( |
| 983 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); | 989 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); |
| 984 } | 990 } |
| 985 | 991 |
| 986 net_log.AddEvent( | 992 net_log.AddEvent( |
| 987 NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, | 993 NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, |
| 988 handle->socket()->NetLog().source().ToEventParametersCallback()); | 994 handle->socket()->NetLog().source().ToEventParametersCallback()); |
| 989 | 995 |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1312 pending_requests_.Erase(pointer); | 1318 pending_requests_.Erase(pointer); |
| 1313 // If there are no more requests, kill the backup timer. | 1319 // If there are no more requests, kill the backup timer. |
| 1314 if (pending_requests_.empty()) | 1320 if (pending_requests_.empty()) |
| 1315 backup_job_timer_.Stop(); | 1321 backup_job_timer_.Stop(); |
| 1316 return request.Pass(); | 1322 return request.Pass(); |
| 1317 } | 1323 } |
| 1318 | 1324 |
| 1319 } // namespace internal | 1325 } // namespace internal |
| 1320 | 1326 |
| 1321 } // namespace net | 1327 } // namespace net |
| OLD | NEW |