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/dns/host_resolver_impl.h" | 5 #include "net/dns/host_resolver_impl.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <Winsock2.h> | 8 #include <Winsock2.h> |
9 #elif defined(OS_POSIX) | 9 #elif defined(OS_POSIX) |
10 #include <netdb.h> | 10 #include <netdb.h> |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 | 62 |
63 // Default TTL for successful resolutions with ProcTask. | 63 // Default TTL for successful resolutions with ProcTask. |
64 const unsigned kCacheEntryTTLSeconds = 60; | 64 const unsigned kCacheEntryTTLSeconds = 60; |
65 | 65 |
66 // Default TTL for unsuccessful resolutions with ProcTask. | 66 // Default TTL for unsuccessful resolutions with ProcTask. |
67 const unsigned kNegativeCacheEntryTTLSeconds = 0; | 67 const unsigned kNegativeCacheEntryTTLSeconds = 0; |
68 | 68 |
69 // Minimum TTL for successful resolutions with DnsTask. | 69 // Minimum TTL for successful resolutions with DnsTask. |
70 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds; | 70 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds; |
71 | 71 |
72 // Number of consecutive failures of DnsTask (with successful fallback) before | |
73 // the DnsClient is disabled until the next DNS change. | |
74 const unsigned kMaximumDnsFailures = 16; | |
75 | |
76 // We use a separate histogram name for each platform to facilitate the | 72 // We use a separate histogram name for each platform to facilitate the |
77 // display of error codes by their symbolic name (since each platform has | 73 // display of error codes by their symbolic name (since each platform has |
78 // different mappings). | 74 // different mappings). |
79 const char kOSErrorsForGetAddrinfoHistogramName[] = | 75 const char kOSErrorsForGetAddrinfoHistogramName[] = |
80 #if defined(OS_WIN) | 76 #if defined(OS_WIN) |
81 "Net.OSErrorsForGetAddrinfo_Win"; | 77 "Net.OSErrorsForGetAddrinfo_Win"; |
82 #elif defined(OS_MACOSX) | 78 #elif defined(OS_MACOSX) |
83 "Net.OSErrorsForGetAddrinfo_Mac"; | 79 "Net.OSErrorsForGetAddrinfo_Mac"; |
84 #elif defined(OS_LINUX) | 80 #elif defined(OS_LINUX) |
85 "Net.OSErrorsForGetAddrinfo_Linux"; | 81 "Net.OSErrorsForGetAddrinfo_Linux"; |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 private: | 445 private: |
450 RequestPriority highest_priority_; | 446 RequestPriority highest_priority_; |
451 size_t total_count_; | 447 size_t total_count_; |
452 size_t counts_[NUM_PRIORITIES]; | 448 size_t counts_[NUM_PRIORITIES]; |
453 }; | 449 }; |
454 | 450 |
455 } // namespace | 451 } // namespace |
456 | 452 |
457 //----------------------------------------------------------------------------- | 453 //----------------------------------------------------------------------------- |
458 | 454 |
| 455 const unsigned HostResolverImpl::kMaximumDnsFailures = 16; |
| 456 |
459 // Holds the data for a request that could not be completed synchronously. | 457 // Holds the data for a request that could not be completed synchronously. |
460 // It is owned by a Job. Canceled Requests are only marked as canceled rather | 458 // It is owned by a Job. Canceled Requests are only marked as canceled rather |
461 // than removed from the Job's |requests_| list. | 459 // than removed from the Job's |requests_| list. |
462 class HostResolverImpl::Request { | 460 class HostResolverImpl::Request { |
463 public: | 461 public: |
464 Request(const BoundNetLog& source_net_log, | 462 Request(const BoundNetLog& source_net_log, |
465 const BoundNetLog& request_net_log, | 463 const BoundNetLog& request_net_log, |
466 const RequestInfo& info, | 464 const RequestInfo& info, |
467 RequestPriority priority, | 465 RequestPriority priority, |
468 const CompletionCallback& callback, | 466 const CompletionCallback& callback, |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
963 | 961 |
964 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); | 962 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); |
965 }; | 963 }; |
966 | 964 |
967 //----------------------------------------------------------------------------- | 965 //----------------------------------------------------------------------------- |
968 | 966 |
969 // Resolves the hostname using DnsTransaction. | 967 // Resolves the hostname using DnsTransaction. |
970 // TODO(szym): This could be moved to separate source file as well. | 968 // TODO(szym): This could be moved to separate source file as well. |
971 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { | 969 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { |
972 public: | 970 public: |
973 typedef base::Callback<void(int net_error, | 971 class Delegate { |
974 const AddressList& addr_list, | 972 public: |
975 base::TimeDelta ttl)> Callback; | 973 virtual void OnDnsTaskComplete(base::TimeTicks start_time, |
| 974 int net_error, |
| 975 const AddressList& addr_list, |
| 976 base::TimeDelta ttl) = 0; |
| 977 |
| 978 // Called when the first of two jobs succeeds. If the first completed |
| 979 // transaction fails, this is not called. Also not called when the DnsTask |
| 980 // only needs to run one transaction. |
| 981 virtual void OnFirstDnsTransactionComplete() = 0; |
| 982 |
| 983 protected: |
| 984 Delegate() {} |
| 985 virtual ~Delegate() {} |
| 986 }; |
976 | 987 |
977 DnsTask(DnsClient* client, | 988 DnsTask(DnsClient* client, |
978 const Key& key, | 989 const Key& key, |
979 const Callback& callback, | 990 Delegate* delegate, |
980 const BoundNetLog& job_net_log) | 991 const BoundNetLog& job_net_log) |
981 : client_(client), | 992 : client_(client), |
982 family_(key.address_family), | 993 key_(key), |
983 callback_(callback), | 994 delegate_(delegate), |
984 net_log_(job_net_log) { | 995 net_log_(job_net_log), |
| 996 num_completed_transactions_(0), |
| 997 task_start_time_(base::TimeTicks::Now()) { |
985 DCHECK(client); | 998 DCHECK(client); |
986 DCHECK(!callback.is_null()); | 999 DCHECK(delegate_); |
| 1000 } |
987 | 1001 |
988 // If unspecified, do IPv4 first, because suffix search will be faster. | 1002 bool needs_two_transactions() const { |
989 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? | 1003 return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED; |
990 dns_protocol::kTypeAAAA : | 1004 } |
991 dns_protocol::kTypeA; | 1005 |
992 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | 1006 bool needs_another_transaction() const { |
993 key.hostname, | 1007 return needs_two_transactions() && !transaction_aaaa_; |
994 qtype, | 1008 } |
| 1009 |
| 1010 void StartFirstTransaction() { |
| 1011 DCHECK_EQ(0u, num_completed_transactions_); |
| 1012 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); |
| 1013 if (key_.address_family == ADDRESS_FAMILY_IPV6) { |
| 1014 StartAAAA(); |
| 1015 } else { |
| 1016 StartA(); |
| 1017 } |
| 1018 } |
| 1019 |
| 1020 void StartSecondTransaction() { |
| 1021 DCHECK(needs_two_transactions()); |
| 1022 StartAAAA(); |
| 1023 } |
| 1024 |
| 1025 private: |
| 1026 void StartA() { |
| 1027 DCHECK(!transaction_a_); |
| 1028 DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family); |
| 1029 transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4); |
| 1030 transaction_a_->Start(); |
| 1031 } |
| 1032 |
| 1033 void StartAAAA() { |
| 1034 DCHECK(!transaction_aaaa_); |
| 1035 DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family); |
| 1036 transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6); |
| 1037 transaction_aaaa_->Start(); |
| 1038 } |
| 1039 |
| 1040 scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) { |
| 1041 DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family); |
| 1042 return client_->GetTransactionFactory()->CreateTransaction( |
| 1043 key_.hostname, |
| 1044 family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA : |
| 1045 dns_protocol::kTypeA, |
995 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | 1046 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), |
996 true /* first_query */, base::TimeTicks::Now()), | 1047 base::TimeTicks::Now()), |
997 net_log_); | 1048 net_log_); |
998 } | 1049 } |
999 | 1050 |
1000 void Start() { | 1051 void OnTransactionComplete(const base::TimeTicks& start_time, |
1001 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); | |
1002 transaction_->Start(); | |
1003 } | |
1004 | |
1005 private: | |
1006 void OnTransactionComplete(bool first_query, | |
1007 const base::TimeTicks& start_time, | |
1008 DnsTransaction* transaction, | 1052 DnsTransaction* transaction, |
1009 int net_error, | 1053 int net_error, |
1010 const DnsResponse* response) { | 1054 const DnsResponse* response) { |
1011 DCHECK(transaction); | 1055 DCHECK(transaction); |
1012 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | 1056 base::TimeDelta duration = base::TimeTicks::Now() - start_time; |
1013 // Run |callback_| last since the owning Job will then delete this DnsTask. | |
1014 if (net_error != OK) { | 1057 if (net_error != OK) { |
1015 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); | 1058 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); |
1016 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); | 1059 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); |
1017 return; | 1060 return; |
1018 } | 1061 } |
1019 | 1062 |
1020 CHECK(response); | |
1021 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); | 1063 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); |
1022 switch (transaction->GetType()) { | 1064 switch (transaction->GetType()) { |
1023 case dns_protocol::kTypeA: | 1065 case dns_protocol::kTypeA: |
1024 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); | 1066 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); |
1025 break; | 1067 break; |
1026 case dns_protocol::kTypeAAAA: | 1068 case dns_protocol::kTypeAAAA: |
1027 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); | 1069 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); |
1028 break; | 1070 break; |
1029 } | 1071 } |
| 1072 |
1030 AddressList addr_list; | 1073 AddressList addr_list; |
1031 base::TimeDelta ttl; | 1074 base::TimeDelta ttl; |
1032 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); | 1075 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); |
1033 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", | 1076 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", |
1034 result, | 1077 result, |
1035 DnsResponse::DNS_PARSE_RESULT_MAX); | 1078 DnsResponse::DNS_PARSE_RESULT_MAX); |
1036 if (result != DnsResponse::DNS_PARSE_OK) { | 1079 if (result != DnsResponse::DNS_PARSE_OK) { |
1037 // Fail even if the other query succeeds. | 1080 // Fail even if the other query succeeds. |
1038 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); | 1081 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); |
1039 return; | 1082 return; |
1040 } | 1083 } |
1041 | 1084 |
1042 bool needs_sort = false; | 1085 ++num_completed_transactions_; |
1043 if (first_query) { | 1086 if (num_completed_transactions_ == 1) { |
1044 DCHECK(client_->GetConfig()) << | 1087 ttl_ = ttl; |
1045 "Transaction should have been aborted when config changed!"; | |
1046 if (family_ == ADDRESS_FAMILY_IPV6) { | |
1047 needs_sort = (addr_list.size() > 1); | |
1048 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) { | |
1049 first_addr_list_ = addr_list; | |
1050 first_ttl_ = ttl; | |
1051 // Use fully-qualified domain name to avoid search. | |
1052 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | |
1053 response->GetDottedName() + ".", | |
1054 dns_protocol::kTypeAAAA, | |
1055 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | |
1056 false /* first_query */, base::TimeTicks::Now()), | |
1057 net_log_); | |
1058 transaction_->Start(); | |
1059 return; | |
1060 } | |
1061 } else { | 1088 } else { |
1062 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); | 1089 ttl_ = std::min(ttl_, ttl); |
1063 bool has_ipv6_addresses = !addr_list.empty(); | |
1064 if (!first_addr_list_.empty()) { | |
1065 ttl = std::min(ttl, first_ttl_); | |
1066 // Place IPv4 addresses after IPv6. | |
1067 addr_list.insert(addr_list.end(), first_addr_list_.begin(), | |
1068 first_addr_list_.end()); | |
1069 } | |
1070 needs_sort = (has_ipv6_addresses && addr_list.size() > 1); | |
1071 } | 1090 } |
1072 | 1091 |
1073 if (addr_list.empty()) { | 1092 if (transaction->GetType() == dns_protocol::kTypeA) { |
| 1093 DCHECK_EQ(transaction_a_.get(), transaction); |
| 1094 // Place IPv4 addresses after IPv6. |
| 1095 addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end()); |
| 1096 } else { |
| 1097 DCHECK_EQ(transaction_aaaa_.get(), transaction); |
| 1098 // Place IPv6 addresses before IPv4. |
| 1099 addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end()); |
| 1100 } |
| 1101 |
| 1102 if (needs_two_transactions() && num_completed_transactions_ == 1) { |
| 1103 // No need to repeat the suffix search. |
| 1104 key_.hostname = transaction->GetHostname(); |
| 1105 delegate_->OnFirstDnsTransactionComplete(); |
| 1106 return; |
| 1107 } |
| 1108 |
| 1109 if (addr_list_.empty()) { |
1074 // TODO(szym): Don't fallback to ProcTask in this case. | 1110 // TODO(szym): Don't fallback to ProcTask in this case. |
1075 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | 1111 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); |
1076 return; | 1112 return; |
1077 } | 1113 } |
1078 | 1114 |
1079 if (needs_sort) { | 1115 // If there are multiple addresses, and at least one is IPv6, need to sort |
1080 // Sort could complete synchronously. | 1116 // them. Note that IPv6 addresses are always put before IPv4 ones, so it's |
| 1117 // sufficient to just check the family of the first address. |
| 1118 if (addr_list_.size() > 1 && |
| 1119 addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) { |
| 1120 // Sort addresses if needed. Sort could complete synchronously. |
1081 client_->GetAddressSorter()->Sort( | 1121 client_->GetAddressSorter()->Sort( |
1082 addr_list, | 1122 addr_list_, |
1083 base::Bind(&DnsTask::OnSortComplete, | 1123 base::Bind(&DnsTask::OnSortComplete, |
1084 AsWeakPtr(), | 1124 AsWeakPtr(), |
1085 base::TimeTicks::Now(), | 1125 base::TimeTicks::Now())); |
1086 ttl)); | |
1087 } else { | 1126 } else { |
1088 OnSuccess(addr_list, ttl); | 1127 OnSuccess(addr_list_); |
1089 } | 1128 } |
1090 } | 1129 } |
1091 | 1130 |
1092 void OnSortComplete(base::TimeTicks start_time, | 1131 void OnSortComplete(base::TimeTicks start_time, |
1093 base::TimeDelta ttl, | |
1094 bool success, | 1132 bool success, |
1095 const AddressList& addr_list) { | 1133 const AddressList& addr_list) { |
1096 if (!success) { | 1134 if (!success) { |
1097 DNS_HISTOGRAM("AsyncDNS.SortFailure", | 1135 DNS_HISTOGRAM("AsyncDNS.SortFailure", |
1098 base::TimeTicks::Now() - start_time); | 1136 base::TimeTicks::Now() - start_time); |
1099 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); | 1137 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); |
1100 return; | 1138 return; |
1101 } | 1139 } |
1102 | 1140 |
1103 DNS_HISTOGRAM("AsyncDNS.SortSuccess", | 1141 DNS_HISTOGRAM("AsyncDNS.SortSuccess", |
1104 base::TimeTicks::Now() - start_time); | 1142 base::TimeTicks::Now() - start_time); |
1105 | 1143 |
1106 // AddressSorter prunes unusable destinations. | 1144 // AddressSorter prunes unusable destinations. |
1107 if (addr_list.empty()) { | 1145 if (addr_list.empty()) { |
1108 LOG(WARNING) << "Address list empty after RFC3484 sort"; | 1146 LOG(WARNING) << "Address list empty after RFC3484 sort"; |
1109 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | 1147 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); |
1110 return; | 1148 return; |
1111 } | 1149 } |
1112 | 1150 |
1113 OnSuccess(addr_list, ttl); | 1151 OnSuccess(addr_list); |
1114 } | 1152 } |
1115 | 1153 |
1116 void OnFailure(int net_error, DnsResponse::Result result) { | 1154 void OnFailure(int net_error, DnsResponse::Result result) { |
1117 DCHECK_NE(OK, net_error); | 1155 DCHECK_NE(OK, net_error); |
1118 net_log_.EndEvent( | 1156 net_log_.EndEvent( |
1119 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | 1157 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, |
1120 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); | 1158 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); |
1121 callback_.Run(net_error, AddressList(), base::TimeDelta()); | 1159 delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(), |
| 1160 base::TimeDelta()); |
1122 } | 1161 } |
1123 | 1162 |
1124 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { | 1163 void OnSuccess(const AddressList& addr_list) { |
1125 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | 1164 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, |
1126 addr_list.CreateNetLogCallback()); | 1165 addr_list.CreateNetLogCallback()); |
1127 callback_.Run(OK, addr_list, ttl); | 1166 delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_); |
1128 } | 1167 } |
1129 | 1168 |
1130 DnsClient* client_; | 1169 DnsClient* client_; |
1131 AddressFamily family_; | 1170 Key key_; |
| 1171 |
1132 // The listener to the results of this DnsTask. | 1172 // The listener to the results of this DnsTask. |
1133 Callback callback_; | 1173 Delegate* delegate_; |
1134 const BoundNetLog net_log_; | 1174 const BoundNetLog net_log_; |
1135 | 1175 |
1136 scoped_ptr<DnsTransaction> transaction_; | 1176 scoped_ptr<DnsTransaction> transaction_a_; |
| 1177 scoped_ptr<DnsTransaction> transaction_aaaa_; |
1137 | 1178 |
1138 // Results from the first transaction. Used only if |family_| is unspecified. | 1179 unsigned num_completed_transactions_; |
1139 AddressList first_addr_list_; | 1180 |
1140 base::TimeDelta first_ttl_; | 1181 // These are updated as each transaction completes. |
| 1182 base::TimeDelta ttl_; |
| 1183 // IPv6 addresses must appear first in the list. |
| 1184 AddressList addr_list_; |
| 1185 |
| 1186 base::TimeTicks task_start_time_; |
1141 | 1187 |
1142 DISALLOW_COPY_AND_ASSIGN(DnsTask); | 1188 DISALLOW_COPY_AND_ASSIGN(DnsTask); |
1143 }; | 1189 }; |
1144 | 1190 |
1145 //----------------------------------------------------------------------------- | 1191 //----------------------------------------------------------------------------- |
1146 | 1192 |
1147 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. | 1193 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. |
1148 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { | 1194 class HostResolverImpl::Job : public PrioritizedDispatcher::Job, |
| 1195 public HostResolverImpl::DnsTask::Delegate { |
1149 public: | 1196 public: |
1150 // Creates new job for |key| where |request_net_log| is bound to the | 1197 // Creates new job for |key| where |request_net_log| is bound to the |
1151 // request that spawned it. | 1198 // request that spawned it. |
1152 Job(const base::WeakPtr<HostResolverImpl>& resolver, | 1199 Job(const base::WeakPtr<HostResolverImpl>& resolver, |
1153 const Key& key, | 1200 const Key& key, |
1154 RequestPriority priority, | 1201 RequestPriority priority, |
1155 const BoundNetLog& request_net_log) | 1202 const BoundNetLog& request_net_log) |
1156 : resolver_(resolver), | 1203 : resolver_(resolver), |
1157 key_(key), | 1204 key_(key), |
1158 priority_tracker_(priority), | 1205 priority_tracker_(priority), |
1159 had_non_speculative_request_(false), | 1206 had_non_speculative_request_(false), |
1160 had_dns_config_(false), | 1207 had_dns_config_(false), |
| 1208 num_occupied_job_slots_(0), |
1161 dns_task_error_(OK), | 1209 dns_task_error_(OK), |
1162 creation_time_(base::TimeTicks::Now()), | 1210 creation_time_(base::TimeTicks::Now()), |
1163 priority_change_time_(creation_time_), | 1211 priority_change_time_(creation_time_), |
1164 net_log_(BoundNetLog::Make(request_net_log.net_log(), | 1212 net_log_(BoundNetLog::Make(request_net_log.net_log(), |
1165 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { | 1213 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { |
1166 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); | 1214 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); |
1167 | 1215 |
1168 net_log_.BeginEvent( | 1216 net_log_.BeginEvent( |
1169 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | 1217 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
1170 base::Bind(&NetLogJobCreationCallback, | 1218 base::Bind(&NetLogJobCreationCallback, |
1171 request_net_log.source(), | 1219 request_net_log.source(), |
1172 &key_.hostname)); | 1220 &key_.hostname)); |
1173 } | 1221 } |
1174 | 1222 |
1175 virtual ~Job() { | 1223 virtual ~Job() { |
1176 if (is_running()) { | 1224 if (is_running()) { |
1177 // |resolver_| was destroyed with this Job still in flight. | 1225 // |resolver_| was destroyed with this Job still in flight. |
1178 // Clean-up, record in the log, but don't run any callbacks. | 1226 // Clean-up, record in the log, but don't run any callbacks. |
1179 if (is_proc_running()) { | 1227 if (is_proc_running()) { |
1180 proc_task_->Cancel(); | 1228 proc_task_->Cancel(); |
1181 proc_task_ = NULL; | 1229 proc_task_ = NULL; |
1182 } | 1230 } |
1183 // Clean up now for nice NetLog. | 1231 // Clean up now for nice NetLog. |
1184 dns_task_.reset(NULL); | 1232 KillDnsTask(); |
1185 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | 1233 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
1186 ERR_ABORTED); | 1234 ERR_ABORTED); |
1187 } else if (is_queued()) { | 1235 } else if (is_queued()) { |
1188 // |resolver_| was destroyed without running this Job. | 1236 // |resolver_| was destroyed without running this Job. |
1189 // TODO(szym): is there any benefit in having this distinction? | 1237 // TODO(szym): is there any benefit in having this distinction? |
1190 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | 1238 net_log_.AddEvent(NetLog::TYPE_CANCELLED); |
1191 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); | 1239 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); |
1192 } | 1240 } |
1193 // else CompleteRequests logged EndEvent. | 1241 // else CompleteRequests logged EndEvent. |
1194 | 1242 |
1195 // Log any remaining Requests as cancelled. | 1243 // Log any remaining Requests as cancelled. |
1196 for (RequestsList::const_iterator it = requests_.begin(); | 1244 for (RequestsList::const_iterator it = requests_.begin(); |
1197 it != requests_.end(); ++it) { | 1245 it != requests_.end(); ++it) { |
1198 Request* req = *it; | 1246 Request* req = *it; |
1199 if (req->was_canceled()) | 1247 if (req->was_canceled()) |
1200 continue; | 1248 continue; |
1201 DCHECK_EQ(this, req->job()); | 1249 DCHECK_EQ(this, req->job()); |
1202 LogCancelRequest(req->source_net_log(), req->request_net_log(), | 1250 LogCancelRequest(req->source_net_log(), req->request_net_log(), |
1203 req->info()); | 1251 req->info()); |
1204 } | 1252 } |
1205 } | 1253 } |
1206 | 1254 |
1207 // Add this job to the dispatcher. | 1255 // Add this job to the dispatcher. If "at_head" is true, adds at the front |
1208 void Schedule() { | 1256 // of the queue. |
1209 handle_ = resolver_->dispatcher_.Add(this, priority()); | 1257 void Schedule(bool at_head) { |
| 1258 DCHECK(!is_queued()); |
| 1259 PrioritizedDispatcher::Handle handle; |
| 1260 if (!at_head) { |
| 1261 handle = resolver_->dispatcher_.Add(this, priority()); |
| 1262 } else { |
| 1263 handle = resolver_->dispatcher_.AddAtHead(this, priority()); |
| 1264 } |
| 1265 // The dispatcher could have started |this| in the above call to Add, which |
| 1266 // could have called Schedule again. In that case |handle| will be null, |
| 1267 // but |handle_| may have been set by the other nested call to Schedule. |
| 1268 if (!handle.is_null()) { |
| 1269 DCHECK(handle_.is_null()); |
| 1270 handle_ = handle; |
| 1271 } |
1210 } | 1272 } |
1211 | 1273 |
1212 void AddRequest(scoped_ptr<Request> req) { | 1274 void AddRequest(scoped_ptr<Request> req) { |
1213 DCHECK_EQ(key_.hostname, req->info().hostname()); | 1275 DCHECK_EQ(key_.hostname, req->info().hostname()); |
1214 | 1276 |
1215 req->set_job(this); | 1277 req->set_job(this); |
1216 priority_tracker_.Add(req->priority()); | 1278 priority_tracker_.Add(req->priority()); |
1217 | 1279 |
1218 req->request_net_log().AddEvent( | 1280 req->request_net_log().AddEvent( |
1219 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, | 1281 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1267 // Called from AbortAllInProgressJobs. Completes all requests and destroys | 1329 // Called from AbortAllInProgressJobs. Completes all requests and destroys |
1268 // the job. This currently assumes the abort is due to a network change. | 1330 // the job. This currently assumes the abort is due to a network change. |
1269 void Abort() { | 1331 void Abort() { |
1270 DCHECK(is_running()); | 1332 DCHECK(is_running()); |
1271 CompleteRequestsWithError(ERR_NETWORK_CHANGED); | 1333 CompleteRequestsWithError(ERR_NETWORK_CHANGED); |
1272 } | 1334 } |
1273 | 1335 |
1274 // If DnsTask present, abort it and fall back to ProcTask. | 1336 // If DnsTask present, abort it and fall back to ProcTask. |
1275 void AbortDnsTask() { | 1337 void AbortDnsTask() { |
1276 if (dns_task_) { | 1338 if (dns_task_) { |
1277 dns_task_.reset(); | 1339 KillDnsTask(); |
1278 dns_task_error_ = OK; | 1340 dns_task_error_ = OK; |
1279 StartProcTask(); | 1341 StartProcTask(); |
1280 } | 1342 } |
1281 } | 1343 } |
1282 | 1344 |
1283 // Called by HostResolverImpl when this job is evicted due to queue overflow. | 1345 // Called by HostResolverImpl when this job is evicted due to queue overflow. |
1284 // Completes all requests and destroys the job. | 1346 // Completes all requests and destroys the job. |
1285 void OnEvicted() { | 1347 void OnEvicted() { |
1286 DCHECK(!is_running()); | 1348 DCHECK(!is_running()); |
1287 DCHECK(is_queued()); | 1349 DCHECK(is_queued()); |
(...skipping 28 matching lines...) Expand all Loading... |
1316 | 1378 |
1317 bool is_queued() const { | 1379 bool is_queued() const { |
1318 return !handle_.is_null(); | 1380 return !handle_.is_null(); |
1319 } | 1381 } |
1320 | 1382 |
1321 bool is_running() const { | 1383 bool is_running() const { |
1322 return is_dns_running() || is_proc_running(); | 1384 return is_dns_running() || is_proc_running(); |
1323 } | 1385 } |
1324 | 1386 |
1325 private: | 1387 private: |
| 1388 void KillDnsTask() { |
| 1389 if (dns_task_) { |
| 1390 ReduceToOneJobSlot(); |
| 1391 dns_task_.reset(); |
| 1392 } |
| 1393 } |
| 1394 |
| 1395 // Reduce the number of job slots occupied and queued in the dispatcher |
| 1396 // to one. If the second Job slot is queued in the dispatcher, cancels the |
| 1397 // queued job. Otherwise, the second Job has been started by the |
| 1398 // PrioritizedDispatcher, so signals it is complete. |
| 1399 void ReduceToOneJobSlot() { |
| 1400 DCHECK_GE(num_occupied_job_slots_, 1u); |
| 1401 if (is_queued()) { |
| 1402 resolver_->dispatcher_.Cancel(handle_); |
| 1403 handle_.Reset(); |
| 1404 } else if (num_occupied_job_slots_ > 1) { |
| 1405 resolver_->dispatcher_.OnJobFinished(); |
| 1406 --num_occupied_job_slots_; |
| 1407 } |
| 1408 DCHECK_EQ(1u, num_occupied_job_slots_); |
| 1409 } |
| 1410 |
1326 void UpdatePriority() { | 1411 void UpdatePriority() { |
1327 if (is_queued()) { | 1412 if (is_queued()) { |
1328 if (priority() != static_cast<RequestPriority>(handle_.priority())) | 1413 if (priority() != static_cast<RequestPriority>(handle_.priority())) |
1329 priority_change_time_ = base::TimeTicks::Now(); | 1414 priority_change_time_ = base::TimeTicks::Now(); |
1330 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); | 1415 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); |
1331 } | 1416 } |
1332 } | 1417 } |
1333 | 1418 |
1334 AddressList MakeAddressListForRequest(const AddressList& list) const { | 1419 AddressList MakeAddressListForRequest(const AddressList& list) const { |
1335 if (requests_.empty()) | 1420 if (requests_.empty()) |
1336 return list; | 1421 return list; |
1337 return AddressList::CopyWithPort(list, requests_.front()->info().port()); | 1422 return AddressList::CopyWithPort(list, requests_.front()->info().port()); |
1338 } | 1423 } |
1339 | 1424 |
1340 // PriorityDispatch::Job: | 1425 // PriorityDispatch::Job: |
1341 virtual void Start() OVERRIDE { | 1426 virtual void Start() OVERRIDE { |
| 1427 DCHECK_LE(num_occupied_job_slots_, 1u); |
| 1428 |
| 1429 handle_.Reset(); |
| 1430 ++num_occupied_job_slots_; |
| 1431 |
| 1432 if (num_occupied_job_slots_ == 2) { |
| 1433 StartSecondDnsTransaction(); |
| 1434 return; |
| 1435 } |
| 1436 |
1342 DCHECK(!is_running()); | 1437 DCHECK(!is_running()); |
1343 handle_.Reset(); | |
1344 | 1438 |
1345 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); | 1439 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); |
1346 | 1440 |
1347 had_dns_config_ = resolver_->HaveDnsConfig(); | 1441 had_dns_config_ = resolver_->HaveDnsConfig(); |
1348 | 1442 |
1349 base::TimeTicks now = base::TimeTicks::Now(); | 1443 base::TimeTicks now = base::TimeTicks::Now(); |
1350 base::TimeDelta queue_time = now - creation_time_; | 1444 base::TimeDelta queue_time = now - creation_time_; |
1351 base::TimeDelta queue_time_after_change = now - priority_change_time_; | 1445 base::TimeDelta queue_time_after_change = now - priority_change_time_; |
1352 | 1446 |
1353 if (had_dns_config_) { | 1447 if (had_dns_config_) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1437 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | 1531 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); |
1438 | 1532 |
1439 // Don't store the |ttl| in cache since it's not obtained from the server. | 1533 // Don't store the |ttl| in cache since it's not obtained from the server. |
1440 CompleteRequests( | 1534 CompleteRequests( |
1441 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), | 1535 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), |
1442 ttl); | 1536 ttl); |
1443 } | 1537 } |
1444 | 1538 |
1445 void StartDnsTask() { | 1539 void StartDnsTask() { |
1446 DCHECK(resolver_->HaveDnsConfig()); | 1540 DCHECK(resolver_->HaveDnsConfig()); |
1447 base::TimeTicks start_time = base::TimeTicks::Now(); | 1541 dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this, |
1448 dns_task_.reset(new DnsTask( | 1542 net_log_)); |
1449 resolver_->dns_client_.get(), | |
1450 key_, | |
1451 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time), | |
1452 net_log_)); | |
1453 | 1543 |
1454 dns_task_->Start(); | 1544 dns_task_->StartFirstTransaction(); |
| 1545 // Schedule a second transaction, if needed. |
| 1546 if (dns_task_->needs_two_transactions()) |
| 1547 Schedule(true); |
| 1548 } |
| 1549 |
| 1550 void StartSecondDnsTransaction() { |
| 1551 DCHECK(dns_task_->needs_two_transactions()); |
| 1552 dns_task_->StartSecondTransaction(); |
1455 } | 1553 } |
1456 | 1554 |
1457 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be | 1555 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be |
1458 // deleted before this callback. In this case dns_task is deleted as well, | 1556 // deleted before this callback. In this case dns_task is deleted as well, |
1459 // so we use it as indicator whether Job is still valid. | 1557 // so we use it as indicator whether Job is still valid. |
1460 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, | 1558 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, |
1461 base::TimeDelta duration, | 1559 base::TimeDelta duration, |
1462 int net_error) { | 1560 int net_error) { |
1463 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); | 1561 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); |
1464 | 1562 |
1465 if (dns_task == NULL) | 1563 if (dns_task == NULL) |
1466 return; | 1564 return; |
1467 | 1565 |
1468 dns_task_error_ = net_error; | 1566 dns_task_error_ = net_error; |
1469 | 1567 |
1470 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. | 1568 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. |
1471 // http://crbug.com/117655 | 1569 // http://crbug.com/117655 |
1472 | 1570 |
1473 // TODO(szym): Some net errors indicate lack of connectivity. Starting | 1571 // TODO(szym): Some net errors indicate lack of connectivity. Starting |
1474 // ProcTask in that case is a waste of time. | 1572 // ProcTask in that case is a waste of time. |
1475 if (resolver_->fallback_to_proctask_) { | 1573 if (resolver_->fallback_to_proctask_) { |
1476 dns_task_.reset(); | 1574 KillDnsTask(); |
1477 StartProcTask(); | 1575 StartProcTask(); |
1478 } else { | 1576 } else { |
1479 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); | 1577 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); |
1480 CompleteRequestsWithError(net_error); | 1578 CompleteRequestsWithError(net_error); |
1481 } | 1579 } |
1482 } | 1580 } |
1483 | 1581 |
1484 // Called by DnsTask when it completes. | 1582 |
1485 void OnDnsTaskComplete(base::TimeTicks start_time, | 1583 // HostResolverImpl::DnsTask::Delegate implementation: |
1486 int net_error, | 1584 |
1487 const AddressList& addr_list, | 1585 virtual void OnDnsTaskComplete(base::TimeTicks start_time, |
1488 base::TimeDelta ttl) { | 1586 int net_error, |
| 1587 const AddressList& addr_list, |
| 1588 base::TimeDelta ttl) OVERRIDE { |
1489 DCHECK(is_dns_running()); | 1589 DCHECK(is_dns_running()); |
1490 | 1590 |
1491 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | 1591 base::TimeDelta duration = base::TimeTicks::Now() - start_time; |
1492 if (net_error != OK) { | 1592 if (net_error != OK) { |
1493 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); | 1593 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); |
1494 return; | 1594 return; |
1495 } | 1595 } |
1496 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); | 1596 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); |
1497 // Log DNS lookups based on |address_family|. | 1597 // Log DNS lookups based on |address_family|. |
1498 switch(key_.address_family) { | 1598 switch(key_.address_family) { |
(...skipping 14 matching lines...) Expand all Loading... |
1513 resolver_->OnDnsTaskResolve(OK); | 1613 resolver_->OnDnsTaskResolve(OK); |
1514 | 1614 |
1515 base::TimeDelta bounded_ttl = | 1615 base::TimeDelta bounded_ttl = |
1516 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); | 1616 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); |
1517 | 1617 |
1518 CompleteRequests( | 1618 CompleteRequests( |
1519 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), | 1619 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), |
1520 bounded_ttl); | 1620 bounded_ttl); |
1521 } | 1621 } |
1522 | 1622 |
| 1623 virtual void OnFirstDnsTransactionComplete() OVERRIDE { |
| 1624 DCHECK(dns_task_->needs_two_transactions()); |
| 1625 DCHECK_EQ(dns_task_->needs_another_transaction(), is_queued()); |
| 1626 // No longer need to occupy two dispatcher slots. |
| 1627 ReduceToOneJobSlot(); |
| 1628 |
| 1629 // We already have a job slot at the dispatcher, so if the second |
| 1630 // transaction hasn't started, reuse it now instead of waiting in the queue |
| 1631 // for the second slot. |
| 1632 if (dns_task_->needs_another_transaction()) |
| 1633 dns_task_->StartSecondTransaction(); |
| 1634 } |
| 1635 |
1523 // Performs Job's last rites. Completes all Requests. Deletes this. | 1636 // Performs Job's last rites. Completes all Requests. Deletes this. |
1524 void CompleteRequests(const HostCache::Entry& entry, | 1637 void CompleteRequests(const HostCache::Entry& entry, |
1525 base::TimeDelta ttl) { | 1638 base::TimeDelta ttl) { |
1526 CHECK(resolver_.get()); | 1639 CHECK(resolver_.get()); |
1527 | 1640 |
1528 // This job must be removed from resolver's |jobs_| now to make room for a | 1641 // This job must be removed from resolver's |jobs_| now to make room for a |
1529 // new job with the same key in case one of the OnComplete callbacks decides | 1642 // new job with the same key in case one of the OnComplete callbacks decides |
1530 // to spawn one. Consequently, the job deletes itself when CompleteRequests | 1643 // to spawn one. Consequently, the job deletes itself when CompleteRequests |
1531 // is done. | 1644 // is done. |
1532 scoped_ptr<Job> self_deleter(this); | 1645 scoped_ptr<Job> self_deleter(this); |
1533 | 1646 |
1534 resolver_->RemoveJob(this); | 1647 resolver_->RemoveJob(this); |
1535 | 1648 |
1536 if (is_running()) { | 1649 if (is_running()) { |
1537 DCHECK(!is_queued()); | |
1538 if (is_proc_running()) { | 1650 if (is_proc_running()) { |
| 1651 DCHECK(!is_queued()); |
1539 proc_task_->Cancel(); | 1652 proc_task_->Cancel(); |
1540 proc_task_ = NULL; | 1653 proc_task_ = NULL; |
1541 } | 1654 } |
1542 dns_task_.reset(); | 1655 KillDnsTask(); |
1543 | 1656 |
1544 // Signal dispatcher that a slot has opened. | 1657 // Signal dispatcher that a slot has opened. |
1545 resolver_->dispatcher_.OnJobFinished(); | 1658 resolver_->dispatcher_.OnJobFinished(); |
1546 } else if (is_queued()) { | 1659 } else if (is_queued()) { |
1547 resolver_->dispatcher_.Cancel(handle_); | 1660 resolver_->dispatcher_.Cancel(handle_); |
1548 handle_.Reset(); | 1661 handle_.Reset(); |
1549 } | 1662 } |
1550 | 1663 |
1551 if (num_active_requests() == 0) { | 1664 if (num_active_requests() == 0) { |
1552 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | 1665 net_log_.AddEvent(NetLog::TYPE_CANCELLED); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1626 Key key_; | 1739 Key key_; |
1627 | 1740 |
1628 // Tracks the highest priority across |requests_|. | 1741 // Tracks the highest priority across |requests_|. |
1629 PriorityTracker priority_tracker_; | 1742 PriorityTracker priority_tracker_; |
1630 | 1743 |
1631 bool had_non_speculative_request_; | 1744 bool had_non_speculative_request_; |
1632 | 1745 |
1633 // Distinguishes measurements taken while DnsClient was fully configured. | 1746 // Distinguishes measurements taken while DnsClient was fully configured. |
1634 bool had_dns_config_; | 1747 bool had_dns_config_; |
1635 | 1748 |
| 1749 // Number of slots occupied by this Job in resolver's PrioritizedDispatcher. |
| 1750 unsigned num_occupied_job_slots_; |
| 1751 |
1636 // Result of DnsTask. | 1752 // Result of DnsTask. |
1637 int dns_task_error_; | 1753 int dns_task_error_; |
1638 | 1754 |
1639 const base::TimeTicks creation_time_; | 1755 const base::TimeTicks creation_time_; |
1640 base::TimeTicks priority_change_time_; | 1756 base::TimeTicks priority_change_time_; |
1641 | 1757 |
1642 BoundNetLog net_log_; | 1758 BoundNetLog net_log_; |
1643 | 1759 |
1644 // Resolves the host using a HostResolverProc. | 1760 // Resolves the host using a HostResolverProc. |
1645 scoped_refptr<ProcTask> proc_task_; | 1761 scoped_refptr<ProcTask> proc_task_; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1713 { | 1829 { |
1714 DnsConfig dns_config; | 1830 DnsConfig dns_config; |
1715 NetworkChangeNotifier::GetDnsConfig(&dns_config); | 1831 NetworkChangeNotifier::GetDnsConfig(&dns_config); |
1716 received_dns_config_ = dns_config.IsValid(); | 1832 received_dns_config_ = dns_config.IsValid(); |
1717 } | 1833 } |
1718 | 1834 |
1719 fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial(); | 1835 fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial(); |
1720 } | 1836 } |
1721 | 1837 |
1722 HostResolverImpl::~HostResolverImpl() { | 1838 HostResolverImpl::~HostResolverImpl() { |
1723 // This will also cancel all outstanding requests. | 1839 // Prevent the dispatcher from starting new jobs. |
| 1840 dispatcher_.SetLimitsToZero(); |
| 1841 // It's now safe for Jobs to call KillDsnTask on destruction, because |
| 1842 // OnJobComplete will not start any new jobs. |
1724 STLDeleteValues(&jobs_); | 1843 STLDeleteValues(&jobs_); |
1725 | 1844 |
1726 NetworkChangeNotifier::RemoveIPAddressObserver(this); | 1845 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
1727 NetworkChangeNotifier::RemoveDNSObserver(this); | 1846 NetworkChangeNotifier::RemoveDNSObserver(this); |
1728 } | 1847 } |
1729 | 1848 |
1730 void HostResolverImpl::SetMaxQueuedJobs(size_t value) { | 1849 void HostResolverImpl::SetMaxQueuedJobs(size_t value) { |
1731 DCHECK_EQ(0u, dispatcher_.num_queued_jobs()); | 1850 DCHECK_EQ(0u, dispatcher_.num_queued_jobs()); |
1732 DCHECK_GT(value, 0u); | 1851 DCHECK_GT(value, 0u); |
1733 max_queued_jobs_ = value; | 1852 max_queued_jobs_ = value; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1766 } | 1885 } |
1767 | 1886 |
1768 // Next we need to attach our request to a "job". This job is responsible for | 1887 // Next we need to attach our request to a "job". This job is responsible for |
1769 // calling "getaddrinfo(hostname)" on a worker thread. | 1888 // calling "getaddrinfo(hostname)" on a worker thread. |
1770 | 1889 |
1771 JobMap::iterator jobit = jobs_.find(key); | 1890 JobMap::iterator jobit = jobs_.find(key); |
1772 Job* job; | 1891 Job* job; |
1773 if (jobit == jobs_.end()) { | 1892 if (jobit == jobs_.end()) { |
1774 job = | 1893 job = |
1775 new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log); | 1894 new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log); |
1776 job->Schedule(); | 1895 job->Schedule(false); |
1777 | 1896 |
1778 // Check for queue overflow. | 1897 // Check for queue overflow. |
1779 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { | 1898 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { |
1780 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); | 1899 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); |
1781 DCHECK(evicted); | 1900 DCHECK(evicted); |
1782 evicted->OnEvicted(); // Deletes |evicted|. | 1901 evicted->OnEvicted(); // Deletes |evicted|. |
1783 if (evicted == job) { | 1902 if (evicted == job) { |
1784 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; | 1903 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; |
1785 LogFinishRequest(source_net_log, request_net_log, info, rv); | 1904 LogFinishRequest(source_net_log, request_net_log, info, rv); |
1786 return rv; | 1905 return rv; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2063 Job* job = it->second; | 2182 Job* job = it->second; |
2064 if (job->is_running()) { | 2183 if (job->is_running()) { |
2065 jobs_to_abort.push_back(job); | 2184 jobs_to_abort.push_back(job); |
2066 jobs_.erase(it++); | 2185 jobs_.erase(it++); |
2067 } else { | 2186 } else { |
2068 DCHECK(job->is_queued()); | 2187 DCHECK(job->is_queued()); |
2069 ++it; | 2188 ++it; |
2070 } | 2189 } |
2071 } | 2190 } |
2072 | 2191 |
2073 // Check if no dispatcher slots leaked out. | 2192 // Pause the dispatcher so it won't start any new dispatcher jobs while |
2074 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size()); | 2193 // aborting the old ones. This is needed so that it won't start the second |
| 2194 // DnsTransaction for a job in |jobs_to_abort| if the DnsConfig just became |
| 2195 // invalid. |
| 2196 PrioritizedDispatcher::Limits limits = dispatcher_.GetLimits(); |
| 2197 dispatcher_.SetLimits( |
| 2198 PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0)); |
2075 | 2199 |
2076 // Life check to bail once |this| is deleted. | 2200 // Life check to bail once |this| is deleted. |
2077 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); | 2201 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); |
2078 | 2202 |
2079 // Then Abort them. | 2203 // Then Abort them. |
2080 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { | 2204 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { |
2081 jobs_to_abort[i]->Abort(); | 2205 jobs_to_abort[i]->Abort(); |
2082 jobs_to_abort[i] = NULL; | 2206 jobs_to_abort[i] = NULL; |
2083 } | 2207 } |
| 2208 |
| 2209 if (self) |
| 2210 dispatcher_.SetLimits(limits); |
| 2211 } |
| 2212 |
| 2213 void HostResolverImpl::AbortDnsTasks() { |
| 2214 // Pause the dispatcher so it won't start any new dispatcher jobs while |
| 2215 // aborting the old ones. This is needed so that it won't start the second |
| 2216 // DnsTransaction for a job if the DnsConfig just changed. |
| 2217 PrioritizedDispatcher::Limits limits = dispatcher_.GetLimits(); |
| 2218 dispatcher_.SetLimits( |
| 2219 PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0)); |
| 2220 |
| 2221 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 2222 it->second->AbortDnsTask(); |
| 2223 dispatcher_.SetLimits(limits); |
2084 } | 2224 } |
2085 | 2225 |
2086 void HostResolverImpl::TryServingAllJobsFromHosts() { | 2226 void HostResolverImpl::TryServingAllJobsFromHosts() { |
2087 if (!HaveDnsConfig()) | 2227 if (!HaveDnsConfig()) |
2088 return; | 2228 return; |
2089 | 2229 |
2090 // TODO(szym): Do not do this if nsswitch.conf instructs not to. | 2230 // TODO(szym): Do not do this if nsswitch.conf instructs not to. |
2091 // http://crbug.com/117655 | 2231 // http://crbug.com/117655 |
2092 | 2232 |
2093 // Life check to bail once |this| is deleted. | 2233 // Life check to bail once |this| is deleted. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2168 | 2308 |
2169 void HostResolverImpl::OnDnsTaskResolve(int net_error) { | 2309 void HostResolverImpl::OnDnsTaskResolve(int net_error) { |
2170 DCHECK(dns_client_); | 2310 DCHECK(dns_client_); |
2171 if (net_error == OK) { | 2311 if (net_error == OK) { |
2172 num_dns_failures_ = 0; | 2312 num_dns_failures_ = 0; |
2173 return; | 2313 return; |
2174 } | 2314 } |
2175 ++num_dns_failures_; | 2315 ++num_dns_failures_; |
2176 if (num_dns_failures_ < kMaximumDnsFailures) | 2316 if (num_dns_failures_ < kMaximumDnsFailures) |
2177 return; | 2317 return; |
2178 // Disable DnsClient until the next DNS change. | 2318 |
2179 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 2319 // Disable DnsClient until the next DNS change. Must be done before aborting |
2180 it->second->AbortDnsTask(); | 2320 // DnsTasks, since doing so may start new jobs. |
2181 dns_client_->SetConfig(DnsConfig()); | 2321 dns_client_->SetConfig(DnsConfig()); |
| 2322 |
| 2323 // Switch jobs with active DnsTasks over to using ProcTasks. |
| 2324 AbortDnsTasks(); |
| 2325 |
2182 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false); | 2326 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false); |
2183 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.DnsClientDisabledReason", | 2327 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.DnsClientDisabledReason", |
2184 std::abs(net_error), | 2328 std::abs(net_error), |
2185 GetAllErrorCodesForUma()); | 2329 GetAllErrorCodesForUma()); |
2186 } | 2330 } |
2187 | 2331 |
2188 void HostResolverImpl::SetDnsClient(scoped_ptr<DnsClient> dns_client) { | 2332 void HostResolverImpl::SetDnsClient(scoped_ptr<DnsClient> dns_client) { |
2189 if (HaveDnsConfig()) { | 2333 // DnsClient and config must be updated before aborting DnsTasks, since doing |
2190 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 2334 // so may start new jobs. |
2191 it->second->AbortDnsTask(); | 2335 dns_client_ = dns_client.Pass(); |
| 2336 if (dns_client_ && !dns_client_->GetConfig() && |
| 2337 num_dns_failures_ < kMaximumDnsFailures) { |
| 2338 DnsConfig dns_config; |
| 2339 NetworkChangeNotifier::GetDnsConfig(&dns_config); |
| 2340 dns_client_->SetConfig(dns_config); |
| 2341 num_dns_failures_ = 0; |
| 2342 if (dns_client_->GetConfig()) |
| 2343 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); |
2192 } | 2344 } |
2193 dns_client_ = dns_client.Pass(); | 2345 |
2194 if (!dns_client_ || dns_client_->GetConfig() || | 2346 AbortDnsTasks(); |
2195 num_dns_failures_ >= kMaximumDnsFailures) { | |
2196 return; | |
2197 } | |
2198 DnsConfig dns_config; | |
2199 NetworkChangeNotifier::GetDnsConfig(&dns_config); | |
2200 dns_client_->SetConfig(dns_config); | |
2201 num_dns_failures_ = 0; | |
2202 if (dns_client_->GetConfig()) | |
2203 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); | |
2204 } | 2347 } |
2205 | 2348 |
2206 } // namespace net | 2349 } // namespace net |
OLD | NEW |