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; |
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 |